comparison: partially fix how links are updated
[smatch.git] / check_redundant_null_check.c
blob372a73ee6d77ffd7207f3358a544c8b1ec9028d2
1 /*
2 * sparse/check_redundant_null_check.c
4 * Copyright (C) 2009 Dan Carpenter.
6 * Licensed under the Open Software License version 1.1
8 */
11 * Some functions are designed to handle NULL values but people always
12 * do stuff like: if (foo) kfree(foo);
13 * The if check is unneeded and a waste of precious CPU cycles. Also a
14 * little bit messy.
16 * List of wine functions taken from Michael Stefaniuc's
17 * redundant_null_check.pl
19 * This test is not the prettiest. Smatch has a feature where it
20 * simplifies comparisons to zero and I wanted to take advantage of
21 * that, but that also makes things a bit complicated.
23 * We work backwards. When we hit a kfree() we ask was the last statement
24 * an if statement, and was the last comparison checking the pointer we
25 * are about to free? If all three answers are yes, then print a message.
29 #include "smatch.h"
31 static int my_id;
33 static struct statement *this_statement = NULL;
34 static struct statement *previous_statement = NULL;
35 static struct expression *previous_condition = NULL;
37 static const char *wine_funcs[] = {
38 "HeapFree",
39 "RtlFreeHeap",
40 "SysFreeString",
41 "CryptMemFree",
42 "DllFreeSplMem",
43 "FreeEnvironmentStringsA",
44 "Free",
45 "GdipFree",
46 "I_RpcFree",
47 "ldap_memfreeA",
48 "ldap_memfreeW",
49 "LsaFreeMemory",
50 "MyFree",
51 "SetupTermDefaultQueueCallback",
54 static void dont_check(const char *fn, struct expression *expr, void *unused)
56 struct expression *arg;
57 char *name = NULL;
58 char *condition_name = NULL;
60 if (!previous_statement || !previous_condition || previous_statement->type != STMT_IF)
61 return;
63 arg = get_argument_from_call_expr(expr->args, 0);
64 name = expr_to_var(arg);
65 if (!name)
66 goto free;
67 condition_name = expr_to_var(previous_condition);
68 if (!condition_name)
69 goto free;
70 if (!strcmp(name, condition_name))
71 sm_msg("info: redundant null check on %s calling %s()", name, fn);
73 free:
74 free_string(name);
75 free_string(condition_name);
78 static void match_statement(struct statement *stmt)
80 if (stmt->type == STMT_COMPOUND)
81 return;
82 previous_statement = this_statement;
83 this_statement = stmt;
86 static void match_condition(struct expression *expr)
88 previous_condition = expr;
91 void check_redundant_null_check(int id)
93 my_id = id;
94 int i;
96 add_hook(&match_statement, STMT_HOOK);
97 add_hook(&match_condition, CONDITION_HOOK);
98 add_function_hook("free", &dont_check, NULL);
99 if (option_project == PROJ_KERNEL) {
100 add_function_hook("kfree", &dont_check, NULL);
101 } else if (option_project == PROJ_WINE) {
102 for (i = 0; i < ARRAY_SIZE(wine_funcs); i++) {
103 add_function_hook(wine_funcs[i], &dont_check, NULL);