Print this page
11506 smatch resync
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/tools/smatch/src/smatch_return_to_param.c
+++ new/usr/src/tools/smatch/src/smatch_return_to_param.c
1 1 /*
2 2 * Copyright (C) 2017 Oracle.
3 3 *
4 4 * This program is free software; you can redistribute it and/or
5 5 * modify it under the terms of the GNU General Public License
6 6 * as published by the Free Software Foundation; either version 2
7 7 * of the License, or (at your option) any later version.
8 8 *
9 9 * This program is distributed in the hope that it will be useful,
10 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 * GNU General Public License for more details.
13 13 *
14 14 * You should have received a copy of the GNU General Public License
15 15 * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
16 16 */
17 17
18 18 /*
19 19 * This is for smatch_extra.c to use. It sort of like check_assigned_expr.c but
20 20 * more limited. Say a function returns "64min-s64max[$0->data]" and the caller
21 21 * does "struct whatever *p = get_data(dev);" then we want to record that p is
22 22 * now the same as "dev->data". Then if we update "p->foo" it means we can
23 23 * update "dev->data->foo" as well.
24 24 *
25 25 */
26 26
27 27 #include "smatch.h"
28 28 #include "smatch_slist.h"
29 29 #include "smatch_extra.h"
30 30
31 31 extern int check_assigned_expr_id;
32 32 static int my_id;
33 33 static int link_id;
34 34
35 35 static struct smatch_state *alloc_my_state(const char *name, struct symbol *sym)
36 36 {
37 37 struct smatch_state *state;
38 38
39 39 state = __alloc_smatch_state(0);
40 40 state->name = alloc_sname(name);
41 41 state->data = sym;
42 42 return state;
43 43 }
44 44
45 45 static void undef(struct sm_state *sm, struct expression *mod_expr)
46 46 {
47 47 if (__in_fake_parameter_assign)
48 48 return;
↓ open down ↓ |
48 lines elided |
↑ open up ↑ |
49 49 set_state(my_id, sm->name, sm->sym, &undefined);
50 50 }
51 51
52 52 char *map_call_to_other_name_sym(const char *name, struct symbol *sym, struct symbol **new_sym)
53 53 {
54 54 struct smatch_state *state;
55 55 int skip;
56 56 char buf[256];
57 57
58 58 /* skip 'foo->'. This was checked in the caller. */
59 - skip = strlen(sym->ident->name) + 2;
59 + skip = sym->ident->len + 2;
60 60
61 61 state = get_state(my_id, sym->ident->name, sym);
62 62 if (!state || !state->data)
63 63 return NULL;
64 64
65 65 snprintf(buf, sizeof(buf), "%s->%s", state->name, name + skip);
66 66 *new_sym = state->data;
67 67 return alloc_string(buf);
68 68 }
69 69
70 70 static char *map_my_state_long_to_short(struct sm_state *sm, const char *name, struct symbol *sym, struct symbol **new_sym, bool stack)
71 71 {
72 72 int len;
73 73 char buf[256];
74 74
75 75 if (sm->state->data != sym)
76 76 return NULL;
77 77 len = strlen(sm->state->name);
78 78 if (strncmp(name, sm->state->name, len) != 0)
79 79 return NULL;
↓ open down ↓ |
10 lines elided |
↑ open up ↑ |
80 80
81 81 if (name[len] == '.')
82 82 return NULL;
83 83 if (!stack && name[len] != '-')
84 84 return NULL;
85 85 snprintf(buf, sizeof(buf), "%s%s", sm->name, name + len);
86 86 *new_sym = sm->sym;
87 87 return alloc_string(buf);
88 88 }
89 89
90 -static char *map_assignment_long_to_short(struct sm_state *sm, const char *name, struct symbol *sym, struct symbol **new_sym, bool stack)
91 -{
92 - struct expression *orig_expr;
93 - struct symbol *orig_sym;
94 - int len;
95 - char buf[256];
96 -
97 - orig_expr = sm->state->data;
98 - if (!orig_expr)
99 - return NULL;
100 -
101 - /*
102 - * Say we have an assignment like:
103 - * foo->bar->my_ptr = my_ptr;
104 - * We still expect the function to carry on using "my_ptr" as the
105 - * shorter name. That's not a long to short mapping.
106 - *
107 - */
108 - if (orig_expr->type == EXPR_SYMBOL)
109 - return NULL;
110 -
111 - orig_sym = expr_to_sym(orig_expr);
112 - if (!orig_sym)
113 - return NULL;
114 - if (sym != orig_sym)
115 - return NULL;
116 -
117 - len = strlen(sm->state->name);
118 - if (strncmp(name, sm->state->name, len) != 0)
119 - return NULL;
120 -
121 - if (name[len] == '.')
122 - return NULL;
123 - if (!stack && name[len] != '-')
124 - return NULL;
125 - snprintf(buf, sizeof(buf), "%s%s", sm->name, name + len);
126 - *new_sym = sm->sym;
127 - return alloc_string(buf);
128 -}
129 -
130 90 /*
131 91 * Normally, we expect people to consistently refer to variables by the shortest
132 92 * name. So they use "b->a" instead of "foo->bar.a" when both point to the
133 93 * same memory location. However, when we're dealing across function boundaries
134 94 * then sometimes we pass frob(foo) which sets foo->bar.a. In that case, we
135 95 * translate it to the shorter name. Smatch extra updates the shorter name,
136 96 * which in turn updates the longer name.
137 97 *
138 98 */
139 -static char *map_long_to_short_name_sym_helper(const char *name, struct symbol *sym, struct symbol **new_sym, bool stack)
99 +char *map_long_to_short_name_sym(const char *name, struct symbol *sym, struct symbol **new_sym, bool use_stack)
140 100 {
141 101 char *ret;
142 102 struct sm_state *sm;
143 103
144 104 *new_sym = NULL;
145 105
146 106 FOR_EACH_SM(__get_cur_stree(), sm) {
147 107 if (sm->owner == my_id) {
148 - ret = map_my_state_long_to_short(sm, name, sym, new_sym, stack);
149 - if (ret)
108 + ret = map_my_state_long_to_short(sm, name, sym, new_sym, use_stack);
109 + if (ret) {
110 + if (local_debug)
111 + sm_msg("%s: my_state: name = '%s' sm = '%s'",
112 + __func__, name, show_sm(sm));
150 113 return ret;
114 + }
151 115 continue;
152 116 }
153 - if (sm->owner == check_assigned_expr_id) {
154 - ret = map_assignment_long_to_short(sm, name, sym, new_sym, stack);
155 - if (ret)
156 - return ret;
157 - continue;
158 - }
159 117 } END_FOR_EACH_SM(sm);
160 118
161 119 return NULL;
162 120 }
163 121
164 -char *map_long_to_short_name_sym(const char *name, struct symbol *sym, struct symbol **new_sym)
165 -{
166 - return map_long_to_short_name_sym_helper(name, sym, new_sym, 1);
167 -}
168 -
169 -char *map_long_to_short_name_sym_nostack(const char *name, struct symbol *sym, struct symbol **new_sym)
170 -{
171 - return map_long_to_short_name_sym_helper(name, sym, new_sym, 0);
172 -}
173 -
174 122 char *map_call_to_param_name_sym(struct expression *expr, struct symbol **sym)
175 123 {
176 124 char *name;
177 125 struct symbol *start_sym;
178 126 struct smatch_state *state;
179 127
180 128 *sym = NULL;
181 129
182 130 name = expr_to_str_sym(expr, &start_sym);
183 131 if (!name)
184 132 return NULL;
185 133 if (expr->type == EXPR_CALL)
186 134 start_sym = expr_to_sym(expr->fn);
187 135
188 136 state = get_state(my_id, name, start_sym);
189 137 free_string(name);
190 138 if (!state || !state->data)
191 139 return NULL;
192 140
193 141 *sym = state->data;
194 142 return alloc_string(state->name);
195 143 }
196 144
197 145 static void store_mapping_helper(char *left_name, struct symbol *left_sym, struct expression *call, const char *return_string)
198 146 {
199 147 const char *p = return_string;
200 148 char *close;
201 149 int param;
202 150 struct expression *arg, *new;
203 151 char *right_name;
204 152 struct symbol *right_sym;
205 153 char buf[256];
206 154
207 155 while (*p && *p != '[')
208 156 p++;
209 157 if (!*p)
210 158 return;
211 159 p++;
212 160 if (*p != '$')
213 161 return;
214 162
215 163 snprintf(buf, sizeof(buf), "%s", p);
216 164 close = strchr(buf, ']');
217 165 if (!close)
218 166 return;
219 167 *close = '\0';
220 168
221 169 param = atoi(buf + 1);
222 170 arg = get_argument_from_call_expr(call->args, param);
223 171 if (!arg)
224 172 return;
225 173
226 174 new = gen_expression_from_key(arg, buf);
227 175 if (!new)
228 176 return;
229 177
230 178 right_name = expr_to_var_sym(new, &right_sym);
231 179 if (!right_name || !right_sym)
232 180 goto free;
233 181
234 182 set_state(my_id, left_name, left_sym, alloc_my_state(right_name, right_sym));
235 183 store_link(link_id, right_name, right_sym, left_name, left_sym);
236 184
237 185 free:
238 186 free_string(right_name);
239 187 }
240 188
241 189 void __add_return_to_param_mapping(struct expression *expr, const char *return_string)
242 190 {
243 191 struct expression *call;
244 192 char *left_name = NULL;
245 193 struct symbol *left_sym;
246 194
247 195 if (expr->type == EXPR_ASSIGNMENT) {
248 196 left_name = expr_to_var_sym(expr->left, &left_sym);
249 197 if (!left_name || !left_sym)
250 198 goto free;
251 199
252 200 call = strip_expr(expr->right);
253 201 if (call->type != EXPR_CALL)
254 202 goto free;
255 203
256 204 store_mapping_helper(left_name, left_sym, call, return_string);
257 205 goto free;
258 206 }
259 207
260 208 if (expr->type == EXPR_CALL &&
261 209 expr_get_parent_stmt(expr) &&
262 210 expr_get_parent_stmt(expr)->type == STMT_RETURN) {
263 211 call = strip_expr(expr);
264 212 left_sym = expr_to_sym(call->fn);
265 213 if (!left_sym)
266 214 return;
267 215 left_name = expr_to_str(call);
268 216 if (!left_name)
269 217 return;
270 218
271 219 store_mapping_helper(left_name, left_sym, call, return_string);
272 220 goto free;
↓ open down ↓ |
89 lines elided |
↑ open up ↑ |
273 221
274 222 }
275 223
276 224 free:
277 225 free_string(left_name);
278 226 }
279 227
280 228 void register_return_to_param(int id)
281 229 {
282 230 my_id = id;
231 + set_dynamic_states(my_id);
283 232 add_modification_hook(my_id, &undef);
284 233 }
285 234
286 235 void register_return_to_param_links(int id)
287 236 {
288 237 link_id = id;
289 238 set_up_link_functions(my_id, link_id);
290 239 }
291 240
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX