Print this page
new smatch
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/tools/smatch/src/smatch_param_set.c
+++ new/usr/src/tools/smatch/src/smatch_param_set.c
1 1 /*
2 2 * Copyright (C) 2012 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 functions like:
20 20 *
21 21 * int foo(int *x)
22 22 * {
23 23 * if (*x == 42) {
24 24 * *x = 0;
25 25 * return 1;
26 26 * }
27 27 * return 0;
28 28 * }
29 29 *
30 30 * If we return 1 that means the value of *x has been set to 0. If we return
31 31 * 0 then we have left *x alone.
32 32 *
33 33 */
34 34
35 35 #include "scope.h"
36 36 #include "smatch.h"
37 37 #include "smatch_slist.h"
38 38 #include "smatch_extra.h"
39 39
40 40 static int my_id;
41 41
42 42 static struct smatch_state *unmatched_state(struct sm_state *sm)
43 43 {
44 44 return alloc_estate_empty();
45 45 }
46 46
47 47 static int parent_is_set(const char *name, struct symbol *sym, struct smatch_state *state)
48 48 {
49 49 struct expression *faked;
50 50 char *left_name;
51 51 int ret = 0;
52 52 int len;
53 53
54 54 if (!__in_fake_assign)
55 55 return 0;
56 56 if (!is_whole_rl(estate_rl(state)))
57 57 return 0;
58 58 if (get_state(my_id, name, sym))
59 59 return 0;
60 60
61 61 faked = get_faked_expression();
62 62 if (!faked)
63 63 return 0;
64 64 if ((faked->type == EXPR_PREOP || faked->type == EXPR_POSTOP) &&
65 65 (faked->op == SPECIAL_INCREMENT || faked->op == SPECIAL_DECREMENT)) {
66 66 faked = strip_expr(faked->unop);
67 67 if (faked->type == EXPR_SYMBOL)
68 68 return 1;
69 69 return 0;
70 70 }
71 71 if (faked->type != EXPR_ASSIGNMENT)
72 72 return 0;
73 73
74 74 left_name = expr_to_var(faked->left);
75 75 if (!left_name)
76 76 return 0;
77 77
78 78 len = strlen(left_name);
79 79 if (strncmp(name, left_name, len) == 0 && name[len] == '-')
80 80 ret = 1;
81 81 free_string(left_name);
82 82
83 83 return ret;
84 84 }
85 85
86 86 static void extra_mod_hook(const char *name, struct symbol *sym, struct expression *expr, struct smatch_state *state)
87 87 {
88 88 if (parent_is_set(name, sym, state))
89 89 return;
90 90 if (get_param_num_from_sym(sym) < 0)
91 91 return;
92 92 set_state(my_id, name, sym, state);
93 93 }
94 94
95 95 /*
96 96 * This function is is a dirty hack because extra_mod_hook is giving us a NULL
97 97 * sym instead of a vsl.
98 98 */
99 99 static void match_array_assignment(struct expression *expr)
100 100 {
101 101 struct expression *array, *offset;
102 102 char *name;
103 103 struct symbol *sym;
104 104 struct range_list *rl;
105 105 sval_t sval;
106 106 char buf[256];
107 107
108 108 if (__in_fake_assign)
109 109 return;
110 110
111 111 if (!is_array(expr->left))
112 112 return;
113 113 array = get_array_base(expr->left);
114 114 offset = get_array_offset(expr->left);
115 115
116 116 /* These are handled by extra_mod_hook() */
117 117 if (get_value(offset, &sval))
118 118 return;
119 119 name = expr_to_var_sym(array, &sym);
120 120 if (!name || !sym)
121 121 goto free;
122 122 if (get_param_num_from_sym(sym) < 0)
↓ open down ↓ |
122 lines elided |
↑ open up ↑ |
123 123 goto free;
124 124 get_absolute_rl(expr->right, &rl);
125 125 rl = cast_rl(get_type(expr->left), rl);
126 126
127 127 snprintf(buf, sizeof(buf), "*%s", name);
128 128 set_state(my_id, buf, sym, alloc_estate_rl(rl));
129 129 free:
130 130 free_string(name);
131 131 }
132 132
133 +static char *get_two_dots(const char *name)
134 +{
135 + static char buf[80];
136 + int i, cnt = 0;
137 +
138 + for (i = 0; i < sizeof(buf); i++) {
139 + if (name[i] == '.') {
140 + cnt++;
141 + if (cnt >= 2) {
142 + buf[i] = '\0';
143 + return buf;
144 + }
145 + }
146 + buf[i] = name[i];
147 + }
148 + return NULL;
149 +}
150 +
133 151 /*
134 152 * This relies on the fact that these states are stored so that
135 153 * foo->bar is before foo->bar->baz.
136 154 */
137 155 static int parent_set(struct string_list *list, const char *name)
138 156 {
139 157 char *tmp;
140 158 int len;
141 159 int ret;
142 160
143 161 FOR_EACH_PTR(list, tmp) {
144 162 len = strlen(tmp);
145 163 ret = strncmp(tmp, name, len);
146 164 if (ret < 0)
↓ open down ↓ |
4 lines elided |
↑ open up ↑ |
147 165 continue;
148 166 if (ret > 0)
149 167 return 0;
150 168 if (name[len] == '-')
151 169 return 1;
152 170 } END_FOR_EACH_PTR(tmp);
153 171
154 172 return 0;
155 173 }
156 174
157 -static void print_return_value_param(int return_id, char *return_ranges, struct expression *expr)
175 +static void print_return_value_param_helper(int return_id, char *return_ranges, struct expression *expr, int limit)
158 176 {
159 177 struct sm_state *sm;
160 178 struct smatch_state *extra;
161 179 int param;
162 180 struct range_list *rl;
163 181 const char *param_name;
164 182 struct string_list *set_list = NULL;
165 183 char *math_str;
166 184 char buf[256];
185 + char two_dot[80] = "";
186 + int count = 0;
167 187
168 188 FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
169 189 if (!estate_rl(sm->state))
170 190 continue;
171 - extra = get_state(SMATCH_EXTRA, sm->name, sm->sym);
191 + extra = __get_state(SMATCH_EXTRA, sm->name, sm->sym);
172 192 if (extra) {
173 193 rl = rl_intersection(estate_rl(sm->state), estate_rl(extra));
174 194 if (!rl)
175 195 continue;
176 196 } else {
177 197 rl = estate_rl(sm->state);
178 198 }
179 199
180 200 param = get_param_num_from_sym(sm->sym);
181 201 if (param < 0)
182 202 continue;
183 203 param_name = get_param_name(sm);
184 204 if (!param_name)
185 205 continue;
186 206 if (strcmp(param_name, "$") == 0) {
187 207 insert_string(&set_list, (char *)sm->name);
188 208 continue;
↓ open down ↓ |
7 lines elided |
↑ open up ↑ |
189 209 }
190 210 if (is_recursive_member(param_name)) {
191 211 insert_string(&set_list, (char *)sm->name);
192 212 continue;
193 213 }
194 214
195 215 if (is_ignored_kernel_data(param_name)) {
196 216 insert_string(&set_list, (char *)sm->name);
197 217 continue;
198 218 }
219 + if (limit) {
220 + char *new = get_two_dots(param_name);
199 221
222 + if (new) {
223 + if (strcmp(new, two_dot) == 0)
224 + continue;
225 + strncpy(two_dot, new, sizeof(two_dot));
226 + sql_insert_return_states(return_id, return_ranges,
227 + PARAM_SET, param, new, "s64min-s64max");
228 + continue;
229 + }
230 + }
231 +
200 232 math_str = get_value_in_terms_of_parameter_math_var_sym(sm->name, sm->sym);
201 233 if (math_str) {
202 234 snprintf(buf, sizeof(buf), "%s[%s]", show_rl(rl), math_str);
203 235 insert_string(&set_list, (char *)sm->name);
204 236 sql_insert_return_states(return_id, return_ranges,
205 237 param_has_filter_data(sm) ? PARAM_ADD : PARAM_SET,
206 238 param, param_name, buf);
207 239 continue;
208 240 }
209 241
210 242 /* no useful information here. */
211 243 if (is_whole_rl(rl) && parent_set(set_list, sm->name))
212 244 continue;
213 245 insert_string(&set_list, (char *)sm->name);
214 246
215 247 sql_insert_return_states(return_id, return_ranges,
216 248 param_has_filter_data(sm) ? PARAM_ADD : PARAM_SET,
217 249 param, param_name, show_rl(rl));
250 + if (limit && ++count > limit)
251 + break;
218 252
219 253 } END_FOR_EACH_SM(sm);
220 254
221 255 free_ptr_list((struct ptr_list **)&set_list);
222 256 }
223 257
258 +static void print_return_value_param(int return_id, char *return_ranges, struct expression *expr)
259 +{
260 + print_return_value_param_helper(return_id, return_ranges, expr, 0);
261 +}
262 +
263 +void print_limited_param_set(int return_id, char *return_ranges, struct expression *expr)
264 +{
265 + print_return_value_param_helper(return_id, return_ranges, expr, 1000);
266 +}
267 +
268 +static int possibly_empty(struct sm_state *sm)
269 +{
270 + struct sm_state *tmp;
271 +
272 + FOR_EACH_PTR(sm->possible, tmp) {
273 + if (strcmp(tmp->name, "") == 0)
274 + return 1;
275 + } END_FOR_EACH_PTR(tmp);
276 + return 0;
277 +}
278 +
224 279 int param_was_set_var_sym(const char *name, struct symbol *sym)
225 280 {
226 281 struct sm_state *sm;
227 - int len;
282 + char buf[80];
283 + int len, i;
228 284
229 - FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
230 - if (sm->sym != sym)
285 + if (!name)
286 + return 0;
287 +
288 + len = strlen(name);
289 + if (len >= sizeof(buf))
290 + len = sizeof(buf) - 1;
291 +
292 + for (i = 0; i <= len; i++) {
293 + if (name[i] != '-' && name[i] != '\0')
231 294 continue;
232 - len = strlen(sm->name);
233 - if (strncmp(sm->name, name, len) != 0)
295 +
296 + memcpy(buf, name, i);
297 + buf[i] = '\0';
298 +
299 + sm = get_sm_state(my_id, buf, sym);
300 + if (!sm)
234 301 continue;
235 - if (name[len] == '\0' ||
236 - name[len] == '-')
237 - return 1;
238 - } END_FOR_EACH_SM(sm);
302 + if (possibly_empty(sm))
303 + continue;
304 + return 1;
305 + }
239 306
307 + if (name[0] == '*')
308 + return param_was_set_var_sym(name + 1, sym);
309 +
240 310 return 0;
241 311 }
242 312
243 313 int param_was_set(struct expression *expr)
244 314 {
245 315 char *name;
246 316 struct symbol *sym;
247 317 int ret = 0;
248 318
249 319 name = expr_to_var_sym(expr, &sym);
250 320 if (!name || !sym)
251 321 goto free;
252 322
253 323 ret = param_was_set_var_sym(name, sym);
254 324 free:
255 325 free_string(name);
256 326 return ret;
257 327 }
258 328
259 329 void register_param_set(int id)
260 330 {
261 331 my_id = id;
262 332
263 333 set_dynamic_states(my_id);
264 334 add_extra_mod_hook(&extra_mod_hook);
265 335 add_hook(match_array_assignment, ASSIGNMENT_HOOK);
266 336 add_unmatched_state_hook(my_id, &unmatched_state);
267 337 add_merge_hook(my_id, &merge_estates);
268 338 add_split_return_callback(&print_return_value_param);
269 339 }
270 340
↓ open down ↓ |
21 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX