Moved all the logic for handling conditions into a seperate file.
[smatch.git] / check_null_deref.c
blobe07754b76de3f419b330518539d7b009e9dce542
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 enum states {
16 ISNULL,
17 NONNULL,
18 IGNORE,
21 static int merge_func(const char *name, struct symbol *sym, int s1, int s2)
23 if (s2 == IGNORE)
24 return IGNORE;
25 return UNDEFINED;
28 static void match_function_call_after(struct expression *expr)
30 struct expression *tmp;
31 struct symbol *sym;
32 char *name;
33 char *func = NULL;
34 int i = 0;
36 if (expr->fn->type == EXPR_SYMBOL) {
37 func = expr->fn->symbol_name->name;
40 FOR_EACH_PTR(expr->args, tmp) {
41 if (tmp->op == '&') {
42 name = get_variable_from_expr_simple(tmp->unop, &sym);
43 if (name) {
44 name = alloc_string(name);
45 set_state(name, my_id, sym, NONNULL);
47 } else {
48 name = get_variable_from_expr_simple(tmp, &sym);
49 if (name && sym) {
50 int state = get_state(name, my_id, sym);
51 if ( state == ISNULL)
52 smatch_msg("Null param %s %d",
53 func, i);
54 else if (state == UNDEFINED)
55 smatch_msg("Undefined param %s %d",
56 func, i);
59 i++;
60 } END_FOR_EACH_PTR(tmp);
63 static int is_null(struct expression *expr)
65 if (expr->type == EXPR_VALUE && expr->value == 0)
66 return 1;
67 if (expr->op == '(')
68 return is_null(expr->unop);
69 if (expr->type == EXPR_CAST)
70 return is_null(expr->cast_expression);
71 return 0;
74 static void match_assign(struct expression *expr)
76 struct symbol *sym;
77 char *name;
79 name = get_variable_from_expr_simple(expr->left, &sym);
80 if (!name)
81 return;
82 name = alloc_string(name);
83 if (is_null(expr->right))
84 set_state(name, my_id, sym, ISNULL);
85 else
86 set_state(name, my_id, sym, NONNULL);
90 * set_new_true_false_states is used in the following conditions
91 * if (a) { ... if (a) { ... } }
92 * The problem is that after the second blog a is set to undefined
93 * even though the second condition is meaning less. (The second test
94 * could be a macro for example).
97 static void set_new_true_false_states(const char *name, int my_id,
98 struct symbol *sym, int true_state,
99 int false_state)
101 int tmp;
103 tmp = get_state(name, my_id, sym);
105 SM_DEBUG("set_new_stuff called at %d value=%d\n", get_lineno(), tmp);
107 if (tmp == NOTFOUND || tmp == UNDEFINED || tmp == ISNULL)
108 set_true_false_states(name, my_id, sym, true_state, false_state);
111 static void match_condition(struct expression *expr)
113 struct symbol *sym;
114 char *name;
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 match_condition(expr->left);
127 return;
128 default:
129 return;
133 static void match_declarations(struct symbol *sym)
135 if (sym->ident) {
136 const char * name;
137 name = sym->ident->name;
138 if (sym->initializer && is_null(sym->initializer))
139 set_state(name, my_id, sym, ISNULL);
143 static int is_array(struct expression *expr)
145 struct symbol *tmp = NULL;
146 char *name;
148 name = get_variable_from_expr_simple(expr, NULL);
149 if (expr->ctype)
150 tmp = get_base_type(expr->ctype);
151 if (!tmp || !name)
152 return 0;
153 if (tmp->type == SYM_PTR)
154 tmp = get_base_type(tmp);
155 if (!tmp)
156 return 0;
157 printf("debug: %s %d\n", name, tmp->type);
158 if (tmp->ident)
159 printf("name %s\n", tmp->ident->name);
161 return 0;
162 if (expr->type != EXPR_BINOP || expr->op != '+')
163 return 0;
164 //if (expr->left->ctype && expr->left->ctype.base_type == &ptr_ctype)
165 // return 1;
166 return 0;
169 static void match_dereferences(struct expression *expr)
171 char *deref = NULL;
172 struct symbol *sym = NULL;
174 if (expr->op == '*') {
175 expr = expr->unop;
176 } else if (expr->type == EXPR_DEREF && expr->deref->op == '*')
177 expr = expr->deref->unop;
180 * Say you have foo->bar.baz.n
181 * In that case we really only care about part to the
182 * left of the ->.
184 while (expr->type == EXPR_DEREF && expr->deref->op != '*')
185 expr = expr->deref;
187 deref = get_variable_from_expr_simple(expr, &sym);
188 if (!deref)
189 return;
190 deref = alloc_string(deref);
192 switch(get_state(deref, my_id, sym)) {
193 case UNDEFINED:
194 smatch_msg("Dereferencing Undefined: %s", deref);
195 set_state(deref, my_id, sym, IGNORE);
196 break;
197 case ISNULL:
198 /* It turns out that you only get false positives from
199 this. Mostly foo = NULL; sizeof(*foo); */
200 /* smatch_msg("Error dereferencing NULL: %s", deref); */
201 set_state(deref, my_id, sym, IGNORE);
202 break;
203 default:
204 free_string(deref);
205 break;
209 void register_null_deref(int id)
211 my_id = id;
212 add_merge_hook(my_id, &merge_func);
213 add_hook(&match_function_call_after, FUNCTION_CALL_AFTER_HOOK);
214 add_hook(&match_assign, ASSIGNMENT_AFTER_HOOK);
215 add_hook(&match_condition, CONDITION_HOOK);
216 add_hook(&match_dereferences, DEREF_HOOK);
217 add_hook(&match_declarations, DECLARATION_HOOK);