Fix bug in or_slist_stack(). if (a && b) wasn't being handled correctly
[smatch.git] / check_null_deref.c
blob0865d4a9b724e35e17e736ac4c5fb101b0dd6700
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 int assign_seen;
67 static void match_assign(struct expression *expr)
69 struct expression *left;
70 struct symbol *sym;
71 char *name;
73 if (assign_seen) {
74 assign_seen--;
75 return;
77 left = strip_expr(expr->left);
78 name = get_variable_from_expr_simple(left, &sym);
79 if (!name)
80 return;
81 name = alloc_string(name);
82 if (is_zero(expr->right))
83 set_state(name, my_id, sym, &isnull);
84 else
85 set_state(name, my_id, sym, &nonnull);
89 * set_new_true_false_states is used in the following conditions
90 * if (a) { ... if (a) { ... } }
91 * The problem is that after the second blog a is set to undefined
92 * even though the second condition is meaning less. (The second test
93 * could be a macro for example).
96 static void set_new_true_false_states(const char *name, int my_id,
97 struct symbol *sym, struct smatch_state *true_state,
98 struct smatch_state *false_state)
100 struct smatch_state *tmp;
102 tmp = get_state(name, my_id, sym);
104 SM_DEBUG("set_new_stuff called at %d value='%s'\n", get_lineno(), show_state(tmp));
106 if (!tmp || tmp == &undefined || tmp == &isnull)
107 set_true_false_states(name, my_id, sym, true_state, false_state);
110 static void match_condition(struct expression *expr)
112 struct symbol *sym;
113 char *name;
115 expr = strip_expr(expr);
116 switch(expr->type) {
117 case EXPR_SYMBOL:
118 case EXPR_DEREF:
119 name = get_variable_from_expr_simple(expr, &sym);
120 if (!name)
121 return;
122 name = alloc_string(name);
123 set_new_true_false_states(name, my_id, sym, &nonnull, &isnull);
124 return;
125 case EXPR_ASSIGNMENT:
126 assign_seen++;
128 * There is a kernel macro that does
129 * for ( ... ; ... || x = NULL ; ) ...
131 if (is_zero(expr->right)) {
132 name = get_variable_from_expr_simple(expr->left, &sym);
133 if (!name)
134 return;
135 name = alloc_string(name);
136 set_new_true_false_states(name, my_id, sym, NULL, &isnull);
137 return;
139 /* You have to deal with stuff like if (a = b = c) */
140 match_condition(expr->right);
141 match_condition(expr->left);
142 return;
143 default:
144 return;
148 static void match_declarations(struct symbol *sym)
150 const char * name;
152 if ((get_base_type(sym))->type == SYM_ARRAY) {
153 return;
156 name = sym->ident->name;
158 if (sym->initializer) {
159 if (is_zero(sym->initializer))
160 set_state(name, my_id, sym, &isnull);
161 else
162 set_state(name, my_id, sym, &nonnull);
163 } else {
164 set_state(name, my_id, sym, &undefined);
168 static void match_dereferences(struct expression *expr)
170 char *deref = NULL;
171 struct symbol *sym = NULL;
172 struct smatch_state *state;
174 if (strcmp(show_special(expr->deref->op), "*"))
175 return;
177 deref = get_variable_from_expr_simple(expr->deref->unop, &sym);
178 if (!deref)
179 return;
180 deref = alloc_string(deref);
182 state = get_state(deref, my_id, sym);
183 if (state == &undefined) {
184 smatch_msg("Dereferencing Undefined: '%s'", deref);
185 set_state(deref, my_id, sym, &ignore);
186 } else if (state == &isnull) {
187 /* It turns out that you only get false positives from
188 this. Mostly foo = NULL; sizeof(*foo); */
189 /* smatch_msg("Error dereferencing NULL: %s", deref); */
190 set_state(deref, my_id, sym, &ignore);
191 } else {
192 free_string(deref);
196 void register_null_deref(int id)
198 my_id = id;
199 add_merge_hook(my_id, &merge_func);
200 add_hook(&match_function_call_after, FUNCTION_CALL_AFTER_HOOK);
201 add_hook(&match_assign, ASSIGNMENT_AFTER_HOOK);
202 add_hook(&match_condition, CONDITION_HOOK);
203 add_hook(&match_dereferences, DEREF_HOOK);
204 add_hook(&match_declarations, DECLARATION_HOOK);