1*1f5207b7SJohn Levon /*
2*1f5207b7SJohn Levon  * Copyright (C) 2010 Dan Carpenter.
3*1f5207b7SJohn Levon  *
4*1f5207b7SJohn Levon  * This program is free software; you can redistribute it and/or
5*1f5207b7SJohn Levon  * modify it under the terms of the GNU General Public License
6*1f5207b7SJohn Levon  * as published by the Free Software Foundation; either version 2
7*1f5207b7SJohn Levon  * of the License, or (at your option) any later version.
8*1f5207b7SJohn Levon  *
9*1f5207b7SJohn Levon  * This program is distributed in the hope that it will be useful,
10*1f5207b7SJohn Levon  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11*1f5207b7SJohn Levon  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12*1f5207b7SJohn Levon  * GNU General Public License for more details.
13*1f5207b7SJohn Levon  *
14*1f5207b7SJohn Levon  * You should have received a copy of the GNU General Public License
15*1f5207b7SJohn Levon  * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
16*1f5207b7SJohn Levon  */
17*1f5207b7SJohn Levon 
18*1f5207b7SJohn Levon /*
19*1f5207b7SJohn Levon  * smatch_equiv.c is for tracking how variables are the same
20*1f5207b7SJohn Levon  *
21*1f5207b7SJohn Levon  * if (a == b) {
22*1f5207b7SJohn Levon  * Or
23*1f5207b7SJohn Levon  * x = y;
24*1f5207b7SJohn Levon  *
25*1f5207b7SJohn Levon  * When a variable gets modified all the old relationships are
26*1f5207b7SJohn Levon  * deleted.  remove_equiv(expr);
27*1f5207b7SJohn Levon  *
28*1f5207b7SJohn Levon  */
29*1f5207b7SJohn Levon 
30*1f5207b7SJohn Levon #include "smatch.h"
31*1f5207b7SJohn Levon #include "smatch_slist.h"
32*1f5207b7SJohn Levon #include "smatch_extra.h"
33*1f5207b7SJohn Levon 
34*1f5207b7SJohn Levon ALLOCATOR(relation, "related variables");
35*1f5207b7SJohn Levon 
36*1f5207b7SJohn Levon static struct relation *alloc_relation(const char *name, struct symbol *sym)
37*1f5207b7SJohn Levon {
38*1f5207b7SJohn Levon 	struct relation *tmp;
39*1f5207b7SJohn Levon 
40*1f5207b7SJohn Levon 	tmp = __alloc_relation(0);
41*1f5207b7SJohn Levon 	tmp->name = alloc_string(name);
42*1f5207b7SJohn Levon 	tmp->sym = sym;
43*1f5207b7SJohn Levon 	return tmp;
44*1f5207b7SJohn Levon }
45*1f5207b7SJohn Levon 
46*1f5207b7SJohn Levon struct related_list *clone_related_list(struct related_list *related)
47*1f5207b7SJohn Levon {
48*1f5207b7SJohn Levon 	struct relation *rel;
49*1f5207b7SJohn Levon 	struct related_list *to_list = NULL;
50*1f5207b7SJohn Levon 
51*1f5207b7SJohn Levon 	FOR_EACH_PTR(related, rel) {
52*1f5207b7SJohn Levon 		add_ptr_list(&to_list, rel);
53*1f5207b7SJohn Levon 	} END_FOR_EACH_PTR(rel);
54*1f5207b7SJohn Levon 
55*1f5207b7SJohn Levon 	return to_list;
56*1f5207b7SJohn Levon }
57*1f5207b7SJohn Levon 
58*1f5207b7SJohn Levon static int cmp_relation(struct relation *a, struct relation *b)
59*1f5207b7SJohn Levon {
60*1f5207b7SJohn Levon 	int ret;
61*1f5207b7SJohn Levon 
62*1f5207b7SJohn Levon 	if (a == b)
63*1f5207b7SJohn Levon 		return 0;
64*1f5207b7SJohn Levon 
65*1f5207b7SJohn Levon 	if (a->sym > b->sym)
66*1f5207b7SJohn Levon 		return -1;
67*1f5207b7SJohn Levon 	if (a->sym < b->sym)
68*1f5207b7SJohn Levon 		return 1;
69*1f5207b7SJohn Levon 
70*1f5207b7SJohn Levon 	ret = strcmp(a->name, b->name);
71*1f5207b7SJohn Levon 	if (ret)
72*1f5207b7SJohn Levon 		return ret;
73*1f5207b7SJohn Levon 
74*1f5207b7SJohn Levon 	return 0;
75*1f5207b7SJohn Levon }
76*1f5207b7SJohn Levon 
77*1f5207b7SJohn Levon struct related_list *get_shared_relations(struct related_list *one,
78*1f5207b7SJohn Levon 					      struct related_list *two)
79*1f5207b7SJohn Levon {
80*1f5207b7SJohn Levon 	struct related_list *ret = NULL;
81*1f5207b7SJohn Levon 	struct relation *one_rel;
82*1f5207b7SJohn Levon 	struct relation *two_rel;
83*1f5207b7SJohn Levon 
84*1f5207b7SJohn Levon 	PREPARE_PTR_LIST(one, one_rel);
85*1f5207b7SJohn Levon 	PREPARE_PTR_LIST(two, two_rel);
86*1f5207b7SJohn Levon 	for (;;) {
87*1f5207b7SJohn Levon 		if (!one_rel || !two_rel)
88*1f5207b7SJohn Levon 			break;
89*1f5207b7SJohn Levon 		if (cmp_relation(one_rel, two_rel) < 0) {
90*1f5207b7SJohn Levon 			NEXT_PTR_LIST(one_rel);
91*1f5207b7SJohn Levon 		} else if (cmp_relation(one_rel, two_rel) == 0) {
92*1f5207b7SJohn Levon 			add_ptr_list(&ret, one_rel);
93*1f5207b7SJohn Levon 			NEXT_PTR_LIST(one_rel);
94*1f5207b7SJohn Levon 			NEXT_PTR_LIST(two_rel);
95*1f5207b7SJohn Levon 		} else {
96*1f5207b7SJohn Levon 			NEXT_PTR_LIST(two_rel);
97*1f5207b7SJohn Levon 		}
98*1f5207b7SJohn Levon 	}
99*1f5207b7SJohn Levon 	FINISH_PTR_LIST(two_rel);
100*1f5207b7SJohn Levon 	FINISH_PTR_LIST(one_rel);
101*1f5207b7SJohn Levon 
102*1f5207b7SJohn Levon 	return ret;
103*1f5207b7SJohn Levon }
104*1f5207b7SJohn Levon 
105*1f5207b7SJohn Levon static void debug_addition(struct related_list *rlist, const char *name)
106*1f5207b7SJohn Levon {
107*1f5207b7SJohn Levon 	struct relation *tmp;
108*1f5207b7SJohn Levon 
109*1f5207b7SJohn Levon 	if (!option_debug_related)
110*1f5207b7SJohn Levon 		return;
111*1f5207b7SJohn Levon 
112*1f5207b7SJohn Levon 	sm_prefix();
113*1f5207b7SJohn Levon 	sm_printf("(");
114*1f5207b7SJohn Levon 	FOR_EACH_PTR(rlist, tmp) {
115*1f5207b7SJohn Levon 		sm_printf("%s ", tmp->name);
116*1f5207b7SJohn Levon 	} END_FOR_EACH_PTR(tmp);
117*1f5207b7SJohn Levon 	sm_printf(") <-- %s\n", name);
118*1f5207b7SJohn Levon }
119*1f5207b7SJohn Levon 
120*1f5207b7SJohn Levon static void add_related(struct related_list **rlist, const char *name, struct symbol *sym)
121*1f5207b7SJohn Levon {
122*1f5207b7SJohn Levon 	struct relation *rel;
123*1f5207b7SJohn Levon 	struct relation *new;
124*1f5207b7SJohn Levon 	struct relation tmp = {
125*1f5207b7SJohn Levon 		.name = (char *)name,
126*1f5207b7SJohn Levon 		.sym = sym
127*1f5207b7SJohn Levon 	};
128*1f5207b7SJohn Levon 
129*1f5207b7SJohn Levon 	debug_addition(*rlist, name);
130*1f5207b7SJohn Levon 
131*1f5207b7SJohn Levon 	FOR_EACH_PTR(*rlist, rel) {
132*1f5207b7SJohn Levon 		if (cmp_relation(rel, &tmp) < 0)
133*1f5207b7SJohn Levon 			continue;
134*1f5207b7SJohn Levon 		if (cmp_relation(rel, &tmp) == 0)
135*1f5207b7SJohn Levon 			return;
136*1f5207b7SJohn Levon 		new = alloc_relation(name, sym);
137*1f5207b7SJohn Levon 		INSERT_CURRENT(new, rel);
138*1f5207b7SJohn Levon 		return;
139*1f5207b7SJohn Levon 	} END_FOR_EACH_PTR(rel);
140*1f5207b7SJohn Levon 	new = alloc_relation(name, sym);
141*1f5207b7SJohn Levon 	add_ptr_list(rlist, new);
142*1f5207b7SJohn Levon }
143*1f5207b7SJohn Levon 
144*1f5207b7SJohn Levon static struct related_list *del_related(struct smatch_state *state, const char *name, struct symbol *sym)
145*1f5207b7SJohn Levon {
146*1f5207b7SJohn Levon 	struct relation *tmp;
147*1f5207b7SJohn Levon 	struct relation remove = {
148*1f5207b7SJohn Levon 		.name = (char *)name,
149*1f5207b7SJohn Levon 		.sym = sym,
150*1f5207b7SJohn Levon 	};
151*1f5207b7SJohn Levon 	struct related_list *ret = NULL;
152*1f5207b7SJohn Levon 
153*1f5207b7SJohn Levon 	FOR_EACH_PTR(estate_related(state), tmp) {
154*1f5207b7SJohn Levon 		if (cmp_relation(tmp, &remove) != 0)
155*1f5207b7SJohn Levon 			add_ptr_list(&ret, tmp);
156*1f5207b7SJohn Levon 	} END_FOR_EACH_PTR(tmp);
157*1f5207b7SJohn Levon 
158*1f5207b7SJohn Levon 	return ret;
159*1f5207b7SJohn Levon }
160*1f5207b7SJohn Levon 
161*1f5207b7SJohn Levon void remove_from_equiv(const char *name, struct symbol *sym)
162*1f5207b7SJohn Levon {
163*1f5207b7SJohn Levon 	struct sm_state *orig_sm;
164*1f5207b7SJohn Levon 	struct relation *rel;
165*1f5207b7SJohn Levon 	struct smatch_state *state;
166*1f5207b7SJohn Levon 	struct related_list *to_update;
167*1f5207b7SJohn Levon 
168*1f5207b7SJohn Levon 	orig_sm = get_sm_state(SMATCH_EXTRA, name, sym);
169*1f5207b7SJohn Levon 	if (!orig_sm || !get_dinfo(orig_sm->state)->related)
170*1f5207b7SJohn Levon 		return;
171*1f5207b7SJohn Levon 
172*1f5207b7SJohn Levon 	state = clone_estate(orig_sm->state);
173*1f5207b7SJohn Levon 	to_update = del_related(state, name, sym);
174*1f5207b7SJohn Levon 
175*1f5207b7SJohn Levon 	FOR_EACH_PTR(to_update, rel) {
176*1f5207b7SJohn Levon 		struct sm_state *old_sm, *new_sm;
177*1f5207b7SJohn Levon 
178*1f5207b7SJohn Levon 		old_sm = get_sm_state(SMATCH_EXTRA, rel->name, rel->sym);
179*1f5207b7SJohn Levon 		if (!old_sm)
180*1f5207b7SJohn Levon 			continue;
181*1f5207b7SJohn Levon 
182*1f5207b7SJohn Levon 		new_sm = clone_sm(old_sm);
183*1f5207b7SJohn Levon 		get_dinfo(new_sm->state)->related = to_update;
184*1f5207b7SJohn Levon 		__set_sm(new_sm);
185*1f5207b7SJohn Levon 	} END_FOR_EACH_PTR(rel);
186*1f5207b7SJohn Levon }
187*1f5207b7SJohn Levon 
188*1f5207b7SJohn Levon void remove_from_equiv_expr(struct expression *expr)
189*1f5207b7SJohn Levon {
190*1f5207b7SJohn Levon 	char *name;
191*1f5207b7SJohn Levon 	struct symbol *sym;
192*1f5207b7SJohn Levon 
193*1f5207b7SJohn Levon 	name = expr_to_var_sym(expr, &sym);
194*1f5207b7SJohn Levon 	if (!name || !sym)
195*1f5207b7SJohn Levon 		goto free;
196*1f5207b7SJohn Levon 	remove_from_equiv(name, sym);
197*1f5207b7SJohn Levon free:
198*1f5207b7SJohn Levon 	free_string(name);
199*1f5207b7SJohn Levon }
200*1f5207b7SJohn Levon 
201*1f5207b7SJohn Levon void set_related(struct smatch_state *estate, struct related_list *rlist)
202*1f5207b7SJohn Levon {
203*1f5207b7SJohn Levon 	if (!estate_related(estate) && !rlist)
204*1f5207b7SJohn Levon 		return;
205*1f5207b7SJohn Levon 	get_dinfo(estate)->related = rlist;
206*1f5207b7SJohn Levon }
207*1f5207b7SJohn Levon 
208*1f5207b7SJohn Levon /*
209*1f5207b7SJohn Levon  * set_equiv() is only used for assignments where we set one variable
210*1f5207b7SJohn Levon  * equal to the other.  a = b;.  It's not used for if conditions where
211*1f5207b7SJohn Levon  * a == b.
212*1f5207b7SJohn Levon  */
213*1f5207b7SJohn Levon void set_equiv(struct expression *left, struct expression *right)
214*1f5207b7SJohn Levon {
215*1f5207b7SJohn Levon 	struct sm_state *right_sm, *left_sm;
216*1f5207b7SJohn Levon 	struct relation *rel;
217*1f5207b7SJohn Levon 	char *left_name;
218*1f5207b7SJohn Levon 	struct symbol *left_sym;
219*1f5207b7SJohn Levon 	struct related_list *rlist;
220*1f5207b7SJohn Levon 
221*1f5207b7SJohn Levon 	left_name = expr_to_var_sym(left, &left_sym);
222*1f5207b7SJohn Levon 	if (!left_name || !left_sym)
223*1f5207b7SJohn Levon 		goto free;
224*1f5207b7SJohn Levon 
225*1f5207b7SJohn Levon 	right_sm = get_sm_state_expr(SMATCH_EXTRA, right);
226*1f5207b7SJohn Levon 	if (!right_sm)
227*1f5207b7SJohn Levon 		right_sm = set_state_expr(SMATCH_EXTRA, right, alloc_estate_whole(get_type(right)));
228*1f5207b7SJohn Levon 	if (!right_sm)
229*1f5207b7SJohn Levon 		goto free;
230*1f5207b7SJohn Levon 
231*1f5207b7SJohn Levon 	/* This block is because we want to preserve the implications. */
232*1f5207b7SJohn Levon 	left_sm = clone_sm(right_sm);
233*1f5207b7SJohn Levon 	left_sm->name = alloc_string(left_name);
234*1f5207b7SJohn Levon 	left_sm->sym = left_sym;
235*1f5207b7SJohn Levon 	left_sm->state = clone_estate_cast(get_type(left), right_sm->state);
236*1f5207b7SJohn Levon 	set_extra_mod_helper(left_name, left_sym, left, left_sm->state);
237*1f5207b7SJohn Levon 	__set_sm(left_sm);
238*1f5207b7SJohn Levon 
239*1f5207b7SJohn Levon 	rlist = clone_related_list(estate_related(right_sm->state));
240*1f5207b7SJohn Levon 	add_related(&rlist, right_sm->name, right_sm->sym);
241*1f5207b7SJohn Levon 	add_related(&rlist, left_name, left_sym);
242*1f5207b7SJohn Levon 
243*1f5207b7SJohn Levon 	FOR_EACH_PTR(rlist, rel) {
244*1f5207b7SJohn Levon 		struct sm_state *old_sm, *new_sm;
245*1f5207b7SJohn Levon 
246*1f5207b7SJohn Levon 		old_sm = get_sm_state(SMATCH_EXTRA, rel->name, rel->sym);
247*1f5207b7SJohn Levon 		if (!old_sm)  /* shouldn't happen */
248*1f5207b7SJohn Levon 			continue;
249*1f5207b7SJohn Levon 		new_sm = clone_sm(old_sm);
250*1f5207b7SJohn Levon 		new_sm->state = clone_estate(old_sm->state);
251*1f5207b7SJohn Levon 		get_dinfo(new_sm->state)->related = rlist;
252*1f5207b7SJohn Levon 		__set_sm(new_sm);
253*1f5207b7SJohn Levon 	} END_FOR_EACH_PTR(rel);
254*1f5207b7SJohn Levon free:
255*1f5207b7SJohn Levon 	free_string(left_name);
256*1f5207b7SJohn Levon }
257*1f5207b7SJohn Levon 
258*1f5207b7SJohn Levon void set_equiv_state_expr(int id, struct expression *expr, struct smatch_state *state)
259*1f5207b7SJohn Levon {
260*1f5207b7SJohn Levon 	struct relation *rel;
261*1f5207b7SJohn Levon 	struct smatch_state *estate;
262*1f5207b7SJohn Levon 
263*1f5207b7SJohn Levon 	estate = get_state_expr(SMATCH_EXTRA, expr);
264*1f5207b7SJohn Levon 
265*1f5207b7SJohn Levon 	if (!estate)
266*1f5207b7SJohn Levon 		return;
267*1f5207b7SJohn Levon 
268*1f5207b7SJohn Levon 	FOR_EACH_PTR(get_dinfo(estate)->related, rel) {
269*1f5207b7SJohn Levon 		set_state(id, rel->name, rel->sym, state);
270*1f5207b7SJohn Levon 	} END_FOR_EACH_PTR(rel);
271*1f5207b7SJohn Levon }
272