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

Martin Sebor <msebor at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Keywords|                            |diagnostic
             Status|UNCONFIRMED                 |NEW
   Last reconfirmed|                            |2017-02-23
                 CC|                            |msebor at gcc dot gnu.org
           Assignee|unassigned at gcc dot gnu.org      |msebor at gcc dot 
gnu.org
     Ever confirmed|0                           |1

--- Comment #1 from Martin Sebor <msebor at gcc dot gnu.org> ---
Confirmed.  A small test case is below.  When an integer directive's argument
is in a known range the checker assumes the result of the directive is also in
a known range even if the width or precision is not.  When the range of the
directive's output is known the checker uses its upper bound to determine
whether or not to warn, even at level 1.

The solution (until this is fixed) is to constrain the width (or precision)
range, e.g., by adding the following above the sprintf call.

  if (w < 0 || w > 7)
    __builtin_unreachable ();

$ cat u.c && gcc -O2 -S -Wall -Wunused -Wpedantic
-fdump-tree-printf-return-value=/dev/stdout u.c
char d[8];

void f (int w, unsigned x)
{
  if (x > 9)
    x = 0;

  __builtin_sprintf (d, "%*x", w, x);
}


;; Function f (f, funcdef_no=0, decl_uid=1797, cgraph_uid=0, symbol_order=1)

u.c:8: __builtin_sprintf: objsize = 8, fmtstr = "%*x"
  Directive 1 at offset 0: "%*x", width in range [0, 2147483648]
u.c: In function ‘f’:
u.c:8:26: warning: ‘%*x’ directive writing between 1 and 2147483648 bytes into
a region of size 8 [-Wformat-overflow=]
   __builtin_sprintf (d, "%*x", w, x);
                          ^~~
u.c:8:25: note: directive argument in the range [0, 9]
   __builtin_sprintf (d, "%*x", w, x);
                         ^~~~~
    Result: 1, 2147483648, 2147483648, 2147483648 (1, 2147483648, 2147483648,
2147483648)
  Directive 2 at offset 3: "", length = 1
u.c:8:3: note: ‘__builtin_sprintf’ output between 2 and 2147483649 bytes into a
destination of size 8
   __builtin_sprintf (d, "%*x", w, x);
   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

f (int w, unsigned int x)
{
  <bb 2> [100.00%]:
  if (x_2(D) > 9)
    goto <bb 3>; [54.00%]
  else
    goto <bb 4>; [46.00%]

  <bb 3> [54.00%]:

  <bb 4> [100.00%]:
  # x_1 = PHI <x_2(D)(2), 0(3)>
  __builtin_sprintf (&d, "%*x", w_4(D), x_1);
  return;

}

Reply via email to