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

Reply via email to