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
;
38 ALLOCATOR(compare_data
, "compare data");
40 static struct symbol
*vsl_to_sym(struct var_sym_list
*vsl
)
46 if (ptr_list_size((struct ptr_list
*)vsl
) != 1)
48 vs
= first_ptr_list((struct ptr_list
*)vsl
);
52 static struct smatch_state
*alloc_compare_state(
53 const char *var1
, struct var_sym_list
*vsl1
,
55 const char *var2
, struct var_sym_list
*vsl2
)
57 struct smatch_state
*state
;
58 struct compare_data
*data
;
60 state
= __alloc_smatch_state(0);
61 state
->name
= alloc_sname(show_special(comparison
));
62 data
= __alloc_compare_data(0);
63 data
->var1
= alloc_sname(var1
);
64 data
->vsl1
= clone_var_sym_list(vsl1
);
65 data
->comparison
= comparison
;
66 data
->var2
= alloc_sname(var2
);
67 data
->vsl2
= clone_var_sym_list(vsl2
);
72 static int state_to_comparison(struct smatch_state
*state
)
74 if (!state
|| !state
->data
)
76 return ((struct compare_data
*)state
->data
)->comparison
;
80 * flip_comparison() reverses the op left and right. So "x >= y" becomes "y <= x".
82 int flip_comparison(int op
)
89 case SPECIAL_UNSIGNED_LT
:
90 return SPECIAL_UNSIGNED_GT
;
93 case SPECIAL_UNSIGNED_LTE
:
94 return SPECIAL_UNSIGNED_GTE
;
97 case SPECIAL_NOTEQUAL
:
98 return SPECIAL_NOTEQUAL
;
101 case SPECIAL_UNSIGNED_GTE
:
102 return SPECIAL_UNSIGNED_LTE
;
105 case SPECIAL_UNSIGNED_GT
:
106 return SPECIAL_UNSIGNED_LT
;
108 sm_msg("internal smatch bug. unhandled comparison %d", op
);
113 int negate_comparison(int op
)
120 case SPECIAL_UNSIGNED_LT
:
121 return SPECIAL_UNSIGNED_GTE
;
124 case SPECIAL_UNSIGNED_LTE
:
125 return SPECIAL_UNSIGNED_GT
;
127 return SPECIAL_NOTEQUAL
;
128 case SPECIAL_NOTEQUAL
:
129 return SPECIAL_EQUAL
;
132 case SPECIAL_UNSIGNED_GTE
:
133 return SPECIAL_UNSIGNED_LT
;
136 case SPECIAL_UNSIGNED_GT
:
137 return SPECIAL_UNSIGNED_LTE
;
139 sm_msg("internal smatch bug. unhandled comparison %d", op
);
144 static int rl_comparison(struct range_list
*left_rl
, struct range_list
*right_rl
)
146 sval_t left_min
, left_max
, right_min
, right_max
;
148 if (!left_rl
|| !right_rl
)
151 left_min
= rl_min(left_rl
);
152 left_max
= rl_max(left_rl
);
153 right_min
= rl_min(right_rl
);
154 right_max
= rl_max(right_rl
);
156 if (left_min
.value
== left_max
.value
&&
157 right_min
.value
== right_max
.value
&&
158 left_min
.value
== right_min
.value
)
159 return SPECIAL_EQUAL
;
161 if (sval_cmp(left_max
, right_min
) < 0)
163 if (sval_cmp(left_max
, right_min
) == 0)
165 if (sval_cmp(left_min
, right_max
) > 0)
167 if (sval_cmp(left_min
, right_max
) == 0)
173 static struct range_list
*get_orig_rl(struct var_sym_list
*vsl
)
176 struct smatch_state
*state
;
180 sym
= vsl_to_sym(vsl
);
181 if (!sym
|| !sym
->ident
)
183 state
= get_orig_estate(sym
->ident
->name
, sym
);
184 return estate_rl(state
);
187 static struct smatch_state
*unmatched_comparison(struct sm_state
*sm
)
189 struct compare_data
*data
= sm
->state
->data
;
190 struct range_list
*left_rl
, *right_rl
;
196 if (strstr(data
->var1
, " orig"))
197 left_rl
= get_orig_rl(data
->vsl1
);
198 else if (!get_implied_rl_var_sym(data
->var1
, vsl_to_sym(data
->vsl1
), &left_rl
))
200 if (strstr(data
->var2
, " orig"))
201 right_rl
= get_orig_rl(data
->vsl2
);
202 else if (!get_implied_rl_var_sym(data
->var2
, vsl_to_sym(data
->vsl2
), &right_rl
))
206 op
= rl_comparison(left_rl
, right_rl
);
208 return alloc_compare_state(data
->var1
, data
->vsl1
, op
, data
->var2
, data
->vsl2
);
213 /* remove_unsigned_from_comparison() is obviously a hack. */
214 static int remove_unsigned_from_comparison(int op
)
217 case SPECIAL_UNSIGNED_LT
:
219 case SPECIAL_UNSIGNED_LTE
:
221 case SPECIAL_UNSIGNED_GTE
:
223 case SPECIAL_UNSIGNED_GT
:
231 * This is for when you merge states "a < b" and "a == b", the result is that
232 * we can say for sure, "a <= b" after the merge.
234 static int merge_comparisons(int one
, int two
)
238 one
= remove_unsigned_from_comparison(one
);
239 two
= remove_unsigned_from_comparison(two
);
286 return SPECIAL_NOTEQUAL
;
297 * This is for if you have "a < b" and "b <= c". Or in other words,
298 * "a < b <= c". You would call this like get_combined_comparison('<', '<=').
299 * The return comparison would be '<'.
301 * This function is different from merge_comparisons(), for example:
302 * merge_comparison('<', '==') returns '<='
303 * get_combined_comparison('<', '==') returns '<'
305 static int combine_comparisons(int left_compare
, int right_compare
)
309 left_compare
= remove_unsigned_from_comparison(left_compare
);
310 right_compare
= remove_unsigned_from_comparison(right_compare
);
314 switch (left_compare
) {
323 return right_compare
;
332 switch (right_compare
) {
364 static int filter_comparison(int orig
, int op
)
376 case SPECIAL_NOTEQUAL
:
386 case SPECIAL_NOTEQUAL
:
395 case SPECIAL_UNSIGNED_LTE
:
396 case SPECIAL_UNSIGNED_GTE
:
397 return SPECIAL_EQUAL
;
400 case SPECIAL_NOTEQUAL
:
405 case SPECIAL_UNSIGNED_LT
:
406 case SPECIAL_UNSIGNED_LTE
:
407 return SPECIAL_UNSIGNED_LT
;
408 case SPECIAL_NOTEQUAL
:
413 case SPECIAL_UNSIGNED_GT
:
414 case SPECIAL_UNSIGNED_GTE
:
415 return SPECIAL_UNSIGNED_GT
;
421 return SPECIAL_EQUAL
;
426 case SPECIAL_NOTEQUAL
:
434 case SPECIAL_NOTEQUAL
:
438 case SPECIAL_UNSIGNED_LT
:
440 case SPECIAL_UNSIGNED_LT
:
441 case SPECIAL_UNSIGNED_LTE
:
442 case SPECIAL_NOTEQUAL
:
443 return SPECIAL_UNSIGNED_LT
;
446 case SPECIAL_UNSIGNED_LTE
:
448 case SPECIAL_UNSIGNED_LT
:
449 case SPECIAL_UNSIGNED_LTE
:
452 case SPECIAL_NOTEQUAL
:
453 return SPECIAL_UNSIGNED_LT
;
454 case SPECIAL_UNSIGNED_GTE
:
455 return SPECIAL_EQUAL
;
458 case SPECIAL_UNSIGNED_GTE
:
460 case SPECIAL_UNSIGNED_LTE
:
461 return SPECIAL_EQUAL
;
462 case SPECIAL_NOTEQUAL
:
463 return SPECIAL_UNSIGNED_GT
;
465 case SPECIAL_UNSIGNED_GTE
:
466 case SPECIAL_UNSIGNED_GT
:
470 case SPECIAL_UNSIGNED_GT
:
472 case SPECIAL_UNSIGNED_GT
:
473 case SPECIAL_UNSIGNED_GTE
:
474 case SPECIAL_NOTEQUAL
:
475 return SPECIAL_UNSIGNED_GT
;
482 static struct smatch_state
*merge_compare_states(struct smatch_state
*s1
, struct smatch_state
*s2
)
484 struct compare_data
*data
= s1
->data
;
487 op
= merge_comparisons(state_to_comparison(s1
), state_to_comparison(s2
));
489 return alloc_compare_state(data
->var1
, data
->vsl1
, op
, data
->var2
, data
->vsl2
);
493 static struct smatch_state
*alloc_link_state(struct string_list
*links
)
495 struct smatch_state
*state
;
496 static char buf
[256];
500 state
= __alloc_smatch_state(0);
503 FOR_EACH_PTR(links
, tmp
) {
505 snprintf(buf
, sizeof(buf
), "%s", tmp
);
507 append(buf
, ", ", sizeof(buf
));
508 append(buf
, tmp
, sizeof(buf
));
510 } END_FOR_EACH_PTR(tmp
);
512 state
->name
= alloc_sname(buf
);
517 static void save_start_states(struct statement
*stmt
)
519 struct symbol
*param
;
521 char state_name
[128];
522 struct smatch_state
*state
;
523 struct string_list
*links
;
526 FOR_EACH_PTR(cur_func_sym
->ctype
.base_type
->arguments
, param
) {
527 struct var_sym_list
*vsl1
= NULL
;
528 struct var_sym_list
*vsl2
= NULL
;
532 snprintf(orig
, sizeof(orig
), "%s orig", param
->ident
->name
);
533 snprintf(state_name
, sizeof(state_name
), "%s vs %s", param
->ident
->name
, orig
);
534 add_var_sym(&vsl1
, param
->ident
->name
, param
);
535 add_var_sym(&vsl2
, orig
, param
);
536 state
= alloc_compare_state(param
->ident
->name
, vsl1
, SPECIAL_EQUAL
, alloc_sname(orig
), vsl2
);
537 set_state(compare_id
, state_name
, NULL
, state
);
539 link
= alloc_sname(state_name
);
541 insert_string(&links
, link
);
542 state
= alloc_link_state(links
);
543 set_state(link_id
, param
->ident
->name
, param
, state
);
544 } END_FOR_EACH_PTR(param
);
547 static struct smatch_state
*merge_links(struct smatch_state
*s1
, struct smatch_state
*s2
)
549 struct smatch_state
*ret
;
550 struct string_list
*links
;
552 links
= combine_string_lists(s1
->data
, s2
->data
);
553 ret
= alloc_link_state(links
);
557 static void save_link_var_sym(const char *var
, struct symbol
*sym
, const char *link
)
559 struct smatch_state
*old_state
, *new_state
;
560 struct string_list
*links
;
563 old_state
= get_state(link_id
, var
, sym
);
565 links
= clone_str_list(old_state
->data
);
569 new = alloc_sname(link
);
570 insert_string(&links
, new);
572 new_state
= alloc_link_state(links
);
573 set_state(link_id
, var
, sym
, new_state
);
576 static void match_inc(struct sm_state
*sm
)
578 struct string_list
*links
;
579 struct smatch_state
*state
;
582 links
= sm
->state
->data
;
584 FOR_EACH_PTR(links
, tmp
) {
585 state
= get_state(compare_id
, tmp
, NULL
);
587 switch (state_to_comparison(state
)) {
590 case SPECIAL_UNSIGNED_GTE
:
592 case SPECIAL_UNSIGNED_GT
: {
593 struct compare_data
*data
= state
->data
;
594 struct smatch_state
*new;
596 new = alloc_compare_state(data
->var1
, data
->vsl1
, '>', data
->var2
, data
->vsl2
);
597 set_state(compare_id
, tmp
, NULL
, new);
601 set_state(compare_id
, tmp
, NULL
, &undefined
);
603 } END_FOR_EACH_PTR(tmp
);
606 static void match_dec(struct sm_state
*sm
)
608 struct string_list
*links
;
609 struct smatch_state
*state
;
612 links
= sm
->state
->data
;
614 FOR_EACH_PTR(links
, tmp
) {
615 state
= get_state(compare_id
, tmp
, NULL
);
617 switch (state_to_comparison(state
)) {
620 case SPECIAL_UNSIGNED_LTE
:
622 case SPECIAL_UNSIGNED_LT
: {
623 struct compare_data
*data
= state
->data
;
624 struct smatch_state
*new;
626 new = alloc_compare_state(data
->var1
, data
->vsl1
, '<', data
->var2
, data
->vsl2
);
627 set_state(compare_id
, tmp
, NULL
, new);
631 set_state(compare_id
, tmp
, NULL
, &undefined
);
633 } END_FOR_EACH_PTR(tmp
);
636 static int match_inc_dec(struct sm_state
*sm
, struct expression
*mod_expr
)
640 if (mod_expr
->type
!= EXPR_PREOP
&& mod_expr
->type
!= EXPR_POSTOP
)
643 if (mod_expr
->op
== SPECIAL_INCREMENT
) {
647 if (mod_expr
->op
== SPECIAL_DECREMENT
) {
654 static void match_modify(struct sm_state
*sm
, struct expression
*mod_expr
)
656 struct string_list
*links
;
659 /* Huh??? This needs a comment! */
660 if (match_inc_dec(sm
, mod_expr
))
663 links
= sm
->state
->data
;
665 FOR_EACH_PTR(links
, tmp
) {
666 set_state(compare_id
, tmp
, NULL
, &undefined
);
667 } END_FOR_EACH_PTR(tmp
);
668 set_state(link_id
, sm
->name
, sm
->sym
, &undefined
);
671 static char *chunk_to_var_sym(struct expression
*expr
, struct symbol
**sym
)
673 char *name
, *left_name
, *right_name
;
677 expr
= strip_expr(expr
);
683 if (expr
->type
== EXPR_PREOP
&&
684 (expr
->op
== SPECIAL_INCREMENT
||
685 expr
->op
== SPECIAL_DECREMENT
))
686 expr
= strip_expr(expr
->unop
);
688 name
= expr_to_var_sym(expr
, &tmp
);
697 if (expr
->type
!= EXPR_BINOP
)
699 if (expr
->op
!= '-' && expr
->op
!= '+')
702 left_name
= expr_to_var(expr
->left
);
705 right_name
= expr_to_var(expr
->right
);
707 free_string(left_name
);
710 snprintf(buf
, sizeof(buf
), "%s %s %s", left_name
, show_special(expr
->op
), right_name
);
711 free_string(left_name
);
712 free_string(right_name
);
713 return alloc_string(buf
);
716 static char *chunk_to_var(struct expression
*expr
)
718 return chunk_to_var_sym(expr
, NULL
);
721 static void save_link(struct expression
*expr
, char *link
)
726 expr
= strip_expr(expr
);
727 if (expr
->type
== EXPR_BINOP
) {
730 chunk
= chunk_to_var(expr
);
734 save_link(expr
->left
, link
);
735 save_link(expr
->right
, link
);
736 save_link_var_sym(chunk
, NULL
, link
);
740 var
= expr_to_var_sym(expr
, &sym
);
744 save_link_var_sym(var
, sym
, link
);
749 static int get_orig_comparison(struct stree
*pre_stree
, const char *left
, const char *right
)
751 struct smatch_state
*state
;
752 struct compare_data
*data
;
754 char state_name
[256];
756 if (strcmp(left
, right
) > 0) {
757 const char *tmp
= right
;
764 snprintf(state_name
, sizeof(state_name
), "%s vs %s", left
, right
);
765 state
= get_state_stree(pre_stree
, compare_id
, state_name
, NULL
);
766 if (!state
|| !state
->data
)
770 return flip_comparison(data
->comparison
);
771 return data
->comparison
;
776 * The idea here is that we take a comparison "a < b" and then we look at all
777 * the things which "b" is compared against "b < c" and we say that that implies
778 * a relationship "a < c".
780 * The names here about because the comparisons are organized like this
784 static void update_tf_links(struct stree
*pre_stree
,
785 const char *left_var
, struct var_sym_list
*left_vsl
,
786 int left_comparison
, int left_false_comparison
,
787 const char *mid_var
, struct var_sym_list
*mid_vsl
,
788 struct string_list
*links
)
790 struct smatch_state
*state
;
791 struct smatch_state
*true_state
, *false_state
;
792 struct compare_data
*data
;
793 const char *right_var
;
794 struct var_sym_list
*right_vsl
;
796 int right_comparison
;
798 int false_comparison
;
800 char state_name
[256];
803 FOR_EACH_PTR(links
, tmp
) {
804 state
= get_state_stree(pre_stree
, compare_id
, tmp
, NULL
);
805 if (!state
|| !state
->data
)
808 right_comparison
= data
->comparison
;
809 right_var
= data
->var2
;
810 right_vsl
= data
->vsl2
;
811 if (strcmp(mid_var
, right_var
) == 0) {
812 right_var
= data
->var1
;
813 right_vsl
= data
->vsl1
;
814 right_comparison
= flip_comparison(right_comparison
);
816 if (strcmp(left_var
, right_var
) == 0)
819 orig_comparison
= get_orig_comparison(pre_stree
, left_var
, right_var
);
821 true_comparison
= combine_comparisons(left_comparison
, right_comparison
);
822 false_comparison
= combine_comparisons(left_false_comparison
, right_comparison
);
824 true_comparison
= filter_comparison(orig_comparison
, true_comparison
);
825 false_comparison
= filter_comparison(orig_comparison
, false_comparison
);
827 if (strcmp(left_var
, right_var
) > 0) {
828 const char *tmp_var
= left_var
;
829 struct var_sym_list
*tmp_vsl
= left_vsl
;
831 left_var
= right_var
;
832 left_vsl
= right_vsl
;
835 true_comparison
= flip_comparison(true_comparison
);
836 false_comparison
= flip_comparison(false_comparison
);
839 if (!true_comparison
&& !false_comparison
)
843 true_state
= alloc_compare_state(left_var
, left_vsl
, true_comparison
, right_var
, right_vsl
);
846 if (false_comparison
)
847 false_state
= alloc_compare_state(left_var
, left_vsl
, false_comparison
, right_var
, right_vsl
);
851 snprintf(state_name
, sizeof(state_name
), "%s vs %s", left_var
, right_var
);
852 set_true_false_states(compare_id
, state_name
, NULL
, true_state
, false_state
);
853 FOR_EACH_PTR(left_vsl
, vs
) {
854 save_link_var_sym(vs
->var
, vs
->sym
, state_name
);
855 } END_FOR_EACH_PTR(vs
);
856 FOR_EACH_PTR(right_vsl
, vs
) {
857 save_link_var_sym(vs
->var
, vs
->sym
, state_name
);
858 } END_FOR_EACH_PTR(vs
);
859 if (!vsl_to_sym(left_vsl
))
860 save_link_var_sym(left_var
, NULL
, state_name
);
861 if (!vsl_to_sym(right_vsl
))
862 save_link_var_sym(right_var
, NULL
, state_name
);
863 } END_FOR_EACH_PTR(tmp
);
866 static void update_tf_data(struct stree
*pre_stree
,
867 const char *left_name
, struct var_sym_list
*left_vsl
,
868 const char *right_name
, struct var_sym_list
*right_vsl
,
869 int true_comparison
, int false_comparison
)
871 struct smatch_state
*state
;
873 state
= get_state_stree(pre_stree
, link_id
, right_name
, vsl_to_sym(right_vsl
));
875 update_tf_links(pre_stree
, left_name
, left_vsl
, true_comparison
, false_comparison
, right_name
, right_vsl
, state
->data
);
877 state
= get_state_stree(pre_stree
, link_id
, left_name
, vsl_to_sym(left_vsl
));
879 update_tf_links(pre_stree
, right_name
, right_vsl
, flip_comparison(true_comparison
), flip_comparison(false_comparison
), left_name
, left_vsl
, state
->data
);
882 static void match_compare(struct expression
*expr
)
886 struct symbol
*left_sym
, *right_sym
;
887 struct var_sym_list
*left_vsl
, *right_vsl
;
890 struct smatch_state
*true_state
, *false_state
;
891 char state_name
[256];
892 struct stree
*pre_stree
;
894 if (expr
->type
!= EXPR_COMPARE
)
896 left
= chunk_to_var_sym(expr
->left
, &left_sym
);
899 left_vsl
= expr_to_vsl(expr
->left
);
900 right
= chunk_to_var_sym(expr
->right
, &right_sym
);
903 right_vsl
= expr_to_vsl(expr
->right
);
905 if (strcmp(left
, right
) > 0) {
906 struct symbol
*tmp_sym
= left_sym
;
907 char *tmp_name
= left
;
908 struct var_sym_list
*tmp_vsl
= left_vsl
;
911 left_sym
= right_sym
;
912 left_vsl
= right_vsl
;
916 op
= flip_comparison(expr
->op
);
920 false_op
= negate_comparison(op
);
922 orig_comparison
= get_comparison_strings(left
, right
);
923 op
= filter_comparison(orig_comparison
, op
);
924 false_op
= filter_comparison(orig_comparison
, false_op
);
926 snprintf(state_name
, sizeof(state_name
), "%s vs %s", left
, right
);
927 true_state
= alloc_compare_state(left
, left_vsl
, op
, right
, right_vsl
);
928 false_state
= alloc_compare_state(left
, left_vsl
, false_op
, right
, right_vsl
);
930 pre_stree
= clone_stree(__get_cur_stree());
931 update_tf_data(pre_stree
, left
, left_vsl
, right
, right_vsl
, op
, false_op
);
932 free_stree(&pre_stree
);
934 set_true_false_states(compare_id
, state_name
, NULL
, true_state
, false_state
);
935 save_link(expr
->left
, state_name
);
936 save_link(expr
->right
, state_name
);
942 static void add_comparison_var_sym(const char *left_name
,
943 struct var_sym_list
*left_vsl
,
945 const char *right_name
, struct var_sym_list
*right_vsl
)
947 struct smatch_state
*state
;
949 char state_name
[256];
951 if (strcmp(left_name
, right_name
) > 0) {
952 const char *tmp_name
= left_name
;
953 struct var_sym_list
*tmp_vsl
= left_vsl
;
955 left_name
= right_name
;
956 left_vsl
= right_vsl
;
957 right_name
= tmp_name
;
959 comparison
= flip_comparison(comparison
);
961 snprintf(state_name
, sizeof(state_name
), "%s vs %s", left_name
, right_name
);
962 state
= alloc_compare_state(left_name
, left_vsl
, comparison
, right_name
, right_vsl
);
964 set_state(compare_id
, state_name
, NULL
, state
);
966 FOR_EACH_PTR(left_vsl
, vs
) {
967 save_link_var_sym(vs
->var
, vs
->sym
, state_name
);
968 } END_FOR_EACH_PTR(vs
);
969 FOR_EACH_PTR(right_vsl
, vs
) {
970 save_link_var_sym(vs
->var
, vs
->sym
, state_name
);
971 } END_FOR_EACH_PTR(vs
);
974 static void add_comparison(struct expression
*left
, int comparison
, struct expression
*right
)
976 char *left_name
= NULL
;
977 char *right_name
= NULL
;
978 struct symbol
*left_sym
, *right_sym
;
979 struct var_sym_list
*left_vsl
, *right_vsl
;
980 struct smatch_state
*state
;
981 char state_name
[256];
983 left_name
= chunk_to_var_sym(left
, &left_sym
);
986 left_vsl
= expr_to_vsl(left
);
987 right_name
= chunk_to_var_sym(right
, &right_sym
);
990 right_vsl
= expr_to_vsl(right
);
992 if (strcmp(left_name
, right_name
) > 0) {
993 struct symbol
*tmp_sym
= left_sym
;
994 char *tmp_name
= left_name
;
995 struct var_sym_list
*tmp_vsl
= left_vsl
;
997 left_name
= right_name
;
998 left_sym
= right_sym
;
999 left_vsl
= right_vsl
;
1000 right_name
= tmp_name
;
1001 right_sym
= tmp_sym
;
1002 right_vsl
= tmp_vsl
;
1003 comparison
= flip_comparison(comparison
);
1005 snprintf(state_name
, sizeof(state_name
), "%s vs %s", left_name
, right_name
);
1006 state
= alloc_compare_state(left_name
, left_vsl
, comparison
, right_name
, right_vsl
);
1008 set_state(compare_id
, state_name
, NULL
, state
);
1009 save_link(left
, state_name
);
1010 save_link(right
, state_name
);
1013 free_string(left_name
);
1014 free_string(right_name
);
1017 static void match_assign_add(struct expression
*expr
)
1019 struct expression
*right
;
1020 struct expression
*r_left
, *r_right
;
1021 sval_t left_tmp
, right_tmp
;
1023 right
= strip_expr(expr
->right
);
1024 r_left
= strip_expr(right
->left
);
1025 r_right
= strip_expr(right
->right
);
1027 get_absolute_min(r_left
, &left_tmp
);
1028 get_absolute_min(r_right
, &right_tmp
);
1030 if (left_tmp
.value
> 0)
1031 add_comparison(expr
->left
, '>', r_right
);
1032 else if (left_tmp
.value
== 0)
1033 add_comparison(expr
->left
, SPECIAL_GTE
, r_right
);
1035 if (right_tmp
.value
> 0)
1036 add_comparison(expr
->left
, '>', r_left
);
1037 else if (right_tmp
.value
== 0)
1038 add_comparison(expr
->left
, SPECIAL_GTE
, r_left
);
1041 static void match_assign_sub(struct expression
*expr
)
1043 struct expression
*right
;
1044 struct expression
*r_left
, *r_right
;
1048 right
= strip_expr(expr
->right
);
1049 r_left
= strip_expr(right
->left
);
1050 r_right
= strip_expr(right
->right
);
1052 if (get_absolute_min(r_right
, &min
) && sval_is_negative(min
))
1055 comparison
= get_comparison(r_left
, r_right
);
1057 switch (comparison
) {
1060 if (implied_not_equal(r_right
, 0))
1061 add_comparison(expr
->left
, '>', r_left
);
1063 add_comparison(expr
->left
, SPECIAL_GTE
, r_left
);
1068 static void match_assign_divide(struct expression
*expr
)
1070 struct expression
*right
;
1071 struct expression
*r_left
, *r_right
;
1074 right
= strip_expr(expr
->right
);
1075 r_left
= strip_expr(right
->left
);
1076 r_right
= strip_expr(right
->right
);
1077 if (!get_implied_min(r_right
, &min
) || min
.value
<= 1)
1080 add_comparison(expr
->left
, '<', r_left
);
1083 static void match_binop_assign(struct expression
*expr
)
1085 struct expression
*right
;
1087 right
= strip_expr(expr
->right
);
1088 if (right
->op
== '+')
1089 match_assign_add(expr
);
1090 if (right
->op
== '-')
1091 match_assign_sub(expr
);
1092 if (right
->op
== '/')
1093 match_assign_divide(expr
);
1096 static void copy_comparisons(struct expression
*left
, struct expression
*right
)
1098 struct string_list
*links
;
1099 struct smatch_state
*state
;
1100 struct compare_data
*data
;
1101 struct symbol
*left_sym
, *right_sym
;
1102 char *left_var
= NULL
;
1103 char *right_var
= NULL
;
1104 struct var_sym_list
*left_vsl
;
1106 struct var_sym_list
*vsl
;
1110 left_var
= chunk_to_var_sym(left
, &left_sym
);
1113 left_vsl
= expr_to_vsl(left
);
1114 right_var
= chunk_to_var_sym(right
, &right_sym
);
1118 state
= get_state(link_id
, right_var
, right_sym
);
1121 links
= state
->data
;
1123 FOR_EACH_PTR(links
, tmp
) {
1124 state
= get_state(compare_id
, tmp
, NULL
);
1125 if (!state
|| !state
->data
)
1128 comparison
= data
->comparison
;
1131 if (strcmp(var
, right_var
) == 0) {
1134 comparison
= flip_comparison(comparison
);
1136 add_comparison_var_sym(left_var
, left_vsl
, comparison
, var
, vsl
);
1137 } END_FOR_EACH_PTR(tmp
);
1140 free_string(right_var
);
1143 static void match_assign(struct expression
*expr
)
1145 struct expression
*right
;
1147 if (expr
->op
!= '=')
1149 if (__in_fake_assign
)
1152 if (is_struct(expr
->left
))
1155 copy_comparisons(expr
->left
, expr
->right
);
1156 add_comparison(expr
->left
, SPECIAL_EQUAL
, expr
->right
);
1158 right
= strip_expr(expr
->right
);
1159 if (right
->type
== EXPR_BINOP
)
1160 match_binop_assign(expr
);
1163 int get_comparison_strings(const char *one
, const char *two
)
1166 struct smatch_state
*state
;
1170 if (strcmp(one
, two
) == 0)
1171 return SPECIAL_EQUAL
;
1173 if (strcmp(one
, two
) > 0) {
1174 const char *tmp
= one
;
1181 snprintf(buf
, sizeof(buf
), "%s vs %s", one
, two
);
1182 state
= get_state(compare_id
, buf
, NULL
);
1184 ret
= state_to_comparison(state
);
1187 ret
= flip_comparison(ret
);
1192 int get_comparison(struct expression
*a
, struct expression
*b
)
1198 one
= chunk_to_var(a
);
1201 two
= chunk_to_var(b
);
1205 ret
= get_comparison_strings(one
, two
);
1212 int possible_comparison(struct expression
*a
, int comparison
, struct expression
*b
)
1218 struct sm_state
*sm
;
1221 one
= chunk_to_var(a
);
1224 two
= chunk_to_var(b
);
1229 if (strcmp(one
, two
) == 0 && comparison
== SPECIAL_EQUAL
) {
1234 if (strcmp(one
, two
) > 0) {
1239 comparison
= flip_comparison(comparison
);
1242 snprintf(buf
, sizeof(buf
), "%s vs %s", one
, two
);
1243 sm
= get_sm_state(compare_id
, buf
, NULL
);
1247 FOR_EACH_PTR(sm
->possible
, sm
) {
1248 if (!sm
->state
->data
)
1250 saved
= ((struct compare_data
*)sm
->state
->data
)->comparison
;
1251 if (saved
== comparison
)
1253 if (comparison
== SPECIAL_EQUAL
&&
1254 (saved
== SPECIAL_LTE
||
1255 saved
== SPECIAL_GTE
||
1256 saved
== SPECIAL_UNSIGNED_LTE
||
1257 saved
== SPECIAL_UNSIGNED_GTE
))
1261 } END_FOR_EACH_PTR(sm
);
1270 struct state_list
*get_all_comparisons(struct expression
*expr
)
1272 struct smatch_state
*state
;
1273 struct string_list
*links
;
1274 struct state_list
*ret
= NULL
;
1275 struct sm_state
*sm
;
1278 state
= get_state_expr(link_id
, expr
);
1281 links
= state
->data
;
1283 FOR_EACH_PTR(links
, tmp
) {
1284 sm
= get_sm_state(compare_id
, tmp
, NULL
);
1287 // FIXME have to compare name with vsl
1288 add_ptr_list(&ret
, sm
);
1289 } END_FOR_EACH_PTR(tmp
);
1294 struct state_list
*get_all_possible_equal_comparisons(struct expression
*expr
)
1296 struct smatch_state
*state
;
1297 struct string_list
*links
;
1298 struct state_list
*ret
= NULL
;
1299 struct sm_state
*sm
;
1302 state
= get_state_expr(link_id
, expr
);
1305 links
= state
->data
;
1307 FOR_EACH_PTR(links
, tmp
) {
1308 sm
= get_sm_state(compare_id
, tmp
, NULL
);
1311 if (!strchr(sm
->state
->name
, '='))
1313 if (strcmp(sm
->state
->name
, "!=") == 0)
1315 add_ptr_list(&ret
, sm
);
1316 } END_FOR_EACH_PTR(tmp
);
1321 static void update_links_from_call(struct expression
*left
,
1323 struct expression
*right
)
1325 struct string_list
*links
;
1326 struct smatch_state
*state
;
1327 struct compare_data
*data
;
1328 struct symbol
*left_sym
, *right_sym
;
1329 char *left_var
= NULL
;
1330 char *right_var
= NULL
;
1331 struct var_sym_list
*left_vsl
;
1333 struct var_sym_list
*vsl
;
1337 left_var
= chunk_to_var_sym(left
, &left_sym
);
1340 left_vsl
= expr_to_vsl(left
);
1341 right_var
= chunk_to_var_sym(right
, &right_sym
);
1345 state
= get_state(link_id
, right_var
, right_sym
);
1348 links
= state
->data
;
1350 FOR_EACH_PTR(links
, tmp
) {
1351 state
= get_state(compare_id
, tmp
, NULL
);
1352 if (!state
|| !state
->data
)
1355 comparison
= data
->comparison
;
1358 if (strcmp(var
, right_var
) == 0) {
1361 comparison
= flip_comparison(comparison
);
1363 comparison
= combine_comparisons(left_compare
, comparison
);
1366 add_comparison_var_sym(left_var
, left_vsl
, comparison
, var
, vsl
);
1367 } END_FOR_EACH_PTR(tmp
);
1370 free_string(right_var
);
1373 void __add_comparison_info(struct expression
*expr
, struct expression
*call
, const char *range
)
1375 struct expression
*arg
;
1377 const char *c
= range
;
1379 if (!str_to_comparison_arg(c
, call
, &comparison
, &arg
))
1381 update_links_from_call(expr
, comparison
, arg
);
1382 add_comparison(expr
, comparison
, arg
);
1385 static char *range_comparison_to_param_helper(struct expression
*expr
, char starts_with
, int ignore
)
1387 struct symbol
*param
;
1390 char *ret_str
= NULL
;
1394 var
= chunk_to_var(expr
);
1399 FOR_EACH_PTR(cur_func_sym
->ctype
.base_type
->arguments
, param
) {
1405 snprintf(buf
, sizeof(buf
), "%s orig", param
->ident
->name
);
1406 compare
= get_comparison_strings(var
, buf
);
1409 if (show_special(compare
)[0] != starts_with
)
1411 snprintf(buf
, sizeof(buf
), "[%s$%d]", show_special(compare
), i
);
1412 ret_str
= alloc_sname(buf
);
1414 } END_FOR_EACH_PTR(param
);
1421 char *expr_equal_to_param(struct expression
*expr
, int ignore
)
1423 return range_comparison_to_param_helper(expr
, '=', ignore
);
1426 char *expr_lte_to_param(struct expression
*expr
, int ignore
)
1428 return range_comparison_to_param_helper(expr
, '<', ignore
);
1431 char *expr_param_comparison(struct expression
*expr
, int ignore
)
1433 struct symbol
*param
;
1436 char *ret_str
= NULL
;
1440 var
= chunk_to_var(expr
);
1445 FOR_EACH_PTR(cur_func_sym
->ctype
.base_type
->arguments
, param
) {
1451 snprintf(buf
, sizeof(buf
), "%s orig", param
->ident
->name
);
1452 compare
= get_comparison_strings(var
, buf
);
1455 snprintf(buf
, sizeof(buf
), "[%s$%d]", show_special(compare
), i
);
1456 ret_str
= alloc_sname(buf
);
1458 } END_FOR_EACH_PTR(param
);
1465 static void free_data(struct symbol
*sym
)
1469 clear_compare_data_alloc();
1472 void register_comparison(int id
)
1475 add_hook(&match_compare
, CONDITION_HOOK
);
1476 add_hook(&match_assign
, ASSIGNMENT_HOOK
);
1477 add_hook(&save_start_states
, AFTER_DEF_HOOK
);
1478 add_unmatched_state_hook(compare_id
, unmatched_comparison
);
1479 add_merge_hook(compare_id
, &merge_compare_states
);
1480 add_hook(&free_data
, AFTER_FUNC_HOOK
);
1483 void register_comparison_links(int id
)
1486 add_merge_hook(link_id
, &merge_links
);
1487 add_modification_hook(link_id
, &match_modify
);