https://gcc.gnu.org/bugzilla/show_bug.cgi?id=78605
Bug ID: 78605 Summary: bogus -Wformat-length=1 with %f 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: --- This issue was raised on the gcc list: https://gcc.gnu.org/ml/gcc/2016-11/msg00102.html In my response I didn't fully understand the problem that was being pointed out. Here's a smaller test case that should hopefully make it clearer. The issue is that while there is no warning for the sprintf call in f one is emitted for the call in g. In both instances the arguments of the call are unknown and may take on values that will fit into the provided buffer as well as values that will not. The -Wformat-length=1 setting is supposed to be conservative in diagnosing potential overflows by assuming unknown integers have the value 1. The same logic should apply to floating point arguments, so the warning for g is a false positive. $ cat c.c && gcc -S -O2 -Wall -Wextra c.c char d[10]; int f (int i) { return __builtin_sprintf (d, "%i %i", i, i); } int g (float f) { return __builtin_sprintf (d, "%.2f %.2f", f, f); } c.c: In function ‘g’: c.c:10:38: warning: ‘%.2f’ directive writing between 4 and 317 bytes into a region of size 0 [-Wformat-length=] return __builtin_sprintf (d, "%.2f %.2f", f, f); ^~~~ c.c:10:10: note: format output between 10 and 636 bytes into a destination of size 10 return __builtin_sprintf (d, "%.2f %.2f", f, f); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Compiling with -Wformat-length=2 on the other hand emits a warning for the sprintf call in f because the unknown argument is assumed to take on the value that results in the largest number of bytes (in this case -DBL_MAX). Similarly, the sprintf call in g is diagnosed (as expected). What is missing is a note indicating the range of values the checker considers in the floating case. As an independent issue, since the type of the arguments to the %f directive is float (not double), the checker should use -FLT_MAX rather than -DBL_MAX to determine the output. As another, separate, issue, the underlining seems off in the first note in the integer case. c.c: In function ‘f’: c.c:5:33: warning: ‘%i’ directive writing between 1 and 11 bytes into a region of size 10 [-Wformat-length=] return __builtin_sprintf (d, "%i %i", i, i); ^~ c.c:5:32: note: using the range [‘1’, ‘-2147483648’] for directive argument return __builtin_sprintf (d, "%i %i", i, i); ^~~~~~~ c.c:5:10: note: format output between 4 and 24 bytes into a destination of size 10 return __builtin_sprintf (d, "%i %i", i, i); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ c.c: In function ‘g’: c.c:10:33: warning: ‘%.2f’ directive writing between 4 and 317 bytes into a region of size 10 [-Wformat-length=] return __builtin_sprintf (d, "%.2f %.2f", f, f); ^~~~ c.c:10:10: note: format output between 10 and 636 bytes into a destination of size 10 return __builtin_sprintf (d, "%.2f %.2f", f, f); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~