2 * Copyright (C) 2009 Dan Carpenter.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
19 * Some functions are designed to handle NULL values but people always
20 * do stuff like: if (foo) kfree(foo);
21 * The if check is unneeded and a waste of precious CPU cycles. Also a
24 * List of wine functions taken from Michael Stefaniuc's
25 * redundant_null_check.pl
27 * This test is not the prettiest. Smatch has a feature where it
28 * simplifies comparisons to zero and I wanted to take advantage of
29 * that, but that also makes things a bit complicated.
31 * We work backwards. When we hit a kfree() we ask was the last statement
32 * an if statement, and was the last comparison checking the pointer we
33 * are about to free? If all three answers are yes, then print a message.
41 static struct statement
*this_statement
= NULL
;
42 static struct statement
*previous_statement
= NULL
;
43 static struct expression
*previous_condition
= NULL
;
45 static const char *wine_funcs
[] = {
51 "FreeEnvironmentStringsA",
59 "SetupTermDefaultQueueCallback",
62 static void dont_check(const char *fn
, struct expression
*expr
, void *unused
)
64 struct expression
*arg
;
66 char *condition_name
= NULL
;
68 if (!previous_statement
|| !previous_condition
|| previous_statement
->type
!= STMT_IF
)
70 if (previous_statement
->if_false
)
72 if (previous_statement
->if_true
->type
!= STMT_EXPRESSION
)
75 arg
= get_argument_from_call_expr(expr
->args
, 0);
76 name
= expr_to_var(arg
);
79 condition_name
= expr_to_var(previous_condition
);
82 if (!strcmp(name
, condition_name
))
83 sm_msg("info: redundant null check on %s calling %s()", name
, fn
);
87 free_string(condition_name
);
90 static void match_statement(struct statement
*stmt
)
92 if (stmt
->type
== STMT_COMPOUND
)
94 previous_statement
= this_statement
;
95 this_statement
= stmt
;
98 static void match_condition(struct expression
*expr
)
100 previous_condition
= expr
;
103 void check_redundant_null_check(int id
)
108 add_hook(&match_statement
, STMT_HOOK
);
109 add_hook(&match_condition
, CONDITION_HOOK
);
110 add_function_hook("free", &dont_check
, NULL
);
111 if (option_project
== PROJ_KERNEL
) {
112 add_function_hook("kfree", &dont_check
, NULL
);
113 } else if (option_project
== PROJ_WINE
) {
114 for (i
= 0; i
< ARRAY_SIZE(wine_funcs
); i
++) {
115 add_function_hook(wine_funcs
[i
], &dont_check
, NULL
);