https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89161

sisyphus359 at gmail dot com changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |sisyphus359 at gmail dot com

--- Comment #3 from sisyphus359 at gmail dot com ---
Another demo of just how nasty this bug can be.
(Apologies if this adds nothing to what has already been ascertained.)

/********************************/
/* overflow.c                           *
 * Build with (eg):                     *
 * gcc -o overflow overflow.c -O2 -Wall */
#include <stdio.h>

void foo(double, unsigned int);

int main(void) {
 double d = 5.1;
 unsigned int precis = 15;

 foo(d, precis);                 
}

void foo(double dub, unsigned int prec) {
 char buf[127];
 if(
   prec < sizeof(buf) && /** LINE 18 **/
   sizeof(buf) - prec > 10
   ){
   sprintf (buf, "%.*g", prec, dub); /** LINE 21 **/
   printf("%s\n", buf);
 }
}

/********************************/

The warning is:

overflow.c:21:19: warning: '%.*g' directive writing between 1 and 133 bytes
into a region of size 127 [-Wformat-overflow=]
    sprintf (buf, "%.*g", prec, dub);
                   ^~~~
overflow.c:21:18: note: assuming directive output of 132 bytes
    sprintf (buf, "%.*g", prec, dub);
                  ^~~~~~
overflow.c:21:4: note: 'sprintf' output between 2 and 134 bytes into a
destination of size 127
    sprintf (buf, "%.*g", prec, dub);
    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

and I'm seeing it on Ubuntu-20.04, gcc-9.3.0 and on Windows 7, gcc-8.3.0.

That's the message as seen on Windows, and it's essentially the same as appears
on Ubuntu except that Ubuntu appends some additional noise:

In file included from /usr/include/stdio.h:867,
                 from overflow.c:4:
/usr/include/x86_64-linux-gnu/bits/stdio2.h:36:10: note:
‘__builtin___sprintf_chk’ output between 2 and 134 bytes into a destination of
size 127
   36 |   return __builtin___sprintf_chk (__s, __USE_FORTIFY_LEVEL - 1,
      |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   37 |       __bos (__s), __fmt, __va_arg_pack ());
      |       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


A couple of things to note:
1) AFAICS, a buffer overflow cannot occur unless sizeof(buf) - prec wraps to a
value greater than 10. That's why we check in advance that prec < sizeof(ebuf)
at line 18.

2) If I comment out the first condition (ie line 18) then no warning is issued,
even though the removal of that condition opens the door to buffer overflow
occurring.

Cheers,
Rob

Reply via email to