[Bug c/79082] -Wformat-truncation inconsistent behaviour

msebor at gcc dot gnu.org gcc-bugzilla@gcc.gnu.org
Mon Jan 23 19:18:00 GMT 2017


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

--- Comment #7 from Martin Sebor <msebor at gcc dot gnu.org> ---
Except for #8, none of the sprintf calls in the extended testcase in attachment
40566 can be handled as accurately at -O0 as with optimization because the
arguments to the format directives are treated as if they had the full range of
int.

The question in my mind is whether, in the absence of any other hints or
constraints (see below), -Wformat-truncation should warn if truncation is
possible (again, given that at -O0 (val & 0xfff) is no different than val) but
not inevitable, or whether it should only warn when truncation certain.  Put
another way, should the set of warnings at -O0 be a strict subset of those with
optimization?  I think you are suggesting that it should be and I tend to
agree.  With my latest patch for bug 78703 (still under review), GCC doesn't
issue any warnings for this test case at -O0.  I suspect trunk warns not so
much as a feature but more by accident.

With optimization enabled, GCC can determine the values (or ranges) of some
non-constant arguments.  The warning pass can then use those to give more
accurate warnings.  It's important to keep in mind that a) due to limitations
or bugs the range information is not available for every expression (e.g., bug
78969 or bug 79191), and b) sometimes these limitations affect the range
information available for unrelated expressions in the same function (e.g., bug
79054).  Your test case unfortunately happens to trigger (b) and as a result
ends up with a false positive for case 3.  You can see that in the dump created
by the -ftree-dump-vrp option where the argument is assumed to include the
negative subrange:

  Value ranges after VRP:
  ...
  iftmp.0_11: [-99, 99]
  ...

    snprintf (buffer_8(D), 3, "%2d", iftmp.0_5);

With the other snprintf calls removed or moved into their own function the
false positive goes away and the test case produces warnings for just the first
two cases with the "should warn" comment.  These cases are diagnosed for two
reasons: 1) given the right value of the argument the directive can overflow,
and 2) the argument conversion has been constrained to some subrange of its
full range.  (2) is important because it suggests that the programmer may have
made an effort to constrain the output to avoid the truncation but didn't go
quite far enough to prevent it.  A common mistake is to forget that the
argument is signed and can be negative (as in assuming that (val % 100) results
in at most 2 bytes).

The last case (#8) isn't diagnosed because it doesn't meet condition (2). 
Since the argument appears completely unconstrained, the conservative level 1
of the warning assumes that may be constrained elsewhere (in the caller of
function test).  The warning should be issued at level 2 but on trunk isn't. 
That's a bug that's also fixed by my latest patch.


More information about the Gcc-bugs mailing list