Remove some false positives and enable the check.
[smatch.git] / smatch_extra.c
blob43eed80b2cabbd85415d44fc415b71ab660721f9
1 /*
2 * sparse/smatch_extra.c
4 * Copyright (C) 2008 Dan Carpenter.
6 * Licensed under the Open Software License version 1.1
8 */
10 #include <stdlib.h>
11 #include "parse.h"
12 #include "smatch.h"
14 static int my_id;
16 static int _zero = 0;
17 static int _one = 1;
19 static struct smatch_state zero = {
20 .name = "zero",
21 .data = &_zero,
24 static struct smatch_state one = {
25 .name = "one",
26 .data = &_one,
29 static struct smatch_state *alloc_state(int val)
31 struct smatch_state *state;
33 if (val == 0)
34 return &zero;
35 if (val == 1)
36 return &one;
37 if (val == UNDEFINED)
38 return &undefined;
40 state = malloc(sizeof(*state));
41 state->name = "value";
42 state->data = malloc(sizeof(int));
43 *(int *)state->data = val;
44 return state;
47 static void match_function_call_after(struct expression *expr)
49 struct expression *tmp;
50 struct symbol *sym;
51 char *name;
52 int i = 0;
54 FOR_EACH_PTR(expr->args, tmp) {
55 if (tmp->op == '&') {
56 name = get_variable_from_expr(tmp->unop, &sym);
57 if (name) {
58 set_state(name, my_id, sym, &undefined);
60 free_string(name);
62 i++;
63 } END_FOR_EACH_PTR(tmp);
66 static void match_assign(struct expression *expr)
68 struct expression *left;
69 struct symbol *sym;
70 char *name;
72 left = strip_expr(expr->left);
73 name = get_variable_from_expr(left, &sym);
74 if (!name)
75 return;
76 set_state(name, my_id, sym, alloc_state(get_value(expr->right)));
77 free_string(name);
80 static void undef_expr(struct expression *expr)
82 struct symbol *sym;
83 char *name;
85 name = get_variable_from_expr(expr->unop, &sym);
86 if (!name)
87 return;
88 if (!get_state(name, my_id, sym)) {
89 free_string(name);
90 return;
92 set_state(name, my_id, sym, &undefined);
93 free_string(name);
96 static void match_declarations(struct symbol *sym)
98 const char *name;
100 if (sym->ident) {
101 name = sym->ident->name;
102 if (sym->initializer) {
103 set_state(name, my_id, sym, alloc_state(get_value(sym->initializer)));
108 static void match_unop(struct expression *expr)
110 struct symbol *sym;
111 char *name;
112 const char *tmp;
115 name = get_variable_from_expr(expr->unop, &sym);
116 if (!name)
117 return;
119 tmp = show_special(expr->op);
120 if ((!strcmp(tmp, "--")) || (!strcmp(tmp, "++")))
121 set_state(name, my_id, sym, &undefined);
122 free_string(name);
125 void register_smatch_extra(int id)
127 my_id = id;
128 add_hook(&undef_expr, OP_HOOK);
129 add_hook(&match_function_call_after, FUNCTION_CALL_AFTER_HOOK);
130 add_hook(&match_assign, ASSIGNMENT_AFTER_HOOK);
131 add_hook(&match_declarations, DECLARATION_HOOK);
132 add_hook(&match_unop, OP_HOOK);
135 static int expr_to_val(struct expression *expr)
137 struct smatch_state *state;
138 int val;
139 struct symbol *sym;
140 char *name;
142 val = get_value(expr);
143 if (val != UNDEFINED)
144 return val;
146 name = get_variable_from_expr(expr, &sym);
147 if (!name)
148 return UNDEFINED;
149 state = get_state(name, my_id, sym);
150 free_string(name);
151 if (!state || !state->data)
152 return UNDEFINED;
153 return *(int *)state->data;
156 int true_comparison(int left, int comparison, int right)
158 switch(comparison){
159 case '<':
160 case SPECIAL_UNSIGNED_LT:
161 if (left < right)
162 return 1;
163 return 0;
164 case SPECIAL_UNSIGNED_LTE:
165 case SPECIAL_LTE:
166 if (left < right)
167 return 1;
168 case SPECIAL_EQUAL:
169 if (left == right)
170 return 1;
171 return 0;
172 case SPECIAL_UNSIGNED_GTE:
173 case SPECIAL_GTE:
174 if (left == right)
175 return 1;
176 case '>':
177 case SPECIAL_UNSIGNED_GT:
178 if (left > right)
179 return 1;
180 return 0;
181 case SPECIAL_NOTEQUAL:
182 if (left != right)
183 return 1;
184 return 0;
185 default:
186 smatch_msg("unhandled comparison %d\n", comparison);
187 return UNDEFINED;
189 return 0;
192 static int do_comparison(struct expression *expr)
194 int left, right, ret;
196 if ((left = expr_to_val(expr->left)) == UNDEFINED)
197 return UNDEFINED;
199 if ((right = expr_to_val(expr->right)) == UNDEFINED)
200 return UNDEFINED;
202 ret = true_comparison(left, expr->op, right);
203 if (ret == 1) {
204 SM_DEBUG("%d known condition: %d %s %d => true\n",
205 get_lineno(), left, show_special(expr->op), right);
206 } else if (ret == 0) {
207 SM_DEBUG("%d known condition: %d %s %d => false\n",
208 get_lineno(), left, show_special(expr->op), right);
210 return ret;
213 int last_stmt_val(struct statement *stmt)
215 struct expression *expr;
217 stmt = last_ptr_list((struct ptr_list *)stmt->stmts);
218 if (stmt->type != STMT_EXPRESSION)
219 return UNDEFINED;
220 expr = stmt->expression;
221 return get_value(expr);
224 int known_condition_true(struct expression *expr)
226 int tmp;
228 if (!expr)
229 return 0;
231 tmp = get_value(expr);
232 if (tmp && tmp != UNDEFINED)
233 return 1;
235 expr = strip_expr(expr);
236 switch(expr->type) {
237 case EXPR_COMPARE:
238 if (do_comparison(expr) == 1)
239 return 1;
240 break;
241 case EXPR_PREOP: {
242 struct statement *stmt;
244 stmt = get_block_thing(expr);
245 if (stmt && (last_stmt_val(stmt) == 1))
246 return 1;
247 break;
250 return 0;
253 int known_condition_false(struct expression *expr)
255 if (!expr)
256 return 0;
258 if (is_zero(expr))
259 return 1;
261 switch(expr->type) {
262 case EXPR_COMPARE:
263 if (do_comparison(expr) == 0)
264 return 1;
265 case EXPR_PREOP: {
266 struct statement *stmt;
267 struct expression *tmp;
269 stmt = get_block_thing(expr);
270 if (stmt && (last_stmt_val(stmt) == 0))
271 return 1;
272 tmp = strip_expr(expr);
273 if (tmp != expr)
274 return known_condition_false(tmp);
275 break;
278 return 0;