introduce in_macro() which returns true if we're in a macro
[smatch.git] / check_null_deref.c
blob38fefedd46643b9225e01fb8f098728faf76e679
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 struct func_n_param {
15 struct symbol *func;
16 int param;
17 int line;
19 ALLOCATOR(func_n_param, "func parameters");
20 DECLARE_PTR_LIST(param_list, struct func_n_param);
22 static struct param_list *funcs;
23 static struct param_list *do_not_call;
24 static struct param_list *calls;
26 static int my_id;
28 STATE(argument);
29 STATE(arg_nonnull);
30 STATE(arg_null);
31 STATE(assumed_nonnull);
32 STATE(ignore);
33 STATE(isnull);
34 STATE(nonnull);
36 static struct symbol *func_sym;
39 * merge_func() is to handle assumed_nonnull.
41 * Assumed_nonnull is a funny state. It's almost the same as
42 * no state. Maybe it would be better to delete it completely...
44 static struct smatch_state *merge_func(const char *name, struct symbol *sym,
45 struct smatch_state *s1,
46 struct smatch_state *s2)
48 if (s1 == &ignore || s2 == &ignore)
49 return &ignore;
50 return &merged;
54 static struct smatch_state *unmatched_state(struct sm_state *sm)
56 if (sm->state == &assumed_nonnull)
57 return &assumed_nonnull;
58 return &undefined;
61 static void set_assumed_nonnull(const char *name, struct symbol *sym, struct expression *expr, void *unused)
63 set_state(my_id, name, sym, &assumed_nonnull);
66 static int is_maybe_null_no_arg(const char *name, struct symbol *sym)
68 struct state_list *slist;
69 struct sm_state *tmp;
70 int ret = 0;
72 slist = get_possible_states(my_id, name, sym);
73 FOR_EACH_PTR(slist, tmp) {
74 if (tmp->state == &ignore)
75 return 0;
76 if (tmp->state == &isnull) {
77 sm_debug("is_maybe_null_no_arg() says %s &isnull\n", name);
78 ret = 1;
80 if (tmp->state == &undefined) {
81 sm_debug("is_maybe_null_no_arg() says %s &undefined\n", name);
82 ret = 1;
84 } END_FOR_EACH_PTR(tmp);
85 return ret;
89 static int is_maybe_null(const char *name, struct symbol *sym)
91 struct state_list *slist;
92 struct sm_state *tmp;
93 int ret = 0;
95 slist = get_possible_states(my_id, name, sym);
96 FOR_EACH_PTR(slist, tmp) {
97 if (tmp->state == &ignore)
98 return 0;
99 if (tmp->state == &isnull) {
100 sm_debug("is_maybe_null() says %s &isnull\n", name);
101 ret = 1;
103 if (tmp->state == &undefined) {
104 sm_debug("is_maybe_null() says %s &undefined\n", name);
105 ret = 1;
107 if (tmp->state == &arg_null) {
108 sm_debug("is_maybe_null() says %s &arg_null\n", name);
109 ret = 1;
111 } END_FOR_EACH_PTR(tmp);
112 return ret;
115 static int is_maybe_null_arg(char *name, struct symbol *sym)
117 struct state_list *slist;
118 struct sm_state *tmp;
119 int maybe_null = 0;
121 slist = get_possible_states(my_id, name, sym);
122 FOR_EACH_PTR(slist, tmp) {
123 if (tmp->state != &argument && tmp->state != &arg_null &&
124 tmp->state != &arg_nonnull && tmp->state != &merged &&
125 tmp->state != &assumed_nonnull)
126 return 0;
127 if (tmp->state == &argument || tmp->state == &arg_null)
128 maybe_null = 1;
129 } END_FOR_EACH_PTR(tmp);
131 /* We really only care about arguments if they are null */
132 return maybe_null;
135 static struct func_n_param *alloc_func_n_param(struct symbol *func, int param,
136 int line)
138 struct func_n_param *tmp = __alloc_func_n_param(0);
140 tmp->func = func;
141 tmp->param = param;
142 tmp->line = line;
143 return tmp;
146 static int get_arg_num(struct symbol *sym)
148 struct symbol *arg;
149 int i = 0;
151 FOR_EACH_PTR(func_sym->ctype.base_type->arguments, arg) {
152 if (arg == sym) {
153 return i;
155 i++;
156 } END_FOR_EACH_PTR(arg);
157 return -1;
160 static void add_do_not_call(struct symbol *sym, int line)
162 struct func_n_param *tmp;
163 int num = get_arg_num(sym);
165 FOR_EACH_PTR(do_not_call, tmp) {
166 if (tmp->func == func_sym && tmp->param == num)
167 return;
168 } END_FOR_EACH_PTR(tmp);
169 tmp = alloc_func_n_param(func_sym, num, line);
170 add_ptr_list(&do_not_call, tmp);
173 static void add_param(struct param_list **list, struct symbol *func, int param,
174 int line)
176 struct func_n_param *tmp;
178 tmp = alloc_func_n_param(func, param, line);
179 add_ptr_list(list, tmp);
182 static void match_function_def(struct symbol *sym)
184 struct symbol *arg;
186 func_sym = sym;
187 add_param(&funcs, sym, 0, 0);
188 FOR_EACH_PTR(sym->ctype.base_type->arguments, arg) {
189 if (!arg->ident) {
190 continue;
192 set_state(my_id, arg->ident->name, arg, &argument);
193 } END_FOR_EACH_PTR(arg);
196 static void match_function_call_after(struct expression *expr)
198 struct expression *tmp;
199 struct symbol *sym;
200 char *name;
201 struct symbol *func = NULL;
202 int i;
204 if (expr->fn->type == EXPR_SYMBOL)
205 func = expr->fn->symbol;
207 i = 0;
208 FOR_EACH_PTR(expr->args, tmp) {
209 tmp = strip_expr(tmp);
210 if (tmp->type == EXPR_PREOP && tmp->op == '&') {
211 set_state_expr(my_id, tmp->unop, &assumed_nonnull);
212 } else if (func) {
213 name = get_variable_from_expr(tmp, &sym);
214 if (final_pass && name && is_maybe_null_no_arg(name, sym))
215 add_param(&calls, func, i, get_lineno());
216 free_string(name);
218 i++;
219 } END_FOR_EACH_PTR(tmp);
222 static void match_assign(struct expression *expr)
224 if (is_zero(expr->right)) {
225 set_state_expr(my_id, expr->left, &isnull);
226 return;
228 /* hack alert. we set the state to here but it might get
229 set later to &undefined in match_function_assign().
230 By default we assume it's assigned something nonnull here. */
231 set_state_expr(my_id, expr->left, &assumed_nonnull);
235 * set_new_true_false_paths() is used in the following conditions
236 * if (a) { ... if (a) { ... } }
237 * The problem is that after the second blog a is set to undefined
238 * even though the second condition is meaning less. (The second test
239 * could be a macro for example).
241 * Also, stuff passed to the condition hook is processed behind the scenes
242 * a bit. Instead of a condition like (foo == 0) which is true when foo is
243 * null, we get just (foo) and the true and false states are adjusted later.
244 * Basically the important thing to remember, is that for us, true is always
245 * non null and false is always null.
247 static void set_new_true_false_paths(struct expression *expr, int recently_assigned)
249 struct smatch_state *tmp;
250 char *name;
251 struct symbol *sym;
254 name = get_variable_from_expr(expr, &sym);
255 if (!name || !sym)
256 goto free;
258 tmp = get_state_expr(my_id, expr);
259 sm_debug("set_new_stuff called at for %s on line %d value='%s'\n",
260 name, get_lineno(), show_state(tmp));
262 if (tmp == &argument) {
263 set_true_false_states_expr(my_id, expr, &arg_nonnull, &arg_null);
264 goto free;
267 if (tmp == &ignore) {
268 set_true_false_states_expr(my_id, expr, &ignore, &ignore);
269 goto free;
272 if (!tmp || recently_assigned || is_maybe_null(name, sym)) {
273 set_true_false_states_expr(my_id, expr, &nonnull, &isnull);
274 goto free;
276 free:
277 free_string(name);
281 static void match_condition(struct expression *expr)
283 expr = strip_expr(expr);
284 switch (expr->type) {
285 case EXPR_PREOP:
286 case EXPR_SYMBOL:
287 case EXPR_DEREF:
288 set_new_true_false_paths(expr, 0);
289 return;
290 case EXPR_ASSIGNMENT:
292 * There is a kernel macro that does
293 * for ( ... ; ... || x = NULL ; ) ...
295 if (is_zero(expr->right)) {
296 set_true_false_states_expr(my_id, expr->left, NULL, &isnull);
297 return;
299 set_new_true_false_paths(expr->left, 1);
300 return;
304 static void match_declarations(struct symbol *sym)
306 const char *name;
308 if ((get_base_type(sym))->type == SYM_ARRAY) {
309 return;
312 name = sym->ident->name;
314 if (!sym->initializer) {
315 set_state(my_id, name, sym, &undefined);
316 scoped_state(my_id, name, sym);
320 static void match_dereferences(struct expression *expr)
322 char *deref = NULL;
323 struct symbol *sym = NULL;
325 if (expr->type != EXPR_PREOP)
326 return;
327 deref = get_variable_from_expr(expr->unop, &sym);
328 if (!deref)
329 return;
331 if (is_maybe_null_arg(deref, sym)) {
332 add_do_not_call(sym, get_lineno());
333 set_state(my_id, deref, sym, &assumed_nonnull);
334 } else if (is_maybe_null(deref, sym)) {
335 sm_msg("error: dereferencing undefined: '%s'", deref);
336 set_state(my_id, deref, sym, &ignore);
338 free_string(deref);
341 static void end_file_processing(void)
343 struct func_n_param *param1, *param2;
345 // if there is an error print it out...
346 FOR_EACH_PTR(calls, param1) {
347 FOR_EACH_PTR(do_not_call, param2) {
348 if (param1->func == param2->func &&
349 param1->param == param2->param)
350 sm_printf("%s +%d error: cross_func deref %s %d\n",
351 get_filename(), param1->line,
352 param1->func->ident->name,
353 param1->param);
354 } END_FOR_EACH_PTR(param2);
355 } END_FOR_EACH_PTR(param1);
357 if (!option_info)
358 return;
360 // if a function is not static print it out...
361 FOR_EACH_PTR(do_not_call, param1) {
362 if (!(param1->func->ctype.modifiers & MOD_STATIC))
363 sm_printf("%s +%d info: unchecked param %s %d\n",
364 get_filename(), param1->line,
365 param1->func->ident->name, param1->param);
366 } END_FOR_EACH_PTR(param1);
368 // if someone calls a non-static function print that..
369 FOR_EACH_PTR(calls, param1) {
370 int defined = 0;
372 FOR_EACH_PTR(funcs, param2) {
373 if (param1->func == param2->func)
374 defined = 1;
375 } END_FOR_EACH_PTR(param2);
376 if (!defined)
377 sm_printf("%s +%d info: undefined param %s %d\n",
378 get_filename(), param1->line,
379 param1->func->ident->name, param1->param);
380 } END_FOR_EACH_PTR(param1);
383 void check_null_deref(int id)
385 if (!option_spammy)
386 return;
388 my_id = id;
389 add_merge_hook(my_id, &merge_func);
390 set_default_modification_hook(my_id, &set_assumed_nonnull);
391 add_unmatched_state_hook(my_id, &unmatched_state);
392 add_hook(&match_function_def, FUNC_DEF_HOOK);
393 add_hook(&match_function_call_after, FUNCTION_CALL_HOOK);
394 add_hook(&match_assign, ASSIGNMENT_HOOK);
395 add_hook(&match_condition, CONDITION_HOOK);
396 add_hook(&match_dereferences, DEREF_HOOK);
397 add_hook(&match_declarations, DECLARATION_HOOK);
398 add_hook(&end_file_processing, END_FILE_HOOK);