public inbox for newlib@sourceware.org
 help / color / mirror / Atom feed
* bug with printf positional arguments?
@ 2023-06-28 13:28 Jon Turney
  2023-07-03 11:14 ` Corinna Vinschen
  0 siblings, 1 reply; 4+ messages in thread
From: Jon Turney @ 2023-06-28 13:28 UTC (permalink / raw)
  To: newlib


The following trivial program (extracted from a glib testcase)

> #include <stdio.h>
> 
> int main()
> {
>   printf ("%1$*2$.*3$s", "abc", 5, 2);
> }

does not produce the expected output of "   ab", on 64-bit Cygwin.

 From a bit of staring at and stepping through get_args() in 
libc/stdio/vfprintf.c, it looks like the problem is (something like) we 
don't have the knowledge that the first positional variadic argument 
should be treated as a pointer, at the point that we store it's value, 
so it gets treated as an integer (the default), which is going to lead 
to truncation on LP64 platforms.

A straightforward way to fix this eludes me.

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: bug with printf positional arguments?
  2023-06-28 13:28 bug with printf positional arguments? Jon Turney
@ 2023-07-03 11:14 ` Corinna Vinschen
  2023-07-03 14:49   ` Jon Turney
  0 siblings, 1 reply; 4+ messages in thread
From: Corinna Vinschen @ 2023-07-03 11:14 UTC (permalink / raw)
  To: Jon Turney; +Cc: newlib

On Jun 28 14:28, Jon Turney wrote:
> 
> The following trivial program (extracted from a glib testcase)
> 
> > #include <stdio.h>
> > 
> > int main()
> > {
> >   printf ("%1$*2$.*3$s", "abc", 5, 2);
> > }
> 
> does not produce the expected output of "   ab", on 64-bit Cygwin.
> 
> From a bit of staring at and stepping through get_args() in
> libc/stdio/vfprintf.c, it looks like the problem is (something like) we
> don't have the knowledge that the first positional variadic argument should
> be treated as a pointer, at the point that we store it's value, so it gets
> treated as an integer (the default), which is going to lead to truncation on
> LP64 platforms.
> 
> A straightforward way to fix this eludes me.

Can you point out where in the code this problem occurs, so maybe
we can discuss the necessary code changes in this thread?


Thanks,
Corinna


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: bug with printf positional arguments?
  2023-07-03 11:14 ` Corinna Vinschen
@ 2023-07-03 14:49   ` Jon Turney
  2023-07-26 13:26     ` Corinna Vinschen
  0 siblings, 1 reply; 4+ messages in thread
From: Jon Turney @ 2023-07-03 14:49 UTC (permalink / raw)
  To: newlib

On 03/07/2023 12:14, Corinna Vinschen wrote:
> On Jun 28 14:28, Jon Turney wrote:
>>
>> The following trivial program (extracted from a glib testcase)
>>
>>> #include <stdio.h>
>>>
>>> int main()
>>> {
>>>    printf ("%1$*2$.*3$s", "abc", 5, 2);
>>> }
>>
>> does not produce the expected output of "   ab", on 64-bit Cygwin.
>>
>>  From a bit of staring at and stepping through get_args() in
>> libc/stdio/vfprintf.c, it looks like the problem is (something like) we
>> don't have the knowledge that the first positional variadic argument should
>> be treated as a pointer, at the point that we store it's value, so it gets
>> treated as an integer (the default), which is going to lead to truncation on
>> LP64 platforms.
>>
>> A straightforward way to fix this eludes me.
> 
> Can you point out where in the code this problem occurs, so maybe
> we can discuss the necessary code changes in this thread?

Sure, I'll try:

Let's suppose you're executing the STC above. This is what I think 
happens...

We end up in _vprintf_r.

We hit line 1072, which digests the '1', and on the following '$', knows 
to interpret this as a positional argument and stores it.

The subsequent '*' is processed at line 967 as introducing the width, 
where we chomp the '2', which again the following '$' indicates should 
be treated as a positional arg.

We hit GET_ARG for the first time, to retrieve the width, which invokes 
get_arg() to do the work (as we haven't yet stored the requested arg in 
args[]).

get_arg() digests the format string (again) using a state machine (to 
populate args[] with the positional parameters)

The state machine moves through START (action NUMBER) -> WDIG (action 
GETPOS) -> DONE.

Stopping here looks like maybe an error in the state machine design?

The loop starting at line 2310 iterates over the seen args, fetching 
their values. Because we haven't processed the 's' at the end in the 
GETARG state, we retrieve the first argument using the default case, as 
an integer (32 bits, truncating the 64-bit pointer value) (it looks like 
we're maybe also lucking out on handling the width properly, as we're 
never hitting the PWPOS state to record that it should be treated as an 
INT).


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: bug with printf positional arguments?
  2023-07-03 14:49   ` Jon Turney
@ 2023-07-26 13:26     ` Corinna Vinschen
  0 siblings, 0 replies; 4+ messages in thread
From: Corinna Vinschen @ 2023-07-26 13:26 UTC (permalink / raw)
  To: newlib; +Cc: Jon Turney

On Jul  3 15:49, Jon Turney wrote:
> On 03/07/2023 12:14, Corinna Vinschen wrote:
> > On Jun 28 14:28, Jon Turney wrote:
> > > 
> > > The following trivial program (extracted from a glib testcase)
> > > 
> > > > #include <stdio.h>
> > > > 
> > > > int main()
> > > > {
> > > >    printf ("%1$*2$.*3$s", "abc", 5, 2);
> > > > }
> > > 
> > > does not produce the expected output of "   ab", on 64-bit Cygwin.
> > > 
> > >  From a bit of staring at and stepping through get_args() in
> > > libc/stdio/vfprintf.c, it looks like the problem is (something like) we
> > > don't have the knowledge that the first positional variadic argument should
> > > be treated as a pointer, at the point that we store it's value, so it gets
> > > treated as an integer (the default), which is going to lead to truncation on
> > > LP64 platforms.
> > > 
> > > A straightforward way to fix this eludes me.
> > 
> > Can you point out where in the code this problem occurs, so maybe
> > we can discuss the necessary code changes in this thread?
> 
> Sure, I'll try:
> 
> Let's suppose you're executing the STC above. This is what I think
> happens...
> 
> We end up in _vprintf_r.
> 
> We hit line 1072, which digests the '1', and on the following '$', knows to
> interpret this as a positional argument and stores it.
> 
> The subsequent '*' is processed at line 967 as introducing the width, where
> we chomp the '2', which again the following '$' indicates should be treated
> as a positional arg.
> 
> We hit GET_ARG for the first time, to retrieve the width, which invokes
> get_arg() to do the work (as we haven't yet stored the requested arg in
> args[]).
> 
> get_arg() digests the format string (again) using a state machine (to
> populate args[] with the positional parameters)
> 
> The state machine moves through START (action NUMBER) -> WDIG (action
> GETPOS) -> DONE.
> 
> Stopping here looks like maybe an error in the state machine design?
> 
> The loop starting at line 2310 iterates over the seen args, fetching their
> values. Because we haven't processed the 's' at the end in the GETARG state,
> we retrieve the first argument using the default case, as an integer (32
> bits, truncating the 64-bit pointer value) (it looks like we're maybe also
> lucking out on handling the width properly, as we're never hitting the PWPOS
> state to record that it should be treated as an INT).

After going a bit cross-eyed looking at the code, I *seriously* wonder,
if we shouldn't start with fresh vfprintf_r/vfwprintf_r, using copies of
the most recent FreeBSD vfprintf/vfwprintf, and just carefully tweak them
to match our build system...


Corinna


^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2023-07-26 13:27 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-06-28 13:28 bug with printf positional arguments? Jon Turney
2023-07-03 11:14 ` Corinna Vinschen
2023-07-03 14:49   ` Jon Turney
2023-07-26 13:26     ` Corinna Vinschen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).