New GCC plugin in 3rd party project (FRRouting): extended printf warnings
David Lamparter
equinox@diac24.net
Fri Jul 17 11:26:08 GMT 2020
Hi all,
the GCC wiki[1] suggests sending an e-mail when having developed a
plugin, so here we are!
I have, for the FRRouting project (a set of daemons implementing the
various internet routing protocols, GPLv2+), implemented a plugin that
does customized checking of extended printf formats. The plugin is
directly derived from GCC's own gcc/c-family/c-format.c. You can find
it at:
https://github.com/FRRouting/frr/tree/master/tools/gcc-plugins
Feature-wise, it provides these things:
[or, you could look at:]
https://github.com/opensourcerouting/frr/blob/build-assorted-20200717/tools/gcc-plugins/format-test.c
- warnings when %zd/%zu aren't used correctly for size_t (both ways, %zu
for non-size_t as well as size_t with something other than %zu)
- warnings for a bunch of known platform-dependent types that should
never be printed without a cast due to their unspecified nature
(pid_t, uid_t, gid_t, time_t, etc.)
- warnings when %Lu/%Ld aren't used for [u]int64_t (the uppercase L
modifier is custom to our project and PRI*64 are redefined to use it)
and the big one:
- support for Linux kernel style %pI4 <> in_addr_t and similar, defined
in the source-to-be-compiled through the use of pragmas like this:
#pragma FRR printfrr_ext "%pI4" (struct in_addr *)
#pragma FRR printfrr_ext "%pI4" (in_addr_t *)
Which emits a warning when trying e.g. printfrr("%pI4", voidptr);
(This is obviously also a custom extension in our printfrr(), inspired
by the Linux kernel[2])
Unfortunately, there are also 2 sad bulletpoints:
- I've used the Linux kernel's gcc-common.h, which is GPLv2 (no "or
newer"), so we can't really distribute binaries. I'll probably look
at dropping gcc-common.h, it shouldn't really be necessary.
- some checks only function correctly when a 1-line patch[3] is applied
to gcc. The problem is that if you do a
int x;
printf("%zu", (size_t)x);
/* => plugin sees "unsigned long" for arg 2, no way to get size_t */
the (size_t) cast is condensed down at a *very* early stage of
compilation, before the plugin can get at it. It only gets "unsigned
long" (or whatever else.) If it's a straight variable, it works as
expected, e.g.:
size_t x;
printf("%zu", x);
/* => plugin sees "size_t" for arg 2 */
I'm planning to submit that patch in a separate mail, but I am not a
GCC hacker at all and don't know whether this might cause any fallout.
I have, however, about a year ago, discussed this on the GCC IRC
channel, and whoever I talked to was saying that the line I'm deleting
there might be a "premature optimization."
The cases where it makes a difference are highlighted here:
https://github.com/opensourcerouting/frr/blob/build-assorted-20200717/tools/gcc-plugins/format-test.c#L85-L89
Anyay, I just thought I'd announce it here for posterity and for future
reference for submitting that one-liner patch.
Cheers,
-David
[1] https://gcc.gnu.org/wiki/plugins
[2] https://www.kernel.org/doc/Documentation/printk-formats.txt
[3] https://github.com/FRRouting/frr/blob/master/tools/gcc-plugins/gcc-retain-typeinfo.patch
More information about the Gcc
mailing list