unwind: use the shared success_fail_return() function
[smatch.git] / smatch_ssa.c
blob2939dcc047affef24fbd7212e50f3aef2808ff9a
1 /*
2 * Copyright (C) 2021 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 truth is I don't know very much about compilers. I've heard about
20 * Single Static Assignment and it seems like a useful feature but it's also
21 * possible I have misunderstood the whole thing.
23 * Anyway, the point is that say we have code like:
24 * ret = alloc();
25 * if (ret < 0)
26 * return ret;
27 * p->foo = ret;
28 * ret = something else;
30 * So the problem here is "p->foo" and "ret" are equivalent at first but then
31 * not at the end. We don't really care if "p->foo" is freed or "ret" is freed,
32 * we care if the value which was initially stored in "ret" is freed. This is
33 * different from equiv because "ret" and "p->foo" are not equiv at the end.
34 * The SSA module doesn't deal with == only with =.
36 * Using this is a bit different and more complicated than I would like. If
37 * there is a new state then call set_ssa_state(). When you're getting the
38 * state it's probably easiest to always use get_ssa_sm_state() because
39 * afterwards you will need to call update_ssa_state(my_id, sm->name, sm->sym,
40 * &state); to change the state. If you call set_ssa_state() that basically
41 * works too but it's slower because it adds a layer of indirection.
45 #include "smatch.h"
46 #include "smatch_extra.h"
47 #include "smatch_slist.h"
49 static int my_id;
51 static unsigned long ssa_id = 1;
53 char *ssa_name(const char *name)
55 char *ret;
56 char *p;
58 ret = alloc_sname(name);
59 p = strchr(ret, ':');
60 if (p)
61 *p = '\0';
62 return ret;
65 static void set_undefined(struct sm_state *sm, struct expression *mod_expr)
67 /* this should be called early before any checks have run */
68 set_state(my_id, sm->name, sm->sym, &undefined);
71 static struct smatch_state *alloc_ssa_new(const char *name)
73 struct smatch_state *state;
74 char buf[64];
76 state = __alloc_smatch_state(0);
77 snprintf(buf, sizeof(buf), "%s:%ld", name, ssa_id);
78 state->name = alloc_sname(buf);
80 ssa_id++;
82 return state;
85 static struct smatch_state *alloc_ssa_copy(struct sm_state *sm)
87 struct smatch_state *state;
89 if (sm->state == &undefined || sm->state == &merged)
90 return sm->state;
92 state = __alloc_smatch_state(0);
93 state->name = alloc_sname(sm->state->name);
94 return state;
97 static bool whatever_close_enough(struct expression *left, struct expression *right)
99 struct symbol *left_type, *right_type;
101 left_type = get_type(left);
102 right_type = get_type(right);
104 if (type_bits(right_type) == 64) {
105 if (type_bits(left_type) == 64)
106 return true;
107 return false;
110 if (type_bits(right_type) == 32) {
111 if (type_bits(left_type) == 64 || type_bits(left_type) == 32)
112 return true;
113 return false;
116 return false;
119 static void match_assign(struct expression *expr)
121 struct smatch_state *left_state;
122 struct sm_state *orig, *clone;
123 struct symbol *left_sym, *right_sym;
124 char *left_name = NULL, *right_name = NULL;
126 if (__in_fake_assign)
127 return;
129 if (expr->op != '=')
130 return;
132 /* The whatever function is more likely to return true #Faster */
133 if (!whatever_close_enough(expr->left, expr->right) &&
134 !values_fit_type(expr->left, expr->right))
135 return;
137 left_name = expr_to_var_sym(expr->left, &left_sym);
138 if (!left_name)
139 goto free;
142 * The ordering of this is really tricky. The issue here is that we
143 * have: "dev = of_node_get(node);". The first thing that happens is
144 * the modified hook sets "dev" to undefined. Then the check for
145 * tracking of_node_get/put() allocates an ssa state for "dev". So if
146 * it's set here we can just return. Otherwise track the SSA state.
148 left_state = get_state(my_id, left_name, left_sym);
149 if (left_state && left_state != &undefined)
150 goto free;
152 right_name = expr_to_var_sym(expr->right, &right_sym);
153 if (!right_name)
154 goto free;
156 orig = get_sm_state(my_id, right_name, right_sym);
157 if (!orig || orig->state == &undefined)
158 orig = set_state(my_id, right_name, right_sym, alloc_ssa_new(right_name));
160 /* This can happen in unreachable code or outside of functions I gess */
161 if (!orig)
162 return;
165 * Cloning is only really necessary for &merged states but it's better
166 * to only have one code path where possible.
169 clone = clone_sm(orig);
170 clone->state = alloc_ssa_copy(orig);
171 clone->name = alloc_sname(left_name);
172 clone->sym = left_sym;
173 __set_sm(clone);
175 free:
176 free_string(left_name);
177 free_string(right_name);
180 void set_ssa_state(int owner, const char *name, struct symbol *sym,
181 struct smatch_state *state)
183 struct sm_state *sm;
185 if (!name)
186 return;
188 sm = get_sm_state(my_id, name, sym);
189 if (!sm || sm->state == &undefined)
190 sm = set_state(my_id, name, sym, alloc_ssa_new(name));
191 if (!sm)
192 return;
193 if (sm->state == &merged) {
194 sm = clone_sm(sm);
195 sm->state = alloc_ssa_new(name);
196 add_possible_sm(sm, sm);
197 __set_sm(sm);
199 if (!sm)
200 return;
201 set_state(owner, sm->state->name, NULL, state);
204 void update_ssa_state(int owner, const char *name, struct symbol *sym,
205 struct smatch_state *state)
207 set_state(owner, name, NULL, state);
210 void update_ssa_sm(int owner, struct sm_state *ssa_sm, struct smatch_state *state)
212 struct sm_state *tmp;
214 FOR_EACH_PTR(ssa_sm->possible, tmp) {
215 if (tmp->state == &merged ||
216 tmp->state == &undefined)
217 continue;
218 set_state(owner, tmp->state->name, NULL, state);
219 } END_FOR_EACH_PTR(tmp);
222 void set_ssa_state_expr(int owner, struct expression *expr,
223 struct smatch_state *state)
225 struct symbol *sym;
226 char *name;
228 name = expr_to_var_sym(expr, &sym);
229 if (!name)
230 return;
231 set_ssa_state(owner, name, sym, state);
232 free_string(name);
235 struct sm_state *get_ssa_sm_state(int owner, const char *name, struct symbol *sym)
237 struct sm_state *sm, *tmp, *owner_sm;
238 struct sm_state *ret = NULL;
240 sm = get_sm_state(my_id, name, sym);
241 if (!sm || sm->state == &undefined)
242 return NULL;
244 FOR_EACH_PTR(sm->possible, tmp) {
245 if (tmp->state == &merged ||
246 tmp->state == &undefined)
247 continue;
248 owner_sm = get_sm_state(owner, tmp->state->name, NULL);
249 if (owner_sm) {
250 if (!ret)
251 ret = clone_sm(owner_sm);
252 else
253 ret = merge_sm_states(ret, owner_sm);
255 } END_FOR_EACH_PTR(tmp);
257 if (!ret)
258 return NULL;
260 tmp = ret;
261 ret = clone_sm(sm);
262 ret->state = tmp->state;
264 return ret;
267 struct sm_state *get_ssa_sm_state_expr(int owner, struct expression *expr)
269 struct sm_state *ret;
270 struct symbol *sym;
271 char *name;
273 name = expr_to_var_sym(expr, &sym);
274 if (!name)
275 return NULL;
276 ret = get_ssa_sm_state(owner, name, sym);
277 free_string(name);
278 return ret;
281 struct smatch_state *get_ssa_state(int owner, const char *name, struct symbol *sym)
283 struct sm_state *sm;
285 sm = get_ssa_sm_state(my_id, name, sym);
286 if (!sm)
287 return NULL;
288 return sm->state;
291 struct smatch_state *get_ssa_state_expr(int owner, struct expression *expr)
293 struct sm_state *sm;
295 sm = get_ssa_sm_state_expr(my_id, expr);
296 if (!sm)
297 return NULL;
298 return sm->state;
301 void register_ssa(int id)
303 my_id = id;
305 set_dynamic_states(my_id);
306 add_hook(&match_assign, ASSIGNMENT_HOOK_AFTER);
307 add_modification_hook(my_id, &set_undefined);