3 # This scripts finds calls of printf and printf-like functions which
4 # do not use a literal string as format. Such calls are potentially
5 # dangerous as they could use formats which do not match their
10 no warnings 'File::Find';
14 # NAME ........ name of function
15 # FORMATPOS ... index of format string argument, first is 1
16 {NAME => 'printf' ,FORMATPOS => 1},
17 {NAME => 'sprintf' ,FORMATPOS => 2},
18 {NAME => 'fprintf' ,FORMATPOS => 2},
19 {NAME => 'dolog' ,FORMATPOS => 1},
20 {NAME => 'dolog_plain',FORMATPOS => 1},
34 for my $f (@FUNCTIONS) {
35 my $name = $f->{NAME};
36 $rxall .= "|" if $rxall;
37 $rxall .= "\\b$name\\b";
38 # push @{$tests{$f->{FORMATPOS}}},$f;
39 $tests{$f->{NAME}} = $f;
41 $rxall = qr/($rxall)/;
47 push @files, $File::Find::name if /\.[ch]$/i;
52 my ($coderef,$file,$line) = @_;
59 unless ($$coderef =~ /\G(.*?)([,()"])/g) {
81 unless($$coderef =~ /\G ( ([^\\"]|\\.)* " ) /gx) {
92 for my $file (@files) {
94 open(FILE,"<$file") or die "Could not open $file: $!";
109 while ($code =~ /$rxall/g) {
110 my $pos = pos($code);
112 my $test = $tests{$fname};
113 while (pos($code) > $pos[$line]) {$line++}
115 unless ($code =~ /\G\s*\(/g) {
116 print STDERR "$file:$line: warning: could not find parenthesis\n";
123 my $args = get_args(\$code,$file,$line);
125 print STDERR "$file:$line:warning: could not parse arguments\n";
130 if (@$args < $test->{FORMATPOS}) {
131 print STDERR "$file:$line: warning: could not find format of $fname\n";
135 my $fmt = $args->[$test->{FORMATPOS} - 1];
137 if ($fmt =~ /^\s*$/) {
138 print "$file:$line: missing format: $fname(".join(',',@$args).")\n";
142 unless ($fmt =~ /^\s*"/) {
143 print "$file:$line: nonliteral format: $fname(".join(',',@$args).")\n";
147 if ($fmt =~ /^\s*"(.*)"\s*$/) {
151 while ($f =~ /(%%?)/g) {$pct++ if length($1)==1};
153 if ($pct != @$args - $test->{FORMATPOS}) {
154 print "$file:$line: arguments?: $fname(".join(',',@$args).")\n";