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.
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
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.
32 #include "smatch_extra.h"
33 #include "smatch_slist.h"
35 static int compare_id
;
40 struct var_sym_list
*vsl1
;
43 struct var_sym_list
*vsl2
;
45 ALLOCATOR(compare_data
, "compare data");
47 int chunk_vsl_eq(const char *a
, struct var_sym_list
*a_vsl
, const char *b
, struct var_sym_list
*b_vsl
)
49 if (strcmp(a
, b
) == 0)
54 static struct symbol
*vsl_to_sym(struct var_sym_list
*vsl
)
60 if (ptr_list_size((struct ptr_list
*)vsl
) != 1)
62 vs
= first_ptr_list((struct ptr_list
*)vsl
);
66 static struct smatch_state
*alloc_compare_state(
67 const char *var1
, struct var_sym_list
*vsl1
,
69 const char *var2
, struct var_sym_list
*vsl2
)
71 struct smatch_state
*state
;
72 struct compare_data
*data
;
74 state
= __alloc_smatch_state(0);
75 state
->name
= alloc_sname(show_special(comparison
));
76 data
= __alloc_compare_data(0);
77 data
->var1
= alloc_sname(var1
);
78 data
->vsl1
= clone_var_sym_list(vsl1
);
79 data
->comparison
= comparison
;
80 data
->var2
= alloc_sname(var2
);
81 data
->vsl2
= clone_var_sym_list(vsl2
);
86 static int state_to_comparison(struct smatch_state
*state
)
88 if (!state
|| !state
->data
)
90 return ((struct compare_data
*)state
->data
)->comparison
;
94 * flip_op() reverses the op left and right. So "x >= y" becomes "y <= x".
96 static int flip_op(int op
)
103 case SPECIAL_UNSIGNED_LT
:
104 return SPECIAL_UNSIGNED_GT
;
107 case SPECIAL_UNSIGNED_LTE
:
108 return SPECIAL_UNSIGNED_GTE
;
110 return SPECIAL_EQUAL
;
111 case SPECIAL_NOTEQUAL
:
112 return SPECIAL_NOTEQUAL
;
115 case SPECIAL_UNSIGNED_GTE
:
116 return SPECIAL_UNSIGNED_LTE
;
119 case SPECIAL_UNSIGNED_GT
:
120 return SPECIAL_UNSIGNED_LT
;
122 sm_msg("internal smatch bug. unhandled comparison %d", op
);
127 static int falsify_op(int op
)
134 case SPECIAL_UNSIGNED_LT
:
135 return SPECIAL_UNSIGNED_GTE
;
138 case SPECIAL_UNSIGNED_LTE
:
139 return SPECIAL_UNSIGNED_GT
;
141 return SPECIAL_NOTEQUAL
;
142 case SPECIAL_NOTEQUAL
:
143 return SPECIAL_EQUAL
;
146 case SPECIAL_UNSIGNED_GTE
:
147 return SPECIAL_UNSIGNED_LT
;
150 case SPECIAL_UNSIGNED_GT
:
151 return SPECIAL_UNSIGNED_LTE
;
153 sm_msg("internal smatch bug. unhandled comparison %d", op
);
158 static int rl_comparison(struct range_list
*left_rl
, struct range_list
*right_rl
)
160 sval_t left_min
, left_max
, right_min
, right_max
;
162 if (!left_rl
|| !right_rl
)
165 left_min
= rl_min(left_rl
);
166 left_max
= rl_max(left_rl
);
167 right_min
= rl_min(right_rl
);
168 right_max
= rl_max(right_rl
);
170 if (left_min
.value
== left_max
.value
&&
171 right_min
.value
== right_max
.value
&&
172 left_min
.value
== right_min
.value
)
173 return SPECIAL_EQUAL
;
175 if (sval_cmp(left_max
, right_min
) < 0)
177 if (sval_cmp(left_max
, right_min
) == 0)
179 if (sval_cmp(left_min
, right_max
) > 0)
181 if (sval_cmp(left_min
, right_max
) == 0)
187 static struct range_list
*get_orig_rl(struct var_sym_list
*vsl
)
190 struct smatch_state
*state
;
194 sym
= vsl_to_sym(vsl
);
195 if (!sym
|| !sym
->ident
)
197 state
= get_orig_estate(sym
->ident
->name
, sym
);
198 return estate_rl(state
);
201 static struct smatch_state
*unmatched_comparison(struct sm_state
*sm
)
203 struct compare_data
*data
= sm
->state
->data
;
204 struct range_list
*left_rl
, *right_rl
;
210 if (strstr(data
->var1
, " orig"))
211 left_rl
= get_orig_rl(data
->vsl1
);
212 else if (!get_implied_rl_var_sym(data
->var1
, vsl_to_sym(data
->vsl1
), &left_rl
))
214 if (strstr(data
->var2
, " orig"))
215 right_rl
= get_orig_rl(data
->vsl2
);
216 else if (!get_implied_rl_var_sym(data
->var2
, vsl_to_sym(data
->vsl2
), &right_rl
))
220 op
= rl_comparison(left_rl
, right_rl
);
222 return alloc_compare_state(data
->var1
, data
->vsl1
, op
, data
->var2
, data
->vsl2
);
227 /* remove_unsigned_from_comparison() is obviously a hack. */
228 static int remove_unsigned_from_comparison(int op
)
231 case SPECIAL_UNSIGNED_LT
:
233 case SPECIAL_UNSIGNED_LTE
:
235 case SPECIAL_UNSIGNED_GTE
:
237 case SPECIAL_UNSIGNED_GT
:
245 * This is for when you merge states "a < b" and "a == b", the result is that
246 * we can say for sure, "a <= b" after the merge.
248 static int merge_comparisons(int one
, int two
)
252 one
= remove_unsigned_from_comparison(one
);
253 two
= remove_unsigned_from_comparison(two
);
300 return SPECIAL_NOTEQUAL
;
311 * This is for if you have "a < b" and "b <= c". Or in other words,
312 * "a < b <= c". You would call this like get_combined_comparison('<', '<=').
313 * The return comparison would be '<'.
315 * This function is different from merge_comparisons(), for example:
316 * merge_comparison('<', '==') returns '<='
317 * get_combined_comparison('<', '==') returns '<'
319 static int combine_comparisons(int left_compare
, int right_compare
)
323 left_compare
= remove_unsigned_from_comparison(left_compare
);
324 right_compare
= remove_unsigned_from_comparison(right_compare
);
328 switch (left_compare
) {
337 return right_compare
;
346 switch (right_compare
) {
378 static struct smatch_state
*merge_compare_states(struct smatch_state
*s1
, struct smatch_state
*s2
)
380 struct compare_data
*data
= s1
->data
;
383 op
= merge_comparisons(state_to_comparison(s1
), state_to_comparison(s2
));
385 return alloc_compare_state(data
->var1
, data
->vsl1
, op
, data
->var2
, data
->vsl2
);
389 static struct smatch_state
*alloc_link_state(struct string_list
*links
)
391 struct smatch_state
*state
;
392 static char buf
[256];
396 state
= __alloc_smatch_state(0);
399 FOR_EACH_PTR(links
, tmp
) {
401 snprintf(buf
, sizeof(buf
), "%s", tmp
);
403 append(buf
, ", ", sizeof(buf
));
404 append(buf
, tmp
, sizeof(buf
));
406 } END_FOR_EACH_PTR(tmp
);
408 state
->name
= alloc_sname(buf
);
413 static void save_start_states(struct statement
*stmt
)
415 struct symbol
*param
;
417 char state_name
[128];
418 struct smatch_state
*state
;
419 struct string_list
*links
;
422 FOR_EACH_PTR(cur_func_sym
->ctype
.base_type
->arguments
, param
) {
423 struct var_sym_list
*vsl1
= NULL
;
424 struct var_sym_list
*vsl2
= NULL
;
428 snprintf(orig
, sizeof(orig
), "%s orig", param
->ident
->name
);
429 snprintf(state_name
, sizeof(state_name
), "%s vs %s", param
->ident
->name
, orig
);
430 add_var_sym(&vsl1
, param
->ident
->name
, param
);
431 add_var_sym(&vsl2
, orig
, param
);
432 state
= alloc_compare_state(param
->ident
->name
, vsl1
, SPECIAL_EQUAL
, alloc_sname(orig
), vsl2
);
433 set_state(compare_id
, state_name
, NULL
, state
);
435 link
= alloc_sname(state_name
);
437 insert_string(&links
, link
);
438 state
= alloc_link_state(links
);
439 set_state(link_id
, param
->ident
->name
, param
, state
);
440 } END_FOR_EACH_PTR(param
);
443 static struct smatch_state
*merge_links(struct smatch_state
*s1
, struct smatch_state
*s2
)
445 struct smatch_state
*ret
;
446 struct string_list
*links
;
448 links
= combine_string_lists(s1
->data
, s2
->data
);
449 ret
= alloc_link_state(links
);
453 static void save_link_var_sym(const char *var
, struct symbol
*sym
, const char *link
)
455 struct smatch_state
*old_state
, *new_state
;
456 struct string_list
*links
;
459 old_state
= get_state(link_id
, var
, sym
);
461 links
= clone_str_list(old_state
->data
);
465 new = alloc_sname(link
);
466 insert_string(&links
, new);
468 new_state
= alloc_link_state(links
);
469 set_state(link_id
, var
, sym
, new_state
);
472 static void match_inc(struct sm_state
*sm
)
474 struct string_list
*links
;
475 struct smatch_state
*state
;
478 links
= sm
->state
->data
;
480 FOR_EACH_PTR(links
, tmp
) {
481 state
= get_state(compare_id
, tmp
, NULL
);
483 switch (state_to_comparison(state
)) {
486 case SPECIAL_UNSIGNED_GTE
:
488 case SPECIAL_UNSIGNED_GT
: {
489 struct compare_data
*data
= state
->data
;
490 struct smatch_state
*new;
492 new = alloc_compare_state(data
->var1
, data
->vsl1
, '>', data
->var2
, data
->vsl2
);
493 set_state(compare_id
, tmp
, NULL
, new);
497 set_state(compare_id
, tmp
, NULL
, &undefined
);
499 } END_FOR_EACH_PTR(tmp
);
502 static void match_dec(struct sm_state
*sm
)
504 struct string_list
*links
;
505 struct smatch_state
*state
;
508 links
= sm
->state
->data
;
510 FOR_EACH_PTR(links
, tmp
) {
511 state
= get_state(compare_id
, tmp
, NULL
);
513 switch (state_to_comparison(state
)) {
516 case SPECIAL_UNSIGNED_LTE
:
518 case SPECIAL_UNSIGNED_LT
: {
519 struct compare_data
*data
= state
->data
;
520 struct smatch_state
*new;
522 new = alloc_compare_state(data
->var1
, data
->vsl1
, '<', data
->var2
, data
->vsl2
);
523 set_state(compare_id
, tmp
, NULL
, new);
527 set_state(compare_id
, tmp
, NULL
, &undefined
);
529 } END_FOR_EACH_PTR(tmp
);
532 static int match_inc_dec(struct sm_state
*sm
, struct expression
*mod_expr
)
536 if (mod_expr
->type
!= EXPR_PREOP
&& mod_expr
->type
!= EXPR_POSTOP
)
539 if (mod_expr
->op
== SPECIAL_INCREMENT
) {
543 if (mod_expr
->op
== SPECIAL_DECREMENT
) {
550 static void match_modify(struct sm_state
*sm
, struct expression
*mod_expr
)
552 struct string_list
*links
;
555 /* Huh??? This needs a comment! */
556 if (match_inc_dec(sm
, mod_expr
))
559 links
= sm
->state
->data
;
561 FOR_EACH_PTR(links
, tmp
) {
562 set_state(compare_id
, tmp
, NULL
, &undefined
);
563 } END_FOR_EACH_PTR(tmp
);
564 set_state(link_id
, sm
->name
, sm
->sym
, &undefined
);
567 static char *chunk_to_var_sym(struct expression
*expr
, struct symbol
**sym
)
569 char *name
, *left_name
, *right_name
;
573 expr
= strip_expr(expr
);
579 name
= expr_to_var_sym(expr
, &tmp
);
588 if (expr
->type
!= EXPR_BINOP
)
590 if (expr
->op
!= '-' && expr
->op
!= '+')
593 left_name
= expr_to_var(expr
->left
);
596 right_name
= expr_to_var(expr
->right
);
598 free_string(left_name
);
601 snprintf(buf
, sizeof(buf
), "%s %s %s", left_name
, show_special(expr
->op
), right_name
);
602 free_string(left_name
);
603 free_string(right_name
);
604 return alloc_string(buf
);
607 static char *chunk_to_var(struct expression
*expr
)
609 return chunk_to_var_sym(expr
, NULL
);
612 static void save_link(struct expression
*expr
, char *link
)
617 expr
= strip_expr(expr
);
618 if (expr
->type
== EXPR_BINOP
) {
621 chunk
= chunk_to_var(expr
);
625 save_link(expr
->left
, link
);
626 save_link(expr
->right
, link
);
627 save_link_var_sym(chunk
, NULL
, link
);
631 var
= expr_to_var_sym(expr
, &sym
);
635 save_link_var_sym(var
, sym
, link
);
640 static void update_tf_links(struct state_list
*pre_slist
,
641 const char *left_var
, struct var_sym_list
*left_vsl
,
643 const char *mid_var
, struct var_sym_list
*mid_vsl
,
644 struct string_list
*links
)
646 struct smatch_state
*state
;
647 struct smatch_state
*true_state
, *false_state
;
648 struct compare_data
*data
;
649 const char *right_var
;
650 struct var_sym_list
*right_vsl
;
651 int right_comparison
;
653 int false_comparison
;
655 char state_name
[256];
658 FOR_EACH_PTR(links
, tmp
) {
659 state
= get_state_slist(pre_slist
, compare_id
, tmp
, NULL
);
660 if (!state
|| !state
->data
)
663 right_comparison
= data
->comparison
;
664 right_var
= data
->var2
;
665 right_vsl
= data
->vsl2
;
666 if (chunk_vsl_eq(mid_var
, mid_vsl
, right_var
, right_vsl
)) {
667 right_var
= data
->var1
;
668 right_vsl
= data
->vsl1
;
669 right_comparison
= flip_op(right_comparison
);
671 true_comparison
= combine_comparisons(left_comparison
, right_comparison
);
672 false_comparison
= combine_comparisons(falsify_op(left_comparison
), right_comparison
);
674 if (strcmp(left_var
, right_var
) > 0) {
675 const char *tmp_var
= left_var
;
676 struct var_sym_list
*tmp_vsl
= left_vsl
;
678 left_var
= right_var
;
679 left_vsl
= right_vsl
;
682 true_comparison
= flip_op(true_comparison
);
683 false_comparison
= flip_op(false_comparison
);
686 if (!true_comparison
&& !false_comparison
)
690 true_state
= alloc_compare_state(left_var
, left_vsl
, true_comparison
, right_var
, right_vsl
);
693 if (false_comparison
)
694 false_state
= alloc_compare_state(left_var
, left_vsl
, false_comparison
, right_var
, right_vsl
);
698 snprintf(state_name
, sizeof(state_name
), "%s vs %s", left_var
, right_var
);
699 set_true_false_states(compare_id
, state_name
, NULL
, true_state
, false_state
);
700 FOR_EACH_PTR(left_vsl
, vs
) {
701 save_link_var_sym(vs
->var
, vs
->sym
, state_name
);
702 } END_FOR_EACH_PTR(vs
);
703 FOR_EACH_PTR(right_vsl
, vs
) {
704 save_link_var_sym(vs
->var
, vs
->sym
, state_name
);
705 } END_FOR_EACH_PTR(vs
);
706 if (!vsl_to_sym(left_vsl
))
707 save_link_var_sym(left_var
, NULL
, state_name
);
708 if (!vsl_to_sym(right_vsl
))
709 save_link_var_sym(right_var
, NULL
, state_name
);
710 } END_FOR_EACH_PTR(tmp
);
713 static void update_tf_data(struct state_list
*pre_slist
,
714 const char *left_name
, struct symbol
*left_sym
,
715 const char *right_name
, struct symbol
*right_sym
,
716 struct compare_data
*tdata
)
718 struct smatch_state
*state
;
720 state
= get_state_slist(pre_slist
, link_id
, tdata
->var2
, vsl_to_sym(tdata
->vsl2
));
722 update_tf_links(pre_slist
, tdata
->var1
, tdata
->vsl1
, tdata
->comparison
, tdata
->var2
, tdata
->vsl2
, state
->data
);
724 state
= get_state_slist(pre_slist
, link_id
, tdata
->var1
, vsl_to_sym(tdata
->vsl1
));
726 update_tf_links(pre_slist
, tdata
->var2
, tdata
->vsl2
, flip_op(tdata
->comparison
), tdata
->var1
, tdata
->vsl1
, state
->data
);
729 static void match_compare(struct expression
*expr
)
733 struct symbol
*left_sym
, *right_sym
;
734 struct var_sym_list
*left_vsl
, *right_vsl
;
736 struct smatch_state
*true_state
, *false_state
;
737 char state_name
[256];
738 struct state_list
*pre_slist
;
740 if (expr
->type
!= EXPR_COMPARE
)
742 left
= chunk_to_var_sym(expr
->left
, &left_sym
);
745 left_vsl
= expr_to_vsl(expr
->left
);
746 right
= chunk_to_var_sym(expr
->right
, &right_sym
);
749 right_vsl
= expr_to_vsl(expr
->right
);
751 if (strcmp(left
, right
) > 0) {
752 struct symbol
*tmp_sym
= left_sym
;
753 char *tmp_name
= left
;
754 struct var_sym_list
*tmp_vsl
= left_vsl
;
757 left_sym
= right_sym
;
758 left_vsl
= right_vsl
;
762 op
= flip_op(expr
->op
);
766 false_op
= falsify_op(op
);
767 snprintf(state_name
, sizeof(state_name
), "%s vs %s", left
, right
);
768 true_state
= alloc_compare_state(left
, left_vsl
, op
, right
, right_vsl
);
769 false_state
= alloc_compare_state(left
, left_vsl
, false_op
, right
, right_vsl
);
771 pre_slist
= clone_slist(__get_cur_slist());
772 update_tf_data(pre_slist
, left
, left_sym
, right
, right_sym
, true_state
->data
);
773 free_slist(&pre_slist
);
775 set_true_false_states(compare_id
, state_name
, NULL
, true_state
, false_state
);
776 save_link(expr
->left
, state_name
);
777 save_link(expr
->right
, state_name
);
783 static void add_comparison_var_sym(const char *left_name
,
784 struct var_sym_list
*left_vsl
,
786 const char *right_name
, struct var_sym_list
*right_vsl
)
788 struct smatch_state
*state
;
790 char state_name
[256];
792 if (strcmp(left_name
, right_name
) > 0) {
793 const char *tmp_name
= left_name
;
794 struct var_sym_list
*tmp_vsl
= left_vsl
;
796 left_name
= right_name
;
797 left_vsl
= right_vsl
;
798 right_name
= tmp_name
;
800 comparison
= flip_op(comparison
);
802 snprintf(state_name
, sizeof(state_name
), "%s vs %s", left_name
, right_name
);
803 state
= alloc_compare_state(left_name
, left_vsl
, comparison
, right_name
, right_vsl
);
805 set_state(compare_id
, state_name
, NULL
, state
);
807 FOR_EACH_PTR(left_vsl
, vs
) {
808 save_link_var_sym(vs
->var
, vs
->sym
, state_name
);
809 } END_FOR_EACH_PTR(vs
);
810 FOR_EACH_PTR(right_vsl
, vs
) {
811 save_link_var_sym(vs
->var
, vs
->sym
, state_name
);
812 } END_FOR_EACH_PTR(vs
);
815 static void add_comparison(struct expression
*left
, int comparison
, struct expression
*right
)
817 char *left_name
= NULL
;
818 char *right_name
= NULL
;
819 struct symbol
*left_sym
, *right_sym
;
820 struct var_sym_list
*left_vsl
, *right_vsl
;
821 struct smatch_state
*state
;
822 char state_name
[256];
824 left_name
= chunk_to_var_sym(left
, &left_sym
);
827 left_vsl
= expr_to_vsl(left
);
828 right_name
= chunk_to_var_sym(right
, &right_sym
);
831 right_vsl
= expr_to_vsl(right
);
833 if (strcmp(left_name
, right_name
) > 0) {
834 struct symbol
*tmp_sym
= left_sym
;
835 char *tmp_name
= left_name
;
836 struct var_sym_list
*tmp_vsl
= left_vsl
;
838 left_name
= right_name
;
839 left_sym
= right_sym
;
840 left_vsl
= right_vsl
;
841 right_name
= tmp_name
;
844 comparison
= flip_op(comparison
);
846 snprintf(state_name
, sizeof(state_name
), "%s vs %s", left_name
, right_name
);
847 state
= alloc_compare_state(left_name
, left_vsl
, comparison
, right_name
, right_vsl
);
849 set_state(compare_id
, state_name
, NULL
, state
);
850 save_link(left
, state_name
);
851 save_link(right
, state_name
);
854 free_string(left_name
);
855 free_string(right_name
);
858 static void match_assign_add(struct expression
*expr
)
860 struct expression
*right
;
861 struct expression
*r_left
, *r_right
;
862 sval_t left_tmp
, right_tmp
;
864 right
= strip_expr(expr
->right
);
865 r_left
= strip_expr(right
->left
);
866 r_right
= strip_expr(right
->right
);
868 get_absolute_min(r_left
, &left_tmp
);
869 get_absolute_min(r_right
, &right_tmp
);
871 if (left_tmp
.value
> 0)
872 add_comparison(expr
->left
, '>', r_right
);
873 else if (left_tmp
.value
== 0)
874 add_comparison(expr
->left
, SPECIAL_GTE
, r_right
);
876 if (right_tmp
.value
> 0)
877 add_comparison(expr
->left
, '>', r_left
);
878 else if (right_tmp
.value
== 0)
879 add_comparison(expr
->left
, SPECIAL_GTE
, r_left
);
882 static void match_assign_sub(struct expression
*expr
)
884 struct expression
*right
;
885 struct expression
*r_left
, *r_right
;
889 right
= strip_expr(expr
->right
);
890 r_left
= strip_expr(right
->left
);
891 r_right
= strip_expr(right
->right
);
893 if (get_absolute_min(r_right
, &min
) && sval_is_negative(min
))
896 comparison
= get_comparison(r_left
, r_right
);
898 switch (comparison
) {
901 if (implied_not_equal(r_right
, 0))
902 add_comparison(expr
->left
, '>', r_left
);
904 add_comparison(expr
->left
, SPECIAL_GTE
, r_left
);
909 static void match_assign_divide(struct expression
*expr
)
911 struct expression
*right
;
912 struct expression
*r_left
, *r_right
;
915 right
= strip_expr(expr
->right
);
916 r_left
= strip_expr(right
->left
);
917 r_right
= strip_expr(right
->right
);
918 if (!get_implied_min(r_right
, &min
) || min
.value
<= 1)
921 add_comparison(expr
->left
, '<', r_left
);
924 static void match_binop_assign(struct expression
*expr
)
926 struct expression
*right
;
928 right
= strip_expr(expr
->right
);
929 if (right
->op
== '+')
930 match_assign_add(expr
);
931 if (right
->op
== '-')
932 match_assign_sub(expr
);
933 if (right
->op
== '/')
934 match_assign_divide(expr
);
937 static void copy_comparisons(struct expression
*left
, struct expression
*right
)
939 struct string_list
*links
;
940 struct smatch_state
*state
;
941 struct compare_data
*data
;
942 struct symbol
*left_sym
, *right_sym
;
943 char *left_var
= NULL
;
944 char *right_var
= NULL
;
945 struct var_sym_list
*left_vsl
;
947 struct var_sym_list
*vsl
;
951 left_var
= chunk_to_var_sym(left
, &left_sym
);
954 left_vsl
= expr_to_vsl(left
);
955 right_var
= chunk_to_var_sym(right
, &right_sym
);
959 state
= get_state(link_id
, right_var
, right_sym
);
964 FOR_EACH_PTR(links
, tmp
) {
965 state
= get_state(compare_id
, tmp
, NULL
);
966 if (!state
|| !state
->data
)
969 comparison
= data
->comparison
;
972 if (chunk_vsl_eq(var
, vsl
, right_var
, NULL
)) {
975 comparison
= flip_op(comparison
);
977 add_comparison_var_sym(left_var
, left_vsl
, comparison
, var
, vsl
);
978 } END_FOR_EACH_PTR(tmp
);
981 free_string(right_var
);
984 static void match_assign(struct expression
*expr
)
986 struct expression
*right
;
991 copy_comparisons(expr
->left
, expr
->right
);
992 add_comparison(expr
->left
, SPECIAL_EQUAL
, expr
->right
);
994 right
= strip_expr(expr
->right
);
995 if (right
->type
== EXPR_BINOP
)
996 match_binop_assign(expr
);
999 int get_comparison_strings(const char *one
, const char *two
)
1002 struct smatch_state
*state
;
1006 if (strcmp(one
, two
) > 0) {
1007 const char *tmp
= one
;
1014 snprintf(buf
, sizeof(buf
), "%s vs %s", one
, two
);
1015 state
= get_state(compare_id
, buf
, NULL
);
1017 ret
= state_to_comparison(state
);
1025 int get_comparison(struct expression
*a
, struct expression
*b
)
1031 one
= chunk_to_var(a
);
1034 two
= chunk_to_var(b
);
1038 ret
= get_comparison_strings(one
, two
);
1045 static void update_links_from_call(struct expression
*left
,
1047 struct expression
*right
)
1049 struct string_list
*links
;
1050 struct smatch_state
*state
;
1051 struct compare_data
*data
;
1052 struct symbol
*left_sym
, *right_sym
;
1053 char *left_var
= NULL
;
1054 char *right_var
= NULL
;
1055 struct var_sym_list
*left_vsl
;
1057 struct var_sym_list
*vsl
;
1061 left_var
= chunk_to_var_sym(left
, &left_sym
);
1064 left_vsl
= expr_to_vsl(left
);
1065 right_var
= chunk_to_var_sym(right
, &right_sym
);
1069 state
= get_state(link_id
, right_var
, right_sym
);
1072 links
= state
->data
;
1074 FOR_EACH_PTR(links
, tmp
) {
1075 state
= get_state(compare_id
, tmp
, NULL
);
1076 if (!state
|| !state
->data
)
1079 comparison
= data
->comparison
;
1082 if (chunk_vsl_eq(var
, vsl
, right_var
, NULL
)) {
1085 comparison
= flip_op(comparison
);
1087 comparison
= combine_comparisons(left_compare
, comparison
);
1090 add_comparison_var_sym(left_var
, left_vsl
, comparison
, var
, vsl
);
1091 } END_FOR_EACH_PTR(tmp
);
1094 free_string(right_var
);
1097 void __add_comparison_info(struct expression
*expr
, struct expression
*call
, const char *range
)
1099 struct expression
*arg
;
1101 const char *c
= range
;
1103 if (!str_to_comparison_arg(c
, call
, &comparison
, &arg
))
1105 update_links_from_call(expr
, comparison
, arg
);
1106 add_comparison(expr
, comparison
, arg
);
1109 static char *range_comparison_to_param_helper(struct expression
*expr
, char starts_with
)
1111 struct symbol
*param
;
1114 char *ret_str
= NULL
;
1118 var
= chunk_to_var(expr
);
1123 FOR_EACH_PTR(cur_func_sym
->ctype
.base_type
->arguments
, param
) {
1127 snprintf(buf
, sizeof(buf
), "%s orig", param
->ident
->name
);
1128 compare
= get_comparison_strings(var
, buf
);
1131 if (show_special(compare
)[0] != starts_with
)
1133 snprintf(buf
, sizeof(buf
), "[%sp%d]", show_special(compare
), i
);
1134 ret_str
= alloc_sname(buf
);
1136 } END_FOR_EACH_PTR(param
);
1143 char *expr_equal_to_param(struct expression
*expr
)
1145 return range_comparison_to_param_helper(expr
, '=');
1148 char *expr_lte_to_param(struct expression
*expr
)
1150 return range_comparison_to_param_helper(expr
, '<');
1153 static void free_data(struct symbol
*sym
)
1157 clear_compare_data_alloc();
1160 void register_comparison(int id
)
1163 add_hook(&match_compare
, CONDITION_HOOK
);
1164 add_hook(&match_assign
, ASSIGNMENT_HOOK
);
1165 add_hook(&save_start_states
, AFTER_DEF_HOOK
);
1166 add_unmatched_state_hook(compare_id
, unmatched_comparison
);
1167 add_merge_hook(compare_id
, &merge_compare_states
);
1168 add_hook(&free_data
, AFTER_FUNC_HOOK
);
1171 void register_comparison_links(int id
)
1174 add_merge_hook(link_id
, &merge_links
);
1175 add_modification_hook(link_id
, &match_modify
);