Ignore array declarations. Those can't be NULL obviously.
[smatch.git] / check_null_deref.c
blobd3bc812076a3bc8867c66c6aaed90827e53b14ca
1 /*
2 * sparse/check_deference.c
4 * Copyright (C) 2006 Dan Carpenter.
6 * Licensed under the Open Software License version 1.1
8 */
10 #include "token.h"
11 #include "smatch.h"
13 static int my_id;
15 STATE(ignore);
16 STATE(isnull);
17 STATE(nonnull);
19 static struct smatch_state *merge_func(const char *name, struct symbol *sym,
20 struct smatch_state *s1,
21 struct smatch_state *s2)
23 if (s1 == &ignore || s2 == &ignore)
24 return &ignore;
25 if (s1 == NULL && s2 == &nonnull)
26 return &nonnull;
27 return &undefined;
30 static void match_function_call_after(struct expression *expr)
32 struct expression *tmp;
33 struct symbol *sym;
34 char *name;
35 char *func = NULL;
36 int i = 0;
38 if (expr->fn->type == EXPR_SYMBOL) {
39 func = expr->fn->symbol_name->name;
42 FOR_EACH_PTR(expr->args, tmp) {
43 tmp = strip_expr(tmp);
44 if (tmp->op == '&') {
45 name = get_variable_from_expr_simple(tmp->unop, &sym);
46 if (name) {
47 name = alloc_string(name);
48 set_state(name, my_id, sym, &nonnull);
50 } else {
51 name = get_variable_from_expr_simple(tmp, &sym);
52 if (name && sym) {
53 struct smatch_state *state = get_state(name, my_id, sym);
54 if ( state == &isnull)
55 smatch_msg("Null param %s %d",
56 func, i);
57 else if (state == &undefined)
58 smatch_msg("Undefined param %s %d",
59 func, i);
62 i++;
63 } END_FOR_EACH_PTR(tmp);
66 static void match_assign(struct expression *expr)
68 struct expression *left;
69 struct symbol *sym;
70 char *name;
72 left = strip_expr(expr->left);
73 name = get_variable_from_expr_simple(left, &sym);
74 if (!name)
75 return;
76 name = alloc_string(name);
77 if (is_zero(expr->right))
78 set_state(name, my_id, sym, &isnull);
79 else
80 set_state(name, my_id, sym, &nonnull);
84 * set_new_true_false_states is used in the following conditions
85 * if (a) { ... if (a) { ... } }
86 * The problem is that after the second blog a is set to undefined
87 * even though the second condition is meaning less. (The second test
88 * could be a macro for example).
91 static void set_new_true_false_states(const char *name, int my_id,
92 struct symbol *sym, struct smatch_state *true_state,
93 struct smatch_state *false_state)
95 struct smatch_state *tmp;
97 tmp = get_state(name, my_id, sym);
99 SM_DEBUG("set_new_stuff called at %d value='%s'\n", get_lineno(), show_state(tmp));
101 if (!tmp || tmp == &undefined || tmp == &isnull)
102 set_true_false_states(name, my_id, sym, true_state, false_state);
105 static void match_condition(struct expression *expr)
107 struct symbol *sym;
108 char *name;
110 switch(expr->type) {
111 case EXPR_SYMBOL:
112 case EXPR_DEREF:
113 name = get_variable_from_expr_simple(expr, &sym);
114 if (!name)
115 return;
116 name = alloc_string(name);
117 set_new_true_false_states(name, my_id, sym, &nonnull, &isnull);
118 return;
119 case EXPR_ASSIGNMENT:
120 match_condition(expr->left);
121 return;
122 default:
123 return;
127 static void match_declarations(struct symbol *sym)
129 const char * name;
131 if ((get_base_type(sym))->type == SYM_ARRAY) {
132 return;
135 name = sym->ident->name;
137 if (sym->initializer) {
138 if (is_zero(sym->initializer))
139 set_state(name, my_id, sym, &isnull);
140 else
141 set_state(name, my_id, sym, &nonnull);
142 } else {
143 set_state(name, my_id, sym, &undefined);
147 static void match_dereferences(struct expression *expr)
149 char *deref = NULL;
150 struct symbol *sym = NULL;
151 struct smatch_state *state;
153 if (strcmp(show_special(expr->deref->op), "*"))
154 return;
156 deref = get_variable_from_expr_simple(expr->deref->unop, &sym);
157 if (!deref)
158 return;
159 deref = alloc_string(deref);
161 state = get_state(deref, my_id, sym);
162 if (state == &undefined) {
163 smatch_msg("Dereferencing Undefined: '%s'", deref);
164 set_state(deref, my_id, sym, &ignore);
165 } else if (state == &isnull) {
166 /* It turns out that you only get false positives from
167 this. Mostly foo = NULL; sizeof(*foo); */
168 /* smatch_msg("Error dereferencing NULL: %s", deref); */
169 set_state(deref, my_id, sym, &ignore);
170 } else {
171 free_string(deref);
175 void register_null_deref(int id)
177 my_id = id;
178 add_merge_hook(my_id, &merge_func);
179 add_hook(&match_function_call_after, FUNCTION_CALL_AFTER_HOOK);
180 add_hook(&match_assign, ASSIGNMENT_AFTER_HOOK);
181 add_hook(&match_condition, CONDITION_HOOK);
182 add_hook(&match_dereferences, DEREF_HOOK);
183 add_hook(&match_declarations, DECLARATION_HOOK);