2 * smatch/smatch_comparison.c
4 * Copyright (C) 2012 Oracle.
6 * Licensed under the Open Software License version 1.1
11 * The point here is to store the relationships between two variables.
13 * To do that we create a state with the two variables in alphabetical order:
14 * ->name = "x vs y" and the state would be "<". On the false path the state
17 * Part of the trick of it is that if x or y is modified then we need to reset
18 * the state. We need to keep a list of all the states which depend on x and
19 * all the states which depend on y. The link_id code handles this.
24 #include "smatch_extra.h"
25 #include "smatch_slist.h"
27 static int compare_id
;
32 struct var_sym_list
*vsl1
;
35 struct var_sym_list
*vsl2
;
37 ALLOCATOR(compare_data
, "compare data");
39 int chunk_vsl_eq(const char *a
, struct var_sym_list
*a_vsl
, const char *b
, struct var_sym_list
*b_vsl
)
41 if (strcmp(a
, b
) == 0)
46 static struct symbol
*vsl_to_sym(struct var_sym_list
*vsl
)
52 if (ptr_list_size((struct ptr_list
*)vsl
) != 1)
54 vs
= first_ptr_list((struct ptr_list
*)vsl
);
58 static struct smatch_state
*alloc_compare_state(
59 const char *var1
, struct var_sym_list
*vsl1
,
61 const char *var2
, struct var_sym_list
*vsl2
)
63 struct smatch_state
*state
;
64 struct compare_data
*data
;
66 state
= __alloc_smatch_state(0);
67 state
->name
= alloc_sname(show_special(comparison
));
68 data
= __alloc_compare_data(0);
69 data
->var1
= alloc_sname(var1
);
70 data
->vsl1
= clone_var_sym_list(vsl1
);
71 data
->comparison
= comparison
;
72 data
->var2
= alloc_sname(var2
);
73 data
->vsl2
= clone_var_sym_list(vsl2
);
78 static int state_to_comparison(struct smatch_state
*state
)
80 if (!state
|| !state
->data
)
82 return ((struct compare_data
*)state
->data
)->comparison
;
86 * flip_op() reverses the op left and right. So "x >= y" becomes "y <= x".
88 static int flip_op(int op
)
95 case SPECIAL_UNSIGNED_LT
:
96 return SPECIAL_UNSIGNED_GT
;
99 case SPECIAL_UNSIGNED_LTE
:
100 return SPECIAL_UNSIGNED_GTE
;
102 return SPECIAL_EQUAL
;
103 case SPECIAL_NOTEQUAL
:
104 return SPECIAL_NOTEQUAL
;
107 case SPECIAL_UNSIGNED_GTE
:
108 return SPECIAL_UNSIGNED_LTE
;
111 case SPECIAL_UNSIGNED_GT
:
112 return SPECIAL_UNSIGNED_LT
;
114 sm_msg("internal smatch bug. unhandled comparison %d", op
);
119 static int falsify_op(int op
)
126 case SPECIAL_UNSIGNED_LT
:
127 return SPECIAL_UNSIGNED_GTE
;
130 case SPECIAL_UNSIGNED_LTE
:
131 return SPECIAL_UNSIGNED_GT
;
133 return SPECIAL_NOTEQUAL
;
134 case SPECIAL_NOTEQUAL
:
135 return SPECIAL_EQUAL
;
138 case SPECIAL_UNSIGNED_GTE
:
139 return SPECIAL_UNSIGNED_LT
;
142 case SPECIAL_UNSIGNED_GT
:
143 return SPECIAL_UNSIGNED_LTE
;
145 sm_msg("internal smatch bug. unhandled comparison %d", op
);
150 static int rl_comparison(struct range_list
*left_rl
, struct range_list
*right_rl
)
152 sval_t left_min
, left_max
, right_min
, right_max
;
154 if (!left_rl
|| !right_rl
)
157 left_min
= rl_min(left_rl
);
158 left_max
= rl_max(left_rl
);
159 right_min
= rl_min(right_rl
);
160 right_max
= rl_max(right_rl
);
162 if (left_min
.value
== left_max
.value
&&
163 right_min
.value
== right_max
.value
&&
164 left_min
.value
== right_min
.value
)
165 return SPECIAL_EQUAL
;
167 if (sval_cmp(left_max
, right_min
) < 0)
169 if (sval_cmp(left_max
, right_min
) == 0)
171 if (sval_cmp(left_min
, right_max
) > 0)
173 if (sval_cmp(left_min
, right_max
) == 0)
179 static struct range_list
*get_orig_rl(struct var_sym_list
*vsl
)
182 struct smatch_state
*state
;
186 sym
= vsl_to_sym(vsl
);
187 if (!sym
|| !sym
->ident
)
189 state
= get_orig_estate(sym
->ident
->name
, sym
);
190 return estate_rl(state
);
193 static struct smatch_state
*unmatched_comparison(struct sm_state
*sm
)
195 struct compare_data
*data
= sm
->state
->data
;
196 struct range_list
*left_rl
, *right_rl
;
202 if (strstr(data
->var1
, " orig"))
203 left_rl
= get_orig_rl(data
->vsl1
);
204 else if (!get_implied_rl_var_sym(data
->var1
, vsl_to_sym(data
->vsl1
), &left_rl
))
206 if (strstr(data
->var2
, " orig"))
207 right_rl
= get_orig_rl(data
->vsl2
);
208 else if (!get_implied_rl_var_sym(data
->var2
, vsl_to_sym(data
->vsl2
), &right_rl
))
212 op
= rl_comparison(left_rl
, right_rl
);
214 return alloc_compare_state(data
->var1
, data
->vsl1
, op
, data
->var2
, data
->vsl2
);
219 /* remove_unsigned_from_comparison() is obviously a hack. */
220 static int remove_unsigned_from_comparison(int op
)
223 case SPECIAL_UNSIGNED_LT
:
225 case SPECIAL_UNSIGNED_LTE
:
227 case SPECIAL_UNSIGNED_GTE
:
229 case SPECIAL_UNSIGNED_GT
:
237 * This is for when you merge states "a < b" and "a == b", the result is that
238 * we can say for sure, "a <= b" after the merge.
240 static int merge_comparisons(int one
, int two
)
244 one
= remove_unsigned_from_comparison(one
);
245 two
= remove_unsigned_from_comparison(two
);
292 return SPECIAL_NOTEQUAL
;
303 * This is for if you have "a < b" and "b <= c". Or in other words,
304 * "a < b <= c". You would call this like get_combined_comparison('<', '<=').
305 * The return comparison would be '<'.
307 * This function is different from merge_comparisons(), for example:
308 * merge_comparison('<', '==') returns '<='
309 * get_combined_comparison('<', '==') returns '<'
311 static int combine_comparisons(int left_compare
, int right_compare
)
315 left_compare
= remove_unsigned_from_comparison(left_compare
);
316 right_compare
= remove_unsigned_from_comparison(right_compare
);
320 switch (left_compare
) {
329 return right_compare
;
338 switch (right_compare
) {
370 static struct smatch_state
*merge_compare_states(struct smatch_state
*s1
, struct smatch_state
*s2
)
372 struct compare_data
*data
= s1
->data
;
375 op
= merge_comparisons(state_to_comparison(s1
), state_to_comparison(s2
));
377 return alloc_compare_state(data
->var1
, data
->vsl1
, op
, data
->var2
, data
->vsl2
);
381 static struct smatch_state
*alloc_link_state(struct string_list
*links
)
383 struct smatch_state
*state
;
384 static char buf
[256];
388 state
= __alloc_smatch_state(0);
391 FOR_EACH_PTR(links
, tmp
) {
393 snprintf(buf
, sizeof(buf
), "%s", tmp
);
395 append(buf
, ", ", sizeof(buf
));
396 append(buf
, tmp
, sizeof(buf
));
398 } END_FOR_EACH_PTR(tmp
);
400 state
->name
= alloc_sname(buf
);
405 static void save_start_states(struct statement
*stmt
)
407 struct symbol
*param
;
409 char state_name
[128];
410 struct smatch_state
*state
;
411 struct string_list
*links
;
414 FOR_EACH_PTR(cur_func_sym
->ctype
.base_type
->arguments
, param
) {
415 struct var_sym_list
*vsl1
= NULL
;
416 struct var_sym_list
*vsl2
= NULL
;
420 snprintf(orig
, sizeof(orig
), "%s orig", param
->ident
->name
);
421 snprintf(state_name
, sizeof(state_name
), "%s vs %s", param
->ident
->name
, orig
);
422 add_var_sym(&vsl1
, param
->ident
->name
, param
);
423 add_var_sym(&vsl2
, orig
, param
);
424 state
= alloc_compare_state(param
->ident
->name
, vsl1
, SPECIAL_EQUAL
, alloc_sname(orig
), vsl2
);
425 set_state(compare_id
, state_name
, NULL
, state
);
427 link
= alloc_sname(state_name
);
429 insert_string(&links
, link
);
430 state
= alloc_link_state(links
);
431 set_state(link_id
, param
->ident
->name
, param
, state
);
432 } END_FOR_EACH_PTR(param
);
435 static struct smatch_state
*merge_links(struct smatch_state
*s1
, struct smatch_state
*s2
)
437 struct smatch_state
*ret
;
438 struct string_list
*links
;
440 links
= combine_string_lists(s1
->data
, s2
->data
);
441 ret
= alloc_link_state(links
);
445 static void save_link_var_sym(const char *var
, struct symbol
*sym
, const char *link
)
447 struct smatch_state
*old_state
, *new_state
;
448 struct string_list
*links
;
451 old_state
= get_state(link_id
, var
, sym
);
453 links
= clone_str_list(old_state
->data
);
457 new = alloc_sname(link
);
458 insert_string(&links
, new);
460 new_state
= alloc_link_state(links
);
461 set_state(link_id
, var
, sym
, new_state
);
464 static void match_inc(struct sm_state
*sm
)
466 struct string_list
*links
;
467 struct smatch_state
*state
;
470 links
= sm
->state
->data
;
472 FOR_EACH_PTR(links
, tmp
) {
473 state
= get_state(compare_id
, tmp
, NULL
);
475 switch (state_to_comparison(state
)) {
478 case SPECIAL_UNSIGNED_GTE
:
480 case SPECIAL_UNSIGNED_GT
: {
481 struct compare_data
*data
= state
->data
;
482 struct smatch_state
*new;
484 new = alloc_compare_state(data
->var1
, data
->vsl1
, '>', data
->var2
, data
->vsl2
);
485 set_state(compare_id
, tmp
, NULL
, new);
489 set_state(compare_id
, tmp
, NULL
, &undefined
);
491 } END_FOR_EACH_PTR(tmp
);
494 static void match_dec(struct sm_state
*sm
)
496 struct string_list
*links
;
497 struct smatch_state
*state
;
500 links
= sm
->state
->data
;
502 FOR_EACH_PTR(links
, tmp
) {
503 state
= get_state(compare_id
, tmp
, NULL
);
505 switch (state_to_comparison(state
)) {
508 case SPECIAL_UNSIGNED_LTE
:
510 case SPECIAL_UNSIGNED_LT
: {
511 struct compare_data
*data
= state
->data
;
512 struct smatch_state
*new;
514 new = alloc_compare_state(data
->var1
, data
->vsl1
, '<', data
->var2
, data
->vsl2
);
515 set_state(compare_id
, tmp
, NULL
, new);
519 set_state(compare_id
, tmp
, NULL
, &undefined
);
521 } END_FOR_EACH_PTR(tmp
);
524 static int match_inc_dec(struct sm_state
*sm
, struct expression
*mod_expr
)
528 if (mod_expr
->type
!= EXPR_PREOP
&& mod_expr
->type
!= EXPR_POSTOP
)
531 if (mod_expr
->op
== SPECIAL_INCREMENT
) {
535 if (mod_expr
->op
== SPECIAL_DECREMENT
) {
542 static void match_modify(struct sm_state
*sm
, struct expression
*mod_expr
)
544 struct string_list
*links
;
547 /* Huh??? This needs a comment! */
548 if (match_inc_dec(sm
, mod_expr
))
551 links
= sm
->state
->data
;
553 FOR_EACH_PTR(links
, tmp
) {
554 set_state(compare_id
, tmp
, NULL
, &undefined
);
555 } END_FOR_EACH_PTR(tmp
);
556 set_state(link_id
, sm
->name
, sm
->sym
, &undefined
);
559 static char *chunk_to_var_sym(struct expression
*expr
, struct symbol
**sym
)
561 char *name
, *left_name
, *right_name
;
565 expr
= strip_expr(expr
);
571 name
= expr_to_var_sym(expr
, &tmp
);
580 if (expr
->type
!= EXPR_BINOP
)
582 if (expr
->op
!= '-' && expr
->op
!= '+')
585 left_name
= expr_to_var(expr
->left
);
588 right_name
= expr_to_var(expr
->right
);
590 free_string(left_name
);
593 snprintf(buf
, sizeof(buf
), "%s %s %s", left_name
, show_special(expr
->op
), right_name
);
594 free_string(left_name
);
595 free_string(right_name
);
596 return alloc_string(buf
);
599 static char *chunk_to_var(struct expression
*expr
)
601 return chunk_to_var_sym(expr
, NULL
);
604 static void save_link(struct expression
*expr
, char *link
)
609 expr
= strip_expr(expr
);
610 if (expr
->type
== EXPR_BINOP
) {
613 chunk
= chunk_to_var(expr
);
617 save_link(expr
->left
, link
);
618 save_link(expr
->right
, link
);
619 save_link_var_sym(chunk
, NULL
, link
);
623 var
= expr_to_var_sym(expr
, &sym
);
627 save_link_var_sym(var
, sym
, link
);
632 static void update_tf_links(struct state_list
*pre_slist
,
633 const char *left_var
, struct var_sym_list
*left_vsl
,
635 const char *mid_var
, struct var_sym_list
*mid_vsl
,
636 struct string_list
*links
)
638 struct smatch_state
*state
;
639 struct smatch_state
*true_state
, *false_state
;
640 struct compare_data
*data
;
641 const char *right_var
;
642 struct var_sym_list
*right_vsl
;
643 int right_comparison
;
645 int false_comparison
;
647 char state_name
[256];
650 FOR_EACH_PTR(links
, tmp
) {
651 state
= get_state_slist(pre_slist
, compare_id
, tmp
, NULL
);
652 if (!state
|| !state
->data
)
655 right_comparison
= data
->comparison
;
656 right_var
= data
->var2
;
657 right_vsl
= data
->vsl2
;
658 if (chunk_vsl_eq(mid_var
, mid_vsl
, right_var
, right_vsl
)) {
659 right_var
= data
->var1
;
660 right_vsl
= data
->vsl1
;
661 right_comparison
= flip_op(right_comparison
);
663 true_comparison
= combine_comparisons(left_comparison
, right_comparison
);
664 false_comparison
= combine_comparisons(falsify_op(left_comparison
), right_comparison
);
666 if (strcmp(left_var
, right_var
) > 0) {
667 const char *tmp_var
= left_var
;
668 struct var_sym_list
*tmp_vsl
= left_vsl
;
670 left_var
= right_var
;
671 left_vsl
= right_vsl
;
674 true_comparison
= flip_op(true_comparison
);
675 false_comparison
= flip_op(false_comparison
);
678 if (!true_comparison
&& !false_comparison
)
682 true_state
= alloc_compare_state(left_var
, left_vsl
, true_comparison
, right_var
, right_vsl
);
685 if (false_comparison
)
686 false_state
= alloc_compare_state(left_var
, left_vsl
, false_comparison
, right_var
, right_vsl
);
690 snprintf(state_name
, sizeof(state_name
), "%s vs %s", left_var
, right_var
);
691 set_true_false_states(compare_id
, state_name
, NULL
, true_state
, false_state
);
692 FOR_EACH_PTR(left_vsl
, vs
) {
693 save_link_var_sym(vs
->var
, vs
->sym
, state_name
);
694 } END_FOR_EACH_PTR(vs
);
695 FOR_EACH_PTR(right_vsl
, vs
) {
696 save_link_var_sym(vs
->var
, vs
->sym
, state_name
);
697 } END_FOR_EACH_PTR(vs
);
698 if (!vsl_to_sym(left_vsl
))
699 save_link_var_sym(left_var
, NULL
, state_name
);
700 if (!vsl_to_sym(right_vsl
))
701 save_link_var_sym(right_var
, NULL
, state_name
);
702 } END_FOR_EACH_PTR(tmp
);
705 static void update_tf_data(struct state_list
*pre_slist
,
706 const char *left_name
, struct symbol
*left_sym
,
707 const char *right_name
, struct symbol
*right_sym
,
708 struct compare_data
*tdata
)
710 struct smatch_state
*state
;
712 state
= get_state_slist(pre_slist
, link_id
, tdata
->var2
, vsl_to_sym(tdata
->vsl2
));
714 update_tf_links(pre_slist
, tdata
->var1
, tdata
->vsl1
, tdata
->comparison
, tdata
->var2
, tdata
->vsl2
, state
->data
);
716 state
= get_state_slist(pre_slist
, link_id
, tdata
->var1
, vsl_to_sym(tdata
->vsl1
));
718 update_tf_links(pre_slist
, tdata
->var2
, tdata
->vsl2
, flip_op(tdata
->comparison
), tdata
->var1
, tdata
->vsl1
, state
->data
);
721 static void match_compare(struct expression
*expr
)
725 struct symbol
*left_sym
, *right_sym
;
726 struct var_sym_list
*left_vsl
, *right_vsl
;
728 struct smatch_state
*true_state
, *false_state
;
729 char state_name
[256];
730 struct state_list
*pre_slist
;
732 if (expr
->type
!= EXPR_COMPARE
)
734 left
= chunk_to_var_sym(expr
->left
, &left_sym
);
737 left_vsl
= expr_to_vsl(expr
->left
);
738 right
= chunk_to_var_sym(expr
->right
, &right_sym
);
741 right_vsl
= expr_to_vsl(expr
->right
);
743 if (strcmp(left
, right
) > 0) {
744 struct symbol
*tmp_sym
= left_sym
;
745 char *tmp_name
= left
;
746 struct var_sym_list
*tmp_vsl
= left_vsl
;
749 left_sym
= right_sym
;
750 left_vsl
= right_vsl
;
754 op
= flip_op(expr
->op
);
758 false_op
= falsify_op(op
);
759 snprintf(state_name
, sizeof(state_name
), "%s vs %s", left
, right
);
760 true_state
= alloc_compare_state(left
, left_vsl
, op
, right
, right_vsl
);
761 false_state
= alloc_compare_state(left
, left_vsl
, false_op
, right
, right_vsl
);
763 pre_slist
= clone_slist(__get_cur_slist());
764 update_tf_data(pre_slist
, left
, left_sym
, right
, right_sym
, true_state
->data
);
765 free_slist(&pre_slist
);
767 set_true_false_states(compare_id
, state_name
, NULL
, true_state
, false_state
);
768 save_link(expr
->left
, state_name
);
769 save_link(expr
->right
, state_name
);
775 static void add_comparison_var_sym(const char *left_name
,
776 struct var_sym_list
*left_vsl
,
778 const char *right_name
, struct var_sym_list
*right_vsl
)
780 struct smatch_state
*state
;
782 char state_name
[256];
784 if (strcmp(left_name
, right_name
) > 0) {
785 const char *tmp_name
= left_name
;
786 struct var_sym_list
*tmp_vsl
= left_vsl
;
788 left_name
= right_name
;
789 left_vsl
= right_vsl
;
790 right_name
= tmp_name
;
792 comparison
= flip_op(comparison
);
794 snprintf(state_name
, sizeof(state_name
), "%s vs %s", left_name
, right_name
);
795 state
= alloc_compare_state(left_name
, left_vsl
, comparison
, right_name
, right_vsl
);
797 set_state(compare_id
, state_name
, NULL
, state
);
799 FOR_EACH_PTR(left_vsl
, vs
) {
800 save_link_var_sym(vs
->var
, vs
->sym
, state_name
);
801 } END_FOR_EACH_PTR(vs
);
802 FOR_EACH_PTR(right_vsl
, vs
) {
803 save_link_var_sym(vs
->var
, vs
->sym
, state_name
);
804 } END_FOR_EACH_PTR(vs
);
807 static void add_comparison(struct expression
*left
, int comparison
, struct expression
*right
)
809 char *left_name
= NULL
;
810 char *right_name
= NULL
;
811 struct symbol
*left_sym
, *right_sym
;
812 struct var_sym_list
*left_vsl
, *right_vsl
;
813 struct smatch_state
*state
;
814 char state_name
[256];
816 left_name
= chunk_to_var_sym(left
, &left_sym
);
819 left_vsl
= expr_to_vsl(left
);
820 right_name
= chunk_to_var_sym(right
, &right_sym
);
823 right_vsl
= expr_to_vsl(right
);
825 if (strcmp(left_name
, right_name
) > 0) {
826 struct symbol
*tmp_sym
= left_sym
;
827 char *tmp_name
= left_name
;
828 struct var_sym_list
*tmp_vsl
= left_vsl
;
830 left_name
= right_name
;
831 left_sym
= right_sym
;
832 left_vsl
= right_vsl
;
833 right_name
= tmp_name
;
836 comparison
= flip_op(comparison
);
838 snprintf(state_name
, sizeof(state_name
), "%s vs %s", left_name
, right_name
);
839 state
= alloc_compare_state(left_name
, left_vsl
, comparison
, right_name
, right_vsl
);
841 set_state(compare_id
, state_name
, NULL
, state
);
842 save_link(left
, state_name
);
843 save_link(right
, state_name
);
846 free_string(left_name
);
847 free_string(right_name
);
850 static void match_assign_add(struct expression
*expr
)
852 struct expression
*right
;
853 struct expression
*r_left
, *r_right
;
854 sval_t left_tmp
, right_tmp
;
856 right
= strip_expr(expr
->right
);
857 r_left
= strip_expr(right
->left
);
858 r_right
= strip_expr(right
->right
);
860 get_absolute_min(r_left
, &left_tmp
);
861 get_absolute_min(r_right
, &right_tmp
);
863 if (left_tmp
.value
> 0)
864 add_comparison(expr
->left
, '>', r_right
);
865 else if (left_tmp
.value
== 0)
866 add_comparison(expr
->left
, SPECIAL_GTE
, r_right
);
868 if (right_tmp
.value
> 0)
869 add_comparison(expr
->left
, '>', r_left
);
870 else if (right_tmp
.value
== 0)
871 add_comparison(expr
->left
, SPECIAL_GTE
, r_left
);
874 static void match_assign_sub(struct expression
*expr
)
876 struct expression
*right
;
877 struct expression
*r_left
, *r_right
;
881 right
= strip_expr(expr
->right
);
882 r_left
= strip_expr(right
->left
);
883 r_right
= strip_expr(right
->right
);
885 if (get_absolute_min(r_right
, &min
) && sval_is_negative(min
))
888 comparison
= get_comparison(r_left
, r_right
);
890 switch (comparison
) {
893 if (implied_not_equal(r_right
, 0))
894 add_comparison(expr
->left
, '>', r_left
);
896 add_comparison(expr
->left
, SPECIAL_GTE
, r_left
);
901 static void match_assign_divide(struct expression
*expr
)
903 struct expression
*right
;
904 struct expression
*r_left
, *r_right
;
907 right
= strip_expr(expr
->right
);
908 r_left
= strip_expr(right
->left
);
909 r_right
= strip_expr(right
->right
);
910 if (!get_implied_min(r_right
, &min
) || min
.value
<= 1)
913 add_comparison(expr
->left
, '<', r_left
);
916 static void match_binop_assign(struct expression
*expr
)
918 struct expression
*right
;
920 right
= strip_expr(expr
->right
);
921 if (right
->op
== '+')
922 match_assign_add(expr
);
923 if (right
->op
== '-')
924 match_assign_sub(expr
);
925 if (right
->op
== '/')
926 match_assign_divide(expr
);
929 static void copy_comparisons(struct expression
*left
, struct expression
*right
)
931 struct string_list
*links
;
932 struct smatch_state
*state
;
933 struct compare_data
*data
;
934 struct symbol
*left_sym
, *right_sym
;
935 char *left_var
= NULL
;
936 char *right_var
= NULL
;
937 struct var_sym_list
*left_vsl
;
939 struct var_sym_list
*vsl
;
943 left_var
= chunk_to_var_sym(left
, &left_sym
);
946 left_vsl
= expr_to_vsl(left
);
947 right_var
= chunk_to_var_sym(right
, &right_sym
);
951 state
= get_state(link_id
, right_var
, right_sym
);
956 FOR_EACH_PTR(links
, tmp
) {
957 state
= get_state(compare_id
, tmp
, NULL
);
958 if (!state
|| !state
->data
)
961 comparison
= data
->comparison
;
964 if (chunk_vsl_eq(var
, vsl
, right_var
, NULL
)) {
967 comparison
= flip_op(comparison
);
969 add_comparison_var_sym(left_var
, left_vsl
, comparison
, var
, vsl
);
970 } END_FOR_EACH_PTR(tmp
);
973 free_string(right_var
);
976 static void match_assign(struct expression
*expr
)
978 struct expression
*right
;
983 copy_comparisons(expr
->left
, expr
->right
);
984 add_comparison(expr
->left
, SPECIAL_EQUAL
, expr
->right
);
986 right
= strip_expr(expr
->right
);
987 if (right
->type
== EXPR_BINOP
)
988 match_binop_assign(expr
);
991 int get_comparison_strings(const char *one
, const char *two
)
994 struct smatch_state
*state
;
998 if (strcmp(one
, two
) > 0) {
999 const char *tmp
= one
;
1006 snprintf(buf
, sizeof(buf
), "%s vs %s", one
, two
);
1007 state
= get_state(compare_id
, buf
, NULL
);
1009 ret
= state_to_comparison(state
);
1017 int get_comparison(struct expression
*a
, struct expression
*b
)
1023 one
= chunk_to_var(a
);
1026 two
= chunk_to_var(b
);
1030 ret
= get_comparison_strings(one
, two
);
1037 static void update_links_from_call(struct expression
*left
,
1039 struct expression
*right
)
1041 struct string_list
*links
;
1042 struct smatch_state
*state
;
1043 struct compare_data
*data
;
1044 struct symbol
*left_sym
, *right_sym
;
1045 char *left_var
= NULL
;
1046 char *right_var
= NULL
;
1047 struct var_sym_list
*left_vsl
;
1049 struct var_sym_list
*vsl
;
1053 left_var
= chunk_to_var_sym(left
, &left_sym
);
1056 left_vsl
= expr_to_vsl(left
);
1057 right_var
= chunk_to_var_sym(right
, &right_sym
);
1061 state
= get_state(link_id
, right_var
, right_sym
);
1064 links
= state
->data
;
1066 FOR_EACH_PTR(links
, tmp
) {
1067 state
= get_state(compare_id
, tmp
, NULL
);
1068 if (!state
|| !state
->data
)
1071 comparison
= data
->comparison
;
1074 if (chunk_vsl_eq(var
, vsl
, right_var
, NULL
)) {
1077 comparison
= flip_op(comparison
);
1079 comparison
= combine_comparisons(left_compare
, comparison
);
1082 add_comparison_var_sym(left_var
, left_vsl
, comparison
, var
, vsl
);
1083 } END_FOR_EACH_PTR(tmp
);
1086 free_string(right_var
);
1089 void __add_comparison_info(struct expression
*expr
, struct expression
*call
, const char *range
)
1091 struct expression
*arg
;
1093 const char *c
= range
;
1095 if (!str_to_comparison_arg(c
, call
, &comparison
, &arg
))
1097 update_links_from_call(expr
, comparison
, arg
);
1098 add_comparison(expr
, comparison
, arg
);
1101 static char *range_comparison_to_param_helper(struct expression
*expr
, char starts_with
)
1103 struct symbol
*param
;
1106 char *ret_str
= NULL
;
1110 var
= chunk_to_var(expr
);
1115 FOR_EACH_PTR(cur_func_sym
->ctype
.base_type
->arguments
, param
) {
1119 snprintf(buf
, sizeof(buf
), "%s orig", param
->ident
->name
);
1120 compare
= get_comparison_strings(var
, buf
);
1123 if (show_special(compare
)[0] != starts_with
)
1125 snprintf(buf
, sizeof(buf
), "[%sp%d]", show_special(compare
), i
);
1126 ret_str
= alloc_sname(buf
);
1128 } END_FOR_EACH_PTR(param
);
1135 char *expr_equal_to_param(struct expression
*expr
)
1137 return range_comparison_to_param_helper(expr
, '=');
1140 char *expr_lte_to_param(struct expression
*expr
)
1142 return range_comparison_to_param_helper(expr
, '<');
1145 static void free_data(struct symbol
*sym
)
1149 clear_compare_data_alloc();
1152 void register_comparison(int id
)
1155 add_hook(&match_compare
, CONDITION_HOOK
);
1156 add_hook(&match_assign
, ASSIGNMENT_HOOK
);
1157 add_hook(&save_start_states
, AFTER_DEF_HOOK
);
1158 add_unmatched_state_hook(compare_id
, unmatched_comparison
);
1159 add_merge_hook(compare_id
, &merge_compare_states
);
1160 add_hook(&free_data
, AFTER_FUNC_HOOK
);
1163 void register_comparison_links(int id
)
1166 add_merge_hook(link_id
, &merge_links
);
1167 add_modification_hook(link_id
, &match_modify
);