Move the implications checking to after the scripts have set their states.
[smatch.git] / check_null_deref.c
blob6ba262a9ca811f336df6fd3fc82e9a3cf1a28281
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"
12 #include "smatch_slist.h"
14 /*
15 * TODO: The return_null list of functions should be determined automatically
17 const char *return_null[] = {
18 "kmalloc",
21 struct func_n_param {
22 struct symbol *func;
23 int param;
24 int line;
26 ALLOCATOR(func_n_param, "func parameters");
27 DECLARE_PTR_LIST(param_list, struct func_n_param);
29 static struct param_list *funcs;
30 static struct param_list *do_not_call;
31 static struct param_list *calls;
33 static int my_id;
35 STATE(argument);
36 STATE(arg_nonnull);
37 STATE(arg_null);
38 STATE(assumed_nonnull);
39 STATE(ignore);
40 STATE(isnull);
41 STATE(nonnull);
43 static struct symbol *func_sym;
45 static int is_maybe_null(const char *name, struct symbol *sym)
47 struct state_list *slist;
48 struct sm_state *tmp;
49 int ret = 0;
51 slist = get_possible_states(name, my_id, sym);
52 FOR_EACH_PTR(slist, tmp) {
53 if (tmp->state == &ignore)
54 return 0;
55 if (tmp->state == &isnull)
56 ret = 1;
57 if (tmp->state == &undefined)
58 ret = 1;
59 if (tmp->state == &arg_null)
60 ret = 1;
61 } END_FOR_EACH_PTR(tmp);
62 return ret;
65 static int is_argument(char *name, struct symbol *sym)
67 struct state_list *slist;
68 struct sm_state *tmp;
70 slist = get_possible_states(name, my_id, sym);
71 FOR_EACH_PTR(slist, tmp) {
72 if (tmp->state != &argument && tmp->state != &arg_null &&
73 tmp->state != &arg_nonnull && tmp->state != &merged)
74 return 0;
75 } END_FOR_EACH_PTR(tmp);
76 return 1;
79 static struct func_n_param *alloc_func_n_param(struct symbol *func, int param,
80 int line)
82 struct func_n_param *tmp = __alloc_func_n_param(0);
84 tmp->func = func;
85 tmp->param = param;
86 tmp->line = line;
87 return tmp;
90 static int get_arg_num(struct symbol *sym)
92 struct symbol *arg;
93 int i = 0;
95 FOR_EACH_PTR(func_sym->ctype.base_type->arguments, arg) {
96 if (arg == sym) {
97 return i;
99 i++;
100 } END_FOR_EACH_PTR(arg);
101 return -1;
104 static void add_do_not_call(struct symbol *sym, int line)
106 struct func_n_param *tmp;
107 int num = get_arg_num(sym);
109 FOR_EACH_PTR(do_not_call, tmp) {
110 if (tmp->func == func_sym && tmp->param == num)
111 return;
112 } END_FOR_EACH_PTR(tmp);
113 tmp = alloc_func_n_param(func_sym, num, line);
114 add_ptr_list(&do_not_call, tmp);
117 static void add_param(struct param_list **list, struct symbol *func, int param,
118 int line)
120 struct func_n_param *tmp;
122 tmp = alloc_func_n_param(func, param, line);
123 add_ptr_list(list, tmp);
126 static void match_function_def(struct symbol *sym)
128 struct symbol *arg;
130 func_sym = sym;
131 add_param(&funcs, sym, 0, 0);
132 FOR_EACH_PTR(sym->ctype.base_type->arguments, arg) {
133 if (!arg->ident) {
134 continue;
136 set_state(arg->ident->name, my_id, arg, &argument);
137 } END_FOR_EACH_PTR(arg);
140 static char *get_function_call(struct expression *expr)
142 if (expr->type != EXPR_CALL)
143 return NULL;
144 if (expr->fn->type == EXPR_SYMBOL && expr->fn->symbol)
145 return expr->fn->symbol->ident->name;
146 return NULL;
149 static void match_function_call_after(struct expression *expr)
151 struct expression *tmp;
152 struct symbol *sym;
153 char *name;
154 struct symbol *func = NULL;
155 int i;
157 if (expr->fn->type == EXPR_SYMBOL)
158 func = expr->fn->symbol;
160 i = 0;
161 FOR_EACH_PTR(expr->args, tmp) {
162 tmp = strip_expr(tmp);
163 if (tmp->op == '&') {
164 name = get_variable_from_expr(tmp->unop, &sym);
165 if (name) {
166 set_state(name, my_id, sym, &assumed_nonnull);
168 } else if (func) {
169 name = get_variable_from_expr(tmp, &sym);
170 if (name && is_maybe_null(name, sym))
171 add_param(&calls, func, i, get_lineno());
172 else
173 free_string(name);
176 i++;
177 } END_FOR_EACH_PTR(tmp);
180 static int check_null_returns(const char *name, struct symbol *sym,
181 struct expression *right)
183 int i;
184 char *func_name;
186 func_name = get_function_call(right);
187 if (!func_name)
188 return 0;
190 for(i = 0; i < sizeof(*return_null)/sizeof(return_null[0]); i++) {
191 if (!strcmp(func_name,return_null[i])) {
192 set_state(name, my_id, sym, &undefined);
193 return 1;
196 return 0;
199 static int assign_seen;
200 static void match_assign(struct expression *expr)
202 struct expression *left, *right;
203 struct symbol *sym;
204 char *name;
206 if (assign_seen) {
207 assign_seen--;
208 return;
210 left = strip_expr(expr->left);
211 name = get_variable_from_expr(left, &sym);
212 if (!name)
213 return;
214 right = strip_expr(expr->right);
215 if (is_zero(right)) {
216 set_state(name, my_id, sym, &isnull);
217 return;
219 if (check_null_returns(name, sym, right))
220 return;
222 /* by default we assume it's assigned something nonnull */
223 set_state(name, my_id, sym, &assumed_nonnull);
227 * set_new_true_false_paths() is used in the following conditions
228 * if (a) { ... if (a) { ... } }
229 * The problem is that after the second blog a is set to undefined
230 * even though the second condition is meaning less. (The second test
231 * could be a macro for example).
233 * Also, stuff passed to the condition hook is processed behind the scenes
234 * a bit. Instead of a condition like (foo == 0) which is true when foo is
235 * null, we get just (foo) and the true and false states are adjusted later.
236 * Basically the important thing to remember, is that for us, true is always
237 * non null and false is always null.
239 static void set_new_true_false_paths(const char *name, struct symbol *sym)
241 struct smatch_state *tmp;
243 tmp = get_state(name, my_id, sym);
245 SM_DEBUG("set_new_stuff called at for %s on line %d value='%s'\n",
246 name, get_lineno(), show_state(tmp));
248 if (tmp == &argument) {
249 set_true_false_states(name, my_id, sym, &arg_nonnull, &arg_null);
250 return;
253 if (!tmp || is_maybe_null(name, sym)) {
254 set_true_false_states(name, my_id, sym, &nonnull, &isnull);
255 return;
260 static void match_condition(struct expression *expr)
262 struct symbol *sym;
263 char *name;
265 expr = strip_expr(expr);
266 switch(expr->type) {
267 case EXPR_PREOP:
268 case EXPR_SYMBOL:
269 case EXPR_DEREF:
270 name = get_variable_from_expr(expr, &sym);
271 if (!name)
272 return;
273 set_new_true_false_paths(name, sym);
274 return;
275 case EXPR_ASSIGNMENT:
276 assign_seen++;
278 * There is a kernel macro that does
279 * for ( ... ; ... || x = NULL ; ) ...
281 if (is_zero(expr->right)) {
282 name = get_variable_from_expr(expr->left, &sym);
283 if (!name)
284 return;
285 set_true_false_states(name, my_id, sym, NULL, &isnull);
286 return;
288 /* You have to deal with stuff like if (a = b = c) */
289 match_condition(expr->right);
290 match_condition(expr->left);
291 return;
292 default:
293 return;
297 static void match_declarations(struct symbol *sym)
299 const char *name;
301 if ((get_base_type(sym))->type == SYM_ARRAY) {
302 return;
305 name = sym->ident->name;
307 if (sym->initializer) {
308 if (is_zero(sym->initializer)) {
309 set_state(name, my_id, sym, &isnull);
310 return;
312 if (check_null_returns(name, sym, strip_expr(sym->initializer)))
313 return;
314 set_state(name, my_id, sym, &assumed_nonnull);
315 } else {
316 set_state(name, my_id, sym, &undefined);
320 static void match_dereferences(struct expression *expr)
322 char *deref = NULL;
323 struct symbol *sym = NULL;
325 if (strcmp(show_special(expr->deref->op), "*"))
326 return;
328 deref = get_variable_from_expr(expr->deref->unop, &sym);
329 if (!deref)
330 return;
332 if (is_argument(deref, sym)) {
333 add_do_not_call(sym, get_lineno());
334 set_state(deref, my_id, sym, &assumed_nonnull);
335 } else if (is_maybe_null(deref, sym)) {
336 smatch_msg("Dereferencing Undefined: '%s'", deref);
337 set_state(deref, my_id, sym, &ignore);
338 } else {
339 free_string(deref);
343 static void end_file_processing()
345 struct func_n_param *param1, *param2;
347 // if a function is not static print it out...
348 FOR_EACH_PTR(do_not_call, param1) {
349 if (!(param1->func->ctype.modifiers & MOD_STATIC))
350 printf("%s +%d unchecked param %s %d\n",
351 get_filename(), param1->line,
352 param1->func->ident->name, param1->param);
353 } END_FOR_EACH_PTR(param1);
355 // if there is an error print it out...
356 FOR_EACH_PTR(calls, param1) {
357 FOR_EACH_PTR(do_not_call, param2) {
358 if (param1->func == param2->func &&
359 param1->param == param2->param)
360 printf("%s +%d cross_func deref %s %d\n",
361 get_filename(), param1->line,
362 param1->func->ident->name,
363 param1->param);
364 } END_FOR_EACH_PTR(param2);
365 } END_FOR_EACH_PTR(param1);
367 // if someone calls a non-static function print that..
368 FOR_EACH_PTR(calls, param1) {
369 int defined = 0;
371 FOR_EACH_PTR(funcs, param2) {
372 if (param1->func == param2->func)
373 defined = 1;
374 } END_FOR_EACH_PTR(param2);
375 if (!defined)
376 printf("%s +%d undefined param %s %d\n", get_filename(),
377 param1->line, param1->func->ident->name,
378 param1->param);
379 } END_FOR_EACH_PTR(param1);
382 void register_null_deref(int id)
384 my_id = id;
385 add_hook(&match_function_def, FUNC_DEF_HOOK);
386 add_hook(&match_function_call_after, FUNCTION_CALL_AFTER_HOOK);
387 add_hook(&match_assign, ASSIGNMENT_AFTER_HOOK);
388 add_hook(&match_condition, CONDITION_HOOK);
389 add_hook(&match_dereferences, DEREF_HOOK);
390 add_hook(&match_declarations, DECLARATION_HOOK);
391 add_hook(&end_file_processing, END_FILE_HOOK);