https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77696
Bug ID: 77696 Summary: Confusing wording for -Wformat-length= Product: gcc Version: 7.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: middle-end Assignee: unassigned at gcc dot gnu.org Reporter: dmalcolm at gcc dot gnu.org Target Milestone: --- Given this example from PR 77672... **************************************************************************** cat v.c && ./xgcc -B. -c v.c -Wall char d[3]; extern int sprintf (char*, const char*, ...); void f (void) { sprintf (d, "%-s!", "abc"); } void g (void) { sprintf (d, "%-s", "abc"); } v.c: In function ‘f’: v.c:6:19: warning: writing format character ‘!’ at offset 3 past the end of the destination [-Wformat-length=] sprintf (d, "%-s!", "abc"); ^ v.c:6:3: note: format output 5 bytes into a destination of size 3 sprintf (d, "%-s!", "abc"); ^~~~~~~~~~~~~~~~~~~~~~~~~~ v.c: In function ‘g’: v.c:10:15: warning: writing a terminating nul past the end of the destination [-Wformat-length=] sprintf (d, "%-s", "abc"); ^~~~~ v.c:10:3: note: format output 4 bytes into a destination of size 3 sprintf (d, "%-s", "abc"); ^~~~~~~~~~~~~~~~~~~~~~~~~ **************************************************************************** ...I find the wording of these messages to be confusing. Consider: v.c: In function ‘f’: v.c:6:19: warning: writing format character ‘!’ at offset 3 past the end of the destination [-Wformat-length=] sprintf (d, "%-s!", "abc"); ^ v.c:6:3: note: format output 5 bytes into a destination of size 3 sprintf (d, "%-s!", "abc"); ^~~~~~~~~~~~~~~~~~~~~~~~~~ My first interpretation of the first message: "writing format character ‘!’ at offset 3 past the end of the destination" was that "!" is written 3 bytes after the end of the destination buffer i.e. at d[6], whereas after several re-readings I think it means that "!" is written at offset 3, and that offset 3 is after the end of the destination buffer. Hence I think this should at least be reworded from: "writing format character ‘!’ at offset 3 past the end of the destination" to: "writing format character ‘!’ at offset 3, which is after the end of the destination" Also, I found myself looking at the sprintf manpage to figure out what the semantics of "format character '!'" were. AIUI, in this context '!' is merely an ordinary character to be copied unchanged. If so, a better working would be: "writing character ‘!’ at offset 3, which is after the end of the destination" But better would be to emphasize that this is a buffer overflow, changing the message to: "buffer overflow will occur when writing character ‘!’ (written to offset 3)" A nice tweak would be to display the decl name in array form if the destination supports it: "buffer overflow will occur when writing character ‘!’ to ‘p[3]’" (would it need to be "will occur" vs "can occur"?) The grammar in the supporting note: v.c:6:3: note: format output 5 bytes into a destination of size 3 sprintf (d, "%-s!", "abc"); ^~~~~~~~~~~~~~~~~~~~~~~~~~ seems to me to be poor - it's hard to tell whether "format" and "output" are meant as nouns or verbs. It could be changed from: format output 5 bytes into a destination of size 3 to: 5 bytes will be written into a destination of size 3 which would be much clearer. In terms of locations, the diagnostics should ideally show the location of the destination decl as the location of the "note"; also, as a tweak, the first location could show an underline from the initial part of the string up to the caret showing the point where buffer overflow occurs: v.c: In function ‘f’: v.c:6:19: warning: buffer overflow will occur when writing format character ‘!’ to ‘p[3]’ [-Wformat-length=] sprintf (d, "%-s!", "abc"); ~~~^ v.c:1:5: note: 5 bytes will be written into a destination of size 3 char d[3]; ^ ~ Ideally it would also underline the size of the buffer as a secondary range in the note (as shown above), but sadly I don't think that location information is available. Similarly, for the 2nd pair of diagnostics, v.c: In function ‘g’: v.c:10:15: warning: buffer overflow will occur when writing terminating nul to ‘p[3]’ [-Wformat-length=] sprintf (d, "%-s", "abc"); ~~~^ v.c:1:5: note: 4 bytes will be written into a destination of size 3 char d[3]; ^ ~ (using the trailing quote for the location of the NUL char; as per PR 77672) Hope this is constructive