This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Add a new warning about redundant printf arguments
authorÆvar Arnfjörð Bjarmason <avar@cpan.org>
Sun, 19 Jan 2014 16:27:58 +0000 (16:27 +0000)
committerÆvar Arnfjörð Bjarmason <avar@cpan.org>
Sat, 21 Jun 2014 13:54:43 +0000 (13:54 +0000)
commit4077a6bc0ae42279f757dffc08ee68ba8ace9924
tree610cd85045108fdd8698d3154dbd7b98bc5f8417
parent3664866ee329279683fd8c71e52e5983da4272dd
Add a new warning about redundant printf arguments

Implement RT #121025 and add a "redundant" warning category that
currently only warns about redundant arguments to printf. Now similarly
to how we already warned about missing printf arguments:

    $ ./miniperl -Ilib -we 'printf "%s\n", qw()'
    Missing argument in printf at -e line 1.

We'll now warn about redundant printf arguments:

    $ ./miniperl -Ilib -we 'printf "%s\n", qw(x y)'
    Redundant argument in printf at -e line 1.
    x

The motivation for this is that I recently fixed an insidious
long-standing 6 year old bug in a codebase I maintain that came down to
an issue that would have been detected by this warning.

Things to note about this patch:

 * It found a some long-standing redundant printf arguments in our own
   ExtUtils::MakeMaker code which I submitted fixes to in
   https://github.com/Perl-Toolchain-Gang/ExtUtils-MakeMaker/pull/84 and
   https://github.com/Perl-Toolchain-Gang/ExtUtils-MakeMaker/pull/86,
   those fixes were merged into blead in v5.19.8-265-gb33b7ab

 * This warning correctly handles format parameter indexes (e.g. "%1$s")
   for some value of correctly. See the comment in t/op/sprintf2.t for
   an extensive discussion of how I've handled that.

 * We do the correct thing in my opinion when a pattern has redundant
   arguments *and* an invalid printf format. E.g. for the pattern "%A%s"
   with one argument we'll just warn about an invalid format as before,
   but with two arguments we'll warn about the invalid format *and* the
   redundant argument.

   This helps to disambiguate cases where the user just meant to write a
   literal "%SOMETHING" v.s. cases where he though "%S" might be a valid
   printf format.

 * I originally wrote this while the 5.19 series was under way, but Dave
   Mitchell has noted that a warning like this should go into blead
   after 5.20 is released:

       "[...] I think it should go into blead just after 5.20 is
       released, rather than now; I think it'd going to kick up a lot of
       dust and we'll want to give CPAN module owners maximum lead time
       to fix up their code. For example, if its generating warnings in
       cpan/ code in blead, then we need those module authors to fix
       their code, produce stable new releases, pull them back into
       blead, and let them bed in before we start pushing out 5.20 RC
       candidates"

   I agree, but we could have our cake and eat it too if "use warnings"
   didn't turn this on but an explicit "use warnings qw(redundant)" did.
   Then in 5.22 we could make "use warnings" also import the "redundant"
   category, and in the meantime you could turn this on
   explicitly.

   There isn't an existing feature for adding that kind of warning in
   the core. And my attempts at doing so failed, see commentary in RT
   #121025.

The warning needed to be added to a few places in sv.c because the "",
"%s" and "%-p" patterns all bypass the normal printf handling for
optimization purposes. The new warning works correctly on all of
them. See the tests in t/op/sprintf2.t.

It's worth mentioning that both Debian Clang 3.3-16 and GCC 4.8.2-12
warn about this in C code under -Wall:

    $ cat redundant.c
    #include <stdio.h>

    int main(void) {
        printf("%d\n", 123, 345);
        return 0;
    }
    $ clang -Wall -o redundant redundant.c
    redundant.c:4:25: warning: data argument not used by format string [-Wformat-extra-args]
        printf("%d\n", 123, 345);
               ~~~~~~       ^
    1 warning generated.
    $ gcc -Wall -o redundant redundant.c
    redundant.c: In function ‘main’:
    redundant.c:4:5: warning: too many arguments for format [-Wformat-extra-args]
         printf("%d\n", 123, 345);
         ^

So I'm not the first person to think that this might be generally
useful.

There are also other internal functions that could benefit from
missing/redundant warnings, e.g. pack. Neither of these things currently
warn, but should:

    $ perl -wE 'say pack "AA", qw(x y z)'
    xy
    $ perl -wE 'say pack "AAAA", qw(x y z)'
    xyz

I'll file a bug for that, and might take a stab at implementing it.
lib/warnings.pm
pod/perldiag.pod
regen/warnings.pl
sv.c
t/op/sprintf.t
t/op/sprintf2.t
warnings.h