https://gcc.gnu.org/bugzilla/show_bug.cgi?id=78622
Bug ID: 78622 Summary: [7 Regression] -Wformat-length/-fprintf-return-value incorrect with overflow/wrapping Product: gcc Version: 7.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: middle-end Assignee: unassigned at gcc dot gnu.org Reporter: msebor at gcc dot gnu.org Target Milestone: --- The following test case reduced from the one in bug 78586, comment 8, shows the problem discussed there. When determining the number of bytes that results from formatting an argument in some range using a directive of a narrower type (such as an int using %hhi), the format_integer function in the gimple-ssa-sprintf pass fails to take into consideration integer overflow (for signed types) and wrapping (for unsigned types). When the range of the argument is such that converting either bound to the type of the directive overflows or wraps, the pass simply takes the number of bytes that formatting the overflowed result would produce without considering that a different value in the same original range can result in a number of bytes that's outside the overflowed range. In the test case below, i's range is determined to be [4105, 4360]. Converting the lower bound of the range to char (the type of the %hhi directive) yields 9, and 4360 yields 8. Formatting both converted bounds takes just one byte. But converting the value 4127 (which is in the [4105, 4360] range) to char yields 31, which formats in 2 bytes. $ cat c.c && /build/gcc-git/gcc/xgcc -B /build/gcc-git/gcc -O2 -Wall -Wextra c.c && ./a.out #define FMT "%hhi" const char *fmt = FMT; volatile int x = 4127; int main (void) { int i = x; if (i < 4104 || i >= 4360) return 0 ; ++i; int n1 = __builtin_snprintf (0, 0, FMT, i); int n2 = __builtin_snprintf (0, 0, fmt, i); __builtin_printf ("%i == %i\n", n1, n2); if (n1 != n2) __builtin_abort (); } 1 == 2 Aborted (core dumped)