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

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

           What    |Removed                     |Added
----------------------------------------------------------------------------
          Component|tree-optimization           |testsuite

--- Comment #5 from Martin Sebor <msebor at gcc dot gnu.org> ---
Great!  With the strlen conversion to ranger
(g:6b8b959675a3e14cfdd2145bd62e4260eb193765) the test now fails on x86_64 as
well:

Excess errors:
/src/gcc/master/gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-16.c:142:5:
warning: '%*u' directive writing 5 or more bytes into a region of size 0
[-Wformat-overflow=]

while on or1k-elf:

Excess errors:
/src/gcc/master/gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-16.c:142:5:
warning: '%*u' directive writing 5 or more bytes into a region of size 0
[-Wformat-overflow=]
/src/gcc/master/gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-16.c:243:5:
warning: '%.*u' directive writing 7 or more bytes into a region of size 0
[-Wformat-overflow=]

I think the test unwittingly depends on GCC not inferring a range from a
conditional (although the intent is clearly that it does).  It uses an unsigned
int as the width argument to sprintf which is undefined, but I suspect it does
it as an attempt to create a signed anti-range.  So this might simply be a
problem with the test.  The difference between EVRP and Ranger can be seen in
the test case below (function g() corresponds to what the test does, and with
EVRP the range for w in it is the same as in f() on some targets like or1k-elf
and on others it's varying):

$ cat pr103161.c && gcc-11 -O2 -S -Wall -fdump-tree-strlen=/dev/stdout
pr103161.c
extern char a[1];

int f (int i, unsigned w)
{
  if (w < 5)
    w = 5;

  return __builtin_sprintf (a + 1, "%*i", w, i);   // w's range is [5, INT_MAX]
}

int g (int i)
{
  extern unsigned w;

  if (w < 5)
    w = 5;

  return __builtin_sprintf (a + 1, "%*i", w, i);   // w's range is [0, INT_MAX]
}

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

;; 1 loops found
;;
;; Loop 0
;;  header 0, latch 1
;;  depth 0, outer -1
;;  nodes: 0 1 2
;; 2 succs { 1 }
pr103161.c:8: __builtin_sprintf: objsize = 0, fmtstr = "%*i"
  Directive 1 at offset 0: "%*i", width in range [5, 4294967295]
pr103161.c: In function ‘f’:
pr103161.c:8:37: warning: ‘%*i’ directive writing 5 or more bytes into a region
of size 0 [-Wformat-overflow=]
    8 |   return __builtin_sprintf (a + 1, "%*i", w, i);   // w's range is [5,
INT_MAX]
      |                                     ^~~
    Result: 5, 5, -1, 4294967295 (5, 5, -1, -1)
  Directive 2 at offset 3: "", length = 1
pr103161.c:8:10: note: ‘__builtin_sprintf’ output 6 or more bytes into a
destination of size 0
    8 |   return __builtin_sprintf (a + 1, "%*i", w, i);   // w's range is [5,
INT_MAX]
      |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  Discarding out-of-bounds return value 0.

int f (int i, unsigned int w)
{
  unsigned int _2;
  int _6;

  <bb 2> [local count: 1073741824]:
  _2 = MAX_EXPR <w_1(D), 5>;
  _6 = __builtin_sprintf (&MEM <char[1]> [(void *)&a + 1B], "%*i", _2, i_4(D));
  return _6;

}



;; Function g (g, funcdef_no=1, decl_uid=1948, cgraph_uid=2, symbol_order=1)

;; 1 loops found
;;
;; Loop 0
;;  header 0, latch 1
;;  depth 0, outer -1
;;  nodes: 0 1 2 3 4
;; 2 succs { 3 4 }
;; 3 succs { 4 }
;; 4 succs { 1 }
pr103161.c:18: __builtin_sprintf: objsize = 0, fmtstr = "%*i"
  Directive 1 at offset 0: "%*i", width in range [0, 2147483648]
pr103161.c: In function ‘g’:
pr103161.c:18:37: warning: ‘%*i’ directive writing between 1 and 2147483648
bytes into a region of size 0 [-Wformat-overflow=]
   18 |   return __builtin_sprintf (a + 1, "%*i", w, i);   // w's range is [0,
INT_MAX]
      |                                     ^~~
    Result: 1, 1, 2147483648, 2147483648 (1, 1, 2147483648, 2147483648)
  Directive 2 at offset 3: "", length = 1
pr103161.c:18:10: note: ‘__builtin_sprintf’ output between 2 and 2147483649
bytes into a destination of size 0
   18 |   return __builtin_sprintf (a + 1, "%*i", w, i);   // w's range is [0,
INT_MAX]
      |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  Discarding out-of-bounds return value 0.

int g (int i)
{
  unsigned int w.0_1;
  int _8;
  unsigned int prephitmp_9;

  <bb 2> [local count: 1073741824]:
  w.0_1 = w;
  if (w.0_1 <= 4)
    goto <bb 3>; [50.00%]
  else
    goto <bb 4>; [50.00%]

  <bb 3> [local count: 536870913]:
  w = 5;

  <bb 4> [local count: 1073741824]:
  # prephitmp_9 = PHI <w.0_1(2), 5(3)>
  _8 = __builtin_sprintf (&MEM <char[1]> [(void *)&a + 1B], "%*i", prephitmp_9,
i_6(D));
  return _8;

}

While with today's trunk:

$ gcc-12 -O2  -S -Wall -fdump-tree-strlen=/dev/stdout pr103161.c
extern char a[1];

int f (int i, unsigned w)
{
  if (w < 5)
    w = 5;

  return __builtin_sprintf (a + 1, "%*i", w, i);   // w's range is [5, INT_MAX]
}

int g (int i)
{
  extern unsigned w;

  if (w < 5)
    w = 5;

  return __builtin_sprintf (a + 1, "%*i", w, i);   // w's range is [5, INT_MAX]
}

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

;; 1 loops found
;;
;; Loop 0
;;  header 0, latch 1
;;  depth 0, outer -1
;;  nodes: 0 1 2
;; 2 succs { 1 }
pr103161.c:8: __builtin_sprintf: objsize = 0, fmtstr = "%*i"
  Directive 1 at offset 0: "%*i", width in range [5, 4294967295]
pr103161.c: In function ‘f’:
pr103161.c:8:37: warning: ‘%*i’ directive writing 5 or more bytes into a region
of size 0 [-Wformat-overflow=]
    8 |   return __builtin_sprintf (a + 1, "%*i", w, i);   // w's range is [5,
INT_MAX]
      |                                     ^~~
    Result: 5, 5, -1, 4294967295 (5, 5, -1, -1)
  Directive 2 at offset 3: "", length = 1
pr103161.c:8:10: note: ‘__builtin_sprintf’ output 6 or more bytes into a
destination of size 0
    8 |   return __builtin_sprintf (a + 1, "%*i", w, i);   // w's range is [5,
INT_MAX]
      |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  Discarding out-of-bounds return value 0.

int f (int i, unsigned int w)
{
  unsigned int _2;
  int _6;

  <bb 2> [local count: 1073741824]:
  _2 = MAX_EXPR <w_1(D), 5>;
  _6 = __builtin_sprintf (&MEM <char[1]> [(void *)&a + 1B], "%*i", _2, i_4(D));
  return _6;

}



;; Function g (g, funcdef_no=1, decl_uid=1983, cgraph_uid=2, symbol_order=1)

;; 1 loops found
;;
;; Loop 0
;;  header 0, latch 1
;;  depth 0, outer -1
;;  nodes: 0 1 2 3 4
;; 2 succs { 3 4 }
;; 3 succs { 4 }
;; 4 succs { 1 }
pr103161.c:18: __builtin_sprintf: objsize = 0, fmtstr = "%*i"
  Directive 1 at offset 0: "%*i", width in range [5, 4294967295]
pr103161.c: In function ‘g’:
pr103161.c:18:37: warning: ‘%*i’ directive writing 5 or more bytes into a
region of size 0 [-Wformat-overflow=]
   18 |   return __builtin_sprintf (a + 1, "%*i", w, i);   // w's range is [5,
INT_MAX]
      |                                     ^~~
    Result: 5, 5, -1, 4294967295 (5, 5, -1, -1)
  Directive 2 at offset 3: "", length = 1
pr103161.c:18:10: note: ‘__builtin_sprintf’ output 6 or more bytes into a
destination of size 0
   18 |   return __builtin_sprintf (a + 1, "%*i", w, i);   // w's range is [5,
INT_MAX]
      |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  Discarding out-of-bounds return value 0.

int g (int i)
{
  unsigned int w.0_1;
  int _8;
  unsigned int prephitmp_9;

  <bb 2> [local count: 1073741824]:
  w.0_1 = w;
  if (w.0_1 <= 4)
    goto <bb 3>; [50.00%]
  else
    goto <bb 4>; [50.00%]

  <bb 3> [local count: 536870913]:
  w = 5;

  <bb 4> [local count: 1073741824]:
  # prephitmp_9 = PHI <w.0_1(2), 5(3)>
  _8 = __builtin_sprintf (&MEM <char[1]> [(void *)&a + 1B], "%*i", prephitmp_9,
i_6(D));
  return _8;

}

Reply via email to