Add a custom merge function.
[smatch.git] / check_null_deref.c
blob4cefde7350d67238d3b753cd049b90aa08a18ef2
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"
13 static int my_id;
15 enum states {
16 ISNULL,
17 NONNULL,
18 IGNORE,
21 static int merge_func(const char *name, struct symbol *sym, int s1, int s2)
23 if (s2 == IGNORE)
24 return IGNORE;
25 return UNDEFINED;
28 static void match_function_call_after(struct expression *expr)
30 struct expression *tmp;
31 struct symbol *sym;
32 char *name;
33 char *func = NULL;
34 int i = 0;
36 if (expr->fn->type == EXPR_SYMBOL) {
37 func = expr->fn->symbol_name->name;
40 FOR_EACH_PTR(expr->args, tmp) {
41 if (tmp->op == '&') {
42 name = get_variable_from_expr_simple(tmp->unop, &sym);
43 if (name) {
44 name = alloc_string(name);
45 set_state(name, my_id, sym, NONNULL);
47 } else {
48 name = get_variable_from_expr_simple(tmp, &sym);
49 if (name && sym) {
50 int state = get_state(name, my_id, sym);
51 if ( state == ISNULL)
52 smatch_msg("Null param %s %d",
53 func, i);
54 else if (state == UNDEFINED)
55 smatch_msg("Undefined param %s %d",
56 func, i);
59 i++;
60 } END_FOR_EACH_PTR(tmp);
63 static int is_null(struct expression *expr)
65 if (expr->type == EXPR_VALUE && expr->value == 0)
66 return 1;
67 if (expr->op == '(')
68 return is_null(expr->unop);
69 if (expr->type == EXPR_CAST)
70 return is_null(expr->cast_expression);
71 return 0;
74 static void match_assign(struct expression *expr)
76 struct symbol *sym;
77 char *name;
79 name = get_variable_from_expr_simple(expr->left, &sym);
80 if (!name)
81 return;
82 name = alloc_string(name);
83 if (is_null(expr->right))
84 set_state(name, my_id, sym, ISNULL);
85 else
86 set_state(name, my_id, sym, NONNULL);
89 static void match_condition(struct expression *expr)
91 struct symbol *sym_left;
92 struct symbol *sym_right;
93 char *left;
94 char *right;
96 switch(expr->type) {
97 case EXPR_COMPARE:
98 left = get_variable_from_expr_simple(expr->left, &sym_left);
99 if (!left)
100 return;
101 left = alloc_string(left);
102 right = get_variable_from_expr_simple(expr->right, &sym_right);
103 if (!right)
104 return;
105 right = alloc_string(right);
107 if (is_null(expr->right)) {
108 if (expr->op == SPECIAL_EQUAL)
109 set_true_false_states(left, my_id, sym_left,
110 ISNULL, NONNULL);
111 else if (expr->op == SPECIAL_NOTEQUAL)
112 set_true_false_states(left, my_id, sym_left,
113 NONNULL, ISNULL);
114 free_string(right);
115 return;
118 if (is_null(expr->left)) {
119 if (expr->op == SPECIAL_EQUAL)
120 set_true_false_states(right, my_id, sym_right,
121 ISNULL, NONNULL);
122 else if (expr->op == SPECIAL_NOTEQUAL)
123 set_true_false_states(right, my_id, sym_right,
124 NONNULL, ISNULL);
125 free_string(left);
126 return;
129 free_string(left);
130 free_string(right);
131 return;
132 case EXPR_SYMBOL:
133 case EXPR_DEREF:
134 left = get_variable_from_expr_simple(expr, &sym_left);
135 if (!left)
136 return;
137 left = alloc_string(left);
138 set_true_false_states(left, my_id, sym_left, NONNULL, ISNULL);
139 SM_DEBUG("set the blasted states\n");
140 return;
141 case EXPR_ASSIGNMENT:
142 match_condition(expr->left);
143 return;
144 default:
145 return;
149 static void match_declarations(struct symbol *sym)
151 if (sym->ident) {
152 const char * name;
153 name = sym->ident->name;
154 if (sym->initializer && is_null(sym->initializer))
155 set_state(name, my_id, sym, ISNULL);
159 static int is_array(struct expression *expr)
161 struct symbol *tmp = NULL;
162 char *name;
164 name = get_variable_from_expr_simple(expr, NULL);
165 if (expr->ctype)
166 tmp = get_base_type(expr->ctype);
167 if (!tmp || !name)
168 return 0;
169 if (tmp->type == SYM_PTR)
170 tmp = get_base_type(tmp);
171 if (!tmp)
172 return 0;
173 printf("debug: %s %d\n", name, tmp->type);
174 if (tmp->ident)
175 printf("name %s\n", tmp->ident->name);
177 return 0;
178 if (expr->type != EXPR_BINOP || expr->op != '+')
179 return 0;
180 //if (expr->left->ctype && expr->left->ctype.base_type == &ptr_ctype)
181 // return 1;
182 return 0;
185 static void match_dereferences(struct expression *expr)
187 char *deref = NULL;
188 struct symbol *sym = NULL;
190 if (expr->op == '*') {
191 expr = expr->unop;
192 } else if (expr->type == EXPR_DEREF && expr->deref->op == '*')
193 expr = expr->deref->unop;
196 * Say you have foo->bar.baz.n
197 * In that case we really only care about part to the
198 * left of the ->.
200 while (expr->type == EXPR_DEREF && expr->deref->op != '*')
201 expr = expr->deref;
203 deref = get_variable_from_expr_simple(expr, &sym);
204 if (!deref)
205 return;
206 deref = alloc_string(deref);
208 switch(get_state(deref, my_id, sym)) {
209 case UNDEFINED:
210 smatch_msg("Dereferencing Undefined: %s", deref);
211 set_state(deref, my_id, sym, IGNORE);
212 break;
213 case ISNULL:
214 /* It turns out that you only get false positives from
215 this. Mostly foo = NULL; sizeof(*foo); */
216 /* smatch_msg("Error dereferencing NULL: %s", deref); */
217 set_state(deref, my_id, sym, IGNORE);
218 break;
219 default:
220 free_string(deref);
221 break;
225 void register_null_deref(int id)
227 my_id = id;
228 add_merge_hook(my_id, &merge_func);
229 add_hook(&match_function_call_after, FUNCTION_CALL_AFTER_HOOK);
230 add_hook(&match_assign, ASSIGNMENT_AFTER_HOOK);
231 add_hook(&match_condition, CONDITION_HOOK);
232 add_hook(&match_dereferences, DEREF_HOOK);
233 add_hook(&match_declarations, DECLARATION_HOOK);