FYI, I've just pushed the patch below. I added test cases to this stand-alone Makefile, but added the final one (for (void*)0) only after pushing the patch below. Then I realized that current limitations prevent detection of that variant of 0/NULL, so have just revised the script accordingly.
u = ./useless-if-before-free do_diff = \ diff -u <($u <(printf "$$i")|sed 's/.*: //') \ <(printf "$$i"'\n'|sed 's/;$$//') SHELL = /bin/bash all: i='if (p) free(p);'; $(do_diff) $u <(printf 'if (p) free(q);') > /dev/null && exit 1 || : i='if (p) free((void)p);'; $(do_diff) i='if (p) free( (void)p);'; $(do_diff) i='if (p) free((T *) p);'; $(do_diff) i='if (*p) free(*p);'; $(do_diff) i='if (p)\nfree(p);'; $(do_diff) i='if ( p ) free(p);'; $(do_diff) i='if (p) free( p );'; $(do_diff) i='if(p) free (p);'; $(do_diff) i='if(p){free (p);}'; $(do_diff) i='if(p){\nfree (p);}'; $(do_diff) $u --name=z <(printf 'if (p) z (p);') > /dev/null $u --name=z <(printf 'if(p)z(p);') > /dev/null $u <(printf 'if(p[i + 1]) free(p[i + 1]);') > /dev/null $u <(printf 'if(p[i + 1]) free(p[i+1]);') > /dev/null test $$($u --name=z <(printf 'if(p)z(p);if(p)z(p);')|wc -l) = 2 i='if(NULL != p){\nfree (p);}'; $(do_diff) i='if(p != NULL){\nfree (p);}'; $(do_diff) i='if(p != 0){\nfree (p);}'; $(do_diff) # i='if((void *)0 != p){\nfree (p);}'; $(do_diff) >From 471cbb075f76e489fa96fad80bca65da7e01f683 Mon Sep 17 00:00:00 2001 From: Jim Meyering <meyer...@redhat.com> Date: Wed, 28 Jan 2009 09:19:28 +0100 Subject: [PATCH] useless-if-before-free: recognize more variants * build-aux/useless-if-before-free: Also recognize e.g., if (NULL != p) free (p); --- ChangeLog | 6 +++++ build-aux/useless-if-before-free | 40 ++++++++++++++++++++++++++++--------- 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/ChangeLog b/ChangeLog index 3b3a0f0..3a3244e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2009-01-28 Jim Meyering <meyer...@redhat.com> + + useless-if-before-free: recognize more variants + * build-aux/useless-if-before-free: Also recognize e.g., + if (NULL != p) free (p); + 2009-01-27 Mark McLoughlin <mar...@redhat.com> test-getaddrinfo: skip (don't fail) this test when there's no network diff --git a/build-aux/useless-if-before-free b/build-aux/useless-if-before-free index 0bae2c4..a2fc773 100755 --- a/build-aux/useless-if-before-free +++ b/build-aux/useless-if-before-free @@ -1,14 +1,16 @@ #!/usr/bin/perl -T # Detect instances of "if (p) free (p);". # Likewise for "if (p != NULL) free (p);". And with braces. +# Also detect "if (NULL != p) free (p);". +# And with 0 or "(void *)0" in place of NULL. -my $VERSION = '2008-05-25 17:36'; # UTC +my $VERSION = '2009-01-28 08:16'; # UTC # The definition above must lie within the first 8 lines in order # for the Emacs time-stamp write hook (at end) to update it. # If you change this file with Emacs, please let the write hook # do its job. Otherwise, update this string manually. -# Copyright (C) 2008 Free Software Foundation, Inc. +# Copyright (C) 2008, 2009 Free Software Foundation, Inc. # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -60,7 +62,7 @@ detect free-like functions named FOO and BAR. OPTIONS: --list print only the name of each matching FILE (\0-terminated) - --name=N add name N to the list of `free'-like functions to detect; + --name=N add name N to the list of \`free\'-like functions to detect; may be repeated --help display this help and exit @@ -84,6 +86,14 @@ EOF exit $exit_code; } +sub is_NULL ($) +{ + my ($expr) = @_; + return ($expr eq 'NULL' + || $expr eq '0' + || $expr =~ /^\(\s*(char|void)\s*\*\s*\)\s*0$/); +} + { sub EXIT_MATCH {0} sub EXIT_NO_MATCH {1} @@ -122,21 +132,31 @@ EOF while (defined (my $line = <FH>)) { while ($line =~ - /\b(if\s*\(\s*([^)]+?)(?:\s*!=\s*NULL)?\s*\) + /\b(if\s*\(\s*([^)]+?)(?:\s*!=\s*([^)]+?))?\s*\) + # 1 2 3 (?: \s*$regexp\s*\((?:\s*\([^)]+\))?\s*([^)]+)\)| \s*\{\s*$regexp\s*\((?:\s*\([^)]+\))?\s*([^)]+)\)\s*;\s*\}))/sxg) { - # Compare "if" expression and free'd expression, - # without regard to white space. - (my $e1 = $2) =~ tr/ \t//d; - my $e2 = defined $3 ? $3 : $4; + my $all = $1; + my ($lhs, $rhs) = ($2, $3); + my ($free_opnd, $braced_free_opnd) = ($4, $5); + my $non_NULL; + if (!defined $rhs) { $non_NULL = $lhs } + elsif (is_NULL $rhs) { $non_NULL = $lhs } + elsif (is_NULL $lhs) { $non_NULL = $rhs } + else { next } + + # Compare the non-NULL part of the "if" expression and the + # free'd expression, without regard to white space. + $non_NULL =~ tr/ \t//d; + my $e2 = defined $free_opnd ? $free_opnd : $braced_free_opnd; $e2 =~ tr/ \t//d; - if ($e1 eq $e2) + if ($non_NULL eq $e2) { $found_match = 1; $list and (print "$file\0"), next FILE; - print "$file: $1\n"; + print "$file: $all\n"; } } } -- 1.6.1.1.374.g0d9d7