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