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

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

           What    |Removed                     |Added
----------------------------------------------------------------------------
         Resolution|---                         |DUPLICATE
             Status|UNCONFIRMED                 |RESOLVED

--- Comment #3 from Martin Sebor <msebor at gcc dot gnu.org> ---
The warning works as designed but the range information it depends on is less
than perfect.  As discussed in pr94021 that's a known limitation of the current
range propagation infrastructure.  GCC 11 adds an improved range engine known
as the Ranger that's expected to remedy this but it is yet to be integrated
with the sprintf/strlen pass.  The argument ranges can be constrained by using
a "narrower" directive such as %hhu.

A small test case that helps see what's going on is this:

$ gcc -O2 -S -Wall -fdump-tree-strlen-all=/dev/stdout pr98281.c
void f (char *d, int i)
{
  if (i >= 3600 * 24 || i <= -3600 * 24)
    return;
  if (i < 0)
    i = -i;

  int h = i / 3600;
  int m = (i - (h * 3600)) / 60;
  int s = (i - (h * 3600) - (m * 60));

  if (s > 0)
    __builtin_snprintf (d, 9, "%c%02d%02d%02d", '+', h, m, s);
}

;; Function f (f, funcdef_no=0, decl_uid=1944, cgraph_uid=1, symbol_order=0)
...
Intersecting
  int [-169140, 169199]
and
  int [1, 169199]
to
  int [1, 169199]
pushing new range for s_11: int [1, 169199]  EQUIVALENCES: { s_11 } (1
elements)   <<< last argument (s)
pr98281.c:13: snprintfD.977: objsize = 9, fmtstr = "%c%02d%02d%02d"            
   <<< snprintf call
  Directive 1 at offset 0: "%c"
    Result: 1, 1, 1, 1 (1, 1, 1, 1)
  Directive 2 at offset 2: "%02d"
    Result: 2, 2, 2, 2 (3, 3, 3, 3)
  Directive 3 at offset 6: "%02d"                                              
   <<< last directive
    Result: 2, 5, 5, 5 (5, 8, 8, 8)                                            
   <<< output between 2 and 5 bytes
  Directive 4 at offset 10: "%02d"
pr98281.c: In function ‘f’:
pr98281.c:13:42: warning: ‘%02d’ directive output may be truncated writing
between 2 and 6 bytes into a region of size between 1 and 4
[-Wformat-truncation=]
   13 |     __builtin_snprintf (d, 9, "%c%02d%02d%02d", '+', h, m, s);
      |                                          ^~~~
pr98281.c:13:31: note: directive argument in the range [1, 169199]
   13 |     __builtin_snprintf (d, 9, "%c%02d%02d%02d", '+', h, m, s);
      |                               ^~~~~~~~~~~~~~~~
    Result: 2, 6, 6, 6 (7, 14, 14, 14)
  Directive 5 at offset 14: "", length = 1
pr98281.c:13:5: note: ‘__builtin_snprintf’ output between 8 and 15 bytes into a
destination of size 9
   13 |     __builtin_snprintf (d, 9, "%c%02d%02d%02d", '+', h, m, s);
      |     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
voidD.51 f (charD.7 * dD.1942, intD.6 iD.1943)
{
  ...
  # RANGE [-169140, 169199]                                                    
   <<< last argument (negative?)
  s_11 = _4 + _6;
  ...
  snprintfD.977 (d_13(D), 9, "%c%02d%02d%02d", 43, h_9, m_10, s_11);
  ...
}

*** This bug has been marked as a duplicate of bug 94021 ***

Reply via email to