1
eval '(exit $?0)' && eval 'exec perl -wST "$0" ${1+"$@"}'
2
& eval 'exec perl -wST "$0" $argv:q'
4
# Detect instances of "if (p) free (p);".
5
# Likewise for "if (p != NULL) free (p);". And with braces.
6
# Also detect "if (NULL != p) free (p);".
7
# And with 0 in place of NULL.
9
my $VERSION = '2009-04-16 15:57'; # UTC
10
# The definition above must lie within the first 8 lines in order
11
# for the Emacs time-stamp write hook (at end) to update it.
12
# If you change this file with Emacs, please let the write hook
13
# do its job. Otherwise, update this string manually.
15
# Copyright (C) 2008-2010 Free Software Foundation, Inc.
17
# This program is free software: you can redistribute it and/or modify
18
# it under the terms of the GNU General Public License as published by
19
# the Free Software Foundation, either version 3 of the License, or
20
# (at your option) any later version.
22
# This program is distributed in the hope that it will be useful,
23
# but WITHOUT ANY WARRANTY; without even the implied warranty of
24
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25
# GNU General Public License for more details.
27
# You should have received a copy of the GNU General Public License
28
# along with this program. If not, see <http://www.gnu.org/licenses/>.
30
# Written by Jim Meyering
36
(my $ME = $0) =~ s|.*/||;
38
# use File::Coda; # http://meyering.net/code/Coda/
40
defined fileno STDOUT or return;
41
close STDOUT and return;
42
warn "$ME: failed to close standard output: $!\n";
49
my $STREAM = ($exit_code == 0 ? *STDOUT : *STDERR);
52
print $STREAM "Try `$ME --help' for more information.\n";
57
Usage: $ME [OPTIONS] FILE...
59
Detect any instance in FILE of a useless "if" test before a free call, e.g.,
60
"if (p) free (p);". Any such test may be safely removed without affecting
61
the semantics of the C code in FILE. Use --name=FOO --name=BAR to also
62
detect free-like functions named FOO and BAR.
66
--list print only the name of each matching FILE (\0-terminated)
67
--name=N add name N to the list of \`free\'-like functions to detect;
70
--help display this help and exit
71
--version output version information and exit
81
For example, this command prints all removable "if" tests before "free"
82
and "kfree" calls in the linux kernel sources:
84
git ls-files -z |xargs -0 $ME --name=kfree
94
return ($expr eq 'NULL' || $expr eq '0');
101
my $err = EXIT_NO_MATCH;
107
help => sub { usage 0 },
108
version => sub { print "$ME version $VERSION\n"; exit },
113
# Make sure we have the right number of non-option arguments.
114
# Always tell the user why we fail.
116
and (warn "$ME: missing FILE argument\n"), usage EXIT_ERROR;
118
my $or = join '|', @name;
119
my $regexp = qr/(?:$or)/;
121
# Set the input record separator.
122
# Note: this makes it impractical to print line numbers.
127
foreach my $file (@ARGV)
130
or (warn "$ME: can't open `$file' for reading: $!\n"),
131
$err = EXIT_ERROR, next;
132
while (defined (my $line = <FH>))
135
/\b(if\s*\(\s*([^)]+?)(?:\s*!=\s*([^)]+?))?\s*\)
137
(?: \s*$regexp\s*\((?:\s*\([^)]+\))?\s*([^)]+)\)|
138
\s*\{\s*$regexp\s*\((?:\s*\([^)]+\))?\s*([^)]+)\)\s*;\s*\}))/sxg)
141
my ($lhs, $rhs) = ($2, $3);
142
my ($free_opnd, $braced_free_opnd) = ($4, $5);
144
if (!defined $rhs) { $non_NULL = $lhs }
145
elsif (is_NULL $rhs) { $non_NULL = $lhs }
146
elsif (is_NULL $lhs) { $non_NULL = $rhs }
149
# Compare the non-NULL part of the "if" expression and the
150
# free'd expression, without regard to white space.
151
$non_NULL =~ tr/ \t//d;
152
my $e2 = defined $free_opnd ? $free_opnd : $braced_free_opnd;
154
if ($non_NULL eq $e2)
158
and (print "$file\0"), next FILE;
159
print "$file: $all\n";
169
$found_match && $err == EXIT_NO_MATCH
170
and $err = EXIT_MATCH;
176
# The above is to *find* them.
177
# This adjusts them, removing the unnecessary "if (p)" part.
179
# FIXME: do something like this as an option (doesn't do braces):
181
git grep -l -z "$free *(" \
182
| xargs -0 useless-if-before-free -l --name="$free" \
183
| xargs -0 perl -0x3b -pi -e \
184
's/\bif\s*\(\s*(\S+?)(?:\s*!=\s*(?:0|NULL))?\s*\)\s+('"$free"'\s*\((?:\s*\([^)]+\))?\s*\1\s*\))/$2/s'
186
# Use the following to remove redundant uses of kfree inside braces.
187
# Note that -0777 puts perl in slurp-whole-file mode;
188
# but we have plenty of memory, these days...
190
git grep -l -z "$free *(" \
191
| xargs -0 useless-if-before-free -l --name="$free" \
192
| xargs -0 perl -0777 -pi -e \
193
's/\bif\s*\(\s*(\S+?)(?:\s*!=\s*(?:0|NULL))?\s*\)\s*\{\s*('"$free"'\s*\((?:\s*\([^)]+\))?\s*\1\s*\);)\s*\}[^\n]*$/$2/gms'
195
Be careful that the result of the above transformation is valid.
196
If the matched string is followed by "else", then obviously, it won't be.
198
When modifying files, refuse to process anything other than a regular file.
203
## indent-tabs-mode: nil
204
## eval: (add-hook 'write-file-hooks 'time-stamp)
205
## time-stamp-start: "my $VERSION = '"
206
## time-stamp-format: "%:y-%02m-%02d %02H:%02M"
207
## time-stamp-time-zone: "UTC"
208
## time-stamp-end: "'; # UTC"