This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
Re: -Wformat-length and floats
- From: Martin Sebor <msebor at gmail dot com>
- To: Gerald Pfeifer <gerald at pfeifer dot com>, gcc at gcc dot gnu dot org
- Date: Tue, 29 Nov 2016 09:32:06 -0700
- Subject: Re: -Wformat-length and floats
- Authentication-results: sourceware.org; auth=none
- References: <alpine.LSU.2.20.1611271501370.2407@anthias.pfeifer.com>
On 11/29/2016 08:38 AM, Gerald Pfeifer wrote:
This took me a bit to get to the bottom of, but I know believe
that we need to work both on the documentation and implementation
of -Wformat-length, in particular when it comes to floats.
#include <stdio.h>
typedef struct M {
float a, b, c;
} M;
char *foo(M *m) {
static char buf[64];
sprintf(buf, "%.2f %.2f %.2f", m->a, m->b, m->c);
return buf;
}
First of all, it turns out that floats are not covered in the
documentation at all. I've had a look at the code, and think
I'll be able to propose a doc change latest this coming weekend.
Thanks for looking at this and bringing it up for discussion!
Suggestions for improvements are very welcome and appreciated.
Now to what actually happens in the example above:
# gcc -c -o x.o -Wall x.c
x.c: In function ʽfooʼ:
x.c:9:24: warning: ʽ%.2fʼ directive writing between 4 and 317 bytes into a region of size 0 [-Wformat-length=]
sprintf(buf, "%.2f %.2f %.2f", m->a, m->b, m->c);
^~~~
x.c:9:5: note: format output between 15 and 954 bytes into a destination of size 64
sprintf(buf, "%.2f %.2f %.2f", m->a, m->b, m->c);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
A couple of issues I find really confusing:
- Where is the number of 317 bytes as the upper limit for a sole
%.2f coming from?
317 the number of bytes that printf("%f", -DBL_MAX) results in.
There's a bug in that the computation doesn't take precision into
account for %e or %g with unknown arguments so the maximum for
%.2f should actually be 312. Let me fix that.
- Where is the number of 954 bytes coming from for the full call?
It's the result of 3 * 317 plus the spaces (again, with the precision
bug).
- What is a region of size 0? Why 0?
Each directive writes into a region of the destination. The start
of the region moves toward the end of the destination as bytes are
"added" until the remaining space is too small for the rest of the
format string or a directive, or until the format string has been
exhausted. An example that might make it clearer is
char buf[4];
sprintf(buf, "i=%i", 12345);
We get:
warning: ʽ%iʼ directive writing 5 bytes into a region of size 2
note: format output 8 bytes into a destination of size 4
- And what is the difference between a region and a destination?
Destination is the whole destination object (or buffer) of the call.
The region is the are of the destination the output of each directive
is being written into (as per the above).
I'll see what I can do about documentation; any input on the above
related to that will be helpful.
And something tells me that there may be in issue with the diagnostics
code?
It could be, though at the moment I'm not aware of any. I am
grateful for testing people do on their own and for this kind
of feedback. There's only so much that compiling software can
reveal.
FWIW, some time ago in bug 77696 David brought up some related
issues and questions. I made an effort to describe the logic
behind the wording choices made in the text of the diagnostics
and the common theme between their various forms. It might be
helpful (to all) for you to review the bug and provide additional
input on the wording of the diagnostics there.
Certainly if you find what looks like a bug or where you are not
sure please open an issue for it in Bugzilla or raise it here.
Thanks
Martin