[Bug c/89161] Bogus -Wformat-overflow warning with value range known

2022-01-19 Thread msebor at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89161

Martin Sebor  changed:

   What|Removed |Added

  Known to fail|10.0|10.3.0, 11.2.0, 12.0
   Last reconfirmed|2020-05-01 00:00:00 |2022-1-19

--- Comment #5 from Martin Sebor  ---
GCC 12 or 11 don't warn on the test case in comment #3 but reconfirming the
warning for the test case in comment #0 with GCC 12:

$ gcc -O2 -S -Wall  -fdump-tree-strlen=/dev/stdout pr89161.c 

;; Function main (main, funcdef_no=12, decl_uid=2421, cgraph_uid=13,
symbol_order=13) (executed once)

...
pr89161.c:7: sprintf: objsize = 3, fmtstr = ".%1u"
  Directive 1 at offset 0: ".", length = 1
Result: 1, 1, 1, 1 (1, 1, 1, 1)
  Directive 2 at offset 1: "%1u"
pr89161.c: In function ‘main’:
pr89161.c:7:24: warning: ‘%1u’ directive writing between 1 and 6 bytes into a
region of size 2 [-Wformat-overflow=]
7 | sprintf(buf, ".%1u", (10 * a[0]) / a[1]);
  |^~~
In function ‘print’,
inlined from ‘main’ at pr89161.c:17:5:
pr89161.c:7:22: note: directive argument in the range [0, 327670]
7 | sprintf(buf, ".%1u", (10 * a[0]) / a[1]);
  |  ^~
Result: 1, 6, 6, 6 (2, 7, 7, 7)
  Directive 3 at offset 4: "", length = 1
pr89161.c:7:9: note: ‘sprintf’ output between 3 and 8 bytes into a destination
of size 3
7 | sprintf(buf, ".%1u", (10 * a[0]) / a[1]);
  | ^~~~

[Bug c/89161] Bogus -Wformat-overflow warning with value range known

2020-10-14 Thread msebor at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89161

--- Comment #4 from Martin Sebor  ---
This should be resolved once the sprintf + strlen pass is converted to the new
Ranger implementation sometime in the coming weeks (hopefully).

In the meantime, changing the controlling expression in the if statement in the
test case in comment #3 to (prec < sizeof buf - 10) should also help.

[Bug c/89161] Bogus -Wformat-overflow warning with value range known

2020-10-12 Thread sisyphus359 at gmail dot com via Gcc-bugs
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 

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

[Bug c/89161] Bogus -Wformat-overflow warning with value range known

2020-05-01 Thread msebor at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89161

Martin Sebor  changed:

   What|Removed |Added

  Known to fail|9.0 |10.0, 9.2.0
   Last reconfirmed|2019-02-02 00:00:00 |2020-5-1

--- Comment #2 from Martin Sebor  ---
Reconfirming with GCC 10 with slightly different output:

pr89161.c:7: sprintf: objsize = 3, fmtstr = ".%1u"
  Directive 1 at offset 0: ".", length = 1
Result: 1, 1, 1, 1 (1, 1, 1, 1)
  Directive 2 at offset 1: "%1u"
pr89161.c: In function ‘main’:
pr89161.c:7:24: warning: ‘%1u’ directive writing between 1 and 6 bytes into a
region of size 2 [-Wformat-overflow=]
7 | sprintf(buf, ".%1u", (10 * a[0]) / a[1]);
  |^~~
pr89161.c:7:22: note: directive argument in the range [0, 327675]
7 | sprintf(buf, ".%1u", (10 * a[0]) / a[1]);
  |  ^~
Result: 1, 6, 6, 6 (2, 7, 7, 7)
  Directive 3 at offset 4: "", length = 1
pr89161.c:7:9: note: ‘sprintf’ output between 3 and 8 bytes into a destination
of size 3
7 | sprintf(buf, ".%1u", (10 * a[0]) / a[1]);
  | ^~~~

[Bug c/89161] Bogus -Wformat-overflow warning with value range known

2019-02-02 Thread msebor at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89161

Martin Sebor  changed:

   What|Removed |Added

   Keywords||diagnostic
 Status|UNCONFIRMED |NEW
   Last reconfirmed||2019-02-02
 CC||msebor at gcc dot gnu.org
 Blocks||85741
 Ever confirmed|0   |1
  Known to fail||7.3.0, 8.2.0, 9.0

--- Comment #1 from Martin Sebor  ---
I can confirm the warning and agree that GCC could in theory figure out that
the result is between 0 and 9 but it currently doesn't do that.  With the
optimization implemented the warning would go away.

Note that there are limitations as how far GCC can go in determining the values
or ranges of non-constant expressions, and warnings that rely on these
abilities (i.e., flow-based warnings) are unavoidably imprecise.  This is
documented in the manual which says about -Wformat-overflow:

  Warn about calls to formatted input/output functions such as sprintf and
vsprintf that might overflow the destination buffer. When the exact number of
bytes written by a format directive cannot be determined at compile-time it is
estimated based on heuristics that depend on the level argument and on
optimization.

A test case for the missing optimization is:

void f (unsigned short a, unsigned short b)
{
  if (a && a < b)
  {
int x = (10 * a) / b;
if (x < 0 || 9 < x)
  __builtin_abort ();
  }
}

Compiling it with the -fdump-tree-vrp=/dev/stdout option shows that range in
which x is computed to be by VRP is:

  x_10: int [0, 655350]
  ...

   [local count: 536870913]:
  _4 = (int) a_8(D);
  _5 = _4 * 10;
  _6 = (int) b_9(D);
  x_10 = _5 / _6;
  if (x_10 > 9)
goto ; [0.00%]
  else
goto ; [100.00%]

   [count: 0]:
  __builtin_abort ();


Referenced Bugs:

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85741
[Bug 85741] [meta-bug] bogus/missing -Wformat-overflow