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 ***