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"
15 * TODO: The return_null list of functions should be determined automatically
17 const char *return_null
[] = {
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
;
38 STATE(assumed_nonnull
);
43 static struct symbol
*func_sym
;
45 static int is_maybe_null(const char *name
, struct symbol
*sym
)
47 struct state_list
*slist
;
51 slist
= get_possible_states(name
, my_id
, sym
);
52 FOR_EACH_PTR(slist
, tmp
) {
53 if (tmp
->state
== &ignore
)
55 if (tmp
->state
== &isnull
)
57 if (tmp
->state
== &undefined
)
59 if (tmp
->state
== &arg_null
)
61 } END_FOR_EACH_PTR(tmp
);
65 static int is_argument(char *name
, struct symbol
*sym
)
67 struct state_list
*slist
;
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
)
75 } END_FOR_EACH_PTR(tmp
);
79 static struct func_n_param
*alloc_func_n_param(struct symbol
*func
, int param
,
82 struct func_n_param
*tmp
= __alloc_func_n_param(0);
90 static int get_arg_num(struct symbol
*sym
)
95 FOR_EACH_PTR(func_sym
->ctype
.base_type
->arguments
, arg
) {
100 } END_FOR_EACH_PTR(arg
);
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
)
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
,
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
)
131 add_param(&funcs
, sym
, 0, 0);
132 FOR_EACH_PTR(sym
->ctype
.base_type
->arguments
, arg
) {
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
)
144 if (expr
->fn
->type
== EXPR_SYMBOL
&& expr
->fn
->symbol
)
145 return expr
->fn
->symbol
->ident
->name
;
149 static void match_function_call_after(struct expression
*expr
)
151 struct expression
*tmp
;
154 struct symbol
*func
= NULL
;
157 if (expr
->fn
->type
== EXPR_SYMBOL
)
158 func
= expr
->fn
->symbol
;
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
);
166 set_state(name
, my_id
, sym
, &assumed_nonnull
);
169 name
= get_variable_from_expr(tmp
, &sym
);
170 if (name
&& is_maybe_null(name
, sym
))
171 add_param(&calls
, func
, i
, get_lineno());
177 } END_FOR_EACH_PTR(tmp
);
180 static int check_null_returns(const char *name
, struct symbol
*sym
,
181 struct expression
*right
)
186 func_name
= get_function_call(right
);
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
);
199 static int assign_seen
;
200 static void match_assign(struct expression
*expr
)
202 struct expression
*left
, *right
;
210 left
= strip_expr(expr
->left
);
211 name
= get_variable_from_expr(left
, &sym
);
214 right
= strip_expr(expr
->right
);
215 if (is_zero(right
)) {
216 set_state(name
, my_id
, sym
, &isnull
);
219 if (check_null_returns(name
, sym
, right
))
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
);
253 if (!tmp
|| is_maybe_null(name
, sym
)) {
254 set_true_false_states(name
, my_id
, sym
, &nonnull
, &isnull
);
260 static void match_condition(struct expression
*expr
)
265 expr
= strip_expr(expr
);
270 name
= get_variable_from_expr(expr
, &sym
);
273 set_new_true_false_paths(name
, sym
);
275 case EXPR_ASSIGNMENT
:
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
);
285 set_true_false_states(name
, my_id
, sym
, NULL
, &isnull
);
288 /* You have to deal with stuff like if (a = b = c) */
289 match_condition(expr
->right
);
290 match_condition(expr
->left
);
297 static void match_declarations(struct symbol
*sym
)
301 if ((get_base_type(sym
))->type
== SYM_ARRAY
) {
305 name
= sym
->ident
->name
;
307 if (sym
->initializer
) {
308 if (is_zero(sym
->initializer
)) {
309 set_state(name
, my_id
, sym
, &isnull
);
312 if (check_null_returns(name
, sym
, strip_expr(sym
->initializer
)))
314 set_state(name
, my_id
, sym
, &assumed_nonnull
);
316 set_state(name
, my_id
, sym
, &undefined
);
320 static void match_dereferences(struct expression
*expr
)
323 struct symbol
*sym
= NULL
;
325 if (strcmp(show_special(expr
->deref
->op
), "*"))
328 deref
= get_variable_from_expr(expr
->deref
->unop
, &sym
);
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
);
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
,
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
) {
371 FOR_EACH_PTR(funcs
, param2
) {
372 if (param1
->func
== param2
->func
)
374 } END_FOR_EACH_PTR(param2
);
376 printf("%s +%d undefined param %s %d\n", get_filename(),
377 param1
->line
, param1
->func
->ident
->name
,
379 } END_FOR_EACH_PTR(param1
);
382 void register_null_deref(int 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
);