Print this page
11972 resync smatch
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/tools/smatch/src/check_free_strict.c
+++ new/usr/src/tools/smatch/src/check_free_strict.c
1 1 /*
2 2 * Copyright (C) 2010 Dan Carpenter.
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 * check_memory() is getting too big and messy.
20 20 *
21 21 */
22 22
23 23 #include <string.h>
24 24 #include "smatch.h"
25 25 #include "smatch_slist.h"
26 26 #include "smatch_extra.h"
27 27
28 28 static int my_id;
↓ open down ↓ |
28 lines elided |
↑ open up ↑ |
29 29
30 30 STATE(freed);
31 31 STATE(ok);
32 32
33 33 static void ok_to_use(struct sm_state *sm, struct expression *mod_expr)
34 34 {
35 35 if (sm->state != &ok)
36 36 set_state(my_id, sm->name, sm->sym, &ok);
37 37 }
38 38
39 -static void pre_merge_hook(struct sm_state *sm)
39 +static void pre_merge_hook(struct sm_state *cur, struct sm_state *other)
40 40 {
41 41 if (is_impossible_path())
42 - set_state(my_id, sm->name, sm->sym, &ok);
42 + set_state(my_id, cur->name, cur->sym, &ok);
43 43 }
44 44
45 +static struct smatch_state *unmatched_state(struct sm_state *sm)
46 +{
47 + struct smatch_state *state;
48 + sval_t sval;
49 +
50 + if (sm->state != &freed)
51 + return &undefined;
52 +
53 + state = get_state(SMATCH_EXTRA, sm->name, sm->sym);
54 + if (!state)
55 + return &undefined;
56 + if (!estate_get_single_value(state, &sval) || sval.value != 0)
57 + return &undefined;
58 + /* It makes it easier to consider NULL pointers as freed. */
59 + return &freed;
60 +}
61 +
45 62 static int is_freed(struct expression *expr)
46 63 {
47 64 struct sm_state *sm;
48 65
49 66 sm = get_sm_state_expr(my_id, expr);
50 67 if (sm && slist_has_state(sm->possible, &freed))
51 68 return 1;
52 69 return 0;
53 70 }
54 71
55 72 static void match_symbol(struct expression *expr)
56 73 {
57 74 struct expression *parent;
58 75 char *name;
59 76
60 77 if (is_impossible_path())
61 78 return;
62 79 if (__in_fake_parameter_assign)
63 80 return;
64 81
65 82 parent = expr_get_parent_expr(expr);
66 83 while (parent && parent->type == EXPR_PREOP && parent->op == '(')
67 84 parent = expr_get_parent_expr(parent);
68 85 if (parent && parent->type == EXPR_PREOP && parent->op == '&')
69 86 return;
70 87
71 88 if (!is_freed(expr))
72 89 return;
73 90 name = expr_to_var(expr);
74 91 sm_warning("'%s' was already freed.", name);
75 92 free_string(name);
76 93 }
77 94
78 95 static void match_dereferences(struct expression *expr)
79 96 {
80 97 char *name;
81 98
82 99 if (expr->type != EXPR_PREOP)
83 100 return;
84 101
85 102 if (is_impossible_path())
86 103 return;
87 104 if (__in_fake_parameter_assign)
88 105 return;
89 106
90 107 expr = strip_expr(expr->unop);
91 108 if (!is_freed(expr))
92 109 return;
93 110 name = expr_to_var(expr);
94 111 sm_error("dereferencing freed memory '%s'", name);
95 112 set_state_expr(my_id, expr, &ok);
96 113 free_string(name);
97 114 }
98 115
99 116 static int ignored_params[16];
100 117
101 118 static void set_ignored_params(struct expression *call)
102 119 {
103 120 struct expression *arg;
104 121 const char *p;
105 122 int i;
106 123
107 124 memset(&ignored_params, 0, sizeof(ignored_params));
108 125
109 126 i = -1;
110 127 FOR_EACH_PTR(call->args, arg) {
111 128 i++;
112 129 if (arg->type != EXPR_STRING)
113 130 continue;
114 131 goto found;
115 132 } END_FOR_EACH_PTR(arg);
116 133
117 134 return;
118 135
119 136 found:
120 137 i++;
121 138 p = arg->string->data;
122 139 while ((p = strchr(p, '%'))) {
123 140 if (i >= ARRAY_SIZE(ignored_params))
124 141 return;
125 142 p++;
126 143 if (*p == '%') {
127 144 p++;
128 145 continue;
129 146 }
130 147 if (*p == '.')
131 148 p++;
132 149 if (*p == '*')
133 150 i++;
134 151 if (*p == 'p')
135 152 ignored_params[i] = 1;
136 153 i++;
137 154 }
138 155 }
139 156
140 157 static int is_free_func(struct expression *fn)
141 158 {
142 159 char *name;
143 160 int ret = 0;
144 161
145 162 name = expr_to_str(fn);
146 163 if (!name)
147 164 return 0;
148 165 if (strstr(name, "free"))
149 166 ret = 1;
150 167 free_string(name);
151 168
152 169 return ret;
153 170 }
154 171
155 172 static void match_call(struct expression *expr)
156 173 {
157 174 struct expression *arg;
158 175 char *name;
159 176 int i;
160 177
161 178 if (is_impossible_path())
162 179 return;
163 180
164 181 set_ignored_params(expr);
165 182
166 183 i = -1;
167 184 FOR_EACH_PTR(expr->args, arg) {
168 185 i++;
169 186 if (!is_pointer(arg))
170 187 continue;
171 188 if (!is_freed(arg))
172 189 continue;
173 190 if (ignored_params[i])
174 191 continue;
175 192
176 193 name = expr_to_var(arg);
177 194 if (is_free_func(expr->fn))
178 195 sm_error("double free of '%s'", name);
179 196 else
180 197 sm_warning("passing freed memory '%s'", name);
181 198 set_state_expr(my_id, arg, &ok);
182 199 free_string(name);
183 200 } END_FOR_EACH_PTR(arg);
184 201 }
185 202
186 203 static void match_return(struct expression *expr)
187 204 {
188 205 char *name;
189 206
190 207 if (is_impossible_path())
191 208 return;
192 209
193 210 if (!expr)
194 211 return;
195 212 if (!is_freed(expr))
196 213 return;
197 214
198 215 name = expr_to_var(expr);
199 216 sm_warning("returning freed memory '%s'", name);
200 217 set_state_expr(my_id, expr, &ok);
201 218 free_string(name);
202 219 }
203 220
204 221 static void match_free(const char *fn, struct expression *expr, void *param)
205 222 {
206 223 struct expression *arg;
207 224
208 225 if (is_impossible_path())
209 226 return;
210 227
211 228 arg = get_argument_from_call_expr(expr->args, PTR_INT(param));
212 229 if (!arg)
213 230 return;
214 231 if (is_freed(arg)) {
215 232 char *name = expr_to_var(arg);
216 233
217 234 sm_error("double free of '%s'", name);
218 235 free_string(name);
219 236 }
220 237 set_state_expr(my_id, arg, &freed);
221 238 }
222 239
223 240 static void set_param_freed(struct expression *expr, int param, char *key, char *value)
224 241 {
225 242 struct expression *arg;
226 243 char *name;
227 244 struct symbol *sym;
228 245 struct sm_state *sm;
229 246
230 247 while (expr->type == EXPR_ASSIGNMENT)
231 248 expr = strip_expr(expr->right);
232 249 if (expr->type != EXPR_CALL)
233 250 return;
234 251
235 252 arg = get_argument_from_call_expr(expr->args, param);
236 253 if (!arg)
237 254 return;
238 255 name = get_variable_from_key(arg, key, &sym);
239 256 if (!name || !sym)
240 257 goto free;
241 258
242 259 if (!is_impossible_path()) {
243 260 sm = get_sm_state(my_id, name, sym);
244 261 if (sm && slist_has_state(sm->possible, &freed)) {
245 262 sm_warning("'%s' double freed", name);
246 263 set_state(my_id, name, sym, &ok); /* fixme: doesn't silence anything. I know */
247 264 }
248 265 }
249 266
250 267 set_state(my_id, name, sym, &freed);
251 268 free:
252 269 free_string(name);
253 270 }
254 271
255 272 int parent_is_free_var_sym_strict(const char *name, struct symbol *sym)
256 273 {
257 274 char buf[256];
258 275 char *start;
259 276 char *end;
260 277 struct smatch_state *state;
261 278
262 279 strncpy(buf, name, sizeof(buf) - 1);
263 280 buf[sizeof(buf) - 1] = '\0';
264 281
265 282 start = &buf[0];
266 283 while ((*start == '&'))
267 284 start++;
268 285
269 286 while ((end = strrchr(start, '-'))) {
270 287 *end = '\0';
271 288 state = __get_state(my_id, start, sym);
272 289 if (state == &freed)
273 290 return 1;
274 291 }
275 292 return 0;
276 293 }
277 294
278 295 int parent_is_free_strict(struct expression *expr)
279 296 {
280 297 struct symbol *sym;
281 298 char *var;
282 299 int ret = 0;
283 300
284 301 expr = strip_expr(expr);
285 302 var = expr_to_var_sym(expr, &sym);
286 303 if (!var || !sym)
287 304 goto free;
288 305 ret = parent_is_free_var_sym_strict(var, sym);
289 306 free:
290 307 free_string(var);
291 308 return ret;
292 309 }
293 310
294 311 static void match_untracked(struct expression *call, int param)
295 312 {
296 313 struct state_list *slist = NULL;
297 314 struct expression *arg;
298 315 struct sm_state *sm;
299 316 char *name;
300 317 char buf[64];
301 318 int len;
302 319
303 320 arg = get_argument_from_call_expr(call->args, param);
304 321 if (!arg)
305 322 return;
306 323
307 324 name = expr_to_var(arg);
308 325 if (!name)
309 326 return;
310 327 snprintf(buf, sizeof(buf), "%s->", name);
311 328 free_string(name);
312 329 len = strlen(buf);
313 330
314 331 FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
315 332 if (strncmp(sm->name, buf, len) == 0)
316 333 add_ptr_list(&slist, sm);
317 334 } END_FOR_EACH_SM(sm);
318 335
319 336 FOR_EACH_PTR(slist, sm) {
320 337 set_state(sm->owner, sm->name, sm->sym, &ok);
321 338 } END_FOR_EACH_PTR(sm);
322 339
323 340 free_slist(&slist);
324 341 }
325 342
326 343 void check_free_strict(int id)
327 344 {
328 345 my_id = id;
329 346
330 347 if (option_project != PROJ_KERNEL)
331 348 return;
332 349
333 350 add_function_hook("kfree", &match_free, INT_PTR(0));
↓ open down ↓ |
279 lines elided |
↑ open up ↑ |
334 351 add_function_hook("kmem_cache_free", &match_free, INT_PTR(1));
335 352
336 353 if (option_spammy)
337 354 add_hook(&match_symbol, SYM_HOOK);
338 355 add_hook(&match_dereferences, DEREF_HOOK);
339 356 add_hook(&match_call, FUNCTION_CALL_HOOK);
340 357 add_hook(&match_return, RETURN_HOOK);
341 358
342 359 add_modification_hook_late(my_id, &ok_to_use);
343 360 add_pre_merge_hook(my_id, &pre_merge_hook);
361 + add_unmatched_state_hook(my_id, &unmatched_state);
344 362
345 363 select_return_states_hook(PARAM_FREED, &set_param_freed);
346 364 add_untracked_param_hook(&match_untracked);
347 365 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX