Add scoped_state() and add_scope_hook().
[smatch.git] / check_null_deref.c
blob5eabddac6e29851ed8b2edfc8a4dcda366b0b01b
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 static 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;
46 * merge_func() is to handle assumed_nonnull.
48 * Assumed_nonnull is a funny state. It's almost the same as
49 * no state. Maybe it would be better to delete it completely...
51 static struct smatch_state *merge_func(const char *name, struct symbol *sym,
52 struct smatch_state *s1,
53 struct smatch_state *s2)
55 if (s1 == &ignore || s2 == &ignore)
56 return &ignore;
57 return &merged;
61 static struct smatch_state *unmatched_state(struct sm_state *sm)
63 if (sm->state == &assumed_nonnull)
64 return &assumed_nonnull;
65 return &undefined;
68 static int is_maybe_null_no_arg(const char *name, struct symbol *sym)
70 struct state_list *slist;
71 struct sm_state *tmp;
72 int ret = 0;
74 slist = get_possible_states(name, my_id, sym);
75 FOR_EACH_PTR(slist, tmp) {
76 if (tmp->state == &ignore)
77 return 0;
78 if (tmp->state == &isnull) {
79 SM_DEBUG("is_maybe_null_no_arg() says %s &isnull\n", name);
80 ret = 1;
82 if (tmp->state == &undefined) {
83 SM_DEBUG("is_maybe_null_no_arg() says %s &undefined\n", name);
84 ret = 1;
86 } END_FOR_EACH_PTR(tmp);
87 return ret;
91 static int is_maybe_null(const char *name, struct symbol *sym)
93 struct state_list *slist;
94 struct sm_state *tmp;
95 int ret = 0;
97 slist = get_possible_states(name, my_id, sym);
98 FOR_EACH_PTR(slist, tmp) {
99 if (tmp->state == &ignore)
100 return 0;
101 if (tmp->state == &isnull) {
102 SM_DEBUG("is_maybe_null() says %s &isnull\n", name);
103 ret = 1;
105 if (tmp->state == &undefined) {
106 SM_DEBUG("is_maybe_null() says %s &undefined\n", name);
107 ret = 1;
109 if (tmp->state == &arg_null) {
110 SM_DEBUG("is_maybe_null() says %s &arg_null\n", name);
111 ret = 1;
113 } END_FOR_EACH_PTR(tmp);
114 return ret;
117 static int is_maybe_null_arg(char *name, struct symbol *sym)
119 struct state_list *slist;
120 struct sm_state *tmp;
121 int maybe_null = 0;
123 slist = get_possible_states(name, my_id, sym);
124 FOR_EACH_PTR(slist, tmp) {
125 if (tmp->state != &argument && tmp->state != &arg_null &&
126 tmp->state != &arg_nonnull && tmp->state != &merged &&
127 tmp->state != &assumed_nonnull)
128 return 0;
129 if (tmp->state == &argument || tmp->state == &arg_null)
130 maybe_null = 1;
131 } END_FOR_EACH_PTR(tmp);
133 /* We really only care about arguments if they are null */
134 return maybe_null;
137 static struct func_n_param *alloc_func_n_param(struct symbol *func, int param,
138 int line)
140 struct func_n_param *tmp = __alloc_func_n_param(0);
142 tmp->func = func;
143 tmp->param = param;
144 tmp->line = line;
145 return tmp;
148 static int get_arg_num(struct symbol *sym)
150 struct symbol *arg;
151 int i = 0;
153 FOR_EACH_PTR(func_sym->ctype.base_type->arguments, arg) {
154 if (arg == sym) {
155 return i;
157 i++;
158 } END_FOR_EACH_PTR(arg);
159 return -1;
162 static void add_do_not_call(struct symbol *sym, int line)
164 struct func_n_param *tmp;
165 int num = get_arg_num(sym);
167 FOR_EACH_PTR(do_not_call, tmp) {
168 if (tmp->func == func_sym && tmp->param == num)
169 return;
170 } END_FOR_EACH_PTR(tmp);
171 tmp = alloc_func_n_param(func_sym, num, line);
172 add_ptr_list(&do_not_call, tmp);
175 static void add_param(struct param_list **list, struct symbol *func, int param,
176 int line)
178 struct func_n_param *tmp;
180 tmp = alloc_func_n_param(func, param, line);
181 add_ptr_list(list, tmp);
184 static void match_function_def(struct symbol *sym)
186 struct symbol *arg;
188 func_sym = sym;
189 add_param(&funcs, sym, 0, 0);
190 FOR_EACH_PTR(sym->ctype.base_type->arguments, arg) {
191 if (!arg->ident) {
192 continue;
194 set_state(arg->ident->name, my_id, arg, &argument);
195 } END_FOR_EACH_PTR(arg);
198 static void match_function_call_after(struct expression *expr)
200 struct expression *tmp;
201 struct symbol *sym;
202 char *name;
203 struct symbol *func = NULL;
204 int i;
206 if (expr->fn->type == EXPR_SYMBOL)
207 func = expr->fn->symbol;
209 i = 0;
210 FOR_EACH_PTR(expr->args, tmp) {
211 tmp = strip_expr(tmp);
212 if (tmp->op == '&') {
213 name = get_variable_from_expr(tmp->unop, &sym);
214 if (name) {
215 set_state(name, my_id, sym, &assumed_nonnull);
217 free_string(name);
218 } else if (func) {
219 name = get_variable_from_expr(tmp, &sym);
220 if (name && is_maybe_null_no_arg(name, sym))
221 add_param(&calls, func, i, get_lineno());
222 free_string(name);
224 i++;
225 } END_FOR_EACH_PTR(tmp);
228 static void match_assign_returns_null(const char *fn, struct expression *expr,
229 void *unused)
231 struct expression *left;
232 struct symbol *sym;
233 char *name;
235 left = strip_expr(expr->left);
236 name = get_variable_from_expr(left, &sym);
237 if (!name)
238 return;
239 set_state(name, my_id, sym, &undefined);
240 free_string(name);
243 static void match_assign(struct expression *expr)
245 struct expression *left, *right;
246 struct symbol *sym;
247 char *name;
249 left = strip_expr(expr->left);
250 name = get_variable_from_expr(left, &sym);
251 if (!name)
252 return;
253 right = strip_expr(expr->right);
254 if (is_zero(right)) {
255 set_state(name, my_id, sym, &isnull);
256 free_string(name);
257 return;
259 /* hack alert. we set the state to here but it might get
260 set later to &undefined in match_function_assign().
261 By default we assume it's assigned something nonnull here. */
262 set_state(name, my_id, sym, &assumed_nonnull);
263 free_string(name);
267 * set_new_true_false_paths() is used in the following conditions
268 * if (a) { ... if (a) { ... } }
269 * The problem is that after the second blog a is set to undefined
270 * even though the second condition is meaning less. (The second test
271 * could be a macro for example).
273 * Also, stuff passed to the condition hook is processed behind the scenes
274 * a bit. Instead of a condition like (foo == 0) which is true when foo is
275 * null, we get just (foo) and the true and false states are adjusted later.
276 * Basically the important thing to remember, is that for us, true is always
277 * non null and false is always null.
279 static void set_new_true_false_paths(const char *name, struct symbol *sym,
280 int recently_assigned)
282 struct smatch_state *tmp;
284 tmp = get_state(name, my_id, sym);
286 SM_DEBUG("set_new_stuff called at for %s on line %d value='%s'\n",
287 name, get_lineno(), show_state(tmp));
289 if (tmp == &argument) {
290 set_true_false_states(name, my_id, sym, &arg_nonnull, &arg_null);
291 return;
294 if (tmp == &ignore) {
295 set_true_false_states(name, my_id, sym, &ignore, &ignore);
296 return;
299 if (!tmp || recently_assigned || is_maybe_null(name, sym)) {
300 set_true_false_states(name, my_id, sym, &nonnull, &isnull);
301 return;
305 static void match_var_null_nonnull(struct expression *expr,
306 int recently_assigned)
308 struct symbol *sym;
309 char *name;
311 name = get_variable_from_expr(expr, &sym);
312 if (!name)
313 return;
314 set_new_true_false_paths(name, sym, recently_assigned);
315 free_string(name);
318 static void match_condition(struct expression *expr)
320 struct symbol *sym;
321 char *name;
322 expr = strip_expr(expr);
323 switch(expr->type) {
324 case EXPR_PREOP:
325 case EXPR_SYMBOL:
326 case EXPR_DEREF:
327 match_var_null_nonnull(expr, 0);
328 return;
329 case EXPR_ASSIGNMENT:
331 * There is a kernel macro that does
332 * for ( ... ; ... || x = NULL ; ) ...
334 if (is_zero(expr->right)) {
335 name = get_variable_from_expr(expr->left, &sym);
336 if (!name)
337 return;
338 set_true_false_states(name, my_id, sym, NULL, &isnull);
339 free_string(name);
340 return;
342 match_var_null_nonnull(expr->left, 1);
343 return;
347 static void match_declarations(struct symbol *sym)
349 const char *name;
351 if ((get_base_type(sym))->type == SYM_ARRAY) {
352 return;
355 name = sym->ident->name;
357 if (sym->initializer) {
358 if (is_zero(sym->initializer)) {
359 set_state(name, my_id, sym, &isnull);
360 scoped_state(name, my_id, sym);
361 return;
363 set_state(name, my_id, sym, &assumed_nonnull);
364 scoped_state(name, my_id, sym);
365 } else {
366 set_state(name, my_id, sym, &undefined);
367 scoped_state(name, my_id, sym);
371 static void match_dereferences(struct expression *expr)
373 char *deref = NULL;
374 struct symbol *sym = NULL;
376 if (strcmp(show_special(expr->deref->op), "*"))
377 return;
379 deref = get_variable_from_expr(expr->deref->unop, &sym);
380 if (!deref)
381 return;
383 if (is_maybe_null_arg(deref, sym)) {
384 add_do_not_call(sym, get_lineno());
385 set_state(deref, my_id, sym, &assumed_nonnull);
386 } else if (is_maybe_null(deref, sym)) {
387 smatch_msg("error: dereferencing undefined: '%s'", deref);
388 set_state(deref, my_id, sym, &ignore);
390 free_string(deref);
393 static void end_file_processing(void)
395 struct func_n_param *param1, *param2;
397 // if a function is not static print it out...
398 FOR_EACH_PTR(do_not_call, param1) {
399 if (!(param1->func->ctype.modifiers & MOD_STATIC))
400 printf("%s +%d info: unchecked param %s %d\n",
401 get_filename(), param1->line,
402 param1->func->ident->name, param1->param);
403 } END_FOR_EACH_PTR(param1);
405 // if there is an error print it out...
406 FOR_EACH_PTR(calls, param1) {
407 FOR_EACH_PTR(do_not_call, param2) {
408 if (param1->func == param2->func &&
409 param1->param == param2->param)
410 printf("%s +%d error: cross_func deref %s %d\n",
411 get_filename(), param1->line,
412 param1->func->ident->name,
413 param1->param);
414 } END_FOR_EACH_PTR(param2);
415 } END_FOR_EACH_PTR(param1);
417 // if someone calls a non-static function print that..
418 FOR_EACH_PTR(calls, param1) {
419 int defined = 0;
421 FOR_EACH_PTR(funcs, param2) {
422 if (param1->func == param2->func)
423 defined = 1;
424 } END_FOR_EACH_PTR(param2);
425 if (!defined)
426 printf("%s +%d info: undefined param %s %d\n",
427 get_filename(), param1->line,
428 param1->func->ident->name, param1->param);
429 } END_FOR_EACH_PTR(param1);
432 static void register_allocation_funcs(void)
434 struct token *token;
435 const char *func;
437 token = get_tokens_file("kernel.allocation_funcs");
438 if (!token)
439 return;
440 if (token_type(token) != TOKEN_STREAMBEGIN)
441 return;
442 token = token->next;
443 while (token_type(token) != TOKEN_STREAMEND) {
444 if (token_type(token) != TOKEN_IDENT)
445 return;
446 func = show_ident(token->ident);
447 add_function_assign_hook(func, &match_assign_returns_null,
448 NULL);
449 token = token->next;
451 clear_token_alloc();
454 void check_null_deref(int id)
456 int i;
458 my_id = id;
459 add_merge_hook(my_id, &merge_func);
460 add_unmatched_state_hook(my_id, &unmatched_state);
461 add_hook(&match_function_def, FUNC_DEF_HOOK);
462 add_hook(&match_function_call_after, FUNCTION_CALL_HOOK);
463 add_hook(&match_assign, ASSIGNMENT_HOOK);
464 add_hook(&match_condition, CONDITION_HOOK);
465 add_hook(&match_dereferences, DEREF_HOOK);
466 add_hook(&match_declarations, DECLARATION_HOOK);
467 add_hook(&end_file_processing, END_FILE_HOOK);
469 for(i = 0; i < sizeof(*return_null)/sizeof(return_null[0]); i++) {
470 add_function_assign_hook(return_null[i],
471 &match_assign_returns_null, NULL);
473 register_allocation_funcs();