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

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

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |aldyh at gcc dot gnu.org

--- Comment #12 from Martin Sebor <msebor at gcc dot gnu.org> ---
Thanks for the test case.  Here's a slightly reduced version of it:

$ cat pr78969.c && gcc -O2 -S -Wall pr78969.c
void f (int, ...);

char d[4];

void g (unsigned i)
{
  if (i >= 1000 && i < 10000)
    __builtin_snprintf (d, 4, "%3d", i / 10);   // bogus -Wformat-truncation
  else
    f (i / 10 % 10);
}
pr78969.c: In function ‘g’:
pr78969.c:8:32: warning: ‘%3d’ directive output may be truncated writing
between 3 and 9 bytes into a region of size 4 [-Wformat-truncation=]
     __builtin_snprintf (d, 4, "%3d", i / 10);   // bogus -Wformat-truncation
                                ^~~
pr78969.c:8:31: note: directive argument in the range [0, 429496729]
     __builtin_snprintf (d, 4, "%3d", i / 10);   // bogus -Wformat-truncation
                               ^~~~~
pr78969.c:8:5: note: ‘__builtin_snprintf’ output between 4 and 10 bytes into a
destination of size 4
     __builtin_snprintf (d, 4, "%3d", i / 10);   // bogus -Wformat-truncation
     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

It does look like the false positive is due to the same underlying limitation
(the range not being reflected accurately outside the VRP pass).  GCC 7 doesn't
warn but GCC 8 does.  That's because in GCC 7 the result of the
get_range_info() function is VR_VARYING for the argument while in GCC 8 it
reports a VR_RANGE of [0, 429496729].  So ironically, the false positive is a
side-effect of the improvement in GCC 8's range tracking.

There is work underway to improve the accuracy of the range information even
further that should reduce the rate of these kinds of false positives.

That being said, a few comments:

1) The problem doesn't affect just -Wstringop-truncation but other warnings as
well, including -Wformat-overflow.  The latter warning, especially, has proven
to be useful enough despite this limitation that removing either from -Wall
doesn't seem a like good solution.
2) The philosophy behind -Wstringop-truncation is based on the assumption that
snprintf() is being called because truncation is possible, and that most
programs aren't prepared to handle it correctly.

In the test case, since truncation isn't possible, calling snprintf() is
unnecessary (and sprintf() would be sufficient -- though calling sprintf with a
fixed-size buffer just big enough for the output would also cause a false
positive).  Otherwise, if truncation were possible, the expectation is that the
caller should detect it by testing the return value from the function and
taking some action (e.g., by aborting).

Until the range improvements I mention above are made, I suggest to assume that
snprintf can truncate and handle the truncation somehow.  In comparison to the
runtime cost of the snprintf call, the overhead of checking the return value
and aborting is negligible.

Reply via email to