Created attachment 57315 [details] A testcase [hjl@gnu-tgl-2 tmp]$ /usr/gcc-14.0.1-x32-apx/bin/gcc -O3 -S x.i -Wall In file included from tests-mbwc/tst_wctype.c:8: tests-mbwc/tsp_common.c: In function ‘result.constprop.isra’: tests-mbwc/tsp_common.c:55:24: warning: ‘%s’ directive writing up to 10218 bytes into a region of size between 0 and 10240 [-Wformat-overflow=] tests-mbwc/tsp_common.c:55:3: note: ‘sprintf’ output between 18 and 20484 bytes into a destination of size 10256 [hjl@gnu-tgl-2 tmp]$ GCC 13 is OK.
It is caused by r14-261.
[hjl@gnu-skx-1 gcc]$ cat /tmp/foo.i char a[10256]; char b; char *c, *g; int d, e, f; int sprintf(char *, char *, ...); unsigned long strlen(char *); int h(char *j) { if (strlen(j) + strlen(c) + strlen(g) + 32 > 10256) return 0; sprintf(a, "%s:%s:%d:%d:%d:%c:%s\n", j, c, d, e, f, b, g); return 1; } void i() { h("wctype"); } [hjl@gnu-skx-1 gcc]$ ./xgcc -B./ -O3 -Wall -S /tmp/foo.i /tmp/foo.i: In function ?i?: /tmp/foo.i:10:33: warning: ?%s? directive writing up to 10218 bytes into a region of size between 0 and 10240 [-Wformat-overflow=] 10 | sprintf(a, "%s:%s:%d:%d:%d:%c:%s\n", j, c, d, e, f, b, g); | ^~ In function ?h?, inlined from ?i? at /tmp/foo.i:13:12: /tmp/foo.i:10:3: note: ?sprintf? output between 18 and 20484 bytes into a destination of size 10256 10 | sprintf(a, "%s:%s:%d:%d:%d:%c:%s\n", j, c, d, e, f, b, g); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [hjl@gnu-skx-1 gcc]$
Can't reproduce on x86-64 on recent trunk: abulafia:~/bld/t/gcc []$ ./xgcc -B./ -c -O3 -Wall a.c abulafia:~/bld/t/gcc []$ cat a.c char a[10256]; char b; char *c, *g; int d, e, f; int sprintf(char *, char *, ...); unsigned long strlen(char *); int h(char *j) { if (strlen(j) + strlen(c) + strlen(g) + 32 > 10256) return 0; sprintf(a, "%s:%s:%d:%d:%d:%c:%s\n", j, c, d, e, f, b, g); return 1; }
Strange, it certainly does reproduce for me: char a[10256], b, *c, *g; int d, e, f; int foo (char *j) { if (__builtin_strlen (j) + __builtin_strlen (c) + __builtin_strlen (g) + 32 > 10256) return 0; __builtin_sprintf (a, "%s:%s:%d:%d:%d:%c:%s\n", j, c, d, e, f, b, g); return 1; } void bar (void) { foo ("wctype"); } /volume/tor/opt/notnfs/gcc-bisect/obj/gcc/cc1.r14-8919 -quiet -O3 -Wall pr113752.c pr113752.c: In function ‘bar’: pr113752.c:9:44: warning: ‘%s’ directive writing up to 10218 bytes into a region of size between 0 and 10240 [-Wformat-overflow=] 9 | __builtin_sprintf (a, "%s:%s:%d:%d:%d:%c:%s\n", j, c, d, e, f, b, g); | ^~ In function ‘foo’, inlined from ‘bar’ at pr113752.c:16:3: pr113752.c:9:3: note: ‘__builtin_sprintf’ output between 18 and 20484 bytes into a destination of size 10256 9 | __builtin_sprintf (a, "%s:%s:%d:%d:%d:%c:%s\n", j, c, d, e, f, b, g); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /volume/tor/opt/notnfs/gcc-bisect/obj/gcc/cc1.r14-260 -quiet -O3 -Wall pr113752.c /volume/tor/opt/notnfs/gcc-bisect/obj/gcc/cc1.r14-261 -quiet -O3 -Wall pr113752.c pr113752.c: In function ‘bar’: pr113752.c:9:44: warning: ‘%s’ directive writing up to 10218 bytes into a region of size between 0 and 10240 [-Wformat-overflow=] 9 | __builtin_sprintf (a, "%s:%s:%d:%d:%d:%c:%s\n", j, c, d, e, f, b, g); | ^~ In function ‘foo’, inlined from ‘bar’ at pr113752.c:16:3: pr113752.c:9:3: note: ‘__builtin_sprintf’ output between 18 and 20484 bytes into a destination of size 10256 9 | __builtin_sprintf (a, "%s:%s:%d:%d:%d:%c:%s\n", j, c, d, e, f, b, g); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
That said, the math at least in the reduced testcase is weird. %d output is at most 11 bytes - strlen ("-2147483648"), + 9 other chars, so that is 42, not 32. But even using + 42 in there instead of 32 doesn't fix it. It wouldn't surprise me if the misdesigned warning just sees that each of the strlens clearly has a range [0, 10256-42], after all, when expressed as a range there isn't much more to derive about it, and then uses that [0, 10214] range for each of the %s specifiers. Though, that is not what the warning says. Ah, maybe it is because j is known short after inlining or some IPA opts. Also, because the strlen + strlen + strlen + cst > cst2 condition uses unsigned type, wrap around is theoretically possible, e.g. one could have some PTRDIFF_MAX - epsilon sized string and call it with c = g = j that string.
I can reproduce it with r14-8930-g1e94648ab7b370
Anyway, I think the testcase is very similar to char a[256], *c, *g; int foo (void) { if (__builtin_strlen (c) + __builtin_strlen (g) + 5 > 256) return 0; __builtin_sprintf (a, "abcd%s%s", c, g); return 1; } which has started diagnosing this with r12-5014-g6b8b959675a3e14cfdd2145bd62e4260eb193765 at -O2 -Wall -W
GCC 14.1 is being released, retargeting bugs to GCC 14.2.