Regularise error reporting
[smatch.git] / smatch_comparison.c
blob51b4a45487ccb351f236cc0a85fdfe04994d80c3
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_perror("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_perror("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);
1894 if (param < 0 || param == ignore)
1895 return NULL;
1897 snprintf(buf, sizeof(buf), "[<=$%d]", param);
1898 return alloc_sname(buf);
1901 static char *range_comparison_to_param_helper(struct expression *expr, char starts_with, int ignore)
1903 struct symbol *param;
1904 char *var = NULL;
1905 char buf[256];
1906 char *ret_str = NULL;
1907 int compare;
1908 int i;
1910 if (!expr)
1911 return NULL;
1913 var = chunk_to_var(expr);
1914 if (!var)
1915 goto try_mask;
1917 i = -1;
1918 FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, param) {
1919 i++;
1920 if (i == ignore)
1921 continue;
1922 if (!param->ident)
1923 continue;
1924 snprintf(buf, sizeof(buf), "%s orig", param->ident->name);
1925 compare = get_comparison_strings(var, buf);
1926 if (!compare)
1927 continue;
1928 if (show_special(compare)[0] != starts_with)
1929 continue;
1930 snprintf(buf, sizeof(buf), "[%s$%d]", show_special(compare), i);
1931 ret_str = alloc_sname(buf);
1932 break;
1933 } END_FOR_EACH_PTR(param);
1935 free_string(var);
1936 if (!ret_str)
1937 goto try_mask;
1939 return ret_str;
1941 try_mask:
1942 if (starts_with == '<')
1943 ret_str = get_mask_comparison(expr, ignore);
1944 return ret_str;
1947 char *name_sym_to_param_comparison(const char *name, struct symbol *sym)
1949 struct symbol *param;
1950 char buf[256];
1951 int compare;
1952 int i;
1954 i = -1;
1955 FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, param) {
1956 i++;
1957 if (!param->ident)
1958 continue;
1959 snprintf(buf, sizeof(buf), "%s orig", param->ident->name);
1960 compare = get_comparison_strings(name, buf);
1961 if (!compare)
1962 continue;
1963 snprintf(buf, sizeof(buf), "[%s$%d]", show_special(compare), i);
1964 return alloc_sname(buf);
1965 } END_FOR_EACH_PTR(param);
1967 return NULL;
1970 char *expr_equal_to_param(struct expression *expr, int ignore)
1972 return range_comparison_to_param_helper(expr, '=', ignore);
1975 char *expr_lte_to_param(struct expression *expr, int ignore)
1977 return range_comparison_to_param_helper(expr, '<', ignore);
1980 char *expr_param_comparison(struct expression *expr, int ignore)
1982 struct symbol *param;
1983 char *var = NULL;
1984 char buf[256];
1985 char *ret_str = NULL;
1986 int compare;
1987 int i;
1989 var = chunk_to_var(expr);
1990 if (!var)
1991 goto free;
1993 i = -1;
1994 FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, param) {
1995 i++;
1996 if (i == ignore)
1997 continue;
1998 if (!param->ident)
1999 continue;
2000 snprintf(buf, sizeof(buf), "%s orig", param->ident->name);
2001 compare = get_comparison_strings(var, buf);
2002 if (!compare)
2003 continue;
2004 snprintf(buf, sizeof(buf), "[%s$%d]", show_special(compare), i);
2005 ret_str = alloc_sname(buf);
2006 break;
2007 } END_FOR_EACH_PTR(param);
2009 free:
2010 free_string(var);
2011 return ret_str;
2014 char *get_printed_param_name(struct expression *call, const char *param_name, struct symbol *param_sym)
2016 struct expression *arg;
2017 char *name;
2018 struct symbol *sym;
2019 static char buf[256];
2020 int len;
2021 int i;
2023 i = -1;
2024 FOR_EACH_PTR(call->args, arg) {
2025 i++;
2027 name = expr_to_var_sym(arg, &sym);
2028 if (!name || !sym)
2029 continue;
2030 if (sym != param_sym)
2031 continue;
2033 len = strlen(name);
2034 if (strncmp(name, param_name, len) != 0)
2035 continue;
2036 if (param_name[len] == '\0') {
2037 snprintf(buf, sizeof(buf), "$%d", i);
2038 return buf;
2040 if (param_name[len] != '-')
2041 continue;
2042 snprintf(buf, sizeof(buf), "$%d%s", i, param_name + len);
2043 return buf;
2044 } END_FOR_EACH_PTR(arg);
2046 return NULL;
2049 static void match_call_info(struct expression *expr)
2051 struct expression *arg;
2052 struct smatch_state *state;
2053 struct sm_state *sm;
2054 struct compare_data *data;
2055 int comparison;
2056 struct string_list *links;
2057 char *arg_name;
2058 const char *right_name;
2059 char *link;
2060 char info_buf[256];
2061 int i;
2063 i = -1;
2064 FOR_EACH_PTR(expr->args, arg) {
2065 i++;
2067 state = get_state_chunk(link_id, arg);
2068 if (!state)
2069 continue;
2071 links = state->data;
2072 FOR_EACH_PTR(links, link) {
2073 struct var_sym_list *right_vsl;
2074 struct var_sym *right_vs;
2077 if (strstr(link, " orig"))
2078 continue;
2079 sm = get_sm_state(compare_id, link, NULL);
2080 if (!sm)
2081 continue;
2082 data = sm->state->data;
2083 if (!data || !data->comparison)
2084 continue;
2085 arg_name = expr_to_var(arg);
2086 if (!arg_name)
2087 continue;
2089 right_vsl = NULL;
2090 if (strcmp(data->left_var, arg_name) == 0) {
2091 comparison = data->comparison;
2092 right_name = data->right_var;
2093 right_vsl = data->right_vsl;
2094 } else if (strcmp(data->right_var, arg_name) == 0) {
2095 comparison = flip_comparison(data->comparison);
2096 right_name = data->left_var;
2097 right_vsl = data->left_vsl;
2099 if (!right_vsl || ptr_list_size((struct ptr_list *)right_vsl) != 1)
2100 goto free;
2102 right_vs = first_ptr_list((struct ptr_list *)right_vsl);
2103 if (strcmp(right_vs->var, right_name) != 0)
2104 goto free;
2105 right_name = get_printed_param_name(expr, right_vs->var, right_vs->sym);
2106 if (!right_name)
2107 goto free;
2108 snprintf(info_buf, sizeof(info_buf), "%s %s", show_special(comparison), right_name);
2109 sql_insert_caller_info(expr, PARAM_COMPARE, i, "$", info_buf);
2111 free:
2112 free_string(arg_name);
2113 } END_FOR_EACH_PTR(link);
2114 } END_FOR_EACH_PTR(arg);
2117 static void struct_member_callback(struct expression *call, int param, char *printed_name, struct sm_state *link_sm)
2119 struct sm_state *compare_sm;
2120 struct string_list *links;
2121 char *link;
2122 struct compare_data *data;
2123 struct var_sym *left, *right;
2124 static char info_buf[256];
2125 const char *right_name;
2127 if (strstr(printed_name, " orig"))
2128 return;
2130 links = link_sm->state->data;
2131 FOR_EACH_PTR(links, link) {
2132 compare_sm = get_sm_state(compare_id, link, NULL);
2133 if (!compare_sm)
2134 continue;
2135 data = compare_sm->state->data;
2136 if (!data || !data->comparison)
2137 continue;
2139 if (ptr_list_size((struct ptr_list *)data->left_vsl) != 1 ||
2140 ptr_list_size((struct ptr_list *)data->right_vsl) != 1)
2141 continue;
2142 left = first_ptr_list((struct ptr_list *)data->left_vsl);
2143 right = first_ptr_list((struct ptr_list *)data->right_vsl);
2144 if (left->sym == right->sym &&
2145 strcmp(left->var, right->var) == 0)
2146 continue;
2148 * Both parameters link to this comparison so only
2149 * record the first one.
2151 if (left->sym != link_sm->sym ||
2152 strcmp(left->var, link_sm->name) != 0)
2153 continue;
2155 right_name = get_printed_param_name(call, right->var, right->sym);
2156 if (!right_name)
2157 continue;
2158 snprintf(info_buf, sizeof(info_buf), "%s %s", show_special(data->comparison), right_name);
2159 sql_insert_caller_info(call, PARAM_COMPARE, param, printed_name, info_buf);
2160 } END_FOR_EACH_PTR(link);
2163 static void print_return_value_comparison(int return_id, char *return_ranges, struct expression *expr)
2165 char *name;
2166 const char *tmp_name;
2167 struct symbol *sym;
2168 int param;
2169 char info_buf[256];
2172 * TODO: This only prints == comparisons. That's probably the most
2173 * useful comparison because == max has lots of implications. But it
2174 * would be good to capture the rest as well.
2176 * This information is already in the DB but it's in the parameter math
2177 * bits and it's awkward to use it. This is is the simpler, possibly
2178 * cleaner way, but not necessarily the best, I don't know.
2181 if (!expr)
2182 return;
2183 name = expr_to_var_sym(expr, &sym);
2184 if (!name || !sym)
2185 goto free;
2187 param = get_param_num_from_sym(sym);
2188 if (param < 0)
2189 goto free;
2190 if (param_was_set_var_sym(name, sym))
2191 goto free;
2193 tmp_name = get_param_name_var_sym(name, sym);
2194 if (!tmp_name)
2195 goto free;
2197 snprintf(info_buf, sizeof(info_buf), "== $%d%s", param, tmp_name + 1);
2198 sql_insert_return_states(return_id, return_ranges,
2199 PARAM_COMPARE, -1, "$", info_buf);
2200 free:
2201 free_string(name);
2204 static void print_return_comparison(int return_id, char *return_ranges, struct expression *expr)
2206 struct sm_state *tmp;
2207 struct string_list *links;
2208 char *link;
2209 struct sm_state *sm;
2210 struct compare_data *data;
2211 struct var_sym *left, *right;
2212 int left_param, right_param;
2213 char left_buf[256];
2214 char right_buf[256];
2215 char info_buf[258];
2216 const char *tmp_name;
2218 print_return_value_comparison(return_id, return_ranges, expr);
2220 FOR_EACH_MY_SM(link_id, __get_cur_stree(), tmp) {
2221 if (get_param_num_from_sym(tmp->sym) < 0)
2222 continue;
2223 links = tmp->state->data;
2224 FOR_EACH_PTR(links, link) {
2225 sm = get_sm_state(compare_id, link, NULL);
2226 if (!sm)
2227 continue;
2228 data = sm->state->data;
2229 if (!data || !data->comparison)
2230 continue;
2231 if (ptr_list_size((struct ptr_list *)data->left_vsl) != 1 ||
2232 ptr_list_size((struct ptr_list *)data->right_vsl) != 1)
2233 continue;
2234 left = first_ptr_list((struct ptr_list *)data->left_vsl);
2235 right = first_ptr_list((struct ptr_list *)data->right_vsl);
2236 if (left->sym == right->sym &&
2237 strcmp(left->var, right->var) == 0)
2238 continue;
2240 * Both parameters link to this comparison so only
2241 * record the first one.
2243 if (left->sym != tmp->sym ||
2244 strcmp(left->var, tmp->name) != 0)
2245 continue;
2247 if (strstr(right->var, " orig"))
2248 continue;
2250 left_param = get_param_num_from_sym(left->sym);
2251 right_param = get_param_num_from_sym(right->sym);
2252 if (left_param < 0 || right_param < 0)
2253 continue;
2255 tmp_name = get_param_name_var_sym(left->var, left->sym);
2256 if (!tmp_name)
2257 continue;
2258 snprintf(left_buf, sizeof(left_buf), "%s", tmp_name);
2260 tmp_name = get_param_name_var_sym(right->var, right->sym);
2261 if (!tmp_name || tmp_name[0] != '$')
2262 continue;
2263 snprintf(right_buf, sizeof(right_buf), "$%d%s", right_param, tmp_name + 1);
2266 * FIXME: this should reject $ type variables (as
2267 * opposed to $->foo type). Those should come from
2268 * smatch_param_compare_limit.c.
2271 snprintf(info_buf, sizeof(info_buf), "%s %s", show_special(data->comparison), right_buf);
2272 sql_insert_return_states(return_id, return_ranges,
2273 PARAM_COMPARE, left_param, left_buf, info_buf);
2274 } END_FOR_EACH_PTR(link);
2276 } END_FOR_EACH_SM(tmp);
2279 static int parse_comparison(char **value, int *op)
2282 *op = **value;
2284 switch (*op) {
2285 case '<':
2286 (*value)++;
2287 if (**value == '=') {
2288 (*value)++;
2289 *op = SPECIAL_LTE;
2291 break;
2292 case '=':
2293 (*value)++;
2294 (*value)++;
2295 *op = SPECIAL_EQUAL;
2296 break;
2297 case '!':
2298 (*value)++;
2299 (*value)++;
2300 *op = SPECIAL_NOTEQUAL;
2301 break;
2302 case '>':
2303 (*value)++;
2304 if (**value == '=') {
2305 (*value)++;
2306 *op = SPECIAL_GTE;
2308 break;
2309 default:
2310 return 0;
2313 if (**value != ' ') {
2314 sm_perror("parsing comparison. %s", *value);
2315 return 0;
2318 (*value)++;
2319 return 1;
2322 static int split_op_param_key(char *value, int *op, int *param, char **key)
2324 static char buf[256];
2325 char *p;
2327 if (!parse_comparison(&value, op))
2328 return 0;
2330 snprintf(buf, sizeof(buf), value);
2332 p = buf;
2333 if (*p++ != '$')
2334 return 0;
2336 *param = atoi(p);
2337 if (*param < 0 || *param > 99)
2338 return 0;
2339 p++;
2340 if (*param > 9)
2341 p++;
2342 p--;
2343 *p = '$';
2344 *key = p;
2346 return 1;
2349 static void db_return_comparison(struct expression *expr, int left_param, char *key, char *value)
2351 struct expression *left_arg, *right_arg;
2352 char *left_name = NULL;
2353 struct symbol *left_sym;
2354 char *right_name = NULL;
2355 struct symbol *right_sym;
2356 int op;
2357 int right_param;
2358 char *right_key;
2359 struct var_sym_list *left_vsl = NULL, *right_vsl = NULL;
2361 if (left_param == -1) {
2362 if (expr->type != EXPR_ASSIGNMENT)
2363 return;
2364 left_arg = strip_expr(expr->left);
2366 while (expr->type == EXPR_ASSIGNMENT)
2367 expr = strip_expr(expr->right);
2368 if (expr->type != EXPR_CALL)
2369 return;
2370 } else {
2371 while (expr->type == EXPR_ASSIGNMENT)
2372 expr = strip_expr(expr->right);
2373 if (expr->type != EXPR_CALL)
2374 return;
2376 left_arg = get_argument_from_call_expr(expr->args, left_param);
2377 if (!left_arg)
2378 return;
2381 if (!split_op_param_key(value, &op, &right_param, &right_key))
2382 return;
2384 right_arg = get_argument_from_call_expr(expr->args, right_param);
2385 if (!right_arg)
2386 return;
2388 left_name = get_variable_from_key(left_arg, key, &left_sym);
2389 if (!left_name || !left_sym)
2390 goto free;
2392 right_name = get_variable_from_key(right_arg, right_key, &right_sym);
2393 if (!right_name || !right_sym)
2394 goto free;
2396 add_var_sym(&left_vsl, left_name, left_sym);
2397 add_var_sym(&right_vsl, right_name, right_sym);
2399 add_comparison_var_sym(NULL, left_name, left_vsl, op, NULL, right_name, right_vsl);
2401 free:
2402 free_string(left_name);
2403 free_string(right_name);
2406 int param_compare_limit_is_impossible(struct expression *expr, int left_param, char *left_key, char *value)
2408 struct smatch_state *state;
2409 char *left_name = NULL;
2410 char *right_name = NULL;
2411 struct symbol *left_sym, *right_sym;
2412 struct expression *left_arg, *right_arg;
2413 int op, state_op;
2414 int right_param;
2415 char *right_key;
2416 int ret = 0;
2417 char buf[256];
2419 while (expr->type == EXPR_ASSIGNMENT)
2420 expr = strip_expr(expr->right);
2421 if (expr->type != EXPR_CALL)
2422 return 0;
2424 if (!split_op_param_key(value, &op, &right_param, &right_key))
2425 return 0;
2427 left_arg = get_argument_from_call_expr(expr->args, left_param);
2428 if (!left_arg)
2429 return 0;
2431 right_arg = get_argument_from_call_expr(expr->args, right_param);
2432 if (!right_arg)
2433 return 0;
2435 left_name = get_variable_from_key(left_arg, left_key, &left_sym);
2436 right_name = get_variable_from_key(right_arg, right_key, &right_sym);
2437 if (!left_name || !right_name)
2438 goto free;
2440 snprintf(buf, sizeof(buf), "%s vs %s", left_name, right_name);
2441 state = get_state(compare_id, buf, NULL);
2442 if (!state)
2443 goto free;
2444 state_op = state_to_comparison(state);
2445 if (!state_op)
2446 goto free;
2448 if (!filter_comparison(remove_unsigned_from_comparison(state_op), op))
2449 ret = 1;
2450 free:
2451 free_string(left_name);
2452 free_string(right_name);
2453 return ret;
2456 int impossibly_high_comparison(struct expression *expr)
2458 struct smatch_state *link_state;
2459 struct sm_state *sm;
2460 struct string_list *links;
2461 char *link;
2462 struct compare_data *data;
2464 link_state = get_state_expr(link_id, expr);
2465 if (!link_state) {
2466 if (expr->type == EXPR_BINOP &&
2467 (impossibly_high_comparison(expr->left) ||
2468 impossibly_high_comparison(expr->right)))
2469 return 1;
2470 return 0;
2473 links = link_state->data;
2474 FOR_EACH_PTR(links, link) {
2475 sm = get_sm_state(compare_id, link, NULL);
2476 if (!sm)
2477 continue;
2478 data = sm->state->data;
2479 if (!data)
2480 continue;
2481 if (!possibly_true(data->left, data->comparison, data->right))
2482 return 1;
2483 } END_FOR_EACH_PTR(link);
2485 return 0;
2488 static void free_data(struct symbol *sym)
2490 if (__inline_fn)
2491 return;
2492 clear_compare_data_alloc();
2495 void register_comparison(int id)
2497 compare_id = id;
2498 add_hook(&save_start_states, AFTER_DEF_HOOK);
2499 add_unmatched_state_hook(compare_id, unmatched_comparison);
2500 add_pre_merge_hook(compare_id, &pre_merge_hook);
2501 add_merge_hook(compare_id, &merge_compare_states);
2502 add_hook(&free_data, AFTER_FUNC_HOOK);
2503 add_hook(&match_call_info, FUNCTION_CALL_HOOK);
2504 add_split_return_callback(&print_return_comparison);
2506 select_return_states_hook(PARAM_COMPARE, &db_return_comparison);
2507 add_hook(&match_preop, OP_HOOK);
2510 void register_comparison_late(int id)
2512 add_hook(&match_assign, ASSIGNMENT_HOOK);
2515 void register_comparison_links(int id)
2517 link_id = id;
2518 add_merge_hook(link_id, &merge_links);
2519 add_modification_hook(link_id, &match_modify);
2520 add_modification_hook_late(link_id, match_inc_dec);
2522 add_member_info_callback(link_id, struct_member_callback);
2525 void register_comparison_inc_dec(int id)
2527 inc_dec_id = id;
2528 add_modification_hook_late(inc_dec_id, &iter_modify);
2531 void register_comparison_inc_dec_links(int id)
2533 inc_dec_link_id = id;
2534 set_up_link_functions(inc_dec_id, inc_dec_link_id);
2537 static void filter_by_sm(struct sm_state *sm, int op,
2538 struct state_list **true_stack,
2539 struct state_list **false_stack)
2541 struct compare_data *data;
2542 int istrue = 0;
2543 int isfalse = 0;
2545 if (!sm)
2546 return;
2547 data = sm->state->data;
2548 if (!data) {
2549 if (sm->merged) {
2550 filter_by_sm(sm->left, op, true_stack, false_stack);
2551 filter_by_sm(sm->right, op, true_stack, false_stack);
2553 return;
2556 if (data->comparison &&
2557 data->comparison == filter_comparison(data->comparison, op))
2558 istrue = 1;
2560 if (data->comparison &&
2561 data->comparison == filter_comparison(data->comparison, negate_comparison(op)))
2562 isfalse = 1;
2564 if (istrue)
2565 add_ptr_list(true_stack, sm);
2566 if (isfalse)
2567 add_ptr_list(false_stack, sm);
2569 if (sm->merged) {
2570 filter_by_sm(sm->left, op, true_stack, false_stack);
2571 filter_by_sm(sm->right, op, true_stack, false_stack);
2575 struct sm_state *comparison_implication_hook(struct expression *expr,
2576 struct state_list **true_stack,
2577 struct state_list **false_stack)
2579 struct sm_state *sm;
2580 char *left, *right;
2581 int op;
2582 static char buf[256];
2584 if (expr->type != EXPR_COMPARE)
2585 return NULL;
2587 op = expr->op;
2589 left = expr_to_var(expr->left);
2590 right = expr_to_var(expr->right);
2591 if (!left || !right) {
2592 free_string(left);
2593 free_string(right);
2594 return NULL;
2597 if (strcmp(left, right) > 0) {
2598 char *tmp = left;
2600 left = right;
2601 right = tmp;
2602 op = flip_comparison(op);
2605 snprintf(buf, sizeof(buf), "%s vs %s", left, right);
2606 sm = get_sm_state(compare_id, buf, NULL);
2607 if (!sm)
2608 return NULL;
2609 if (!sm->merged)
2610 return NULL;
2612 filter_by_sm(sm, op, true_stack, false_stack);
2613 if (!*true_stack && !*false_stack)
2614 return NULL;
2616 if (option_debug)
2617 sm_msg("implications from comparison: (%s)", show_sm(sm));
2619 return sm;