flow: fix a crashing bug
[smatch.git] / smatch_comparison.c
blob923a1f82781e44bcb4d7fd21a7eb86139d1698d5
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 (__in_fake_assign || outside_of_function())
1559 return;
1561 if (is_struct(expr->left))
1562 return;
1564 if (is_self_assign(expr))
1565 return;
1567 copy_comparisons(expr->left, expr->right);
1568 add_comparison(expr->left, SPECIAL_EQUAL, expr->right);
1570 right = strip_expr(expr->right);
1571 if (right->type == EXPR_BINOP)
1572 match_binop_assign(expr);
1575 int get_comparison_strings(const char *one, const char *two)
1577 char buf[256];
1578 struct smatch_state *state;
1579 int invert = 0;
1580 int ret = 0;
1582 if (!one || !two)
1583 return 0;
1585 if (strcmp(one, two) == 0)
1586 return SPECIAL_EQUAL;
1588 if (strcmp(one, two) > 0) {
1589 const char *tmp = one;
1591 one = two;
1592 two = tmp;
1593 invert = 1;
1596 snprintf(buf, sizeof(buf), "%s vs %s", one, two);
1597 state = get_state(compare_id, buf, NULL);
1598 if (state)
1599 ret = state_to_comparison(state);
1601 if (invert)
1602 ret = flip_comparison(ret);
1604 return ret;
1607 int get_comparison(struct expression *a, struct expression *b)
1609 char *one = NULL;
1610 char *two = NULL;
1611 int ret = 0;
1613 if (!a || !b)
1614 return 0;
1616 a = strip_parens(a);
1617 b = strip_parens(b);
1619 move_plus_to_minus(&a, &b);
1621 one = chunk_to_var(a);
1622 if (!one)
1623 goto free;
1624 two = chunk_to_var(b);
1625 if (!two)
1626 goto free;
1628 ret = get_comparison_strings(one, two);
1629 if (ret)
1630 goto free;
1632 if (is_plus_one(a) || is_minus_one(a)) {
1633 free_string(one);
1634 one = chunk_to_var(a->left);
1635 ret = get_comparison_strings(one, two);
1636 } else if (is_plus_one(b) || is_minus_one(b)) {
1637 free_string(two);
1638 two = chunk_to_var(b->left);
1639 ret = get_comparison_strings(one, two);
1642 if (!ret)
1643 goto free;
1645 if ((is_plus_one(a) || is_minus_one(b)) && ret == '<')
1646 ret = SPECIAL_LTE;
1647 else if ((is_minus_one(a) || is_plus_one(b)) && ret == '>')
1648 ret = SPECIAL_GTE;
1649 else
1650 ret = 0;
1652 free:
1653 free_string(one);
1654 free_string(two);
1656 if (!ret)
1657 return comparison_from_extra(a, b);
1658 return ret;
1661 int possible_comparison(struct expression *a, int comparison, struct expression *b)
1663 char *one = NULL;
1664 char *two = NULL;
1665 int ret = 0;
1666 char buf[256];
1667 struct sm_state *sm;
1668 int saved;
1670 one = chunk_to_var(a);
1671 if (!one)
1672 goto free;
1673 two = chunk_to_var(b);
1674 if (!two)
1675 goto free;
1678 if (strcmp(one, two) == 0 && comparison == SPECIAL_EQUAL) {
1679 ret = 1;
1680 goto free;
1683 if (strcmp(one, two) > 0) {
1684 char *tmp = one;
1686 one = two;
1687 two = tmp;
1688 comparison = flip_comparison(comparison);
1691 snprintf(buf, sizeof(buf), "%s vs %s", one, two);
1692 sm = get_sm_state(compare_id, buf, NULL);
1693 if (!sm)
1694 goto free;
1696 FOR_EACH_PTR(sm->possible, sm) {
1697 if (!sm->state->data)
1698 continue;
1699 saved = ((struct compare_data *)sm->state->data)->comparison;
1700 if (saved == comparison)
1701 ret = 1;
1702 if (comparison == SPECIAL_EQUAL &&
1703 (saved == SPECIAL_LTE ||
1704 saved == SPECIAL_GTE ||
1705 saved == SPECIAL_UNSIGNED_LTE ||
1706 saved == SPECIAL_UNSIGNED_GTE))
1707 ret = 1;
1708 if (ret == 1)
1709 goto free;
1710 } END_FOR_EACH_PTR(sm);
1712 return ret;
1713 free:
1714 free_string(one);
1715 free_string(two);
1716 return ret;
1719 struct state_list *get_all_comparisons(struct expression *expr)
1721 struct smatch_state *state;
1722 struct string_list *links;
1723 struct state_list *ret = NULL;
1724 struct sm_state *sm;
1725 char *tmp;
1727 state = get_state_chunk(link_id, expr);
1728 if (!state)
1729 return NULL;
1730 links = state->data;
1732 FOR_EACH_PTR(links, tmp) {
1733 sm = get_sm_state(compare_id, tmp, NULL);
1734 if (!sm)
1735 continue;
1736 // FIXME have to compare name with vsl
1737 add_ptr_list(&ret, sm);
1738 } END_FOR_EACH_PTR(tmp);
1740 return ret;
1743 struct state_list *get_all_possible_equal_comparisons(struct expression *expr)
1745 struct smatch_state *state;
1746 struct string_list *links;
1747 struct state_list *ret = NULL;
1748 struct sm_state *sm;
1749 char *tmp;
1751 state = get_state_chunk(link_id, expr);
1752 if (!state)
1753 return NULL;
1754 links = state->data;
1756 FOR_EACH_PTR(links, tmp) {
1757 sm = get_sm_state(compare_id, tmp, NULL);
1758 if (!sm)
1759 continue;
1760 if (!strchr(sm->state->name, '='))
1761 continue;
1762 if (strcmp(sm->state->name, "!=") == 0)
1763 continue;
1764 add_ptr_list(&ret, sm);
1765 } END_FOR_EACH_PTR(tmp);
1767 return ret;
1770 struct state_list *get_all_possible_not_equal_comparisons(struct expression *expr)
1772 struct smatch_state *state;
1773 struct string_list *links;
1774 struct state_list *ret = NULL;
1775 struct sm_state *sm;
1776 struct sm_state *possible;
1777 char *link;
1779 return NULL;
1781 state = get_state_chunk(link_id, expr);
1782 if (!state)
1783 return NULL;
1784 links = state->data;
1786 FOR_EACH_PTR(links, link) {
1787 sm = get_sm_state(compare_id, link, NULL);
1788 if (!sm)
1789 continue;
1790 FOR_EACH_PTR(sm->possible, possible) {
1791 if (strcmp(possible->state->name, "!=") != 0)
1792 continue;
1793 add_ptr_list(&ret, sm);
1794 break;
1795 } END_FOR_EACH_PTR(link);
1796 } END_FOR_EACH_PTR(link);
1798 return ret;
1801 static void update_links_from_call(struct expression *left,
1802 int left_compare,
1803 struct expression *right)
1805 struct string_list *links;
1806 struct smatch_state *state;
1807 struct compare_data *data;
1808 struct symbol *left_sym, *right_sym;
1809 char *left_var = NULL;
1810 char *right_var = NULL;
1811 struct var_sym_list *left_vsl;
1812 struct expression *expr;
1813 const char *var;
1814 struct var_sym_list *vsl;
1815 int comparison;
1816 char *tmp;
1818 left_var = chunk_to_var_sym(left, &left_sym);
1819 if (!left_var)
1820 goto done;
1821 left_vsl = expr_to_vsl(left);
1822 right_var = chunk_to_var_sym(right, &right_sym);
1823 if (!right_var)
1824 goto done;
1826 state = get_state(link_id, right_var, right_sym);
1827 if (!state)
1828 return;
1829 links = state->data;
1831 FOR_EACH_PTR(links, tmp) {
1832 state = get_state(compare_id, tmp, NULL);
1833 if (!state || !state->data)
1834 continue;
1835 data = state->data;
1836 comparison = data->comparison;
1837 expr = data->right;
1838 var = data->right_var;
1839 vsl = data->right_vsl;
1840 if (strcmp(var, right_var) == 0) {
1841 expr = data->left;
1842 var = data->left_var;
1843 vsl = data->left_vsl;
1844 comparison = flip_comparison(comparison);
1846 comparison = combine_comparisons(left_compare, comparison);
1847 if (!comparison)
1848 continue;
1849 add_comparison_var_sym(left, left_var, left_vsl, comparison, expr, var, vsl);
1850 } END_FOR_EACH_PTR(tmp);
1852 done:
1853 free_string(right_var);
1856 void __add_return_comparison(struct expression *call, const char *range)
1858 struct expression *arg;
1859 int comparison;
1860 char buf[4];
1862 if (!str_to_comparison_arg(range, call, &comparison, &arg))
1863 return;
1864 snprintf(buf, sizeof(buf), "%s", show_special(comparison));
1865 update_links_from_call(call, comparison, arg);
1866 add_comparison(call, comparison, arg);
1869 void __add_comparison_info(struct expression *expr, struct expression *call, const char *range)
1871 copy_comparisons(expr, call);
1874 static char *get_mask_comparison(struct expression *expr, int ignore)
1876 struct expression *tmp, *right;
1877 int count, param;
1878 char buf[256];
1880 /* The return value for "return foo & param;" is <= param */
1882 count = 0;
1883 while ((tmp = get_assigned_expr(expr))) {
1884 expr = strip_expr(tmp);
1885 if (count++ > 4)
1886 break;
1889 if (expr->type != EXPR_BINOP || expr->op != '&')
1890 return NULL;
1892 right = strip_expr(expr->right);
1893 param = get_param_num(right);
1895 if (param == ignore)
1896 return NULL;
1898 snprintf(buf, sizeof(buf), "[<=$%d]", param);
1899 return alloc_sname(buf);
1902 static char *range_comparison_to_param_helper(struct expression *expr, char starts_with, int ignore)
1904 struct symbol *param;
1905 char *var = NULL;
1906 char buf[256];
1907 char *ret_str = NULL;
1908 int compare;
1909 int i;
1911 if (!expr)
1912 return NULL;
1914 var = chunk_to_var(expr);
1915 if (!var)
1916 goto try_mask;
1918 i = -1;
1919 FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, param) {
1920 i++;
1921 if (i == ignore)
1922 continue;
1923 if (!param->ident)
1924 continue;
1925 snprintf(buf, sizeof(buf), "%s orig", param->ident->name);
1926 compare = get_comparison_strings(var, buf);
1927 if (!compare)
1928 continue;
1929 if (show_special(compare)[0] != starts_with)
1930 continue;
1931 snprintf(buf, sizeof(buf), "[%s$%d]", show_special(compare), i);
1932 ret_str = alloc_sname(buf);
1933 break;
1934 } END_FOR_EACH_PTR(param);
1936 free_string(var);
1937 if (!ret_str)
1938 goto try_mask;
1940 return ret_str;
1942 try_mask:
1943 if (starts_with == '<')
1944 ret_str = get_mask_comparison(expr, ignore);
1945 return ret_str;
1948 char *name_sym_to_param_comparison(const char *name, struct symbol *sym)
1950 struct symbol *param;
1951 char buf[256];
1952 int compare;
1953 int i;
1955 i = -1;
1956 FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, param) {
1957 i++;
1958 if (!param->ident)
1959 continue;
1960 snprintf(buf, sizeof(buf), "%s orig", param->ident->name);
1961 compare = get_comparison_strings(name, buf);
1962 if (!compare)
1963 continue;
1964 snprintf(buf, sizeof(buf), "[%s$%d]", show_special(compare), i);
1965 return alloc_sname(buf);
1966 } END_FOR_EACH_PTR(param);
1968 return NULL;
1971 char *expr_equal_to_param(struct expression *expr, int ignore)
1973 return range_comparison_to_param_helper(expr, '=', ignore);
1976 char *expr_lte_to_param(struct expression *expr, int ignore)
1978 return range_comparison_to_param_helper(expr, '<', ignore);
1981 char *expr_param_comparison(struct expression *expr, int ignore)
1983 struct symbol *param;
1984 char *var = NULL;
1985 char buf[256];
1986 char *ret_str = NULL;
1987 int compare;
1988 int i;
1990 var = chunk_to_var(expr);
1991 if (!var)
1992 goto free;
1994 i = -1;
1995 FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, param) {
1996 i++;
1997 if (i == ignore)
1998 continue;
1999 if (!param->ident)
2000 continue;
2001 snprintf(buf, sizeof(buf), "%s orig", param->ident->name);
2002 compare = get_comparison_strings(var, buf);
2003 if (!compare)
2004 continue;
2005 snprintf(buf, sizeof(buf), "[%s$%d]", show_special(compare), i);
2006 ret_str = alloc_sname(buf);
2007 break;
2008 } END_FOR_EACH_PTR(param);
2010 free:
2011 free_string(var);
2012 return ret_str;
2015 char *get_printed_param_name(struct expression *call, const char *param_name, struct symbol *param_sym)
2017 struct expression *arg;
2018 char *name;
2019 struct symbol *sym;
2020 static char buf[256];
2021 int len;
2022 int i;
2024 i = -1;
2025 FOR_EACH_PTR(call->args, arg) {
2026 i++;
2028 name = expr_to_var_sym(arg, &sym);
2029 if (!name || !sym)
2030 continue;
2031 if (sym != param_sym)
2032 continue;
2034 len = strlen(name);
2035 if (strncmp(name, param_name, len) != 0)
2036 continue;
2037 if (param_name[len] == '\0') {
2038 snprintf(buf, sizeof(buf), "$%d", i);
2039 return buf;
2041 if (param_name[len] != '-')
2042 continue;
2043 snprintf(buf, sizeof(buf), "$%d%s", i, param_name + len);
2044 return buf;
2045 } END_FOR_EACH_PTR(arg);
2047 return NULL;
2050 static void match_call_info(struct expression *expr)
2052 struct expression *arg;
2053 struct smatch_state *state;
2054 struct sm_state *sm;
2055 struct compare_data *data;
2056 int comparison;
2057 struct string_list *links;
2058 char *arg_name;
2059 const char *right_name;
2060 char *link;
2061 char info_buf[256];
2062 int i;
2064 i = -1;
2065 FOR_EACH_PTR(expr->args, arg) {
2066 i++;
2068 state = get_state_chunk(link_id, arg);
2069 if (!state)
2070 continue;
2072 links = state->data;
2073 FOR_EACH_PTR(links, link) {
2074 struct var_sym_list *right_vsl;
2075 struct var_sym *right_vs;
2078 if (strstr(link, " orig"))
2079 continue;
2080 sm = get_sm_state(compare_id, link, NULL);
2081 if (!sm)
2082 continue;
2083 data = sm->state->data;
2084 if (!data || !data->comparison)
2085 continue;
2086 arg_name = expr_to_var(arg);
2087 if (!arg_name)
2088 continue;
2090 right_vsl = NULL;
2091 if (strcmp(data->left_var, arg_name) == 0) {
2092 comparison = data->comparison;
2093 right_name = data->right_var;
2094 right_vsl = data->right_vsl;
2095 } else if (strcmp(data->right_var, arg_name) == 0) {
2096 comparison = flip_comparison(data->comparison);
2097 right_name = data->left_var;
2098 right_vsl = data->left_vsl;
2100 if (!right_vsl || ptr_list_size((struct ptr_list *)right_vsl) != 1)
2101 goto free;
2103 right_vs = first_ptr_list((struct ptr_list *)right_vsl);
2104 if (strcmp(right_vs->var, right_name) != 0)
2105 goto free;
2106 right_name = get_printed_param_name(expr, right_vs->var, right_vs->sym);
2107 if (!right_name)
2108 goto free;
2109 snprintf(info_buf, sizeof(info_buf), "%s %s", show_special(comparison), right_name);
2110 sql_insert_caller_info(expr, PARAM_COMPARE, i, "$", info_buf);
2112 free:
2113 free_string(arg_name);
2114 } END_FOR_EACH_PTR(link);
2115 } END_FOR_EACH_PTR(arg);
2118 static void struct_member_callback(struct expression *call, int param, char *printed_name, struct sm_state *link_sm)
2120 struct sm_state *compare_sm;
2121 struct string_list *links;
2122 char *link;
2123 struct compare_data *data;
2124 struct var_sym *left, *right;
2125 static char info_buf[256];
2126 const char *right_name;
2128 if (strstr(printed_name, " orig"))
2129 return;
2131 links = link_sm->state->data;
2132 FOR_EACH_PTR(links, link) {
2133 compare_sm = get_sm_state(compare_id, link, NULL);
2134 if (!compare_sm)
2135 continue;
2136 data = compare_sm->state->data;
2137 if (!data || !data->comparison)
2138 continue;
2140 if (ptr_list_size((struct ptr_list *)data->left_vsl) != 1 ||
2141 ptr_list_size((struct ptr_list *)data->right_vsl) != 1)
2142 continue;
2143 left = first_ptr_list((struct ptr_list *)data->left_vsl);
2144 right = first_ptr_list((struct ptr_list *)data->right_vsl);
2145 if (left->sym == right->sym &&
2146 strcmp(left->var, right->var) == 0)
2147 continue;
2149 * Both parameters link to this comparison so only
2150 * record the first one.
2152 if (left->sym != link_sm->sym ||
2153 strcmp(left->var, link_sm->name) != 0)
2154 continue;
2156 right_name = get_printed_param_name(call, right->var, right->sym);
2157 if (!right_name)
2158 continue;
2159 snprintf(info_buf, sizeof(info_buf), "%s %s", show_special(data->comparison), right_name);
2160 sql_insert_caller_info(call, PARAM_COMPARE, param, printed_name, info_buf);
2161 } END_FOR_EACH_PTR(link);
2164 static void print_return_value_comparison(int return_id, char *return_ranges, struct expression *expr)
2166 char *name;
2167 const char *tmp_name;
2168 struct symbol *sym;
2169 int param;
2170 char info_buf[256];
2173 * TODO: This only prints == comparisons. That's probably the most
2174 * useful comparison because == max has lots of implications. But it
2175 * would be good to capture the rest as well.
2177 * This information is already in the DB but it's in the parameter math
2178 * bits and it's awkward to use it. This is is the simpler, possibly
2179 * cleaner way, but not necessarily the best, I don't know.
2182 if (!expr)
2183 return;
2184 name = expr_to_var_sym(expr, &sym);
2185 if (!name || !sym)
2186 goto free;
2188 param = get_param_num_from_sym(sym);
2189 if (param < 0)
2190 goto free;
2191 if (param_was_set_var_sym(name, sym))
2192 goto free;
2194 tmp_name = get_param_name_var_sym(name, sym);
2195 if (!tmp_name)
2196 goto free;
2198 snprintf(info_buf, sizeof(info_buf), "== $%d%s", param, tmp_name + 1);
2199 sql_insert_return_states(return_id, return_ranges,
2200 PARAM_COMPARE, -1, "$", info_buf);
2201 free:
2202 free_string(name);
2205 static void print_return_comparison(int return_id, char *return_ranges, struct expression *expr)
2207 struct sm_state *tmp;
2208 struct string_list *links;
2209 char *link;
2210 struct sm_state *sm;
2211 struct compare_data *data;
2212 struct var_sym *left, *right;
2213 int left_param, right_param;
2214 char left_buf[256];
2215 char right_buf[256];
2216 char info_buf[256];
2217 const char *tmp_name;
2219 print_return_value_comparison(return_id, return_ranges, expr);
2221 FOR_EACH_MY_SM(link_id, __get_cur_stree(), tmp) {
2222 if (get_param_num_from_sym(tmp->sym) < 0)
2223 continue;
2224 links = tmp->state->data;
2225 FOR_EACH_PTR(links, link) {
2226 sm = get_sm_state(compare_id, link, NULL);
2227 if (!sm)
2228 continue;
2229 data = sm->state->data;
2230 if (!data || !data->comparison)
2231 continue;
2232 if (ptr_list_size((struct ptr_list *)data->left_vsl) != 1 ||
2233 ptr_list_size((struct ptr_list *)data->right_vsl) != 1)
2234 continue;
2235 left = first_ptr_list((struct ptr_list *)data->left_vsl);
2236 right = first_ptr_list((struct ptr_list *)data->right_vsl);
2237 if (left->sym == right->sym &&
2238 strcmp(left->var, right->var) == 0)
2239 continue;
2241 * Both parameters link to this comparison so only
2242 * record the first one.
2244 if (left->sym != tmp->sym ||
2245 strcmp(left->var, tmp->name) != 0)
2246 continue;
2248 if (strstr(right->var, " orig"))
2249 continue;
2251 left_param = get_param_num_from_sym(left->sym);
2252 right_param = get_param_num_from_sym(right->sym);
2253 if (left_param < 0 || right_param < 0)
2254 continue;
2256 tmp_name = get_param_name_var_sym(left->var, left->sym);
2257 if (!tmp_name)
2258 continue;
2259 snprintf(left_buf, sizeof(left_buf), "%s", tmp_name);
2261 tmp_name = get_param_name_var_sym(right->var, right->sym);
2262 if (!tmp_name || tmp_name[0] != '$')
2263 continue;
2264 snprintf(right_buf, sizeof(right_buf), "$%d%s", right_param, tmp_name + 1);
2267 * FIXME: this should reject $ type variables (as
2268 * opposed to $->foo type). Those should come from
2269 * smatch_param_compare_limit.c.
2272 snprintf(info_buf, sizeof(info_buf), "%s %s", show_special(data->comparison), right_buf);
2273 sql_insert_return_states(return_id, return_ranges,
2274 PARAM_COMPARE, left_param, left_buf, info_buf);
2275 } END_FOR_EACH_PTR(link);
2277 } END_FOR_EACH_SM(tmp);
2280 static int parse_comparison(char **value, int *op)
2283 *op = **value;
2285 switch (*op) {
2286 case '<':
2287 (*value)++;
2288 if (**value == '=') {
2289 (*value)++;
2290 *op = SPECIAL_LTE;
2292 break;
2293 case '=':
2294 (*value)++;
2295 (*value)++;
2296 *op = SPECIAL_EQUAL;
2297 break;
2298 case '!':
2299 (*value)++;
2300 (*value)++;
2301 *op = SPECIAL_NOTEQUAL;
2302 break;
2303 case '>':
2304 (*value)++;
2305 if (**value == '=') {
2306 (*value)++;
2307 *op = SPECIAL_GTE;
2309 break;
2310 default:
2311 return 0;
2314 if (**value != ' ') {
2315 sm_msg("internal error parsing comparison. %s", *value);
2316 return 0;
2319 (*value)++;
2320 return 1;
2323 static int split_op_param_key(char *value, int *op, int *param, char **key)
2325 static char buf[256];
2326 char *p;
2328 if (!parse_comparison(&value, op))
2329 return 0;
2331 snprintf(buf, sizeof(buf), value);
2333 p = buf;
2334 if (*p++ != '$')
2335 return 0;
2337 *param = atoi(p);
2338 if (*param < 0 || *param > 99)
2339 return 0;
2340 p++;
2341 if (*param > 9)
2342 p++;
2343 p--;
2344 *p = '$';
2345 *key = p;
2347 return 1;
2350 static void db_return_comparison(struct expression *expr, int left_param, char *key, char *value)
2352 struct expression *left_arg, *right_arg;
2353 char *left_name = NULL;
2354 struct symbol *left_sym;
2355 char *right_name = NULL;
2356 struct symbol *right_sym;
2357 int op;
2358 int right_param;
2359 char *right_key;
2360 struct var_sym_list *left_vsl = NULL, *right_vsl = NULL;
2362 if (left_param == -1) {
2363 if (expr->type != EXPR_ASSIGNMENT)
2364 return;
2365 left_arg = strip_expr(expr->left);
2367 while (expr->type == EXPR_ASSIGNMENT)
2368 expr = strip_expr(expr->right);
2369 if (expr->type != EXPR_CALL)
2370 return;
2371 } else {
2372 while (expr->type == EXPR_ASSIGNMENT)
2373 expr = strip_expr(expr->right);
2374 if (expr->type != EXPR_CALL)
2375 return;
2377 left_arg = get_argument_from_call_expr(expr->args, left_param);
2378 if (!left_arg)
2379 return;
2382 if (!split_op_param_key(value, &op, &right_param, &right_key))
2383 return;
2385 right_arg = get_argument_from_call_expr(expr->args, right_param);
2386 if (!right_arg)
2387 return;
2389 left_name = get_variable_from_key(left_arg, key, &left_sym);
2390 if (!left_name || !left_sym)
2391 goto free;
2393 right_name = get_variable_from_key(right_arg, right_key, &right_sym);
2394 if (!right_name || !right_sym)
2395 goto free;
2397 add_var_sym(&left_vsl, left_name, left_sym);
2398 add_var_sym(&right_vsl, right_name, right_sym);
2400 add_comparison_var_sym(NULL, left_name, left_vsl, op, NULL, right_name, right_vsl);
2402 free:
2403 free_string(left_name);
2404 free_string(right_name);
2407 int param_compare_limit_is_impossible(struct expression *expr, int left_param, char *left_key, char *value)
2409 struct smatch_state *state;
2410 char *left_name = NULL;
2411 char *right_name = NULL;
2412 struct symbol *left_sym, *right_sym;
2413 struct expression *left_arg, *right_arg;
2414 int op, state_op;
2415 int right_param;
2416 char *right_key;
2417 int ret = 0;
2418 char buf[256];
2420 while (expr->type == EXPR_ASSIGNMENT)
2421 expr = strip_expr(expr->right);
2422 if (expr->type != EXPR_CALL)
2423 return 0;
2425 if (!split_op_param_key(value, &op, &right_param, &right_key))
2426 return 0;
2428 left_arg = get_argument_from_call_expr(expr->args, left_param);
2429 if (!left_arg)
2430 return 0;
2432 right_arg = get_argument_from_call_expr(expr->args, right_param);
2433 if (!right_arg)
2434 return 0;
2436 left_name = get_variable_from_key(left_arg, left_key, &left_sym);
2437 right_name = get_variable_from_key(right_arg, right_key, &right_sym);
2438 if (!left_name || !right_name)
2439 goto free;
2441 snprintf(buf, sizeof(buf), "%s vs %s", left_name, right_name);
2442 state = get_state(compare_id, buf, NULL);
2443 if (!state)
2444 goto free;
2445 state_op = state_to_comparison(state);
2446 if (!state_op)
2447 goto free;
2449 if (!filter_comparison(remove_unsigned_from_comparison(state_op), op))
2450 ret = 1;
2451 free:
2452 free_string(left_name);
2453 free_string(right_name);
2454 return ret;
2457 int impossibly_high_comparison(struct expression *expr)
2459 struct smatch_state *link_state;
2460 struct sm_state *sm;
2461 struct string_list *links;
2462 char *link;
2463 struct compare_data *data;
2465 link_state = get_state_expr(link_id, expr);
2466 if (!link_state) {
2467 if (expr->type == EXPR_BINOP &&
2468 (impossibly_high_comparison(expr->left) ||
2469 impossibly_high_comparison(expr->right)))
2470 return 1;
2471 return 0;
2474 links = link_state->data;
2475 FOR_EACH_PTR(links, link) {
2476 sm = get_sm_state(compare_id, link, NULL);
2477 if (!sm)
2478 continue;
2479 data = sm->state->data;
2480 if (!data)
2481 continue;
2482 if (!possibly_true(data->left, data->comparison, data->right))
2483 return 1;
2484 } END_FOR_EACH_PTR(link);
2486 return 0;
2489 static void free_data(struct symbol *sym)
2491 if (__inline_fn)
2492 return;
2493 clear_compare_data_alloc();
2496 void register_comparison(int id)
2498 compare_id = id;
2499 add_hook(&save_start_states, AFTER_DEF_HOOK);
2500 add_unmatched_state_hook(compare_id, unmatched_comparison);
2501 add_pre_merge_hook(compare_id, &pre_merge_hook);
2502 add_merge_hook(compare_id, &merge_compare_states);
2503 add_hook(&free_data, AFTER_FUNC_HOOK);
2504 add_hook(&match_call_info, FUNCTION_CALL_HOOK);
2505 add_split_return_callback(&print_return_comparison);
2507 select_return_states_hook(PARAM_COMPARE, &db_return_comparison);
2508 add_hook(&match_preop, OP_HOOK);
2511 void register_comparison_late(int id)
2513 add_hook(&match_assign, ASSIGNMENT_HOOK);
2516 void register_comparison_links(int id)
2518 link_id = id;
2519 add_merge_hook(link_id, &merge_links);
2520 add_modification_hook(link_id, &match_modify);
2521 add_modification_hook_late(link_id, match_inc_dec);
2523 add_member_info_callback(link_id, struct_member_callback);
2526 void register_comparison_inc_dec(int id)
2528 inc_dec_id = id;
2529 add_modification_hook_late(inc_dec_id, &iter_modify);
2532 void register_comparison_inc_dec_links(int id)
2534 inc_dec_link_id = id;
2535 set_up_link_functions(inc_dec_id, inc_dec_link_id);
2538 static void filter_by_sm(struct sm_state *sm, int op,
2539 struct state_list **true_stack,
2540 struct state_list **false_stack)
2542 struct compare_data *data;
2543 int istrue = 0;
2544 int isfalse = 0;
2546 if (!sm)
2547 return;
2548 data = sm->state->data;
2549 if (!data) {
2550 if (sm->merged) {
2551 filter_by_sm(sm->left, op, true_stack, false_stack);
2552 filter_by_sm(sm->right, op, true_stack, false_stack);
2554 return;
2557 if (data->comparison &&
2558 data->comparison == filter_comparison(data->comparison, op))
2559 istrue = 1;
2561 if (data->comparison &&
2562 data->comparison == filter_comparison(data->comparison, negate_comparison(op)))
2563 isfalse = 1;
2565 if (istrue)
2566 add_ptr_list(true_stack, sm);
2567 if (isfalse)
2568 add_ptr_list(false_stack, sm);
2570 if (sm->merged) {
2571 filter_by_sm(sm->left, op, true_stack, false_stack);
2572 filter_by_sm(sm->right, op, true_stack, false_stack);
2576 struct sm_state *comparison_implication_hook(struct expression *expr,
2577 struct state_list **true_stack,
2578 struct state_list **false_stack)
2580 struct sm_state *sm;
2581 char *left, *right;
2582 int op;
2583 static char buf[256];
2585 if (expr->type != EXPR_COMPARE)
2586 return NULL;
2588 op = expr->op;
2590 left = expr_to_var(expr->left);
2591 right = expr_to_var(expr->right);
2592 if (!left || !right) {
2593 free_string(left);
2594 free_string(right);
2595 return NULL;
2598 if (strcmp(left, right) > 0) {
2599 char *tmp = left;
2601 left = right;
2602 right = tmp;
2603 op = flip_comparison(op);
2606 snprintf(buf, sizeof(buf), "%s vs %s", left, right);
2607 sm = get_sm_state(compare_id, buf, NULL);
2608 if (!sm)
2609 return NULL;
2610 if (!sm->merged)
2611 return NULL;
2613 filter_by_sm(sm, op, true_stack, false_stack);
2614 if (!*true_stack && !*false_stack)
2615 return NULL;
2617 if (option_debug)
2618 sm_msg("implications from comparison: (%s)", show_sm(sm));
2620 return sm;