db: move type_size to use raw SQL
[smatch.git] / smatch_comparison.c
blob16ebaee82b5c5449c80748e8e6def343c36695b1
2 /*
3 * smatch/smatch_comparison.c
5 * Copyright (C) 2012 Oracle.
7 * Licensed under the Open Software License version 1.1
9 */
12 * The point here is to store the relationships between two variables.
13 * Ie: y > x.
14 * To do that we create a state with the two variables in alphabetical order:
15 * ->name = "x vs y" and the state would be "<". On the false path the state
16 * would be ">=".
18 * Part of the trick of it is that if x or y is modified then we need to reset
19 * the state. We need to keep a list of all the states which depend on x and
20 * all the states which depend on y. The link_id code handles this.
22 * Future work: If we know that x is greater than y and y is greater than z
23 * then we know that x is greater than z.
26 #include "smatch.h"
27 #include "smatch_slist.h"
29 static int compare_id;
30 static int link_id;
32 static struct smatch_state compare_states[] = {
33 ['<'] = {
34 .name = "<",
35 .data = (void *)'<',
37 [SPECIAL_UNSIGNED_LT] = {
38 .name = "<",
39 .data = (void *)SPECIAL_UNSIGNED_LT,
41 [SPECIAL_LTE] = {
42 .name = "<=",
43 .data = (void *)SPECIAL_LTE,
45 [SPECIAL_UNSIGNED_LTE] = {
46 .name = "<=",
47 .data = (void *)SPECIAL_UNSIGNED_LTE,
49 [SPECIAL_EQUAL] = {
50 .name = "==",
51 .data = (void *)SPECIAL_EQUAL,
53 [SPECIAL_NOTEQUAL] = {
54 .name = "!=",
55 .data = (void *)SPECIAL_NOTEQUAL,
57 [SPECIAL_GTE] = {
58 .name = ">=",
59 .data = (void *)SPECIAL_GTE,
61 [SPECIAL_UNSIGNED_GTE] = {
62 .name = ">=",
63 .data = (void *)SPECIAL_UNSIGNED_GTE,
65 ['>'] = {
66 .name = ">",
67 .data = (void *)'>',
69 [SPECIAL_UNSIGNED_GT] = {
70 .name = ">",
71 .data = (void *)SPECIAL_UNSIGNED_GT,
75 static int flip_op(int op)
77 switch (op) {
78 case 0:
79 return 0;
80 case '<':
81 return '>';
82 case SPECIAL_UNSIGNED_LT:
83 return SPECIAL_UNSIGNED_GT;
84 case SPECIAL_LTE:
85 return SPECIAL_GTE;
86 case SPECIAL_UNSIGNED_LTE:
87 return SPECIAL_UNSIGNED_GTE;
88 case SPECIAL_EQUAL:
89 return SPECIAL_EQUAL;
90 case SPECIAL_NOTEQUAL:
91 return SPECIAL_NOTEQUAL;
92 case SPECIAL_GTE:
93 return SPECIAL_LTE;
94 case SPECIAL_UNSIGNED_GTE:
95 return SPECIAL_UNSIGNED_LTE;
96 case '>':
97 return '<';
98 case SPECIAL_UNSIGNED_GT:
99 return SPECIAL_UNSIGNED_LT;
100 default:
101 sm_msg("internal smatch bug. unhandled comparison %d", op);
102 return op;
106 static int falsify_op(int op)
108 switch (op) {
109 case 0:
110 return 0;
111 case '<':
112 return SPECIAL_GTE;
113 case SPECIAL_UNSIGNED_LT:
114 return SPECIAL_UNSIGNED_GTE;
115 case SPECIAL_LTE:
116 return '>';
117 case SPECIAL_UNSIGNED_LTE:
118 return SPECIAL_UNSIGNED_GT;
119 case SPECIAL_EQUAL:
120 return SPECIAL_NOTEQUAL;
121 case SPECIAL_NOTEQUAL:
122 return SPECIAL_EQUAL;
123 case SPECIAL_GTE:
124 return '<';
125 case SPECIAL_UNSIGNED_GTE:
126 return SPECIAL_UNSIGNED_LT;
127 case '>':
128 return SPECIAL_LTE;
129 case SPECIAL_UNSIGNED_GT:
130 return SPECIAL_UNSIGNED_LTE;
131 default:
132 sm_msg("internal smatch bug. unhandled comparison %d", op);
133 return op;
137 struct smatch_state *alloc_link_state(struct string_list *links)
139 struct smatch_state *state;
140 static char buf[256];
141 char *tmp;
142 int i;
144 state = __alloc_smatch_state(0);
146 i = 0;
147 FOR_EACH_PTR(links, tmp) {
148 if (!i++)
149 snprintf(buf, sizeof(buf), "%s", tmp);
150 else
151 snprintf(buf, sizeof(buf), "%s, %s", buf, tmp);
152 } END_FOR_EACH_PTR(tmp);
154 state->name = alloc_sname(buf);
155 state->data = links;
156 return state;
159 static void insert_string(struct string_list **str_list, char *new)
161 char *tmp;
163 FOR_EACH_PTR(*str_list, tmp) {
164 if (strcmp(tmp, new) < 0)
165 continue;
166 else if (strcmp(tmp, new) == 0) {
167 return;
168 } else {
169 INSERT_CURRENT(new, tmp);
170 return;
172 } END_FOR_EACH_PTR(tmp);
173 add_ptr_list(str_list, new);
176 struct string_list *clone_str_list(struct string_list *orig)
178 char *tmp;
179 struct string_list *ret = NULL;
181 FOR_EACH_PTR(orig, tmp) {
182 add_ptr_list(&ret, tmp);
183 } END_FOR_EACH_PTR(tmp);
184 return ret;
187 static struct string_list *combine_string_lists(struct string_list *one, struct string_list *two)
189 struct string_list *ret;
190 char *tmp;
192 ret = clone_str_list(one);
193 FOR_EACH_PTR(two, tmp) {
194 insert_string(&ret, tmp);
195 } END_FOR_EACH_PTR(tmp);
196 return ret;
199 static struct smatch_state *merge_func(struct smatch_state *s1, struct smatch_state *s2)
201 struct smatch_state *ret;
202 struct string_list *links;
204 links = combine_string_lists(s1->data, s2->data);
205 ret = alloc_link_state(links);
206 return ret;
209 static void save_link(struct expression *expr, char *link)
211 struct smatch_state *old_state, *new_state;
212 struct string_list *links;
213 char *new;
215 old_state = get_state_expr(link_id, expr);
216 if (old_state)
217 links = clone_str_list(old_state->data);
218 else
219 links = NULL;
221 new = alloc_sname(link);
222 insert_string(&links, new);
224 new_state = alloc_link_state(links);
225 set_state_expr(link_id, expr, new_state);
228 static void clear_links(struct sm_state *sm)
230 struct string_list *links;
231 char *tmp;
233 links = sm->state->data;
235 FOR_EACH_PTR(links, tmp) {
236 set_state(compare_id, tmp, NULL, &undefined);
237 } END_FOR_EACH_PTR(tmp);
238 set_state(link_id, sm->name, sm->sym, &undefined);
241 static void match_logic(struct expression *expr)
243 char *left = NULL;
244 char *right = NULL;
245 struct symbol *left_sym, *right_sym;
246 int op, false_op;
247 struct smatch_state *true_state, *false_state;
248 char state_name[256];
250 if (expr->type != EXPR_COMPARE)
251 return;
252 left = expr_to_var_sym(expr->left, &left_sym);
253 if (!left || !left_sym)
254 goto free;
255 right = expr_to_var_sym(expr->right, &right_sym);
256 if (!right || !right_sym)
257 goto free;
259 if (strcmp(left, right) > 0) {
260 char *tmp = left;
261 left = right;
262 right = tmp;
263 op = flip_op(expr->op);
264 } else {
265 op = expr->op;
267 false_op = falsify_op(op);
268 snprintf(state_name, sizeof(state_name), "%s vs %s", left, right);
269 true_state = &compare_states[op];
270 false_state = &compare_states[false_op];
272 set_true_false_states(compare_id, state_name, NULL, true_state, false_state);
273 save_link(expr->left, state_name);
274 save_link(expr->right, state_name);
275 free:
276 free_string(left);
277 free_string(right);
280 int get_comparison(struct expression *a, struct expression *b)
282 char *one = NULL;
283 char *two = NULL;
284 char buf[256];
285 struct smatch_state *state;
286 int invert = 0;
287 int ret = 0;
289 one = expr_to_var(a);
290 if (!one)
291 goto free;
292 two = expr_to_var(b);
293 if (!two)
294 goto free;
296 if (strcmp(one, two) > 0) {
297 char *tmp = one;
299 one = two;
300 two = tmp;
301 invert = 1;
304 snprintf(buf, sizeof(buf), "%s vs %s", one, two);
305 state = get_state(compare_id, buf, NULL);
306 if (state)
307 ret = PTR_INT(state->data);
309 if (invert)
310 ret = flip_op(ret);
312 free:
313 free_string(one);
314 free_string(two);
315 return ret;
319 void register_comparison(int id)
321 compare_id = id;
322 add_hook(&match_logic, CONDITION_HOOK);
325 void register_comparison_links(int id)
327 link_id = id;
328 add_merge_hook(link_id, &merge_func);
329 add_modification_hook(link_id, &clear_links);