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 int filter_comparison(int orig
, int op
)
387 case SPECIAL_NOTEQUAL
:
397 case SPECIAL_NOTEQUAL
:
406 return SPECIAL_EQUAL
;
409 case SPECIAL_NOTEQUAL
:
414 case SPECIAL_NOTEQUAL
:
427 case SPECIAL_NOTEQUAL
:
436 case SPECIAL_NOTEQUAL
:
441 sm_msg("Internal: what did I forget? orig = %d op = '%s'", orig
, show_special(op
));
445 static struct smatch_state
*merge_compare_states(struct smatch_state
*s1
, struct smatch_state
*s2
)
447 struct compare_data
*data
= s1
->data
;
450 op
= merge_comparisons(state_to_comparison(s1
), state_to_comparison(s2
));
452 return alloc_compare_state(data
->var1
, data
->vsl1
, op
, data
->var2
, data
->vsl2
);
456 static struct smatch_state
*alloc_link_state(struct string_list
*links
)
458 struct smatch_state
*state
;
459 static char buf
[256];
463 state
= __alloc_smatch_state(0);
466 FOR_EACH_PTR(links
, tmp
) {
468 snprintf(buf
, sizeof(buf
), "%s", tmp
);
470 append(buf
, ", ", sizeof(buf
));
471 append(buf
, tmp
, sizeof(buf
));
473 } END_FOR_EACH_PTR(tmp
);
475 state
->name
= alloc_sname(buf
);
480 static void save_start_states(struct statement
*stmt
)
482 struct symbol
*param
;
484 char state_name
[128];
485 struct smatch_state
*state
;
486 struct string_list
*links
;
489 FOR_EACH_PTR(cur_func_sym
->ctype
.base_type
->arguments
, param
) {
490 struct var_sym_list
*vsl1
= NULL
;
491 struct var_sym_list
*vsl2
= NULL
;
495 snprintf(orig
, sizeof(orig
), "%s orig", param
->ident
->name
);
496 snprintf(state_name
, sizeof(state_name
), "%s vs %s", param
->ident
->name
, orig
);
497 add_var_sym(&vsl1
, param
->ident
->name
, param
);
498 add_var_sym(&vsl2
, orig
, param
);
499 state
= alloc_compare_state(param
->ident
->name
, vsl1
, SPECIAL_EQUAL
, alloc_sname(orig
), vsl2
);
500 set_state(compare_id
, state_name
, NULL
, state
);
502 link
= alloc_sname(state_name
);
504 insert_string(&links
, link
);
505 state
= alloc_link_state(links
);
506 set_state(link_id
, param
->ident
->name
, param
, state
);
507 } END_FOR_EACH_PTR(param
);
510 static struct smatch_state
*merge_links(struct smatch_state
*s1
, struct smatch_state
*s2
)
512 struct smatch_state
*ret
;
513 struct string_list
*links
;
515 links
= combine_string_lists(s1
->data
, s2
->data
);
516 ret
= alloc_link_state(links
);
520 static void save_link_var_sym(const char *var
, struct symbol
*sym
, const char *link
)
522 struct smatch_state
*old_state
, *new_state
;
523 struct string_list
*links
;
526 old_state
= get_state(link_id
, var
, sym
);
528 links
= clone_str_list(old_state
->data
);
532 new = alloc_sname(link
);
533 insert_string(&links
, new);
535 new_state
= alloc_link_state(links
);
536 set_state(link_id
, var
, sym
, new_state
);
539 static void match_inc(struct sm_state
*sm
)
541 struct string_list
*links
;
542 struct smatch_state
*state
;
545 links
= sm
->state
->data
;
547 FOR_EACH_PTR(links
, tmp
) {
548 state
= get_state(compare_id
, tmp
, NULL
);
550 switch (state_to_comparison(state
)) {
553 case SPECIAL_UNSIGNED_GTE
:
555 case SPECIAL_UNSIGNED_GT
: {
556 struct compare_data
*data
= state
->data
;
557 struct smatch_state
*new;
559 new = alloc_compare_state(data
->var1
, data
->vsl1
, '>', data
->var2
, data
->vsl2
);
560 set_state(compare_id
, tmp
, NULL
, new);
564 set_state(compare_id
, tmp
, NULL
, &undefined
);
566 } END_FOR_EACH_PTR(tmp
);
569 static void match_dec(struct sm_state
*sm
)
571 struct string_list
*links
;
572 struct smatch_state
*state
;
575 links
= sm
->state
->data
;
577 FOR_EACH_PTR(links
, tmp
) {
578 state
= get_state(compare_id
, tmp
, NULL
);
580 switch (state_to_comparison(state
)) {
583 case SPECIAL_UNSIGNED_LTE
:
585 case SPECIAL_UNSIGNED_LT
: {
586 struct compare_data
*data
= state
->data
;
587 struct smatch_state
*new;
589 new = alloc_compare_state(data
->var1
, data
->vsl1
, '<', data
->var2
, data
->vsl2
);
590 set_state(compare_id
, tmp
, NULL
, new);
594 set_state(compare_id
, tmp
, NULL
, &undefined
);
596 } END_FOR_EACH_PTR(tmp
);
599 static int match_inc_dec(struct sm_state
*sm
, struct expression
*mod_expr
)
603 if (mod_expr
->type
!= EXPR_PREOP
&& mod_expr
->type
!= EXPR_POSTOP
)
606 if (mod_expr
->op
== SPECIAL_INCREMENT
) {
610 if (mod_expr
->op
== SPECIAL_DECREMENT
) {
617 static void match_modify(struct sm_state
*sm
, struct expression
*mod_expr
)
619 struct string_list
*links
;
622 /* Huh??? This needs a comment! */
623 if (match_inc_dec(sm
, mod_expr
))
626 links
= sm
->state
->data
;
628 FOR_EACH_PTR(links
, tmp
) {
629 set_state(compare_id
, tmp
, NULL
, &undefined
);
630 } END_FOR_EACH_PTR(tmp
);
631 set_state(link_id
, sm
->name
, sm
->sym
, &undefined
);
634 static char *chunk_to_var_sym(struct expression
*expr
, struct symbol
**sym
)
636 char *name
, *left_name
, *right_name
;
640 expr
= strip_expr(expr
);
646 name
= expr_to_var_sym(expr
, &tmp
);
655 if (expr
->type
!= EXPR_BINOP
)
657 if (expr
->op
!= '-' && expr
->op
!= '+')
660 left_name
= expr_to_var(expr
->left
);
663 right_name
= expr_to_var(expr
->right
);
665 free_string(left_name
);
668 snprintf(buf
, sizeof(buf
), "%s %s %s", left_name
, show_special(expr
->op
), right_name
);
669 free_string(left_name
);
670 free_string(right_name
);
671 return alloc_string(buf
);
674 static char *chunk_to_var(struct expression
*expr
)
676 return chunk_to_var_sym(expr
, NULL
);
679 static void save_link(struct expression
*expr
, char *link
)
684 expr
= strip_expr(expr
);
685 if (expr
->type
== EXPR_BINOP
) {
688 chunk
= chunk_to_var(expr
);
692 save_link(expr
->left
, link
);
693 save_link(expr
->right
, link
);
694 save_link_var_sym(chunk
, NULL
, link
);
698 var
= expr_to_var_sym(expr
, &sym
);
702 save_link_var_sym(var
, sym
, link
);
707 static void update_tf_links(struct stree
*pre_stree
,
708 const char *left_var
, struct var_sym_list
*left_vsl
,
710 const char *mid_var
, struct var_sym_list
*mid_vsl
,
711 struct string_list
*links
)
713 struct smatch_state
*state
;
714 struct smatch_state
*true_state
, *false_state
;
715 struct compare_data
*data
;
716 const char *right_var
;
717 struct var_sym_list
*right_vsl
;
718 int right_comparison
;
720 int false_comparison
;
722 char state_name
[256];
725 FOR_EACH_PTR(links
, tmp
) {
726 state
= get_state_stree(pre_stree
, compare_id
, tmp
, NULL
);
727 if (!state
|| !state
->data
)
730 right_comparison
= data
->comparison
;
731 right_var
= data
->var2
;
732 right_vsl
= data
->vsl2
;
733 if (chunk_vsl_eq(mid_var
, mid_vsl
, right_var
, right_vsl
)) {
734 right_var
= data
->var1
;
735 right_vsl
= data
->vsl1
;
736 right_comparison
= flip_op(right_comparison
);
738 true_comparison
= combine_comparisons(left_comparison
, right_comparison
);
739 false_comparison
= combine_comparisons(falsify_op(left_comparison
), right_comparison
);
741 if (strcmp(left_var
, right_var
) > 0) {
742 const char *tmp_var
= left_var
;
743 struct var_sym_list
*tmp_vsl
= left_vsl
;
745 left_var
= right_var
;
746 left_vsl
= right_vsl
;
749 true_comparison
= flip_op(true_comparison
);
750 false_comparison
= flip_op(false_comparison
);
753 if (!true_comparison
&& !false_comparison
)
757 true_state
= alloc_compare_state(left_var
, left_vsl
, true_comparison
, right_var
, right_vsl
);
760 if (false_comparison
)
761 false_state
= alloc_compare_state(left_var
, left_vsl
, false_comparison
, right_var
, right_vsl
);
765 snprintf(state_name
, sizeof(state_name
), "%s vs %s", left_var
, right_var
);
766 set_true_false_states(compare_id
, state_name
, NULL
, true_state
, false_state
);
767 FOR_EACH_PTR(left_vsl
, vs
) {
768 save_link_var_sym(vs
->var
, vs
->sym
, state_name
);
769 } END_FOR_EACH_PTR(vs
);
770 FOR_EACH_PTR(right_vsl
, vs
) {
771 save_link_var_sym(vs
->var
, vs
->sym
, state_name
);
772 } END_FOR_EACH_PTR(vs
);
773 if (!vsl_to_sym(left_vsl
))
774 save_link_var_sym(left_var
, NULL
, state_name
);
775 if (!vsl_to_sym(right_vsl
))
776 save_link_var_sym(right_var
, NULL
, state_name
);
777 } END_FOR_EACH_PTR(tmp
);
780 static void update_tf_data(struct stree
*pre_stree
,
781 const char *left_name
, struct symbol
*left_sym
,
782 const char *right_name
, struct symbol
*right_sym
,
783 struct compare_data
*tdata
)
785 struct smatch_state
*state
;
787 state
= get_state_stree(pre_stree
, link_id
, tdata
->var2
, vsl_to_sym(tdata
->vsl2
));
789 update_tf_links(pre_stree
, tdata
->var1
, tdata
->vsl1
, tdata
->comparison
, tdata
->var2
, tdata
->vsl2
, state
->data
);
791 state
= get_state_stree(pre_stree
, link_id
, tdata
->var1
, vsl_to_sym(tdata
->vsl1
));
793 update_tf_links(pre_stree
, tdata
->var2
, tdata
->vsl2
, flip_op(tdata
->comparison
), tdata
->var1
, tdata
->vsl1
, state
->data
);
796 static void match_compare(struct expression
*expr
)
800 struct symbol
*left_sym
, *right_sym
;
801 struct var_sym_list
*left_vsl
, *right_vsl
;
804 struct smatch_state
*true_state
, *false_state
;
805 char state_name
[256];
806 struct stree
*pre_stree
;
808 if (expr
->type
!= EXPR_COMPARE
)
810 left
= chunk_to_var_sym(expr
->left
, &left_sym
);
813 left_vsl
= expr_to_vsl(expr
->left
);
814 right
= chunk_to_var_sym(expr
->right
, &right_sym
);
817 right_vsl
= expr_to_vsl(expr
->right
);
819 if (strcmp(left
, right
) > 0) {
820 struct symbol
*tmp_sym
= left_sym
;
821 char *tmp_name
= left
;
822 struct var_sym_list
*tmp_vsl
= left_vsl
;
825 left_sym
= right_sym
;
826 left_vsl
= right_vsl
;
830 op
= flip_op(expr
->op
);
834 false_op
= falsify_op(op
);
836 orig_comparison
= get_comparison_strings(left
, right
);
837 op
= filter_comparison(orig_comparison
, op
);
838 false_op
= filter_comparison(orig_comparison
, false_op
);
840 snprintf(state_name
, sizeof(state_name
), "%s vs %s", left
, right
);
841 true_state
= alloc_compare_state(left
, left_vsl
, op
, right
, right_vsl
);
842 false_state
= alloc_compare_state(left
, left_vsl
, false_op
, right
, right_vsl
);
844 pre_stree
= clone_stree(__get_cur_stree());
845 update_tf_data(pre_stree
, left
, left_sym
, right
, right_sym
, true_state
->data
);
846 free_stree(&pre_stree
);
848 set_true_false_states(compare_id
, state_name
, NULL
, true_state
, false_state
);
849 save_link(expr
->left
, state_name
);
850 save_link(expr
->right
, state_name
);
856 static void add_comparison_var_sym(const char *left_name
,
857 struct var_sym_list
*left_vsl
,
859 const char *right_name
, struct var_sym_list
*right_vsl
)
861 struct smatch_state
*state
;
863 char state_name
[256];
865 if (strcmp(left_name
, right_name
) > 0) {
866 const char *tmp_name
= left_name
;
867 struct var_sym_list
*tmp_vsl
= left_vsl
;
869 left_name
= right_name
;
870 left_vsl
= right_vsl
;
871 right_name
= tmp_name
;
873 comparison
= flip_op(comparison
);
875 snprintf(state_name
, sizeof(state_name
), "%s vs %s", left_name
, right_name
);
876 state
= alloc_compare_state(left_name
, left_vsl
, comparison
, right_name
, right_vsl
);
878 set_state(compare_id
, state_name
, NULL
, state
);
880 FOR_EACH_PTR(left_vsl
, vs
) {
881 save_link_var_sym(vs
->var
, vs
->sym
, state_name
);
882 } END_FOR_EACH_PTR(vs
);
883 FOR_EACH_PTR(right_vsl
, vs
) {
884 save_link_var_sym(vs
->var
, vs
->sym
, state_name
);
885 } END_FOR_EACH_PTR(vs
);
888 static void add_comparison(struct expression
*left
, int comparison
, struct expression
*right
)
890 char *left_name
= NULL
;
891 char *right_name
= NULL
;
892 struct symbol
*left_sym
, *right_sym
;
893 struct var_sym_list
*left_vsl
, *right_vsl
;
894 struct smatch_state
*state
;
895 char state_name
[256];
897 left_name
= chunk_to_var_sym(left
, &left_sym
);
900 left_vsl
= expr_to_vsl(left
);
901 right_name
= chunk_to_var_sym(right
, &right_sym
);
904 right_vsl
= expr_to_vsl(right
);
906 if (strcmp(left_name
, right_name
) > 0) {
907 struct symbol
*tmp_sym
= left_sym
;
908 char *tmp_name
= left_name
;
909 struct var_sym_list
*tmp_vsl
= left_vsl
;
911 left_name
= right_name
;
912 left_sym
= right_sym
;
913 left_vsl
= right_vsl
;
914 right_name
= tmp_name
;
917 comparison
= flip_op(comparison
);
919 snprintf(state_name
, sizeof(state_name
), "%s vs %s", left_name
, right_name
);
920 state
= alloc_compare_state(left_name
, left_vsl
, comparison
, right_name
, right_vsl
);
922 set_state(compare_id
, state_name
, NULL
, state
);
923 save_link(left
, state_name
);
924 save_link(right
, state_name
);
927 free_string(left_name
);
928 free_string(right_name
);
931 static void match_assign_add(struct expression
*expr
)
933 struct expression
*right
;
934 struct expression
*r_left
, *r_right
;
935 sval_t left_tmp
, right_tmp
;
937 right
= strip_expr(expr
->right
);
938 r_left
= strip_expr(right
->left
);
939 r_right
= strip_expr(right
->right
);
941 get_absolute_min(r_left
, &left_tmp
);
942 get_absolute_min(r_right
, &right_tmp
);
944 if (left_tmp
.value
> 0)
945 add_comparison(expr
->left
, '>', r_right
);
946 else if (left_tmp
.value
== 0)
947 add_comparison(expr
->left
, SPECIAL_GTE
, r_right
);
949 if (right_tmp
.value
> 0)
950 add_comparison(expr
->left
, '>', r_left
);
951 else if (right_tmp
.value
== 0)
952 add_comparison(expr
->left
, SPECIAL_GTE
, r_left
);
955 static void match_assign_sub(struct expression
*expr
)
957 struct expression
*right
;
958 struct expression
*r_left
, *r_right
;
962 right
= strip_expr(expr
->right
);
963 r_left
= strip_expr(right
->left
);
964 r_right
= strip_expr(right
->right
);
966 if (get_absolute_min(r_right
, &min
) && sval_is_negative(min
))
969 comparison
= get_comparison(r_left
, r_right
);
971 switch (comparison
) {
974 if (implied_not_equal(r_right
, 0))
975 add_comparison(expr
->left
, '>', r_left
);
977 add_comparison(expr
->left
, SPECIAL_GTE
, r_left
);
982 static void match_assign_divide(struct expression
*expr
)
984 struct expression
*right
;
985 struct expression
*r_left
, *r_right
;
988 right
= strip_expr(expr
->right
);
989 r_left
= strip_expr(right
->left
);
990 r_right
= strip_expr(right
->right
);
991 if (!get_implied_min(r_right
, &min
) || min
.value
<= 1)
994 add_comparison(expr
->left
, '<', r_left
);
997 static void match_binop_assign(struct expression
*expr
)
999 struct expression
*right
;
1001 right
= strip_expr(expr
->right
);
1002 if (right
->op
== '+')
1003 match_assign_add(expr
);
1004 if (right
->op
== '-')
1005 match_assign_sub(expr
);
1006 if (right
->op
== '/')
1007 match_assign_divide(expr
);
1010 static void copy_comparisons(struct expression
*left
, struct expression
*right
)
1012 struct string_list
*links
;
1013 struct smatch_state
*state
;
1014 struct compare_data
*data
;
1015 struct symbol
*left_sym
, *right_sym
;
1016 char *left_var
= NULL
;
1017 char *right_var
= NULL
;
1018 struct var_sym_list
*left_vsl
;
1020 struct var_sym_list
*vsl
;
1024 left_var
= chunk_to_var_sym(left
, &left_sym
);
1027 left_vsl
= expr_to_vsl(left
);
1028 right_var
= chunk_to_var_sym(right
, &right_sym
);
1032 state
= get_state(link_id
, right_var
, right_sym
);
1035 links
= state
->data
;
1037 FOR_EACH_PTR(links
, tmp
) {
1038 state
= get_state(compare_id
, tmp
, NULL
);
1039 if (!state
|| !state
->data
)
1042 comparison
= data
->comparison
;
1045 if (chunk_vsl_eq(var
, vsl
, right_var
, NULL
)) {
1048 comparison
= flip_op(comparison
);
1050 add_comparison_var_sym(left_var
, left_vsl
, comparison
, var
, vsl
);
1051 } END_FOR_EACH_PTR(tmp
);
1054 free_string(right_var
);
1057 static void match_assign(struct expression
*expr
)
1059 struct expression
*right
;
1061 if (expr
->op
!= '=')
1064 if (is_struct(expr
->left
))
1067 copy_comparisons(expr
->left
, expr
->right
);
1068 add_comparison(expr
->left
, SPECIAL_EQUAL
, expr
->right
);
1070 right
= strip_expr(expr
->right
);
1071 if (right
->type
== EXPR_BINOP
)
1072 match_binop_assign(expr
);
1075 int get_comparison_strings(const char *one
, const char *two
)
1078 struct smatch_state
*state
;
1082 if (strcmp(one
, two
) == 0)
1083 return SPECIAL_EQUAL
;
1085 if (strcmp(one
, two
) > 0) {
1086 const char *tmp
= one
;
1093 snprintf(buf
, sizeof(buf
), "%s vs %s", one
, two
);
1094 state
= get_state(compare_id
, buf
, NULL
);
1096 ret
= state_to_comparison(state
);
1104 int get_comparison(struct expression
*a
, struct expression
*b
)
1110 one
= chunk_to_var(a
);
1113 two
= chunk_to_var(b
);
1117 ret
= get_comparison_strings(one
, two
);
1124 int possible_comparison(struct expression
*a
, int comparison
, struct expression
*b
)
1130 struct sm_state
*sm
;
1133 one
= chunk_to_var(a
);
1136 two
= chunk_to_var(b
);
1141 if (strcmp(one
, two
) == 0 && comparison
== SPECIAL_EQUAL
) {
1146 if (strcmp(one
, two
) > 0) {
1151 comparison
= flip_op(comparison
);
1154 snprintf(buf
, sizeof(buf
), "%s vs %s", one
, two
);
1155 sm
= get_sm_state(compare_id
, buf
, NULL
);
1159 FOR_EACH_PTR(sm
->possible
, sm
) {
1160 if (!sm
->state
->data
)
1162 saved
= ((struct compare_data
*)sm
->state
->data
)->comparison
;
1163 if (saved
== comparison
)
1165 if (comparison
== SPECIAL_EQUAL
&&
1166 (saved
== SPECIAL_LTE
||
1167 saved
== SPECIAL_GTE
||
1168 saved
== SPECIAL_UNSIGNED_LTE
||
1169 saved
== SPECIAL_UNSIGNED_GTE
))
1173 } END_FOR_EACH_PTR(sm
);
1182 static void update_links_from_call(struct expression
*left
,
1184 struct expression
*right
)
1186 struct string_list
*links
;
1187 struct smatch_state
*state
;
1188 struct compare_data
*data
;
1189 struct symbol
*left_sym
, *right_sym
;
1190 char *left_var
= NULL
;
1191 char *right_var
= NULL
;
1192 struct var_sym_list
*left_vsl
;
1194 struct var_sym_list
*vsl
;
1198 left_var
= chunk_to_var_sym(left
, &left_sym
);
1201 left_vsl
= expr_to_vsl(left
);
1202 right_var
= chunk_to_var_sym(right
, &right_sym
);
1206 state
= get_state(link_id
, right_var
, right_sym
);
1209 links
= state
->data
;
1211 FOR_EACH_PTR(links
, tmp
) {
1212 state
= get_state(compare_id
, tmp
, NULL
);
1213 if (!state
|| !state
->data
)
1216 comparison
= data
->comparison
;
1219 if (chunk_vsl_eq(var
, vsl
, right_var
, NULL
)) {
1222 comparison
= flip_op(comparison
);
1224 comparison
= combine_comparisons(left_compare
, comparison
);
1227 add_comparison_var_sym(left_var
, left_vsl
, comparison
, var
, vsl
);
1228 } END_FOR_EACH_PTR(tmp
);
1231 free_string(right_var
);
1234 void __add_comparison_info(struct expression
*expr
, struct expression
*call
, const char *range
)
1236 struct expression
*arg
;
1238 const char *c
= range
;
1240 if (!str_to_comparison_arg(c
, call
, &comparison
, &arg
))
1242 update_links_from_call(expr
, comparison
, arg
);
1243 add_comparison(expr
, comparison
, arg
);
1246 static char *range_comparison_to_param_helper(struct expression
*expr
, char starts_with
, int ignore
)
1248 struct symbol
*param
;
1251 char *ret_str
= NULL
;
1255 var
= chunk_to_var(expr
);
1260 FOR_EACH_PTR(cur_func_sym
->ctype
.base_type
->arguments
, param
) {
1266 snprintf(buf
, sizeof(buf
), "%s orig", param
->ident
->name
);
1267 compare
= get_comparison_strings(var
, buf
);
1270 if (show_special(compare
)[0] != starts_with
)
1272 snprintf(buf
, sizeof(buf
), "[%s$%d]", show_special(compare
), i
);
1273 ret_str
= alloc_sname(buf
);
1275 } END_FOR_EACH_PTR(param
);
1282 char *expr_equal_to_param(struct expression
*expr
, int ignore
)
1284 return range_comparison_to_param_helper(expr
, '=', ignore
);
1287 char *expr_lte_to_param(struct expression
*expr
, int ignore
)
1289 return range_comparison_to_param_helper(expr
, '<', ignore
);
1292 static void free_data(struct symbol
*sym
)
1296 clear_compare_data_alloc();
1299 void register_comparison(int id
)
1302 add_hook(&match_compare
, CONDITION_HOOK
);
1303 add_hook(&match_assign
, ASSIGNMENT_HOOK
);
1304 add_hook(&save_start_states
, AFTER_DEF_HOOK
);
1305 add_unmatched_state_hook(compare_id
, unmatched_comparison
);
1306 add_merge_hook(compare_id
, &merge_compare_states
);
1307 add_hook(&free_data
, AFTER_FUNC_HOOK
);
1310 void register_comparison_links(int id
)
1313 add_merge_hook(link_id
, &merge_links
);
1314 add_modification_hook(link_id
, &match_modify
);