[PATCH 01/15] stdio-common: Don't read real input beyond the field width in scanf [BZ #13988]

Maciej W. Rozycki macro@redhat.com
Mon Jun 2 19:03:14 GMT 2025


On Tue, 20 May 2025, Florian Weimer wrote:

> >  No need or desire to set `errno' here; it's not used anyway.  So it'll 
> > just be:
> >
> >   if (avail == 0)
> >     {
> >       c = EOF;
> >       break;
> >     }
> >   if (inchar () == EOF)
> >     break;
> >
> > across.  Or, hmm, maybe:
> >
> >   if (avail == 0 || inchar () == EOF)
> >     {
> >       c = EOF;
> >       break;
> >     }
> >
> > -- letting the compiler figure out that `c' will have been set by `inchar' 
> > to EOF already and optimise duplicate code accordingly.
> 
> The latter seems quite reasonable to me.

 However sadly both variants result in worse machine code produced:

$ size -G stdio-common/vfscanf-internal-?.o
      text       data        bss      total filename
     27248        303          0      27551 stdio-common/vfscanf-internal-0.o
     28036        303          0      28339 stdio-common/vfscanf-internal-1.o
     27264        303          0      27567 stdio-common/vfscanf-internal-2.o
$ 

I can see extra register spills even with the second replacement variant 
(I didn't bother to look through the first one as grossly worse).  This is 
with GCC 14 on `powerpc64le-linux-gnu'.

 Would factoring out the (avail == 0 && (c = EOF)) expression to a macro 
with a side effect (analogous to that of `inchar') be an acceptable 
compromise?

 Or shall we just choose to live with it and instead challenge the GCC 
optimiser to produce better code, given that the code quality regression 
isn't that substantial?

> >  So this `c = EOF' assignment is needed precisely for that call: so that 
> > `ungetc' does not push back the final character previously consumed that 
> > fitted in the field width and which therefore must not be available there 
> > in the input to re-retrieve for any subsequent read call from the stream.
> > Just as it doesn't push back any genuine EOF retrieved by `inchar'.
> >
> >  Have I cleared your concern here?
> 
> I wasn't aware that ungetc of EOF is required to fail without doing
> anything.  It's not documented in the manual page (but our manual
> mentions it).

 And with the local macro implementation of `ungetc' in vfscanf-internal.c 
the EOF case is literally a no-op, or alternatively `ungetc_not_eof' does 
push EOF back too for the callers that need it.

  Maciej



More information about the Libc-alpha mailing list