https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88251
--- Comment #4 from Martin Sebor <msebor at gcc dot gnu.org> --- The warning in the test case in comment #2 is due to the warning at this level assuming the "worst case" result from the first call. Below is a simpler example to make it clear. The result of the first call is unknown but after the test, n is in the range [0, 7]. In the second call to snprintf the amount of space remaining at &a[n] is in the range [1, 8]. Level 1 of the warning optimistically uses the upper bound of the range and assumes there's still 8 bytes worth of space. But the conservative level 2 uses the lower bound and assumes there's just 1 byte left (i.e., n == 7). Hence the warning. The warning is justified because the code really isn't 100% safe from truncation. It's working as designed and documented: Level 2 warns also about calls to bounded functions whose return value is used and that might result in truncation given an argument of sufficient length or magnitude. $ cat t.c && gcc -O2 -S -Wall -Wformat-truncation=2 t.c char a[8]; void f (char const *s) { int n = __builtin_snprintf (a, sizeof a, "%s", s); if (n < 0 || n >= sizeof a) __builtin_abort (); unsigned r = sizeof a - n; n = __builtin_snprintf (&a[n], r, "12"); if (n < 0 || n >= sizeof a) __builtin_abort (); } t.c: In function ‘f’: t.c:12:39: warning: ‘12’ directive output truncated writing 2 bytes into a region of size 1 [-Wformat-truncation=] 12 | n = __builtin_snprintf (&a[n], r, "12"); | ~^ t.c:12:7: note: ‘__builtin_snprintf’ output 3 bytes into a destination of size 1 12 | n = __builtin_snprintf (&a[n], r, "12"); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ I forgot that level 2 doesn't consider whether the return value is used. It might perhaps be worth reconsidering whether the warning should trigger when the return value is used at level 2. But even if this change were made, at level 2 not all false positives can be avoided. For example, the warning pass isn't integrated with the string length pass, so even though GCC might be able to track the lengths of some dynamically created strings the warning doesn't know about them. For instance, in the following GCC eliminates the test because it knows that strlen(b) is 3 but the warning still triggers. We plan to make this work better in GCC 10. $ cat t.c && gcc -O2 -S -Wall -Wformat-truncation=2 t.c char a[8]; void f (void) { char b[10]; __builtin_strcpy (b, "123"); if (__builtin_strlen (b) > 3) return; __builtin_snprintf (a, sizeof a, "%s", b); } t.c: In function ‘f’: t.c:11:37: warning: ‘%s’ directive output may be truncated writing up to 9 bytes into a region of size 8 [-Wformat-truncation=] 11 | __builtin_snprintf (a, sizeof a, "%s", b); | ^~ ~ t.c:11:3: note: ‘__builtin_snprintf’ output between 1 and 10 bytes into a destination of size 8 11 | __builtin_snprintf (a, sizeof a, "%s", b); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~