Print this page
12724 update smatch to 0.6.1-rc1-il-5
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.
↓ open down ↓ |
7 lines elided |
↑ open up ↑ |
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 +#include <ctype.h>
19 +
18 20 #include "smatch.h"
19 21 #include "smatch_extra.h"
20 22 #include "smatch_slist.h"
21 23
22 24 static int my_id;
23 25
24 26 STATE(inc);
25 27 STATE(orig);
26 28 STATE(dec);
27 29
30 +static struct smatch_state *unmatched_state(struct sm_state *sm)
31 +{
32 + if (parent_is_gone_var_sym(sm->name, sm->sym))
33 + return sm->state;
34 + return &undefined;
35 +}
36 +
37 +static struct stree *start_states;
38 +static struct stree_stack *saved_stack;
39 +static void set_start_state(const char *name, struct symbol *sym, struct smatch_state *start)
40 +{
41 + struct smatch_state *orig;
42 +
43 + orig = get_state_stree(start_states, my_id, name, sym);
44 + if (!orig)
45 + set_state_stree(&start_states, my_id, name, sym, start);
46 + else if (orig != start)
47 + set_state_stree(&start_states, my_id, name, sym, &undefined);
48 +}
49 +
50 +static struct sm_state *get_best_match(const char *key)
51 +{
52 + struct sm_state *sm;
53 + struct sm_state *match;
54 + int cnt = 0;
55 + int start_pos, state_len, key_len, chunks, i;
56 +
57 + if (strncmp(key, "$->", 3) == 0)
58 + key += 3;
59 +
60 + key_len = strlen(key);
61 + chunks = 0;
62 + for (i = key_len - 1; i > 0; i--) {
63 + if (key[i] == '>' || key[i] == '.')
64 + chunks++;
65 + if (chunks == 2) {
66 + key += (i + 1);
67 + key_len = strlen(key);
68 + break;
69 + }
70 + }
71 +
72 + FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
73 + state_len = strlen(sm->name);
74 + if (state_len < key_len)
75 + continue;
76 + start_pos = state_len - key_len;
77 + if ((start_pos == 0 || !isalnum(sm->name[start_pos - 1])) &&
78 + strcmp(sm->name + start_pos, key) == 0) {
79 + cnt++;
80 + match = sm;
81 + }
82 + } END_FOR_EACH_SM(sm);
83 +
84 + if (cnt == 1)
85 + return match;
86 + return NULL;
87 +}
88 +
28 89 static void db_inc_dec(struct expression *expr, int param, const char *key, const char *value, int inc_dec)
29 90 {
30 - struct smatch_state *start_state;
91 + struct sm_state *start_sm;
31 92 struct expression *arg;
32 93 char *name;
33 94 struct symbol *sym;
95 + bool free_at_end = true;
34 96
35 97 while (expr->type == EXPR_ASSIGNMENT)
36 98 expr = strip_expr(expr->right);
37 99 if (expr->type != EXPR_CALL)
38 100 return;
39 101
40 102 arg = get_argument_from_call_expr(expr->args, param);
41 103 if (!arg)
42 104 return;
43 105
44 106 name = get_variable_from_key(arg, key, &sym);
45 107 if (!name || !sym)
46 108 goto free;
47 109
48 - start_state = get_state(my_id, name, sym);
110 + start_sm = get_sm_state(my_id, name, sym);
111 + if (!start_sm && inc_dec == ATOMIC_DEC) {
112 + start_sm = get_best_match(key);
113 + if (start_sm) {
114 + free_string(name);
115 + free_at_end = false;
116 + name = (char *)start_sm->name;
117 + sym = start_sm->sym;
118 + }
119 + }
49 120
50 121 if (inc_dec == ATOMIC_INC) {
51 -// if (start_state == &inc)
52 -// sm_error("XXX double increment '%s'", name);
122 + if (!start_sm)
123 + set_start_state(name, sym, &dec);
124 +// set_refcount_inc(name, sym);
53 125 set_state(my_id, name, sym, &inc);
54 126 } else {
55 -// if (start_state == &dec)
56 -// sm_error("XXX double decrement '%s'", name);
57 - if (start_state == &inc)
127 +// set_refcount_dec(name, sym);
128 + if (!start_sm)
129 + set_start_state(name, sym, &inc);
130 +
131 + if (start_sm && start_sm->state == &inc)
58 132 set_state(my_id, name, sym, &orig);
59 133 else
60 134 set_state(my_id, name, sym, &dec);
61 135 }
62 136
63 137 free:
64 - free_string(name);
138 + if (free_at_end)
139 + free_string(name);
65 140 }
66 141
67 142 static void db_inc(struct expression *expr, int param, char *key, char *value)
68 143 {
69 144 db_inc_dec(expr, param, key, value, ATOMIC_INC);
70 145 }
71 146
72 147 static void db_dec(struct expression *expr, int param, char *key, char *value)
73 148 {
74 149 db_inc_dec(expr, param, key, value, ATOMIC_DEC);
75 150 }
76 151
77 152 static void match_atomic_inc(const char *fn, struct expression *expr, void *_unused)
78 153 {
79 154 db_inc_dec(expr, 0, "$->counter", "", ATOMIC_INC);
80 155 }
81 156
82 157 static void match_atomic_dec(const char *fn, struct expression *expr, void *_unused)
83 158 {
84 159 db_inc_dec(expr, 0, "$->counter", "", ATOMIC_DEC);
85 160 }
86 161
87 162 static void match_atomic_add(const char *fn, struct expression *expr, void *_unused)
88 163 {
89 164 struct expression *amount;
90 165 sval_t sval;
91 166
92 167 amount = get_argument_from_call_expr(expr->args, 0);
93 168 if (get_implied_value(amount, &sval) && sval_is_negative(sval)) {
94 169 db_inc_dec(expr, 1, "$->counter", "", ATOMIC_DEC);
95 170 return;
96 171 }
97 172
98 173 db_inc_dec(expr, 1, "$->counter", "", ATOMIC_INC);
99 174 }
100 175
101 176 static void match_atomic_sub(const char *fn, struct expression *expr, void *_unused)
102 177 {
103 178 db_inc_dec(expr, 1, "$->counter", "", ATOMIC_DEC);
104 179 }
105 180
106 181 static void refcount_inc(const char *fn, struct expression *expr, void *param)
107 182 {
108 183 db_inc_dec(expr, PTR_INT(param), "$->ref.counter", "", ATOMIC_INC);
109 184 }
110 185
111 186 static void refcount_dec(const char *fn, struct expression *expr, void *param)
112 187 {
113 188 db_inc_dec(expr, PTR_INT(param), "$->ref.counter", "", ATOMIC_DEC);
114 189 }
115 190
↓ open down ↓ |
41 lines elided |
↑ open up ↑ |
116 191 static void match_return_info(int return_id, char *return_ranges, struct expression *expr)
117 192 {
118 193 struct sm_state *sm;
119 194 const char *param_name;
120 195 int param;
121 196
122 197 FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
123 198 if (sm->state != &inc &&
124 199 sm->state != &dec)
125 200 continue;
201 + if (parent_is_gone_var_sym(sm->name, sm->sym))
202 + continue;
126 203 param = get_param_num_from_sym(sm->sym);
127 204 if (param < 0)
128 205 continue;
129 206 param_name = get_param_name(sm);
130 207 if (!param_name)
131 208 continue;
132 209 sql_insert_return_states(return_id, return_ranges,
133 210 (sm->state == &inc) ? ATOMIC_INC : ATOMIC_DEC,
134 211 param, param_name, "");
135 212 } END_FOR_EACH_SM(sm);
136 213 }
137 214
138 215 enum {
139 - NEGATIVE, ZERO, POSITIVE,
216 + EMPTY, NEGATIVE, ZERO, POSITIVE, NUM_BUCKETS
140 217 };
141 218
142 219 static int success_fail_positive(struct range_list *rl)
143 220 {
144 221 if (!rl)
145 - return ZERO;
222 + return EMPTY;
146 223
147 224 if (sval_is_negative(rl_min(rl)))
148 225 return NEGATIVE;
149 226
150 227 if (rl_min(rl).value == 0)
151 228 return ZERO;
152 229
153 230 return POSITIVE;
154 231 }
155 232
156 233 static void check_counter(const char *name, struct symbol *sym)
157 234 {
158 235 struct range_list *inc_lines = NULL;
159 236 struct range_list *dec_lines = NULL;
160 - int inc_buckets[3] = {};
161 - struct stree *stree;
237 + int inc_buckets[NUM_BUCKETS] = {};
238 + int dec_buckets[NUM_BUCKETS] = {};
239 + struct stree *stree, *orig_stree;
162 240 struct sm_state *return_sm;
163 241 struct sm_state *sm;
164 242 sval_t line = sval_type_val(&int_ctype, 0);
243 + int bucket;
165 244
166 245 FOR_EACH_PTR(get_all_return_strees(), stree) {
167 - return_sm = get_sm_state_stree(stree, RETURN_ID, "return_ranges", NULL);
246 + orig_stree = __swap_cur_stree(stree);
247 +
248 + return_sm = get_sm_state(RETURN_ID, "return_ranges", NULL);
168 249 if (!return_sm)
169 - continue;
250 + goto swap_stree;
170 251 line.value = return_sm->line;
171 252
172 - sm = get_sm_state_stree(stree, my_id, name, sym);
253 + if (get_state_stree(start_states, my_id, name, sym) == &inc)
254 + goto swap_stree;
255 +
256 + if (parent_is_gone_var_sym(name, sym))
257 + goto swap_stree;
258 +
259 + sm = get_sm_state(my_id, name, sym);
173 260 if (!sm)
174 - continue;
261 + goto swap_stree;
175 262
176 - if (sm->state != &inc && sm->state != &dec)
177 - continue;
263 + if (sm->state != &inc &&
264 + sm->state != &dec &&
265 + sm->state != &orig)
266 + goto swap_stree;
178 267
268 + bucket = success_fail_positive(estate_rl(return_sm->state));
269 +
179 270 if (sm->state == &inc) {
180 271 add_range(&inc_lines, line, line);
181 - inc_buckets[success_fail_positive(estate_rl(return_sm->state))] = 1;
272 + inc_buckets[bucket] = true;
182 273 }
183 - if (sm->state == &dec)
274 + if (sm->state == &dec || sm->state == &orig) {
184 275 add_range(&dec_lines, line, line);
276 + dec_buckets[bucket] = true;
277 + }
278 +swap_stree:
279 + __swap_cur_stree(orig_stree);
185 280 } END_FOR_EACH_PTR(stree);
186 281
187 282 if (inc_buckets[NEGATIVE] &&
188 283 inc_buckets[ZERO]) {
189 284 // sm_warning("XXX '%s' not decremented on lines: %s.", name, show_rl(inc_lines));
190 285 }
191 286
192 287 }
193 288
194 289 static void match_check_missed(struct symbol *sym)
195 290 {
196 291 struct sm_state *sm;
197 292
198 293 FOR_EACH_MY_SM(my_id, get_all_return_states(), sm) {
199 294 check_counter(sm->name, sm->sym);
200 295 } END_FOR_EACH_SM(sm);
201 296 }
202 297
203 298 int on_atomic_dec_path(void)
204 299 {
205 300 struct sm_state *sm;
206 301
207 302 FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
208 303 if (sm->state == &dec)
209 304 return 1;
↓ open down ↓ |
15 lines elided |
↑ open up ↑ |
210 305 } END_FOR_EACH_SM(sm);
211 306
212 307 return 0;
213 308 }
214 309
215 310 int was_inced(const char *name, struct symbol *sym)
216 311 {
217 312 return get_state(my_id, name, sym) == &inc;
218 313 }
219 314
315 +static void match_save_states(struct expression *expr)
316 +{
317 + push_stree(&saved_stack, start_states);
318 + start_states = NULL;
319 +}
320 +
321 +static void match_restore_states(struct expression *expr)
322 +{
323 + start_states = pop_stree(&saved_stack);
324 +}
325 +
326 +static void match_after_func(struct symbol *sym)
327 +{
328 + free_stree(&start_states);
329 +}
330 +
220 331 void check_atomic_inc_dec(int id)
221 332 {
222 333 my_id = id;
223 334
224 335 if (option_project != PROJ_KERNEL)
225 336 return;
226 337
338 + add_unmatched_state_hook(my_id, &unmatched_state);
339 +
340 + add_split_return_callback(match_return_info);
227 341 select_return_states_hook(ATOMIC_INC, &db_inc);
228 342 select_return_states_hook(ATOMIC_DEC, &db_dec);
343 +
229 344 add_function_hook("atomic_inc_return", &match_atomic_inc, NULL);
230 345 add_function_hook("atomic_add_return", &match_atomic_add, NULL);
231 346 add_function_hook("atomic_sub_return", &match_atomic_sub, NULL);
232 347 add_function_hook("atomic_sub_and_test", &match_atomic_sub, NULL);
233 348 add_function_hook("atomic_dec_and_test", &match_atomic_dec, NULL);
234 349 add_function_hook("_atomic_dec_and_lock", &match_atomic_dec, NULL);
235 350 add_function_hook("atomic_dec", &match_atomic_dec, NULL);
236 351 add_function_hook("atomic_long_inc", &match_atomic_inc, NULL);
237 352 add_function_hook("atomic_long_dec", &match_atomic_dec, NULL);
238 353 add_function_hook("atomic_inc", &match_atomic_inc, NULL);
239 354 add_function_hook("atomic_sub", &match_atomic_sub, NULL);
240 - add_split_return_callback(match_return_info);
241 355
356 + add_function_hook("refcount_inc", &refcount_inc, INT_PTR(0));
357 + add_function_hook("refcount_dec", &refcount_dec, INT_PTR(0));
358 + add_function_hook("refcount_add", &refcount_inc, INT_PTR(1));
242 359 add_function_hook("refcount_add_not_zero", &refcount_inc, INT_PTR(1));
243 360 add_function_hook("refcount_inc_not_zero", &refcount_inc, INT_PTR(0));
244 361 add_function_hook("refcount_sub_and_test", &refcount_dec, INT_PTR(1));
245 - add_function_hook("refcount_dec_and_test", &refcount_dec, INT_PTR(1));
362 + add_function_hook("refcount_dec_and_test", &refcount_dec, INT_PTR(0));
246 363
247 364 add_hook(&match_check_missed, END_FUNC_HOOK);
365 +
366 + add_hook(&match_after_func, AFTER_FUNC_HOOK);
367 + add_hook(&match_save_states, INLINE_FN_START);
368 + add_hook(&match_restore_states, INLINE_FN_END);
248 369 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX