2 * sparse/check_deference.c
4 * Copyright (C) 2006 Dan Carpenter.
6 * Licensed under the Open Software License version 1.1
12 #include "smatch_slist.h"
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
;
31 STATE(assumed_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
)
54 static struct smatch_state
*unmatched_state(struct sm_state
*sm
)
56 if (sm
->state
== &assumed_nonnull
)
57 return &assumed_nonnull
;
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
;
72 slist
= get_possible_states(my_id
, name
, sym
);
73 FOR_EACH_PTR(slist
, tmp
) {
74 if (tmp
->state
== &ignore
)
76 if (tmp
->state
== &isnull
) {
77 sm_debug("is_maybe_null_no_arg() says %s &isnull\n", name
);
80 if (tmp
->state
== &undefined
) {
81 sm_debug("is_maybe_null_no_arg() says %s &undefined\n", name
);
84 } END_FOR_EACH_PTR(tmp
);
89 static int is_maybe_null(const char *name
, struct symbol
*sym
)
91 struct state_list
*slist
;
95 slist
= get_possible_states(my_id
, name
, sym
);
96 FOR_EACH_PTR(slist
, tmp
) {
97 if (tmp
->state
== &ignore
)
99 if (tmp
->state
== &isnull
) {
100 sm_debug("is_maybe_null() says %s &isnull\n", name
);
103 if (tmp
->state
== &undefined
) {
104 sm_debug("is_maybe_null() says %s &undefined\n", name
);
107 if (tmp
->state
== &arg_null
) {
108 sm_debug("is_maybe_null() says %s &arg_null\n", name
);
111 } END_FOR_EACH_PTR(tmp
);
115 static int is_maybe_null_arg(char *name
, struct symbol
*sym
)
117 struct state_list
*slist
;
118 struct sm_state
*tmp
;
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
)
127 if (tmp
->state
== &argument
|| tmp
->state
== &arg_null
)
129 } END_FOR_EACH_PTR(tmp
);
131 /* We really only care about arguments if they are null */
135 static struct func_n_param
*alloc_func_n_param(struct symbol
*func
, int param
,
138 struct func_n_param
*tmp
= __alloc_func_n_param(0);
146 static int get_arg_num(struct symbol
*sym
)
151 FOR_EACH_PTR(func_sym
->ctype
.base_type
->arguments
, arg
) {
156 } END_FOR_EACH_PTR(arg
);
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
)
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
,
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
)
187 add_param(&funcs
, sym
, 0, 0);
188 FOR_EACH_PTR(sym
->ctype
.base_type
->arguments
, arg
) {
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
;
201 struct symbol
*func
= NULL
;
204 if (expr
->fn
->type
== EXPR_SYMBOL
)
205 func
= expr
->fn
->symbol
;
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
);
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());
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
);
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
;
254 name
= get_variable_from_expr(expr
, &sym
);
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
);
267 if (tmp
== &ignore
) {
268 set_true_false_states_expr(my_id
, expr
, &ignore
, &ignore
);
272 if (!tmp
|| recently_assigned
|| is_maybe_null(name
, sym
)) {
273 set_true_false_states_expr(my_id
, expr
, &nonnull
, &isnull
);
281 static void match_condition(struct expression
*expr
)
283 expr
= strip_expr(expr
);
284 switch (expr
->type
) {
288 set_new_true_false_paths(expr
, 0);
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
);
299 set_new_true_false_paths(expr
->left
, 1);
304 static void match_declarations(struct symbol
*sym
)
308 if ((get_base_type(sym
))->type
== SYM_ARRAY
) {
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
)
323 struct symbol
*sym
= NULL
;
325 if (expr
->type
!= EXPR_PREOP
)
327 deref
= get_variable_from_expr(expr
->unop
, &sym
);
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
);
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
,
354 } END_FOR_EACH_PTR(param2
);
355 } END_FOR_EACH_PTR(param1
);
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
) {
372 FOR_EACH_PTR(funcs
, param2
) {
373 if (param1
->func
== param2
->func
)
375 } END_FOR_EACH_PTR(param2
);
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
)
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
);