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; }