Print this page
12826 update to smatch 0.6.1-rc1-il-6
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/tools/smatch/src/check_atomic_inc_dec.c
+++ new/usr/src/tools/smatch/src/check_atomic_inc_dec.c
1 1 /*
2 2 * Copyright (C) 2016 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 */
↓ open down ↓ |
16 lines elided |
↑ open up ↑ |
17 17
18 18 #include <ctype.h>
19 19
20 20 #include "smatch.h"
21 21 #include "smatch_extra.h"
22 22 #include "smatch_slist.h"
23 23
24 24 static int my_id;
25 25
26 26 STATE(inc);
27 -STATE(orig);
27 +STATE(start_state);
28 28 STATE(dec);
29 29
30 30 static struct smatch_state *unmatched_state(struct sm_state *sm)
31 31 {
32 - if (parent_is_gone_var_sym(sm->name, sm->sym))
32 + /*
33 + * We default to decremented. For example, say we have:
34 + * if (p)
35 + * atomic_dec(p);
36 + * <- p is decreemented.
37 + *
38 + */
39 + if ((sm->state == &dec) &&
40 + parent_is_gone_var_sym(sm->name, sm->sym))
33 41 return sm->state;
34 - return &undefined;
42 + return &start_state;
35 43 }
36 44
37 45 static struct stree *start_states;
38 46 static struct stree_stack *saved_stack;
39 47 static void set_start_state(const char *name, struct symbol *sym, struct smatch_state *start)
40 48 {
41 49 struct smatch_state *orig;
42 50
43 51 orig = get_state_stree(start_states, my_id, name, sym);
44 52 if (!orig)
45 53 set_state_stree(&start_states, my_id, name, sym, start);
46 54 else if (orig != start)
47 55 set_state_stree(&start_states, my_id, name, sym, &undefined);
48 56 }
49 57
50 58 static struct sm_state *get_best_match(const char *key)
51 59 {
52 60 struct sm_state *sm;
53 61 struct sm_state *match;
54 62 int cnt = 0;
55 63 int start_pos, state_len, key_len, chunks, i;
56 64
57 65 if (strncmp(key, "$->", 3) == 0)
58 66 key += 3;
59 67
60 68 key_len = strlen(key);
61 69 chunks = 0;
62 70 for (i = key_len - 1; i > 0; i--) {
63 71 if (key[i] == '>' || key[i] == '.')
64 72 chunks++;
65 73 if (chunks == 2) {
66 74 key += (i + 1);
67 75 key_len = strlen(key);
68 76 break;
69 77 }
70 78 }
71 79
72 80 FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
73 81 state_len = strlen(sm->name);
74 82 if (state_len < key_len)
75 83 continue;
76 84 start_pos = state_len - key_len;
77 85 if ((start_pos == 0 || !isalnum(sm->name[start_pos - 1])) &&
78 86 strcmp(sm->name + start_pos, key) == 0) {
↓ open down ↓ |
34 lines elided |
↑ open up ↑ |
79 87 cnt++;
80 88 match = sm;
81 89 }
82 90 } END_FOR_EACH_SM(sm);
83 91
84 92 if (cnt == 1)
85 93 return match;
86 94 return NULL;
87 95 }
88 96
89 -static void db_inc_dec(struct expression *expr, int param, const char *key, const char *value, int inc_dec)
97 +static void db_inc_dec(struct expression *expr, int param, const char *key, int inc_dec)
90 98 {
91 99 struct sm_state *start_sm;
92 100 struct expression *arg;
93 101 char *name;
94 102 struct symbol *sym;
95 103 bool free_at_end = true;
96 104
97 105 while (expr->type == EXPR_ASSIGNMENT)
98 106 expr = strip_expr(expr->right);
99 107 if (expr->type != EXPR_CALL)
100 108 return;
101 109
102 110 arg = get_argument_from_call_expr(expr->args, param);
103 111 if (!arg)
104 112 return;
105 113
106 114 name = get_variable_from_key(arg, key, &sym);
107 115 if (!name || !sym)
108 116 goto free;
109 117
110 118 start_sm = get_sm_state(my_id, name, sym);
111 119 if (!start_sm && inc_dec == ATOMIC_DEC) {
112 120 start_sm = get_best_match(key);
113 121 if (start_sm) {
114 122 free_string(name);
115 123 free_at_end = false;
116 124 name = (char *)start_sm->name;
117 125 sym = start_sm->sym;
118 126 }
119 127 }
120 128
121 129 if (inc_dec == ATOMIC_INC) {
↓ open down ↓ |
22 lines elided |
↑ open up ↑ |
122 130 if (!start_sm)
123 131 set_start_state(name, sym, &dec);
124 132 // set_refcount_inc(name, sym);
125 133 set_state(my_id, name, sym, &inc);
126 134 } else {
127 135 // set_refcount_dec(name, sym);
128 136 if (!start_sm)
129 137 set_start_state(name, sym, &inc);
130 138
131 139 if (start_sm && start_sm->state == &inc)
132 - set_state(my_id, name, sym, &orig);
140 + set_state(my_id, name, sym, &start_state);
133 141 else
134 142 set_state(my_id, name, sym, &dec);
135 143 }
136 144
137 145 free:
138 146 if (free_at_end)
139 147 free_string(name);
140 148 }
141 149
150 +static const char *primitive_funcs[] = {
151 + "atomic_inc_return",
152 + "atomic_add_return",
153 + "atomic_sub_return",
154 + "atomic_sub_and_test",
155 + "atomic_dec_and_test",
156 + "_atomic_dec_and_lock",
157 + "atomic_dec",
158 + "atomic_long_inc",
159 + "atomic_long_dec",
160 + "atomic_inc",
161 + "atomic_sub",
162 + "refcount_inc",
163 + "refcount_dec",
164 + "refcount_add",
165 + "refcount_add_not_zero",
166 + "refcount_inc_not_zero",
167 + "refcount_sub_and_test",
168 + "refcount_dec_and_test",
169 + "atomic_dec_if_positive",
170 +};
171 +
172 +static bool is_inc_dec_primitive(struct expression *expr)
173 +{
174 + int i;
175 +
176 + while (expr->type == EXPR_ASSIGNMENT)
177 + expr = strip_expr(expr->right);
178 + if (expr->type != EXPR_CALL)
179 + return false;
180 +
181 + if (expr->fn->type != EXPR_SYMBOL)
182 + return false;
183 +
184 + for (i = 0; i < ARRAY_SIZE(primitive_funcs); i++) {
185 + if (sym_name_is(primitive_funcs[i], expr->fn))
186 + return true;
187 + }
188 +
189 + return false;
190 +}
191 +
142 192 static void db_inc(struct expression *expr, int param, char *key, char *value)
143 193 {
144 - db_inc_dec(expr, param, key, value, ATOMIC_INC);
194 + if (is_inc_dec_primitive(expr))
195 + return;
196 + db_inc_dec(expr, param, key, ATOMIC_INC);
145 197 }
146 198
147 199 static void db_dec(struct expression *expr, int param, char *key, char *value)
148 200 {
149 - db_inc_dec(expr, param, key, value, ATOMIC_DEC);
201 + if (is_inc_dec_primitive(expr))
202 + return;
203 + db_inc_dec(expr, param, key, ATOMIC_DEC);
150 204 }
151 205
152 206 static void match_atomic_inc(const char *fn, struct expression *expr, void *_unused)
153 207 {
154 - db_inc_dec(expr, 0, "$->counter", "", ATOMIC_INC);
208 + db_inc_dec(expr, 0, "$->counter", ATOMIC_INC);
155 209 }
156 210
157 211 static void match_atomic_dec(const char *fn, struct expression *expr, void *_unused)
158 212 {
159 - db_inc_dec(expr, 0, "$->counter", "", ATOMIC_DEC);
213 + db_inc_dec(expr, 0, "$->counter", ATOMIC_DEC);
160 214 }
161 215
162 216 static void match_atomic_add(const char *fn, struct expression *expr, void *_unused)
163 217 {
164 218 struct expression *amount;
165 219 sval_t sval;
166 220
167 221 amount = get_argument_from_call_expr(expr->args, 0);
168 222 if (get_implied_value(amount, &sval) && sval_is_negative(sval)) {
169 - db_inc_dec(expr, 1, "$->counter", "", ATOMIC_DEC);
223 + db_inc_dec(expr, 1, "$->counter", ATOMIC_DEC);
170 224 return;
171 225 }
172 226
173 - db_inc_dec(expr, 1, "$->counter", "", ATOMIC_INC);
227 + db_inc_dec(expr, 1, "$->counter", ATOMIC_INC);
174 228 }
175 229
176 230 static void match_atomic_sub(const char *fn, struct expression *expr, void *_unused)
177 231 {
178 - db_inc_dec(expr, 1, "$->counter", "", ATOMIC_DEC);
232 + db_inc_dec(expr, 1, "$->counter", ATOMIC_DEC);
179 233 }
180 234
181 235 static void refcount_inc(const char *fn, struct expression *expr, void *param)
182 236 {
183 - db_inc_dec(expr, PTR_INT(param), "$->ref.counter", "", ATOMIC_INC);
237 + db_inc_dec(expr, PTR_INT(param), "$->ref.counter", ATOMIC_INC);
184 238 }
185 239
186 240 static void refcount_dec(const char *fn, struct expression *expr, void *param)
187 241 {
188 - db_inc_dec(expr, PTR_INT(param), "$->ref.counter", "", ATOMIC_DEC);
242 + db_inc_dec(expr, PTR_INT(param), "$->ref.counter", ATOMIC_DEC);
189 243 }
190 244
245 +static void pm_runtime_get_sync(const char *fn, struct expression *expr, void *param)
246 +{
247 + db_inc_dec(expr, PTR_INT(param), "$->power.usage_count.counter", ATOMIC_INC);
248 +}
249 +
250 +static void match_implies_inc(const char *fn, struct expression *call_expr,
251 + struct expression *assign_expr, void *param)
252 +{
253 + db_inc_dec(call_expr, PTR_INT(param), "$->ref.counter", ATOMIC_INC);
254 +}
255 +
256 +static void match_implies_atomic_dec(const char *fn, struct expression *call_expr,
257 + struct expression *assign_expr, void *param)
258 +{
259 + db_inc_dec(call_expr, PTR_INT(param), "$->counter", ATOMIC_DEC);
260 +}
261 +
262 +static bool is_maybe_dec(struct sm_state *sm)
263 +{
264 + if (sm->state == &dec)
265 + return true;
266 + if (slist_has_state(sm->possible, &dec) &&
267 + !slist_has_state(sm->possible, &inc))
268 + return true;
269 + return false;
270 +}
271 +
191 272 static void match_return_info(int return_id, char *return_ranges, struct expression *expr)
192 273 {
193 274 struct sm_state *sm;
194 275 const char *param_name;
195 276 int param;
196 277
278 + if (is_impossible_path())
279 + return;
280 +
197 281 FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
198 - if (sm->state != &inc &&
199 - sm->state != &dec)
282 + if (sm->state != &inc && !is_maybe_dec(sm))
200 283 continue;
284 + if (sm->state == get_state_stree(start_states, my_id, sm->name, sm->sym))
285 + continue;
201 286 if (parent_is_gone_var_sym(sm->name, sm->sym))
202 287 continue;
203 288 param = get_param_num_from_sym(sm->sym);
204 289 if (param < 0)
205 290 continue;
206 291 param_name = get_param_name(sm);
207 292 if (!param_name)
208 293 continue;
209 294 sql_insert_return_states(return_id, return_ranges,
210 295 (sm->state == &inc) ? ATOMIC_INC : ATOMIC_DEC,
211 296 param, param_name, "");
212 297 } END_FOR_EACH_SM(sm);
213 298 }
↓ open down ↓ |
3 lines elided |
↑ open up ↑ |
214 299
215 300 enum {
216 301 EMPTY, NEGATIVE, ZERO, POSITIVE, NUM_BUCKETS
217 302 };
218 303
219 304 static int success_fail_positive(struct range_list *rl)
220 305 {
221 306 if (!rl)
222 307 return EMPTY;
223 308
224 - if (sval_is_negative(rl_min(rl)))
309 + if (!is_whole_rl(rl) && sval_is_negative(rl_min(rl)))
225 310 return NEGATIVE;
226 311
227 312 if (rl_min(rl).value == 0)
228 313 return ZERO;
229 314
230 315 return POSITIVE;
231 316 }
232 317
233 318 static void check_counter(const char *name, struct symbol *sym)
234 319 {
235 320 struct range_list *inc_lines = NULL;
236 321 struct range_list *dec_lines = NULL;
237 322 int inc_buckets[NUM_BUCKETS] = {};
238 323 int dec_buckets[NUM_BUCKETS] = {};
239 324 struct stree *stree, *orig_stree;
325 + struct smatch_state *state;
240 326 struct sm_state *return_sm;
241 327 struct sm_state *sm;
242 328 sval_t line = sval_type_val(&int_ctype, 0);
243 329 int bucket;
244 330
331 + /* static variable are probably just counters */
332 + if (sym->ctype.modifiers & MOD_STATIC &&
333 + !(sym->ctype.modifiers & MOD_TOPLEVEL))
334 + return;
335 +
245 336 FOR_EACH_PTR(get_all_return_strees(), stree) {
246 337 orig_stree = __swap_cur_stree(stree);
247 338
339 + if (is_impossible_path())
340 + goto swap_stree;
341 +
248 342 return_sm = get_sm_state(RETURN_ID, "return_ranges", NULL);
249 343 if (!return_sm)
250 344 goto swap_stree;
251 345 line.value = return_sm->line;
252 346
253 347 if (get_state_stree(start_states, my_id, name, sym) == &inc)
254 348 goto swap_stree;
255 349
256 350 if (parent_is_gone_var_sym(name, sym))
257 351 goto swap_stree;
258 352
259 353 sm = get_sm_state(my_id, name, sym);
260 - if (!sm)
261 - goto swap_stree;
354 + if (sm)
355 + state = sm->state;
356 + else
357 + state = &start_state;
262 358
263 - if (sm->state != &inc &&
264 - sm->state != &dec &&
265 - sm->state != &orig)
359 + if (state != &inc &&
360 + state != &dec &&
361 + state != &start_state)
266 362 goto swap_stree;
267 363
268 364 bucket = success_fail_positive(estate_rl(return_sm->state));
269 365
270 - if (sm->state == &inc) {
366 + if (state == &inc) {
271 367 add_range(&inc_lines, line, line);
272 368 inc_buckets[bucket] = true;
273 369 }
274 - if (sm->state == &dec || sm->state == &orig) {
370 + if (state == &dec || state == &start_state) {
275 371 add_range(&dec_lines, line, line);
276 372 dec_buckets[bucket] = true;
277 373 }
278 374 swap_stree:
279 375 __swap_cur_stree(orig_stree);
280 376 } END_FOR_EACH_PTR(stree);
281 377
282 378 if (inc_buckets[NEGATIVE] &&
283 379 inc_buckets[ZERO]) {
284 380 // sm_warning("XXX '%s' not decremented on lines: %s.", name, show_rl(inc_lines));
285 381 }
286 382
287 383 }
288 384
289 385 static void match_check_missed(struct symbol *sym)
290 386 {
291 387 struct sm_state *sm;
292 388
293 389 FOR_EACH_MY_SM(my_id, get_all_return_states(), sm) {
294 390 check_counter(sm->name, sm->sym);
295 391 } END_FOR_EACH_SM(sm);
296 392 }
297 393
298 394 int on_atomic_dec_path(void)
299 395 {
300 396 struct sm_state *sm;
301 397
302 398 FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
303 399 if (sm->state == &dec)
304 400 return 1;
305 401 } END_FOR_EACH_SM(sm);
306 402
307 403 return 0;
308 404 }
309 405
310 406 int was_inced(const char *name, struct symbol *sym)
311 407 {
312 408 return get_state(my_id, name, sym) == &inc;
313 409 }
314 410
315 411 static void match_save_states(struct expression *expr)
316 412 {
317 413 push_stree(&saved_stack, start_states);
318 414 start_states = NULL;
319 415 }
320 416
321 417 static void match_restore_states(struct expression *expr)
322 418 {
323 419 start_states = pop_stree(&saved_stack);
324 420 }
325 421
326 422 static void match_after_func(struct symbol *sym)
327 423 {
328 424 free_stree(&start_states);
329 425 }
330 426
331 427 void check_atomic_inc_dec(int id)
332 428 {
333 429 my_id = id;
334 430
335 431 if (option_project != PROJ_KERNEL)
336 432 return;
337 433
↓ open down ↓ |
53 lines elided |
↑ open up ↑ |
338 434 add_unmatched_state_hook(my_id, &unmatched_state);
339 435
340 436 add_split_return_callback(match_return_info);
341 437 select_return_states_hook(ATOMIC_INC, &db_inc);
342 438 select_return_states_hook(ATOMIC_DEC, &db_dec);
343 439
344 440 add_function_hook("atomic_inc_return", &match_atomic_inc, NULL);
345 441 add_function_hook("atomic_add_return", &match_atomic_add, NULL);
346 442 add_function_hook("atomic_sub_return", &match_atomic_sub, NULL);
347 443 add_function_hook("atomic_sub_and_test", &match_atomic_sub, NULL);
444 + add_function_hook("atomic_long_sub_and_test", &match_atomic_sub, NULL);
445 + add_function_hook("atomic64_sub_and_test", &match_atomic_sub, NULL);
348 446 add_function_hook("atomic_dec_and_test", &match_atomic_dec, NULL);
447 + add_function_hook("atomic_long_dec_and_test", &match_atomic_dec, NULL);
448 + add_function_hook("atomic64_dec_and_test", &match_atomic_dec, NULL);
349 449 add_function_hook("_atomic_dec_and_lock", &match_atomic_dec, NULL);
350 450 add_function_hook("atomic_dec", &match_atomic_dec, NULL);
451 + add_function_hook("atomic_dec_return", &match_atomic_dec, NULL);
351 452 add_function_hook("atomic_long_inc", &match_atomic_inc, NULL);
352 453 add_function_hook("atomic_long_dec", &match_atomic_dec, NULL);
353 454 add_function_hook("atomic_inc", &match_atomic_inc, NULL);
354 455 add_function_hook("atomic_sub", &match_atomic_sub, NULL);
355 456
356 457 add_function_hook("refcount_inc", &refcount_inc, INT_PTR(0));
357 458 add_function_hook("refcount_dec", &refcount_dec, INT_PTR(0));
358 459 add_function_hook("refcount_add", &refcount_inc, INT_PTR(1));
359 - add_function_hook("refcount_add_not_zero", &refcount_inc, INT_PTR(1));
360 - add_function_hook("refcount_inc_not_zero", &refcount_inc, INT_PTR(0));
460 +
461 + return_implies_state("refcount_add_not_zero", 1, 1, &match_implies_inc, INT_PTR(1));
462 + return_implies_state("refcount_inc_not_zero", 1, 1, &match_implies_inc, INT_PTR(0));
463 +
464 + return_implies_state("atomic_dec_if_positive", 0, INT_MAX, &match_implies_atomic_dec, INT_PTR(0));
465 +
361 466 add_function_hook("refcount_sub_and_test", &refcount_dec, INT_PTR(1));
362 467 add_function_hook("refcount_dec_and_test", &refcount_dec, INT_PTR(0));
363 468
469 + add_function_hook("pm_runtime_get_sync", &pm_runtime_get_sync, INT_PTR(0));
470 +
364 471 add_hook(&match_check_missed, END_FUNC_HOOK);
365 472
366 473 add_hook(&match_after_func, AFTER_FUNC_HOOK);
367 474 add_hook(&match_save_states, INLINE_FN_START);
368 475 add_hook(&match_restore_states, INLINE_FN_END);
369 476 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX