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)