2 * sparse/check_deference.c
4 * Copyright (C) 2006 Dan Carpenter.
6 * Licensed under the Open Software License version 1.1
19 static struct smatch_state
*merge_func(const char *name
, struct symbol
*sym
,
20 struct smatch_state
*s1
,
21 struct smatch_state
*s2
)
23 if (s1
== &ignore
|| s2
== &ignore
)
25 if (s1
== NULL
&& s2
== &nonnull
)
30 static void match_function_call_after(struct expression
*expr
)
32 struct expression
*tmp
;
38 if (expr
->fn
->type
== EXPR_SYMBOL
) {
39 func
= expr
->fn
->symbol_name
->name
;
42 FOR_EACH_PTR(expr
->args
, tmp
) {
43 tmp
= strip_expr(tmp
);
45 name
= get_variable_from_expr_simple(tmp
->unop
, &sym
);
47 name
= alloc_string(name
);
48 set_state(name
, my_id
, sym
, &nonnull
);
51 name
= get_variable_from_expr_simple(tmp
, &sym
);
53 struct smatch_state
*state
= get_state(name
, my_id
, sym
);
54 if ( state
== &isnull
)
55 smatch_msg("Null param %s %d",
57 else if (state
== &undefined
)
58 smatch_msg("Undefined param %s %d",
63 } END_FOR_EACH_PTR(tmp
);
66 static int assign_seen
;
67 static void match_assign(struct expression
*expr
)
69 struct expression
*left
;
77 left
= strip_expr(expr
->left
);
78 name
= get_variable_from_expr_simple(left
, &sym
);
81 name
= alloc_string(name
);
82 if (is_zero(expr
->right
))
83 set_state(name
, my_id
, sym
, &isnull
);
85 set_state(name
, my_id
, sym
, &nonnull
);
89 * set_new_true_false_states is used in the following conditions
90 * if (a) { ... if (a) { ... } }
91 * The problem is that after the second blog a is set to undefined
92 * even though the second condition is meaning less. (The second test
93 * could be a macro for example).
96 static void set_new_true_false_states(const char *name
, int my_id
,
97 struct symbol
*sym
, struct smatch_state
*true_state
,
98 struct smatch_state
*false_state
)
100 struct smatch_state
*tmp
;
102 tmp
= get_state(name
, my_id
, sym
);
104 SM_DEBUG("set_new_stuff called at %d value='%s'\n", get_lineno(), show_state(tmp
));
106 if (!tmp
|| tmp
== &undefined
|| tmp
== &isnull
)
107 set_true_false_states(name
, my_id
, sym
, true_state
, false_state
);
110 static void match_condition(struct expression
*expr
)
115 expr
= strip_expr(expr
);
119 name
= get_variable_from_expr_simple(expr
, &sym
);
122 name
= alloc_string(name
);
123 set_new_true_false_states(name
, my_id
, sym
, &nonnull
, &isnull
);
125 case EXPR_ASSIGNMENT
:
128 * There is a kernel macro that does
129 * for ( ... ; ... || x = NULL ; ) ...
131 if (is_zero(expr
->right
)) {
132 name
= get_variable_from_expr_simple(expr
->left
, &sym
);
135 name
= alloc_string(name
);
136 set_new_true_false_states(name
, my_id
, sym
, NULL
, &isnull
);
139 /* You have to deal with stuff like if (a = b = c) */
140 match_condition(expr
->right
);
141 match_condition(expr
->left
);
148 static void match_declarations(struct symbol
*sym
)
152 if ((get_base_type(sym
))->type
== SYM_ARRAY
) {
156 name
= sym
->ident
->name
;
158 if (sym
->initializer
) {
159 if (is_zero(sym
->initializer
))
160 set_state(name
, my_id
, sym
, &isnull
);
162 set_state(name
, my_id
, sym
, &nonnull
);
164 set_state(name
, my_id
, sym
, &undefined
);
168 static void match_dereferences(struct expression
*expr
)
171 struct symbol
*sym
= NULL
;
172 struct smatch_state
*state
;
174 if (strcmp(show_special(expr
->deref
->op
), "*"))
177 deref
= get_variable_from_expr_simple(expr
->deref
->unop
, &sym
);
180 deref
= alloc_string(deref
);
182 state
= get_state(deref
, my_id
, sym
);
183 if (state
== &undefined
) {
184 smatch_msg("Dereferencing Undefined: '%s'", deref
);
185 set_state(deref
, my_id
, sym
, &ignore
);
186 } else if (state
== &isnull
) {
187 /* It turns out that you only get false positives from
188 this. Mostly foo = NULL; sizeof(*foo); */
189 /* smatch_msg("Error dereferencing NULL: %s", deref); */
190 set_state(deref
, my_id
, sym
, &ignore
);
196 void register_null_deref(int id
)
199 add_merge_hook(my_id
, &merge_func
);
200 add_hook(&match_function_call_after
, FUNCTION_CALL_AFTER_HOOK
);
201 add_hook(&match_assign
, ASSIGNMENT_AFTER_HOOK
);
202 add_hook(&match_condition
, CONDITION_HOOK
);
203 add_hook(&match_dereferences
, DEREF_HOOK
);
204 add_hook(&match_declarations
, DECLARATION_HOOK
);