function_hooks: hack around fallout from moving the assignment to the end
[smatch.git] / smatch_comparison.c
blobbf30734e8ca5e5922709e49e730ebdadd4abf9ac
1 /*
2 * Copyright (C) 2012 Oracle.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
19 * The point here is to store the relationships between two variables.
20 * Ie: y > x.
21 * To do that we create a state with the two variables in alphabetical order:
22 * ->name = "x vs y" and the state would be "<". On the false path the state
23 * would be ">=".
25 * Part of the trick of it is that if x or y is modified then we need to reset
26 * the state. We need to keep a list of all the states which depend on x and
27 * all the states which depend on y. The link_id code handles this.
31 #include "smatch.h"
32 #include "smatch_extra.h"
33 #include "smatch_slist.h"
35 static int compare_id;
36 static int link_id;
37 static int inc_dec_id;
38 static int inc_dec_link_id;
40 static void add_comparison(struct expression *left, int comparison, struct expression *right);
42 /* for handling for loops */
43 STATE(start);
44 STATE(incremented);
46 ALLOCATOR(compare_data, "compare data");
48 static struct symbol *vsl_to_sym(struct var_sym_list *vsl)
50 struct var_sym *vs;
52 if (!vsl)
53 return NULL;
54 if (ptr_list_size((struct ptr_list *)vsl) != 1)
55 return NULL;
56 vs = first_ptr_list((struct ptr_list *)vsl);
57 return vs->sym;
60 struct smatch_state *alloc_compare_state(
61 struct expression *left,
62 const char *left_var, struct var_sym_list *left_vsl,
63 int comparison,
64 struct expression *right,
65 const char *right_var, struct var_sym_list *right_vsl)
67 struct smatch_state *state;
68 struct compare_data *data;
70 state = __alloc_smatch_state(0);
71 state->name = alloc_sname(show_special(comparison));
72 data = __alloc_compare_data(0);
73 data->left = left;
74 data->left_var = alloc_sname(left_var);
75 data->left_vsl = clone_var_sym_list(left_vsl);
76 data->comparison = comparison;
77 data->right = right;
78 data->right_var = alloc_sname(right_var);
79 data->right_vsl = clone_var_sym_list(right_vsl);
80 state->data = data;
81 return state;
84 int state_to_comparison(struct smatch_state *state)
86 if (!state || !state->data)
87 return 0;
88 return ((struct compare_data *)state->data)->comparison;
92 * flip_comparison() reverses the op left and right. So "x >= y" becomes "y <= x".
94 int flip_comparison(int op)
96 switch (op) {
97 case 0:
98 return 0;
99 case '<':
100 return '>';
101 case SPECIAL_UNSIGNED_LT:
102 return SPECIAL_UNSIGNED_GT;
103 case SPECIAL_LTE:
104 return SPECIAL_GTE;
105 case SPECIAL_UNSIGNED_LTE:
106 return SPECIAL_UNSIGNED_GTE;
107 case SPECIAL_EQUAL:
108 return SPECIAL_EQUAL;
109 case SPECIAL_NOTEQUAL:
110 return SPECIAL_NOTEQUAL;
111 case SPECIAL_GTE:
112 return SPECIAL_LTE;
113 case SPECIAL_UNSIGNED_GTE:
114 return SPECIAL_UNSIGNED_LTE;
115 case '>':
116 return '<';
117 case SPECIAL_UNSIGNED_GT:
118 return SPECIAL_UNSIGNED_LT;
119 default:
120 sm_msg("internal smatch bug. unhandled comparison %d", op);
121 return op;
125 int negate_comparison(int op)
127 switch (op) {
128 case 0:
129 return 0;
130 case '<':
131 return SPECIAL_GTE;
132 case SPECIAL_UNSIGNED_LT:
133 return SPECIAL_UNSIGNED_GTE;
134 case SPECIAL_LTE:
135 return '>';
136 case SPECIAL_UNSIGNED_LTE:
137 return SPECIAL_UNSIGNED_GT;
138 case SPECIAL_EQUAL:
139 return SPECIAL_NOTEQUAL;
140 case SPECIAL_NOTEQUAL:
141 return SPECIAL_EQUAL;
142 case SPECIAL_GTE:
143 return '<';
144 case SPECIAL_UNSIGNED_GTE:
145 return SPECIAL_UNSIGNED_LT;
146 case '>':
147 return SPECIAL_LTE;
148 case SPECIAL_UNSIGNED_GT:
149 return SPECIAL_UNSIGNED_LTE;
150 default:
151 sm_msg("internal smatch bug. unhandled comparison %d", op);
152 return op;
156 static int rl_comparison(struct range_list *left_rl, struct range_list *right_rl)
158 sval_t left_min, left_max, right_min, right_max;
159 struct symbol *type = &int_ctype;
161 if (!left_rl || !right_rl)
162 return 0;
164 if (type_positive_bits(rl_type(left_rl)) > type_positive_bits(type))
165 type = rl_type(left_rl);
166 if (type_positive_bits(rl_type(right_rl)) > type_positive_bits(type))
167 type = rl_type(right_rl);
169 left_rl = cast_rl(type, left_rl);
170 right_rl = cast_rl(type, right_rl);
172 left_min = rl_min(left_rl);
173 left_max = rl_max(left_rl);
174 right_min = rl_min(right_rl);
175 right_max = rl_max(right_rl);
177 if (left_min.value == left_max.value &&
178 right_min.value == right_max.value &&
179 left_min.value == right_min.value)
180 return SPECIAL_EQUAL;
182 if (sval_cmp(left_max, right_min) < 0)
183 return '<';
184 if (sval_cmp(left_max, right_min) == 0)
185 return SPECIAL_LTE;
186 if (sval_cmp(left_min, right_max) > 0)
187 return '>';
188 if (sval_cmp(left_min, right_max) == 0)
189 return SPECIAL_GTE;
191 return 0;
194 static int comparison_from_extra(struct expression *a, struct expression *b)
196 struct range_list *left, *right;
198 if (!get_implied_rl(a, &left))
199 return 0;
200 if (!get_implied_rl(b, &right))
201 return 0;
203 return rl_comparison(left, right);
206 static struct range_list *get_orig_rl(struct var_sym_list *vsl)
208 struct symbol *sym;
209 struct smatch_state *state;
211 if (!vsl)
212 return NULL;
213 sym = vsl_to_sym(vsl);
214 if (!sym || !sym->ident)
215 return NULL;
216 state = get_orig_estate(sym->ident->name, sym);
217 return estate_rl(state);
220 static struct smatch_state *unmatched_comparison(struct sm_state *sm)
222 struct compare_data *data = sm->state->data;
223 struct range_list *left_rl, *right_rl;
224 int op;
226 if (!data)
227 return &undefined;
229 if (strstr(data->left_var, " orig"))
230 left_rl = get_orig_rl(data->left_vsl);
231 else if (!get_implied_rl_var_sym(data->left_var, vsl_to_sym(data->left_vsl), &left_rl))
232 return &undefined;
234 if (strstr(data->right_var, " orig"))
235 right_rl = get_orig_rl(data->right_vsl);
236 else if (!get_implied_rl_var_sym(data->right_var, vsl_to_sym(data->right_vsl), &right_rl))
237 return &undefined;
239 op = rl_comparison(left_rl, right_rl);
240 if (op)
241 return alloc_compare_state(
242 data->left, data->left_var, data->left_vsl,
244 data->right, data->right_var, data->right_vsl);
246 return &undefined;
249 /* remove_unsigned_from_comparison() is obviously a hack. */
250 int remove_unsigned_from_comparison(int op)
252 switch (op) {
253 case SPECIAL_UNSIGNED_LT:
254 return '<';
255 case SPECIAL_UNSIGNED_LTE:
256 return SPECIAL_LTE;
257 case SPECIAL_UNSIGNED_GTE:
258 return SPECIAL_GTE;
259 case SPECIAL_UNSIGNED_GT:
260 return '>';
261 default:
262 return op;
267 * This is for when you merge states "a < b" and "a == b", the result is that
268 * we can say for sure, "a <= b" after the merge.
270 int merge_comparisons(int one, int two)
272 int LT, EQ, GT;
274 if (!one || !two)
275 return 0;
277 one = remove_unsigned_from_comparison(one);
278 two = remove_unsigned_from_comparison(two);
280 if (one == two)
281 return one;
283 LT = EQ = GT = 0;
285 switch (one) {
286 case '<':
287 LT = 1;
288 break;
289 case SPECIAL_LTE:
290 LT = 1;
291 EQ = 1;
292 break;
293 case SPECIAL_EQUAL:
294 EQ = 1;
295 break;
296 case SPECIAL_GTE:
297 GT = 1;
298 EQ = 1;
299 break;
300 case '>':
301 GT = 1;
304 switch (two) {
305 case '<':
306 LT = 1;
307 break;
308 case SPECIAL_LTE:
309 LT = 1;
310 EQ = 1;
311 break;
312 case SPECIAL_EQUAL:
313 EQ = 1;
314 break;
315 case SPECIAL_GTE:
316 GT = 1;
317 EQ = 1;
318 break;
319 case '>':
320 GT = 1;
323 if (LT && EQ && GT)
324 return 0;
325 if (LT && EQ)
326 return SPECIAL_LTE;
327 if (LT && GT)
328 return SPECIAL_NOTEQUAL;
329 if (LT)
330 return '<';
331 if (EQ && GT)
332 return SPECIAL_GTE;
333 if (GT)
334 return '>';
335 return 0;
339 * This is for if you have "a < b" and "b <= c". Or in other words,
340 * "a < b <= c". You would call this like get_combined_comparison('<', '<=').
341 * The return comparison would be '<'.
343 * This function is different from merge_comparisons(), for example:
344 * merge_comparison('<', '==') returns '<='
345 * get_combined_comparison('<', '==') returns '<'
347 int combine_comparisons(int left_compare, int right_compare)
349 int LT, EQ, GT;
351 left_compare = remove_unsigned_from_comparison(left_compare);
352 right_compare = remove_unsigned_from_comparison(right_compare);
354 LT = EQ = GT = 0;
356 switch (left_compare) {
357 case '<':
358 LT++;
359 break;
360 case SPECIAL_LTE:
361 LT++;
362 EQ++;
363 break;
364 case SPECIAL_EQUAL:
365 return right_compare;
366 case SPECIAL_GTE:
367 GT++;
368 EQ++;
369 break;
370 case '>':
371 GT++;
374 switch (right_compare) {
375 case '<':
376 LT++;
377 break;
378 case SPECIAL_LTE:
379 LT++;
380 EQ++;
381 break;
382 case SPECIAL_EQUAL:
383 return left_compare;
384 case SPECIAL_GTE:
385 GT++;
386 EQ++;
387 break;
388 case '>':
389 GT++;
392 if (LT == 2) {
393 if (EQ == 2)
394 return SPECIAL_LTE;
395 return '<';
398 if (GT == 2) {
399 if (EQ == 2)
400 return SPECIAL_GTE;
401 return '>';
403 return 0;
406 int filter_comparison(int orig, int op)
408 if (orig == op)
409 return orig;
411 orig = remove_unsigned_from_comparison(orig);
412 op = remove_unsigned_from_comparison(op);
414 switch (orig) {
415 case 0:
416 return op;
417 case '<':
418 switch (op) {
419 case '<':
420 case SPECIAL_LTE:
421 case SPECIAL_NOTEQUAL:
422 return '<';
424 return 0;
425 case SPECIAL_LTE:
426 switch (op) {
427 case '<':
428 case SPECIAL_LTE:
429 case SPECIAL_EQUAL:
430 return op;
431 case SPECIAL_NOTEQUAL:
432 return '<';
434 return 0;
435 case SPECIAL_EQUAL:
436 switch (op) {
437 case SPECIAL_LTE:
438 case SPECIAL_EQUAL:
439 case SPECIAL_GTE:
440 case SPECIAL_UNSIGNED_LTE:
441 case SPECIAL_UNSIGNED_GTE:
442 return SPECIAL_EQUAL;
444 return 0;
445 case SPECIAL_NOTEQUAL:
446 switch (op) {
447 case '<':
448 case SPECIAL_LTE:
449 return '<';
450 case SPECIAL_UNSIGNED_LT:
451 case SPECIAL_UNSIGNED_LTE:
452 return SPECIAL_UNSIGNED_LT;
453 case SPECIAL_NOTEQUAL:
454 return op;
455 case '>':
456 case SPECIAL_GTE:
457 return '>';
458 case SPECIAL_UNSIGNED_GT:
459 case SPECIAL_UNSIGNED_GTE:
460 return SPECIAL_UNSIGNED_GT;
462 return 0;
463 case SPECIAL_GTE:
464 switch (op) {
465 case SPECIAL_LTE:
466 return SPECIAL_EQUAL;
467 case '>':
468 case SPECIAL_GTE:
469 case SPECIAL_EQUAL:
470 return op;
471 case SPECIAL_NOTEQUAL:
472 return '>';
474 return 0;
475 case '>':
476 switch (op) {
477 case '>':
478 case SPECIAL_GTE:
479 case SPECIAL_NOTEQUAL:
480 return '>';
482 return 0;
483 case SPECIAL_UNSIGNED_LT:
484 switch (op) {
485 case SPECIAL_UNSIGNED_LT:
486 case SPECIAL_UNSIGNED_LTE:
487 case SPECIAL_NOTEQUAL:
488 return SPECIAL_UNSIGNED_LT;
490 return 0;
491 case SPECIAL_UNSIGNED_LTE:
492 switch (op) {
493 case SPECIAL_UNSIGNED_LT:
494 case SPECIAL_UNSIGNED_LTE:
495 case SPECIAL_EQUAL:
496 return op;
497 case SPECIAL_NOTEQUAL:
498 return SPECIAL_UNSIGNED_LT;
499 case SPECIAL_UNSIGNED_GTE:
500 return SPECIAL_EQUAL;
502 return 0;
503 case SPECIAL_UNSIGNED_GTE:
504 switch (op) {
505 case SPECIAL_UNSIGNED_LTE:
506 return SPECIAL_EQUAL;
507 case SPECIAL_NOTEQUAL:
508 return SPECIAL_UNSIGNED_GT;
509 case SPECIAL_EQUAL:
510 case SPECIAL_UNSIGNED_GTE:
511 case SPECIAL_UNSIGNED_GT:
512 return op;
514 return 0;
515 case SPECIAL_UNSIGNED_GT:
516 switch (op) {
517 case SPECIAL_UNSIGNED_GT:
518 case SPECIAL_UNSIGNED_GTE:
519 case SPECIAL_NOTEQUAL:
520 return SPECIAL_UNSIGNED_GT;
522 return 0;
524 return 0;
527 static void pre_merge_hook(struct sm_state *sm)
529 struct compare_data *data = sm->state->data;
530 int other;
532 if (!data)
533 return;
534 other = get_comparison(data->left, data->right);
535 if (!other)
536 return;
538 set_state(compare_id, sm->name, NULL,
539 alloc_compare_state(data->left, data->left_var, data->left_vsl,
540 other,
541 data->right, data->right_var, data->right_vsl));
544 struct smatch_state *merge_compare_states(struct smatch_state *s1, struct smatch_state *s2)
546 struct compare_data *data = s1->data;
547 int op;
549 op = merge_comparisons(state_to_comparison(s1), state_to_comparison(s2));
550 if (op)
551 return alloc_compare_state(
552 data->left, data->left_var, data->left_vsl,
554 data->right, data->right_var, data->right_vsl);
555 return &undefined;
558 static struct smatch_state *alloc_link_state(struct string_list *links)
560 struct smatch_state *state;
561 static char buf[256];
562 char *tmp;
563 int i;
565 state = __alloc_smatch_state(0);
567 i = 0;
568 FOR_EACH_PTR(links, tmp) {
569 if (!i++) {
570 snprintf(buf, sizeof(buf), "%s", tmp);
571 } else {
572 append(buf, ", ", sizeof(buf));
573 append(buf, tmp, sizeof(buf));
575 } END_FOR_EACH_PTR(tmp);
577 state->name = alloc_sname(buf);
578 state->data = links;
579 return state;
582 static void save_start_states(struct statement *stmt)
584 struct symbol *param;
585 char orig[64];
586 char state_name[128];
587 struct smatch_state *state;
588 struct string_list *links;
589 char *link;
591 FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, param) {
592 struct var_sym_list *left_vsl = NULL;
593 struct var_sym_list *right_vsl = NULL;
595 if (!param->ident)
596 continue;
597 snprintf(orig, sizeof(orig), "%s orig", param->ident->name);
598 snprintf(state_name, sizeof(state_name), "%s vs %s", param->ident->name, orig);
599 add_var_sym(&left_vsl, param->ident->name, param);
600 add_var_sym(&right_vsl, orig, param);
601 state = alloc_compare_state(
602 NULL, param->ident->name, left_vsl,
603 SPECIAL_EQUAL,
604 NULL, alloc_sname(orig), right_vsl);
605 set_state(compare_id, state_name, NULL, state);
607 link = alloc_sname(state_name);
608 links = NULL;
609 insert_string(&links, link);
610 state = alloc_link_state(links);
611 set_state(link_id, param->ident->name, param, state);
612 } END_FOR_EACH_PTR(param);
615 static struct smatch_state *merge_links(struct smatch_state *s1, struct smatch_state *s2)
617 struct smatch_state *ret;
618 struct string_list *links;
620 links = combine_string_lists(s1->data, s2->data);
621 ret = alloc_link_state(links);
622 return ret;
625 static void save_link_var_sym(const char *var, struct symbol *sym, const char *link)
627 struct smatch_state *old_state, *new_state;
628 struct string_list *links;
629 char *new;
631 old_state = get_state(link_id, var, sym);
632 if (old_state)
633 links = clone_str_list(old_state->data);
634 else
635 links = NULL;
637 new = alloc_sname(link);
638 insert_string(&links, new);
640 new_state = alloc_link_state(links);
641 set_state(link_id, var, sym, new_state);
644 static void match_inc(struct sm_state *sm)
646 struct string_list *links;
647 struct smatch_state *state, *new;
648 struct compare_data *data;
649 char *tmp;
650 int flip;
651 int op;
653 links = sm->state->data;
655 FOR_EACH_PTR(links, tmp) {
656 state = get_state(compare_id, tmp, NULL);
657 if (!state)
658 continue;
659 data = state->data;
660 if (!data)
661 continue;
663 flip = 0;
664 if (strncmp(sm->name, tmp, strlen(sm->name)) != 0 ||
665 tmp[strlen(sm->name)] != ' ')
666 flip = 1;
668 op = state_to_comparison(state);
670 switch (flip ? flip_comparison(op) : op) {
671 case SPECIAL_EQUAL:
672 case SPECIAL_GTE:
673 case SPECIAL_UNSIGNED_GTE:
674 case '>':
675 case SPECIAL_UNSIGNED_GT:
676 new = alloc_compare_state(
677 data->left, data->left_var, data->left_vsl,
678 flip ? '<' : '>',
679 data->right, data->right_var, data->right_vsl);
680 set_state(compare_id, tmp, NULL, new);
681 break;
682 case '<':
683 case SPECIAL_UNSIGNED_LT:
684 new = alloc_compare_state(
685 data->left, data->left_var, data->left_vsl,
686 flip ? SPECIAL_GTE : SPECIAL_LTE,
687 data->right, data->right_var, data->right_vsl);
688 set_state(compare_id, tmp, NULL, new);
689 break;
690 default:
691 set_state(compare_id, tmp, NULL, &undefined);
693 } END_FOR_EACH_PTR(tmp);
696 static void match_dec(struct sm_state *sm)
698 struct string_list *links;
699 struct smatch_state *state;
700 char *tmp;
702 links = sm->state->data;
704 FOR_EACH_PTR(links, tmp) {
705 state = get_state(compare_id, tmp, NULL);
707 switch (state_to_comparison(state)) {
708 case SPECIAL_EQUAL:
709 case SPECIAL_LTE:
710 case SPECIAL_UNSIGNED_LTE:
711 case '<':
712 case SPECIAL_UNSIGNED_LT: {
713 struct compare_data *data = state->data;
714 struct smatch_state *new;
716 new = alloc_compare_state(
717 data->left, data->left_var, data->left_vsl,
718 '<',
719 data->right, data->right_var, data->right_vsl);
720 set_state(compare_id, tmp, NULL, new);
721 break;
723 default:
724 set_state(compare_id, tmp, NULL, &undefined);
726 } END_FOR_EACH_PTR(tmp);
729 static void match_inc_dec(struct sm_state *sm, struct expression *mod_expr)
732 * if (foo > bar) then ++foo is also > bar.
734 if (!mod_expr)
735 return;
736 if (mod_expr->type != EXPR_PREOP && mod_expr->type != EXPR_POSTOP)
737 return;
739 if (mod_expr->op == SPECIAL_INCREMENT)
740 match_inc(sm);
741 else if (mod_expr->op == SPECIAL_DECREMENT)
742 match_dec(sm);
745 static int is_self_assign(struct expression *expr)
747 if (!expr || expr->type != EXPR_ASSIGNMENT || expr->op != '=')
748 return 0;
749 return expr_equiv(expr->left, expr->right);
752 static void match_modify(struct sm_state *sm, struct expression *mod_expr)
754 struct string_list *links;
755 char *tmp;
757 if (mod_expr && is_self_assign(mod_expr))
758 return;
760 /* handled by match_inc_dec() */
761 if (mod_expr &&
762 ((mod_expr->type == EXPR_PREOP || mod_expr->type == EXPR_POSTOP) &&
763 (mod_expr->op == SPECIAL_INCREMENT || mod_expr->op == SPECIAL_DECREMENT)))
764 return;
766 links = sm->state->data;
768 FOR_EACH_PTR(links, tmp) {
769 set_state(compare_id, tmp, NULL, &undefined);
770 } END_FOR_EACH_PTR(tmp);
771 set_state(link_id, sm->name, sm->sym, &undefined);
774 static void match_preop(struct expression *expr)
776 struct expression *parent;
777 struct range_list *left, *right;
778 int op;
781 * This is an important special case. Say you have:
783 * if (++j == limit)
785 * Assume that we know the range of limit is higher than the start
786 * value for "j". Then the first thing that we process is the ++j. We
787 * have not comparison states set up so it doesn't get caught by the
788 * modification hook. But it does get caught by smatch_extra which sets
789 * j to unknown then we parse the "j == limit" and sets false to != but
790 * really we want false to be <.
792 * So what we do is we set j < limit here, then the match_modify catches
793 * it and we do a match_inc_dec().
797 if (expr->type != EXPR_PREOP ||
798 (expr->op != SPECIAL_INCREMENT && expr->op != SPECIAL_DECREMENT))
799 return;
801 parent = expr_get_parent_expr(expr);
802 if (!parent)
803 return;
804 if (parent->type != EXPR_COMPARE || parent->op != SPECIAL_EQUAL)
805 return;
806 if (parent->left != expr)
807 return;
809 if (!get_implied_rl(expr->unop, &left) ||
810 !get_implied_rl(parent->right, &right))
811 return;
813 op = rl_comparison(left, right);
814 if (!op)
815 return;
817 add_comparison(expr->unop, op, parent->right);
820 static char *chunk_to_var_sym(struct expression *expr, struct symbol **sym)
822 expr = strip_expr(expr);
823 if (!expr)
824 return NULL;
825 if (sym)
826 *sym = NULL;
828 if (expr->type == EXPR_PREOP &&
829 (expr->op == SPECIAL_INCREMENT ||
830 expr->op == SPECIAL_DECREMENT))
831 expr = strip_expr(expr->unop);
833 if (expr->type == EXPR_CALL) {
834 char buf[64];
836 snprintf(buf, sizeof(buf), "return %p", expr);
837 return alloc_string(buf);
840 return expr_to_chunk_sym_vsl(expr, sym, NULL);
843 static char *chunk_to_var(struct expression *expr)
845 return chunk_to_var_sym(expr, NULL);
848 static struct smatch_state *get_state_chunk(int owner, struct expression *expr)
850 char *name;
851 struct symbol *sym;
852 struct smatch_state *ret;
854 name = chunk_to_var_sym(expr, &sym);
855 if (!name)
856 return NULL;
858 ret = get_state(owner, name, sym);
859 free_string(name);
860 return ret;
863 static void save_link(struct expression *expr, char *link)
865 char *var;
866 struct symbol *sym;
868 expr = strip_expr(expr);
869 if (expr->type == EXPR_BINOP) {
870 char *chunk;
872 chunk = chunk_to_var(expr);
873 if (!chunk)
874 return;
876 save_link(expr->left, link);
877 save_link(expr->right, link);
878 save_link_var_sym(chunk, NULL, link);
879 return;
882 var = chunk_to_var_sym(expr, &sym);
883 if (!var)
884 return;
886 save_link_var_sym(var, sym, link);
887 free_string(var);
890 static int get_orig_comparison(struct stree *pre_stree, const char *left, const char *right)
892 struct smatch_state *state;
893 struct compare_data *data;
894 int flip = 0;
895 char state_name[256];
897 if (strcmp(left, right) > 0) {
898 const char *tmp = right;
900 flip = 1;
901 right = left;
902 left = tmp;
905 snprintf(state_name, sizeof(state_name), "%s vs %s", left, right);
906 state = get_state_stree(pre_stree, compare_id, state_name, NULL);
907 if (!state || !state->data)
908 return 0;
909 data = state->data;
910 if (flip)
911 return flip_comparison(data->comparison);
912 return data->comparison;
916 static int have_common_var_sym(struct var_sym_list *left_vsl, struct var_sym_list *right_vsl)
918 struct var_sym *tmp;
920 FOR_EACH_PTR(left_vsl, tmp) {
921 if (in_var_sym_list(right_vsl, tmp->var, tmp->sym))
922 return 1;
923 } END_FOR_EACH_PTR(tmp);
925 return 0;
929 * The idea here is that we take a comparison "a < b" and then we look at all
930 * the things which "b" is compared against "b < c" and we say that that implies
931 * a relationship "a < c".
933 * The names here about because the comparisons are organized like this
934 * "a < b < c".
937 static void update_tf_links(struct stree *pre_stree,
938 struct expression *left_expr,
939 const char *left_var, struct var_sym_list *left_vsl,
940 int left_comparison, int left_false_comparison,
941 const char *mid_var, struct var_sym_list *mid_vsl,
942 struct string_list *links)
944 struct smatch_state *state;
945 struct smatch_state *true_state, *false_state;
946 struct compare_data *data;
947 struct expression *right_expr;
948 const char *right_var;
949 struct var_sym_list *right_vsl;
950 int orig_comparison;
951 int right_comparison;
952 int true_comparison;
953 int false_comparison;
954 char *tmp;
955 char state_name[256];
956 struct var_sym *vs;
958 FOR_EACH_PTR(links, tmp) {
959 state = get_state_stree(pre_stree, compare_id, tmp, NULL);
960 if (!state || !state->data)
961 continue;
962 data = state->data;
963 right_comparison = data->comparison;
964 right_expr = data->right;
965 right_var = data->right_var;
966 right_vsl = data->right_vsl;
967 if (strcmp(mid_var, right_var) == 0) {
968 right_expr = data->left;
969 right_var = data->left_var;
970 right_vsl = data->left_vsl;
971 right_comparison = flip_comparison(right_comparison);
973 if (have_common_var_sym(left_vsl, right_vsl))
974 continue;
976 orig_comparison = get_orig_comparison(pre_stree, left_var, right_var);
978 true_comparison = combine_comparisons(left_comparison, right_comparison);
979 false_comparison = combine_comparisons(left_false_comparison, right_comparison);
981 true_comparison = filter_comparison(orig_comparison, true_comparison);
982 false_comparison = filter_comparison(orig_comparison, false_comparison);
984 if (strcmp(left_var, right_var) > 0) {
985 struct expression *tmp_expr = left_expr;
986 const char *tmp_var = left_var;
987 struct var_sym_list *tmp_vsl = left_vsl;
989 left_expr = right_expr;
990 left_var = right_var;
991 left_vsl = right_vsl;
992 right_expr = tmp_expr;
993 right_var = tmp_var;
994 right_vsl = tmp_vsl;
995 true_comparison = flip_comparison(true_comparison);
996 false_comparison = flip_comparison(false_comparison);
999 if (!true_comparison && !false_comparison)
1000 continue;
1002 if (true_comparison)
1003 true_state = alloc_compare_state(
1004 left_expr, left_var, left_vsl,
1005 true_comparison,
1006 right_expr, right_var, right_vsl);
1007 else
1008 true_state = NULL;
1009 if (false_comparison)
1010 false_state = alloc_compare_state(
1011 left_expr, left_var, left_vsl,
1012 false_comparison,
1013 right_expr, right_var, right_vsl);
1014 else
1015 false_state = NULL;
1017 snprintf(state_name, sizeof(state_name), "%s vs %s", left_var, right_var);
1018 set_true_false_states(compare_id, state_name, NULL, true_state, false_state);
1019 FOR_EACH_PTR(left_vsl, vs) {
1020 save_link_var_sym(vs->var, vs->sym, state_name);
1021 } END_FOR_EACH_PTR(vs);
1022 FOR_EACH_PTR(right_vsl, vs) {
1023 save_link_var_sym(vs->var, vs->sym, state_name);
1024 } END_FOR_EACH_PTR(vs);
1025 if (!vsl_to_sym(left_vsl))
1026 save_link_var_sym(left_var, NULL, state_name);
1027 if (!vsl_to_sym(right_vsl))
1028 save_link_var_sym(right_var, NULL, state_name);
1029 } END_FOR_EACH_PTR(tmp);
1032 static void update_tf_data(struct stree *pre_stree,
1033 struct expression *left_expr,
1034 const char *left_name, struct var_sym_list *left_vsl,
1035 struct expression *right_expr,
1036 const char *right_name, struct var_sym_list *right_vsl,
1037 int true_comparison, int false_comparison)
1039 struct smatch_state *state;
1041 state = get_state_stree(pre_stree, link_id, right_name, vsl_to_sym(right_vsl));
1042 if (state)
1043 update_tf_links(pre_stree, left_expr, left_name, left_vsl, true_comparison, false_comparison, right_name, right_vsl, state->data);
1045 state = get_state_stree(pre_stree, link_id, left_name, vsl_to_sym(left_vsl));
1046 if (state)
1047 update_tf_links(pre_stree, right_expr, right_name, right_vsl, flip_comparison(true_comparison), flip_comparison(false_comparison), left_name, left_vsl, state->data);
1050 static void iter_modify(struct sm_state *sm, struct expression *mod_expr)
1052 if (sm->state != &start ||
1053 !mod_expr ||
1054 (mod_expr->type != EXPR_PREOP && mod_expr->type != EXPR_POSTOP) ||
1055 mod_expr->op != SPECIAL_INCREMENT)
1056 set_state(inc_dec_id, sm->name, sm->sym, &undefined);
1057 else
1058 set_state(inc_dec_id, sm->name, sm->sym, &incremented);
1061 static void handle_for_loops(struct expression *expr, char *state_name, struct smatch_state *false_state)
1063 sval_t sval;
1064 char *iter_name, *cap_name;
1065 struct symbol *iter_sym, *cap_sym;
1066 struct compare_data *data;
1068 if (expr->op != '<' && expr->op != SPECIAL_UNSIGNED_LT)
1069 return;
1071 if (!__cur_stmt || !__prev_stmt)
1072 return;
1073 if (__cur_stmt->type != STMT_ITERATOR)
1074 return;
1075 if (__cur_stmt->iterator_pre_condition != expr)
1076 return;
1078 /* literals are handled in smatch_extra.c */
1079 if (get_value(expr->right, &sval))
1080 return;
1082 /* First time checking the condition */
1083 if (__prev_stmt == __cur_stmt->iterator_pre_statement) {
1084 if (!get_implied_value(expr->left, &sval) ||
1085 sval.value != 0)
1086 return;
1088 iter_name = expr_to_var_sym(expr->left, &iter_sym);
1089 cap_name = expr_to_var_sym(expr->right, &cap_sym);
1090 if (!iter_name || !cap_name || !iter_sym || !cap_sym) {
1091 free_string(iter_name);
1092 free_string(cap_name);
1093 return;
1096 set_state(inc_dec_id, iter_name, iter_sym, &start);
1097 store_link(inc_dec_link_id, cap_name, cap_sym, iter_name, iter_sym);
1099 free_string(iter_name);
1100 free_string(cap_name);
1101 return;
1104 /* Second time checking the condtion */
1105 if (__prev_stmt != __cur_stmt->iterator_post_statement)
1106 return;
1108 if (get_state_chunk(inc_dec_id, expr->left) != &incremented)
1109 return;
1111 data = false_state->data;
1112 false_state = alloc_compare_state(
1113 data->left, data->left_var, data->left_vsl,
1114 SPECIAL_EQUAL,
1115 data->right, data->right_var, data->right_vsl);
1117 set_true_false_states(compare_id, state_name, NULL, NULL, false_state);
1120 static int is_plus_one(struct expression *expr)
1122 sval_t sval;
1124 if (expr->type != EXPR_BINOP || expr->op != '+')
1125 return 0;
1126 if (!get_implied_value(expr->right, &sval) || sval.value != 1)
1127 return 0;
1128 return 1;
1131 static int is_minus_one(struct expression *expr)
1133 sval_t sval;
1135 if (expr->type != EXPR_BINOP || expr->op != '-')
1136 return 0;
1137 if (!get_implied_value(expr->right, &sval) || sval.value != 1)
1138 return 0;
1139 return 1;
1142 static void move_plus_to_minus_helper(struct expression **left_p, struct expression **right_p)
1144 struct expression *left = *left_p;
1145 struct expression *right = *right_p;
1148 * These two are basically equivalent: "foo + 1 != bar" and
1149 * "foo != bar - 1". There are issues with signedness and integer
1150 * overflows. There are also issues with type as well. But let's
1151 * pretend we can ignore all that stuff for now.
1155 if (!is_plus_one(left))
1156 return;
1158 *left_p = left->left;
1159 *right_p = binop_expression(right, '-', left->right);
1162 static void move_plus_to_minus(struct expression **left_p, struct expression **right_p)
1164 if (is_plus_one(*left_p) && is_plus_one(*right_p))
1165 return;
1167 move_plus_to_minus_helper(left_p, right_p);
1168 move_plus_to_minus_helper(right_p, left_p);
1171 static void handle_comparison(struct expression *left_expr, int op, struct expression *right_expr, char **_state_name, struct smatch_state **_false_state)
1173 char *left = NULL;
1174 char *right = NULL;
1175 struct symbol *left_sym, *right_sym;
1176 struct var_sym_list *left_vsl = NULL;
1177 struct var_sym_list *right_vsl = NULL;
1178 int false_op;
1179 int orig_comparison;
1180 struct smatch_state *true_state, *false_state;
1181 static char state_name[256];
1182 struct stree *pre_stree;
1183 sval_t sval;
1185 if (!left_expr || !right_expr)
1186 return;
1188 left_expr = strip_parens(left_expr);
1189 right_expr = strip_parens(right_expr);
1191 while (left_expr->type == EXPR_ASSIGNMENT)
1192 left_expr = strip_parens(left_expr->left);
1193 while (right_expr->type == EXPR_ASSIGNMENT)
1194 right_expr = strip_parens(right_expr->left);
1196 false_op = negate_comparison(op);
1198 move_plus_to_minus(&left_expr, &right_expr);
1200 if (op == SPECIAL_UNSIGNED_LT &&
1201 get_implied_value(left_expr, &sval) &&
1202 sval.value == 0)
1203 false_op = SPECIAL_EQUAL;
1205 if (op == SPECIAL_UNSIGNED_GT &&
1206 get_implied_value(right_expr, &sval) &&
1207 sval.value == 0)
1208 false_op = SPECIAL_EQUAL;
1210 left = chunk_to_var_sym(left_expr, &left_sym);
1211 if (!left)
1212 goto free;
1213 if (left_sym)
1214 add_var_sym(&left_vsl, left, left_sym);
1215 else
1216 left_vsl = expr_to_vsl(left_expr);
1217 right = chunk_to_var_sym(right_expr, &right_sym);
1218 if (!right)
1219 goto free;
1220 if (right_sym)
1221 add_var_sym(&right_vsl, right, right_sym);
1222 else
1223 right_vsl = expr_to_vsl(right_expr);
1225 if (strcmp(left, right) > 0) {
1226 char *tmp_name = left;
1227 struct var_sym_list *tmp_vsl = left_vsl;
1228 struct expression *tmp_expr = left_expr;
1230 left = right;
1231 left_vsl = right_vsl;
1232 left_expr = right_expr;
1233 right = tmp_name;
1234 right_vsl = tmp_vsl;
1235 right_expr = tmp_expr;
1236 op = flip_comparison(op);
1237 false_op = flip_comparison(false_op);
1240 orig_comparison = get_comparison(left_expr, right_expr);
1241 op = filter_comparison(orig_comparison, op);
1242 false_op = filter_comparison(orig_comparison, false_op);
1244 snprintf(state_name, sizeof(state_name), "%s vs %s", left, right);
1245 true_state = alloc_compare_state(
1246 left_expr, left, left_vsl,
1248 right_expr, right, right_vsl);
1249 false_state = alloc_compare_state(
1250 left_expr, left, left_vsl,
1251 false_op,
1252 right_expr, right, right_vsl);
1254 pre_stree = clone_stree(__get_cur_stree());
1255 update_tf_data(pre_stree, left_expr, left, left_vsl, right_expr, right, right_vsl, op, false_op);
1256 free_stree(&pre_stree);
1258 set_true_false_states(compare_id, state_name, NULL, true_state, false_state);
1259 __compare_param_limit_hook(left_expr, right_expr, state_name, true_state, false_state);
1260 save_link(left_expr, state_name);
1261 save_link(right_expr, state_name);
1263 if (_false_state)
1264 *_false_state = false_state;
1265 if (_state_name)
1266 *_state_name = state_name;
1267 free:
1268 free_string(left);
1269 free_string(right);
1272 void __comparison_match_condition(struct expression *expr)
1274 struct expression *left, *right, *new_left, *new_right, *tmp;
1275 struct smatch_state *false_state = NULL;
1276 char *state_name = NULL;
1277 int redo, count;
1279 if (expr->type != EXPR_COMPARE)
1280 return;
1282 handle_comparison(expr->left, expr->op, expr->right, &state_name, &false_state);
1283 if (false_state && state_name)
1284 handle_for_loops(expr, state_name, false_state);
1286 left = strip_parens(expr->left);
1287 right = strip_parens(expr->right);
1289 if (left->type == EXPR_BINOP && left->op == '+') {
1290 new_left = left->left;
1291 new_right = binop_expression(right, '-', left->right);
1292 handle_comparison(new_left, expr->op, new_right, NULL, NULL);
1294 new_left = left->right;
1295 new_right = binop_expression(right, '-', left->left);
1296 handle_comparison(new_left, expr->op, new_right, NULL, NULL);
1300 redo = 0;
1301 left = strip_parens(expr->left);
1302 right = strip_parens(expr->right);
1303 if (get_last_expr_from_expression_stmt(expr->left)) {
1304 left = get_last_expr_from_expression_stmt(expr->left);
1305 redo = 1;
1307 if (get_last_expr_from_expression_stmt(expr->right)) {
1308 right = get_last_expr_from_expression_stmt(expr->right);
1309 redo = 1;
1312 if (!redo)
1313 return;
1315 count = 0;
1316 while ((tmp = get_assigned_expr(left))) {
1317 if (count++ > 3)
1318 break;
1319 left = strip_expr(tmp);
1321 count = 0;
1322 while ((tmp = get_assigned_expr(right))) {
1323 if (count++ > 3)
1324 break;
1325 right = strip_expr(tmp);
1328 handle_comparison(left, expr->op, right, NULL, NULL);
1331 static void add_comparison_var_sym(
1332 struct expression *left_expr,
1333 const char *left_name, struct var_sym_list *left_vsl,
1334 int comparison,
1335 struct expression *right_expr,
1336 const char *right_name, struct var_sym_list *right_vsl)
1338 struct smatch_state *state;
1339 struct var_sym *vs;
1340 char state_name[256];
1342 if (strcmp(left_name, right_name) > 0) {
1343 struct expression *tmp_expr = left_expr;
1344 const char *tmp_name = left_name;
1345 struct var_sym_list *tmp_vsl = left_vsl;
1347 left_expr = right_expr;
1348 left_name = right_name;
1349 left_vsl = right_vsl;
1350 right_expr = tmp_expr;
1351 right_name = tmp_name;
1352 right_vsl = tmp_vsl;
1353 comparison = flip_comparison(comparison);
1355 snprintf(state_name, sizeof(state_name), "%s vs %s", left_name, right_name);
1356 state = alloc_compare_state(
1357 left_expr, left_name, left_vsl,
1358 comparison,
1359 right_expr, right_name, right_vsl);
1361 set_state(compare_id, state_name, NULL, state);
1363 FOR_EACH_PTR(left_vsl, vs) {
1364 save_link_var_sym(vs->var, vs->sym, state_name);
1365 } END_FOR_EACH_PTR(vs);
1366 FOR_EACH_PTR(right_vsl, vs) {
1367 save_link_var_sym(vs->var, vs->sym, state_name);
1368 } END_FOR_EACH_PTR(vs);
1371 static void add_comparison(struct expression *left, int comparison, struct expression *right)
1373 char *left_name = NULL;
1374 char *right_name = NULL;
1375 struct symbol *left_sym, *right_sym;
1376 struct var_sym_list *left_vsl, *right_vsl;
1377 struct smatch_state *state;
1378 char state_name[256];
1380 left_name = chunk_to_var_sym(left, &left_sym);
1381 if (!left_name)
1382 goto free;
1383 left_vsl = expr_to_vsl(left);
1384 right_name = chunk_to_var_sym(right, &right_sym);
1385 if (!right_name)
1386 goto free;
1387 right_vsl = expr_to_vsl(right);
1389 if (strcmp(left_name, right_name) > 0) {
1390 struct expression *tmp_expr = left;
1391 struct symbol *tmp_sym = left_sym;
1392 char *tmp_name = left_name;
1393 struct var_sym_list *tmp_vsl = left_vsl;
1395 left = right;
1396 left_name = right_name;
1397 left_sym = right_sym;
1398 left_vsl = right_vsl;
1399 right = tmp_expr;
1400 right_name = tmp_name;
1401 right_sym = tmp_sym;
1402 right_vsl = tmp_vsl;
1403 comparison = flip_comparison(comparison);
1405 snprintf(state_name, sizeof(state_name), "%s vs %s", left_name, right_name);
1406 state = alloc_compare_state(
1407 left, left_name, left_vsl,
1408 comparison,
1409 right, right_name, right_vsl);
1411 set_state(compare_id, state_name, NULL, state);
1412 save_link(left, state_name);
1413 save_link(right, state_name);
1415 free:
1416 free_string(left_name);
1417 free_string(right_name);
1420 static void match_assign_add(struct expression *expr)
1422 struct expression *right;
1423 struct expression *r_left, *r_right;
1424 sval_t left_tmp, right_tmp;
1426 right = strip_expr(expr->right);
1427 r_left = strip_expr(right->left);
1428 r_right = strip_expr(right->right);
1430 get_absolute_min(r_left, &left_tmp);
1431 get_absolute_min(r_right, &right_tmp);
1433 if (left_tmp.value > 0)
1434 add_comparison(expr->left, '>', r_right);
1435 else if (left_tmp.value == 0)
1436 add_comparison(expr->left, SPECIAL_GTE, r_right);
1438 if (right_tmp.value > 0)
1439 add_comparison(expr->left, '>', r_left);
1440 else if (right_tmp.value == 0)
1441 add_comparison(expr->left, SPECIAL_GTE, r_left);
1444 static void match_assign_sub(struct expression *expr)
1446 struct expression *right;
1447 struct expression *r_left, *r_right;
1448 int comparison;
1449 sval_t min;
1451 right = strip_expr(expr->right);
1452 r_left = strip_expr(right->left);
1453 r_right = strip_expr(right->right);
1455 if (get_absolute_min(r_right, &min) && sval_is_negative(min))
1456 return;
1458 comparison = get_comparison(r_left, r_right);
1460 switch (comparison) {
1461 case '>':
1462 case SPECIAL_GTE:
1463 if (implied_not_equal(r_right, 0))
1464 add_comparison(expr->left, '>', r_left);
1465 else
1466 add_comparison(expr->left, SPECIAL_GTE, r_left);
1467 return;
1471 static void match_assign_divide(struct expression *expr)
1473 struct expression *right;
1474 struct expression *r_left, *r_right;
1475 sval_t min;
1477 right = strip_expr(expr->right);
1478 r_left = strip_expr(right->left);
1479 r_right = strip_expr(right->right);
1480 if (!get_implied_min(r_right, &min) || min.value <= 1)
1481 return;
1483 add_comparison(expr->left, '<', r_left);
1486 static void match_binop_assign(struct expression *expr)
1488 struct expression *right;
1490 right = strip_expr(expr->right);
1491 if (right->op == '+')
1492 match_assign_add(expr);
1493 if (right->op == '-')
1494 match_assign_sub(expr);
1495 if (right->op == '/')
1496 match_assign_divide(expr);
1499 static void copy_comparisons(struct expression *left, struct expression *right)
1501 struct string_list *links;
1502 struct smatch_state *state;
1503 struct compare_data *data;
1504 struct symbol *left_sym, *right_sym;
1505 char *left_var = NULL;
1506 char *right_var = NULL;
1507 struct var_sym_list *left_vsl;
1508 struct expression *expr;
1509 const char *var;
1510 struct var_sym_list *vsl;
1511 int comparison;
1512 char *tmp;
1514 left_var = chunk_to_var_sym(left, &left_sym);
1515 if (!left_var)
1516 goto done;
1517 left_vsl = expr_to_vsl(left);
1518 right_var = chunk_to_var_sym(right, &right_sym);
1519 if (!right_var)
1520 goto done;
1522 state = get_state(link_id, right_var, right_sym);
1523 if (!state)
1524 return;
1525 links = state->data;
1527 FOR_EACH_PTR(links, tmp) {
1528 state = get_state(compare_id, tmp, NULL);
1529 if (!state || !state->data)
1530 continue;
1531 data = state->data;
1532 comparison = data->comparison;
1533 expr = data->right;
1534 var = data->right_var;
1535 vsl = data->right_vsl;
1536 if (strcmp(var, right_var) == 0) {
1537 expr = data->left;
1538 var = data->left_var;
1539 vsl = data->left_vsl;
1540 comparison = flip_comparison(comparison);
1542 /* n = copy_from_user(dest, src, n); leads to n <= n which is nonsense */
1543 if (strcmp(left_var, var) == 0)
1544 continue;
1545 add_comparison_var_sym(left, left_var, left_vsl, comparison, expr, var, vsl);
1546 } END_FOR_EACH_PTR(tmp);
1548 done:
1549 free_string(right_var);
1552 static void match_assign(struct expression *expr)
1554 struct expression *right;
1556 if (expr->op != '=')
1557 return;
1558 if (outside_of_function())
1559 return;
1561 * This is a hack. We want the faked expression in smatch_function_hooks.c
1562 * to be handled. But we want to ingore the stuff in
1563 * smatch_struct_assignment.c.
1566 if (__in_fake_assign && get_faked_expression())
1567 return;
1569 if (is_struct(expr->left))
1570 return;
1572 if (is_self_assign(expr))
1573 return;
1575 copy_comparisons(expr->left, expr->right);
1576 add_comparison(expr->left, SPECIAL_EQUAL, expr->right);
1578 right = strip_expr(expr->right);
1579 if (right->type == EXPR_BINOP)
1580 match_binop_assign(expr);
1583 int get_comparison_strings(const char *one, const char *two)
1585 char buf[256];
1586 struct smatch_state *state;
1587 int invert = 0;
1588 int ret = 0;
1590 if (!one || !two)
1591 return 0;
1593 if (strcmp(one, two) == 0)
1594 return SPECIAL_EQUAL;
1596 if (strcmp(one, two) > 0) {
1597 const char *tmp = one;
1599 one = two;
1600 two = tmp;
1601 invert = 1;
1604 snprintf(buf, sizeof(buf), "%s vs %s", one, two);
1605 state = get_state(compare_id, buf, NULL);
1606 if (state)
1607 ret = state_to_comparison(state);
1609 if (invert)
1610 ret = flip_comparison(ret);
1612 return ret;
1615 int get_comparison(struct expression *a, struct expression *b)
1617 char *one = NULL;
1618 char *two = NULL;
1619 int ret = 0;
1621 if (!a || !b)
1622 return 0;
1624 a = strip_parens(a);
1625 b = strip_parens(b);
1627 move_plus_to_minus(&a, &b);
1629 one = chunk_to_var(a);
1630 if (!one)
1631 goto free;
1632 two = chunk_to_var(b);
1633 if (!two)
1634 goto free;
1636 ret = get_comparison_strings(one, two);
1637 if (ret)
1638 goto free;
1640 if (is_plus_one(a) || is_minus_one(a)) {
1641 free_string(one);
1642 one = chunk_to_var(a->left);
1643 ret = get_comparison_strings(one, two);
1644 } else if (is_plus_one(b) || is_minus_one(b)) {
1645 free_string(two);
1646 two = chunk_to_var(b->left);
1647 ret = get_comparison_strings(one, two);
1650 if (!ret)
1651 goto free;
1653 if ((is_plus_one(a) || is_minus_one(b)) && ret == '<')
1654 ret = SPECIAL_LTE;
1655 else if ((is_minus_one(a) || is_plus_one(b)) && ret == '>')
1656 ret = SPECIAL_GTE;
1657 else
1658 ret = 0;
1660 free:
1661 free_string(one);
1662 free_string(two);
1664 if (!ret)
1665 return comparison_from_extra(a, b);
1666 return ret;
1669 int possible_comparison(struct expression *a, int comparison, struct expression *b)
1671 char *one = NULL;
1672 char *two = NULL;
1673 int ret = 0;
1674 char buf[256];
1675 struct sm_state *sm;
1676 int saved;
1678 one = chunk_to_var(a);
1679 if (!one)
1680 goto free;
1681 two = chunk_to_var(b);
1682 if (!two)
1683 goto free;
1686 if (strcmp(one, two) == 0 && comparison == SPECIAL_EQUAL) {
1687 ret = 1;
1688 goto free;
1691 if (strcmp(one, two) > 0) {
1692 char *tmp = one;
1694 one = two;
1695 two = tmp;
1696 comparison = flip_comparison(comparison);
1699 snprintf(buf, sizeof(buf), "%s vs %s", one, two);
1700 sm = get_sm_state(compare_id, buf, NULL);
1701 if (!sm)
1702 goto free;
1704 FOR_EACH_PTR(sm->possible, sm) {
1705 if (!sm->state->data)
1706 continue;
1707 saved = ((struct compare_data *)sm->state->data)->comparison;
1708 if (saved == comparison)
1709 ret = 1;
1710 if (comparison == SPECIAL_EQUAL &&
1711 (saved == SPECIAL_LTE ||
1712 saved == SPECIAL_GTE ||
1713 saved == SPECIAL_UNSIGNED_LTE ||
1714 saved == SPECIAL_UNSIGNED_GTE))
1715 ret = 1;
1716 if (ret == 1)
1717 goto free;
1718 } END_FOR_EACH_PTR(sm);
1720 return ret;
1721 free:
1722 free_string(one);
1723 free_string(two);
1724 return ret;
1727 struct state_list *get_all_comparisons(struct expression *expr)
1729 struct smatch_state *state;
1730 struct string_list *links;
1731 struct state_list *ret = NULL;
1732 struct sm_state *sm;
1733 char *tmp;
1735 state = get_state_chunk(link_id, expr);
1736 if (!state)
1737 return NULL;
1738 links = state->data;
1740 FOR_EACH_PTR(links, tmp) {
1741 sm = get_sm_state(compare_id, tmp, NULL);
1742 if (!sm)
1743 continue;
1744 // FIXME have to compare name with vsl
1745 add_ptr_list(&ret, sm);
1746 } END_FOR_EACH_PTR(tmp);
1748 return ret;
1751 struct state_list *get_all_possible_equal_comparisons(struct expression *expr)
1753 struct smatch_state *state;
1754 struct string_list *links;
1755 struct state_list *ret = NULL;
1756 struct sm_state *sm;
1757 char *tmp;
1759 state = get_state_chunk(link_id, expr);
1760 if (!state)
1761 return NULL;
1762 links = state->data;
1764 FOR_EACH_PTR(links, tmp) {
1765 sm = get_sm_state(compare_id, tmp, NULL);
1766 if (!sm)
1767 continue;
1768 if (!strchr(sm->state->name, '='))
1769 continue;
1770 if (strcmp(sm->state->name, "!=") == 0)
1771 continue;
1772 add_ptr_list(&ret, sm);
1773 } END_FOR_EACH_PTR(tmp);
1775 return ret;
1778 struct state_list *get_all_possible_not_equal_comparisons(struct expression *expr)
1780 struct smatch_state *state;
1781 struct string_list *links;
1782 struct state_list *ret = NULL;
1783 struct sm_state *sm;
1784 struct sm_state *possible;
1785 char *link;
1787 return NULL;
1789 state = get_state_chunk(link_id, expr);
1790 if (!state)
1791 return NULL;
1792 links = state->data;
1794 FOR_EACH_PTR(links, link) {
1795 sm = get_sm_state(compare_id, link, NULL);
1796 if (!sm)
1797 continue;
1798 FOR_EACH_PTR(sm->possible, possible) {
1799 if (strcmp(possible->state->name, "!=") != 0)
1800 continue;
1801 add_ptr_list(&ret, sm);
1802 break;
1803 } END_FOR_EACH_PTR(link);
1804 } END_FOR_EACH_PTR(link);
1806 return ret;
1809 static void update_links_from_call(struct expression *left,
1810 int left_compare,
1811 struct expression *right)
1813 struct string_list *links;
1814 struct smatch_state *state;
1815 struct compare_data *data;
1816 struct symbol *left_sym, *right_sym;
1817 char *left_var = NULL;
1818 char *right_var = NULL;
1819 struct var_sym_list *left_vsl;
1820 struct expression *expr;
1821 const char *var;
1822 struct var_sym_list *vsl;
1823 int comparison;
1824 char *tmp;
1826 left_var = chunk_to_var_sym(left, &left_sym);
1827 if (!left_var)
1828 goto done;
1829 left_vsl = expr_to_vsl(left);
1830 right_var = chunk_to_var_sym(right, &right_sym);
1831 if (!right_var)
1832 goto done;
1834 state = get_state(link_id, right_var, right_sym);
1835 if (!state)
1836 return;
1837 links = state->data;
1839 FOR_EACH_PTR(links, tmp) {
1840 state = get_state(compare_id, tmp, NULL);
1841 if (!state || !state->data)
1842 continue;
1843 data = state->data;
1844 comparison = data->comparison;
1845 expr = data->right;
1846 var = data->right_var;
1847 vsl = data->right_vsl;
1848 if (strcmp(var, right_var) == 0) {
1849 expr = data->left;
1850 var = data->left_var;
1851 vsl = data->left_vsl;
1852 comparison = flip_comparison(comparison);
1854 comparison = combine_comparisons(left_compare, comparison);
1855 if (!comparison)
1856 continue;
1857 add_comparison_var_sym(left, left_var, left_vsl, comparison, expr, var, vsl);
1858 } END_FOR_EACH_PTR(tmp);
1860 done:
1861 free_string(right_var);
1864 void __add_return_comparison(struct expression *call, const char *range)
1866 struct expression *arg;
1867 int comparison;
1868 char buf[4];
1870 if (!str_to_comparison_arg(range, call, &comparison, &arg))
1871 return;
1872 snprintf(buf, sizeof(buf), "%s", show_special(comparison));
1873 update_links_from_call(call, comparison, arg);
1874 add_comparison(call, comparison, arg);
1877 void __add_comparison_info(struct expression *expr, struct expression *call, const char *range)
1879 copy_comparisons(expr, call);
1882 static char *get_mask_comparison(struct expression *expr, int ignore)
1884 struct expression *tmp, *right;
1885 int count, param;
1886 char buf[256];
1888 /* The return value for "return foo & param;" is <= param */
1890 count = 0;
1891 while ((tmp = get_assigned_expr(expr))) {
1892 expr = strip_expr(tmp);
1893 if (count++ > 4)
1894 break;
1897 if (expr->type != EXPR_BINOP || expr->op != '&')
1898 return NULL;
1900 right = strip_expr(expr->right);
1901 param = get_param_num(right);
1902 if (param < 0 || param == ignore)
1903 return NULL;
1905 snprintf(buf, sizeof(buf), "[<=$%d]", param);
1906 return alloc_sname(buf);
1909 static char *range_comparison_to_param_helper(struct expression *expr, char starts_with, int ignore)
1911 struct symbol *param;
1912 char *var = NULL;
1913 char buf[256];
1914 char *ret_str = NULL;
1915 int compare;
1916 int i;
1918 if (!expr)
1919 return NULL;
1921 var = chunk_to_var(expr);
1922 if (!var)
1923 goto try_mask;
1925 i = -1;
1926 FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, param) {
1927 i++;
1928 if (i == ignore)
1929 continue;
1930 if (!param->ident)
1931 continue;
1932 snprintf(buf, sizeof(buf), "%s orig", param->ident->name);
1933 compare = get_comparison_strings(var, buf);
1934 if (!compare)
1935 continue;
1936 if (show_special(compare)[0] != starts_with)
1937 continue;
1938 snprintf(buf, sizeof(buf), "[%s$%d]", show_special(compare), i);
1939 ret_str = alloc_sname(buf);
1940 break;
1941 } END_FOR_EACH_PTR(param);
1943 free_string(var);
1944 if (!ret_str)
1945 goto try_mask;
1947 return ret_str;
1949 try_mask:
1950 if (starts_with == '<')
1951 ret_str = get_mask_comparison(expr, ignore);
1952 return ret_str;
1955 char *name_sym_to_param_comparison(const char *name, struct symbol *sym)
1957 struct symbol *param;
1958 char buf[256];
1959 int compare;
1960 int i;
1962 i = -1;
1963 FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, param) {
1964 i++;
1965 if (!param->ident)
1966 continue;
1967 snprintf(buf, sizeof(buf), "%s orig", param->ident->name);
1968 compare = get_comparison_strings(name, buf);
1969 if (!compare)
1970 continue;
1971 snprintf(buf, sizeof(buf), "[%s$%d]", show_special(compare), i);
1972 return alloc_sname(buf);
1973 } END_FOR_EACH_PTR(param);
1975 return NULL;
1978 char *expr_equal_to_param(struct expression *expr, int ignore)
1980 return range_comparison_to_param_helper(expr, '=', ignore);
1983 char *expr_lte_to_param(struct expression *expr, int ignore)
1985 return range_comparison_to_param_helper(expr, '<', ignore);
1988 char *expr_param_comparison(struct expression *expr, int ignore)
1990 struct symbol *param;
1991 char *var = NULL;
1992 char buf[256];
1993 char *ret_str = NULL;
1994 int compare;
1995 int i;
1997 var = chunk_to_var(expr);
1998 if (!var)
1999 goto free;
2001 i = -1;
2002 FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, param) {
2003 i++;
2004 if (i == ignore)
2005 continue;
2006 if (!param->ident)
2007 continue;
2008 snprintf(buf, sizeof(buf), "%s orig", param->ident->name);
2009 compare = get_comparison_strings(var, buf);
2010 if (!compare)
2011 continue;
2012 snprintf(buf, sizeof(buf), "[%s$%d]", show_special(compare), i);
2013 ret_str = alloc_sname(buf);
2014 break;
2015 } END_FOR_EACH_PTR(param);
2017 free:
2018 free_string(var);
2019 return ret_str;
2022 char *get_printed_param_name(struct expression *call, const char *param_name, struct symbol *param_sym)
2024 struct expression *arg;
2025 char *name;
2026 struct symbol *sym;
2027 static char buf[256];
2028 int len;
2029 int i;
2031 i = -1;
2032 FOR_EACH_PTR(call->args, arg) {
2033 i++;
2035 name = expr_to_var_sym(arg, &sym);
2036 if (!name || !sym)
2037 continue;
2038 if (sym != param_sym)
2039 continue;
2041 len = strlen(name);
2042 if (strncmp(name, param_name, len) != 0)
2043 continue;
2044 if (param_name[len] == '\0') {
2045 snprintf(buf, sizeof(buf), "$%d", i);
2046 return buf;
2048 if (param_name[len] != '-')
2049 continue;
2050 snprintf(buf, sizeof(buf), "$%d%s", i, param_name + len);
2051 return buf;
2052 } END_FOR_EACH_PTR(arg);
2054 return NULL;
2057 static void match_call_info(struct expression *expr)
2059 struct expression *arg;
2060 struct smatch_state *state;
2061 struct sm_state *sm;
2062 struct compare_data *data;
2063 int comparison;
2064 struct string_list *links;
2065 char *arg_name;
2066 const char *right_name;
2067 char *link;
2068 char info_buf[256];
2069 int i;
2071 i = -1;
2072 FOR_EACH_PTR(expr->args, arg) {
2073 i++;
2075 state = get_state_chunk(link_id, arg);
2076 if (!state)
2077 continue;
2079 links = state->data;
2080 FOR_EACH_PTR(links, link) {
2081 struct var_sym_list *right_vsl;
2082 struct var_sym *right_vs;
2085 if (strstr(link, " orig"))
2086 continue;
2087 sm = get_sm_state(compare_id, link, NULL);
2088 if (!sm)
2089 continue;
2090 data = sm->state->data;
2091 if (!data || !data->comparison)
2092 continue;
2093 arg_name = expr_to_var(arg);
2094 if (!arg_name)
2095 continue;
2097 right_vsl = NULL;
2098 if (strcmp(data->left_var, arg_name) == 0) {
2099 comparison = data->comparison;
2100 right_name = data->right_var;
2101 right_vsl = data->right_vsl;
2102 } else if (strcmp(data->right_var, arg_name) == 0) {
2103 comparison = flip_comparison(data->comparison);
2104 right_name = data->left_var;
2105 right_vsl = data->left_vsl;
2107 if (!right_vsl || ptr_list_size((struct ptr_list *)right_vsl) != 1)
2108 goto free;
2110 right_vs = first_ptr_list((struct ptr_list *)right_vsl);
2111 if (strcmp(right_vs->var, right_name) != 0)
2112 goto free;
2113 right_name = get_printed_param_name(expr, right_vs->var, right_vs->sym);
2114 if (!right_name)
2115 goto free;
2116 snprintf(info_buf, sizeof(info_buf), "%s %s", show_special(comparison), right_name);
2117 sql_insert_caller_info(expr, PARAM_COMPARE, i, "$", info_buf);
2119 free:
2120 free_string(arg_name);
2121 } END_FOR_EACH_PTR(link);
2122 } END_FOR_EACH_PTR(arg);
2125 static void struct_member_callback(struct expression *call, int param, char *printed_name, struct sm_state *link_sm)
2127 struct sm_state *compare_sm;
2128 struct string_list *links;
2129 char *link;
2130 struct compare_data *data;
2131 struct var_sym *left, *right;
2132 static char info_buf[256];
2133 const char *right_name;
2135 if (strstr(printed_name, " orig"))
2136 return;
2138 links = link_sm->state->data;
2139 FOR_EACH_PTR(links, link) {
2140 compare_sm = get_sm_state(compare_id, link, NULL);
2141 if (!compare_sm)
2142 continue;
2143 data = compare_sm->state->data;
2144 if (!data || !data->comparison)
2145 continue;
2147 if (ptr_list_size((struct ptr_list *)data->left_vsl) != 1 ||
2148 ptr_list_size((struct ptr_list *)data->right_vsl) != 1)
2149 continue;
2150 left = first_ptr_list((struct ptr_list *)data->left_vsl);
2151 right = first_ptr_list((struct ptr_list *)data->right_vsl);
2152 if (left->sym == right->sym &&
2153 strcmp(left->var, right->var) == 0)
2154 continue;
2156 * Both parameters link to this comparison so only
2157 * record the first one.
2159 if (left->sym != link_sm->sym ||
2160 strcmp(left->var, link_sm->name) != 0)
2161 continue;
2163 right_name = get_printed_param_name(call, right->var, right->sym);
2164 if (!right_name)
2165 continue;
2166 snprintf(info_buf, sizeof(info_buf), "%s %s", show_special(data->comparison), right_name);
2167 sql_insert_caller_info(call, PARAM_COMPARE, param, printed_name, info_buf);
2168 } END_FOR_EACH_PTR(link);
2171 static void print_return_value_comparison(int return_id, char *return_ranges, struct expression *expr)
2173 char *name;
2174 const char *tmp_name;
2175 struct symbol *sym;
2176 int param;
2177 char info_buf[256];
2180 * TODO: This only prints == comparisons. That's probably the most
2181 * useful comparison because == max has lots of implications. But it
2182 * would be good to capture the rest as well.
2184 * This information is already in the DB but it's in the parameter math
2185 * bits and it's awkward to use it. This is is the simpler, possibly
2186 * cleaner way, but not necessarily the best, I don't know.
2189 if (!expr)
2190 return;
2191 name = expr_to_var_sym(expr, &sym);
2192 if (!name || !sym)
2193 goto free;
2195 param = get_param_num_from_sym(sym);
2196 if (param < 0)
2197 goto free;
2198 if (param_was_set_var_sym(name, sym))
2199 goto free;
2201 tmp_name = get_param_name_var_sym(name, sym);
2202 if (!tmp_name)
2203 goto free;
2205 snprintf(info_buf, sizeof(info_buf), "== $%d%s", param, tmp_name + 1);
2206 sql_insert_return_states(return_id, return_ranges,
2207 PARAM_COMPARE, -1, "$", info_buf);
2208 free:
2209 free_string(name);
2212 static void print_return_comparison(int return_id, char *return_ranges, struct expression *expr)
2214 struct sm_state *tmp;
2215 struct string_list *links;
2216 char *link;
2217 struct sm_state *sm;
2218 struct compare_data *data;
2219 struct var_sym *left, *right;
2220 int left_param, right_param;
2221 char left_buf[256];
2222 char right_buf[256];
2223 char info_buf[256];
2224 const char *tmp_name;
2226 print_return_value_comparison(return_id, return_ranges, expr);
2228 FOR_EACH_MY_SM(link_id, __get_cur_stree(), tmp) {
2229 if (get_param_num_from_sym(tmp->sym) < 0)
2230 continue;
2231 links = tmp->state->data;
2232 FOR_EACH_PTR(links, link) {
2233 sm = get_sm_state(compare_id, link, NULL);
2234 if (!sm)
2235 continue;
2236 data = sm->state->data;
2237 if (!data || !data->comparison)
2238 continue;
2239 if (ptr_list_size((struct ptr_list *)data->left_vsl) != 1 ||
2240 ptr_list_size((struct ptr_list *)data->right_vsl) != 1)
2241 continue;
2242 left = first_ptr_list((struct ptr_list *)data->left_vsl);
2243 right = first_ptr_list((struct ptr_list *)data->right_vsl);
2244 if (left->sym == right->sym &&
2245 strcmp(left->var, right->var) == 0)
2246 continue;
2248 * Both parameters link to this comparison so only
2249 * record the first one.
2251 if (left->sym != tmp->sym ||
2252 strcmp(left->var, tmp->name) != 0)
2253 continue;
2255 if (strstr(right->var, " orig"))
2256 continue;
2258 left_param = get_param_num_from_sym(left->sym);
2259 right_param = get_param_num_from_sym(right->sym);
2260 if (left_param < 0 || right_param < 0)
2261 continue;
2263 tmp_name = get_param_name_var_sym(left->var, left->sym);
2264 if (!tmp_name)
2265 continue;
2266 snprintf(left_buf, sizeof(left_buf), "%s", tmp_name);
2268 tmp_name = get_param_name_var_sym(right->var, right->sym);
2269 if (!tmp_name || tmp_name[0] != '$')
2270 continue;
2271 snprintf(right_buf, sizeof(right_buf), "$%d%s", right_param, tmp_name + 1);
2274 * FIXME: this should reject $ type variables (as
2275 * opposed to $->foo type). Those should come from
2276 * smatch_param_compare_limit.c.
2279 snprintf(info_buf, sizeof(info_buf), "%s %s", show_special(data->comparison), right_buf);
2280 sql_insert_return_states(return_id, return_ranges,
2281 PARAM_COMPARE, left_param, left_buf, info_buf);
2282 } END_FOR_EACH_PTR(link);
2284 } END_FOR_EACH_SM(tmp);
2287 static int parse_comparison(char **value, int *op)
2290 *op = **value;
2292 switch (*op) {
2293 case '<':
2294 (*value)++;
2295 if (**value == '=') {
2296 (*value)++;
2297 *op = SPECIAL_LTE;
2299 break;
2300 case '=':
2301 (*value)++;
2302 (*value)++;
2303 *op = SPECIAL_EQUAL;
2304 break;
2305 case '!':
2306 (*value)++;
2307 (*value)++;
2308 *op = SPECIAL_NOTEQUAL;
2309 break;
2310 case '>':
2311 (*value)++;
2312 if (**value == '=') {
2313 (*value)++;
2314 *op = SPECIAL_GTE;
2316 break;
2317 default:
2318 return 0;
2321 if (**value != ' ') {
2322 sm_msg("internal error parsing comparison. %s", *value);
2323 return 0;
2326 (*value)++;
2327 return 1;
2330 static int split_op_param_key(char *value, int *op, int *param, char **key)
2332 static char buf[256];
2333 char *p;
2335 if (!parse_comparison(&value, op))
2336 return 0;
2338 snprintf(buf, sizeof(buf), value);
2340 p = buf;
2341 if (*p++ != '$')
2342 return 0;
2344 *param = atoi(p);
2345 if (*param < 0 || *param > 99)
2346 return 0;
2347 p++;
2348 if (*param > 9)
2349 p++;
2350 p--;
2351 *p = '$';
2352 *key = p;
2354 return 1;
2357 static void db_return_comparison(struct expression *expr, int left_param, char *key, char *value)
2359 struct expression *left_arg, *right_arg;
2360 char *left_name = NULL;
2361 struct symbol *left_sym;
2362 char *right_name = NULL;
2363 struct symbol *right_sym;
2364 int op;
2365 int right_param;
2366 char *right_key;
2367 struct var_sym_list *left_vsl = NULL, *right_vsl = NULL;
2369 if (left_param == -1) {
2370 if (expr->type != EXPR_ASSIGNMENT)
2371 return;
2372 left_arg = strip_expr(expr->left);
2374 while (expr->type == EXPR_ASSIGNMENT)
2375 expr = strip_expr(expr->right);
2376 if (expr->type != EXPR_CALL)
2377 return;
2378 } else {
2379 while (expr->type == EXPR_ASSIGNMENT)
2380 expr = strip_expr(expr->right);
2381 if (expr->type != EXPR_CALL)
2382 return;
2384 left_arg = get_argument_from_call_expr(expr->args, left_param);
2385 if (!left_arg)
2386 return;
2389 if (!split_op_param_key(value, &op, &right_param, &right_key))
2390 return;
2392 right_arg = get_argument_from_call_expr(expr->args, right_param);
2393 if (!right_arg)
2394 return;
2396 left_name = get_variable_from_key(left_arg, key, &left_sym);
2397 if (!left_name || !left_sym)
2398 goto free;
2400 right_name = get_variable_from_key(right_arg, right_key, &right_sym);
2401 if (!right_name || !right_sym)
2402 goto free;
2404 add_var_sym(&left_vsl, left_name, left_sym);
2405 add_var_sym(&right_vsl, right_name, right_sym);
2407 add_comparison_var_sym(NULL, left_name, left_vsl, op, NULL, right_name, right_vsl);
2409 free:
2410 free_string(left_name);
2411 free_string(right_name);
2414 int param_compare_limit_is_impossible(struct expression *expr, int left_param, char *left_key, char *value)
2416 struct smatch_state *state;
2417 char *left_name = NULL;
2418 char *right_name = NULL;
2419 struct symbol *left_sym, *right_sym;
2420 struct expression *left_arg, *right_arg;
2421 int op, state_op;
2422 int right_param;
2423 char *right_key;
2424 int ret = 0;
2425 char buf[256];
2427 while (expr->type == EXPR_ASSIGNMENT)
2428 expr = strip_expr(expr->right);
2429 if (expr->type != EXPR_CALL)
2430 return 0;
2432 if (!split_op_param_key(value, &op, &right_param, &right_key))
2433 return 0;
2435 left_arg = get_argument_from_call_expr(expr->args, left_param);
2436 if (!left_arg)
2437 return 0;
2439 right_arg = get_argument_from_call_expr(expr->args, right_param);
2440 if (!right_arg)
2441 return 0;
2443 left_name = get_variable_from_key(left_arg, left_key, &left_sym);
2444 right_name = get_variable_from_key(right_arg, right_key, &right_sym);
2445 if (!left_name || !right_name)
2446 goto free;
2448 snprintf(buf, sizeof(buf), "%s vs %s", left_name, right_name);
2449 state = get_state(compare_id, buf, NULL);
2450 if (!state)
2451 goto free;
2452 state_op = state_to_comparison(state);
2453 if (!state_op)
2454 goto free;
2456 if (!filter_comparison(remove_unsigned_from_comparison(state_op), op))
2457 ret = 1;
2458 free:
2459 free_string(left_name);
2460 free_string(right_name);
2461 return ret;
2464 int impossibly_high_comparison(struct expression *expr)
2466 struct smatch_state *link_state;
2467 struct sm_state *sm;
2468 struct string_list *links;
2469 char *link;
2470 struct compare_data *data;
2472 link_state = get_state_expr(link_id, expr);
2473 if (!link_state) {
2474 if (expr->type == EXPR_BINOP &&
2475 (impossibly_high_comparison(expr->left) ||
2476 impossibly_high_comparison(expr->right)))
2477 return 1;
2478 return 0;
2481 links = link_state->data;
2482 FOR_EACH_PTR(links, link) {
2483 sm = get_sm_state(compare_id, link, NULL);
2484 if (!sm)
2485 continue;
2486 data = sm->state->data;
2487 if (!data)
2488 continue;
2489 if (!possibly_true(data->left, data->comparison, data->right))
2490 return 1;
2491 } END_FOR_EACH_PTR(link);
2493 return 0;
2496 static void free_data(struct symbol *sym)
2498 if (__inline_fn)
2499 return;
2500 clear_compare_data_alloc();
2503 void register_comparison(int id)
2505 compare_id = id;
2506 add_hook(&save_start_states, AFTER_DEF_HOOK);
2507 add_unmatched_state_hook(compare_id, unmatched_comparison);
2508 add_pre_merge_hook(compare_id, &pre_merge_hook);
2509 add_merge_hook(compare_id, &merge_compare_states);
2510 add_hook(&free_data, AFTER_FUNC_HOOK);
2511 add_hook(&match_call_info, FUNCTION_CALL_HOOK);
2512 add_split_return_callback(&print_return_comparison);
2514 select_return_states_hook(PARAM_COMPARE, &db_return_comparison);
2515 add_hook(&match_preop, OP_HOOK);
2518 void register_comparison_late(int id)
2520 add_hook(&match_assign, ASSIGNMENT_HOOK);
2523 void register_comparison_links(int id)
2525 link_id = id;
2526 add_merge_hook(link_id, &merge_links);
2527 add_modification_hook(link_id, &match_modify);
2528 add_modification_hook_late(link_id, match_inc_dec);
2530 add_member_info_callback(link_id, struct_member_callback);
2533 void register_comparison_inc_dec(int id)
2535 inc_dec_id = id;
2536 add_modification_hook_late(inc_dec_id, &iter_modify);
2539 void register_comparison_inc_dec_links(int id)
2541 inc_dec_link_id = id;
2542 set_up_link_functions(inc_dec_id, inc_dec_link_id);
2545 static void filter_by_sm(struct sm_state *sm, int op,
2546 struct state_list **true_stack,
2547 struct state_list **false_stack)
2549 struct compare_data *data;
2550 int istrue = 0;
2551 int isfalse = 0;
2553 if (!sm)
2554 return;
2555 data = sm->state->data;
2556 if (!data) {
2557 if (sm->merged) {
2558 filter_by_sm(sm->left, op, true_stack, false_stack);
2559 filter_by_sm(sm->right, op, true_stack, false_stack);
2561 return;
2564 if (data->comparison &&
2565 data->comparison == filter_comparison(data->comparison, op))
2566 istrue = 1;
2568 if (data->comparison &&
2569 data->comparison == filter_comparison(data->comparison, negate_comparison(op)))
2570 isfalse = 1;
2572 if (istrue)
2573 add_ptr_list(true_stack, sm);
2574 if (isfalse)
2575 add_ptr_list(false_stack, sm);
2577 if (sm->merged) {
2578 filter_by_sm(sm->left, op, true_stack, false_stack);
2579 filter_by_sm(sm->right, op, true_stack, false_stack);
2583 struct sm_state *comparison_implication_hook(struct expression *expr,
2584 struct state_list **true_stack,
2585 struct state_list **false_stack)
2587 struct sm_state *sm;
2588 char *left, *right;
2589 int op;
2590 static char buf[256];
2592 if (expr->type != EXPR_COMPARE)
2593 return NULL;
2595 op = expr->op;
2597 left = expr_to_var(expr->left);
2598 right = expr_to_var(expr->right);
2599 if (!left || !right) {
2600 free_string(left);
2601 free_string(right);
2602 return NULL;
2605 if (strcmp(left, right) > 0) {
2606 char *tmp = left;
2608 left = right;
2609 right = tmp;
2610 op = flip_comparison(op);
2613 snprintf(buf, sizeof(buf), "%s vs %s", left, right);
2614 sm = get_sm_state(compare_id, buf, NULL);
2615 if (!sm)
2616 return NULL;
2617 if (!sm->merged)
2618 return NULL;
2620 filter_by_sm(sm, op, true_stack, false_stack);
2621 if (!*true_stack && !*false_stack)
2622 return NULL;
2624 if (option_debug)
2625 sm_msg("implications from comparison: (%s)", show_sm(sm));
2627 return sm;