comparison: call simplify_binops() in get_comparison_helper()
[smatch.git] / check_free_strict.c
blob8c46f237d97a922d3e146291265c1b81d1b12143
1 /*
2 * Copyright (C) 2010 Dan Carpenter.
3 * Copyright (C) 2020 Oracle.
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
20 * This is the "strict" version which is more daring and ambitious than
21 * the check_free.c file. The difference is that this looks at split
22 * returns and the other only looks at if every path frees a parameter.
23 * Also this has a bunch of kernel specific things to do with reference
24 * counted memory.
27 #include <string.h>
28 #include "smatch.h"
29 #include "smatch_slist.h"
30 #include "smatch_extra.h"
32 static int my_id;
34 STATE(freed);
35 STATE(maybe_freed);
36 STATE(ok);
38 static void ok_to_use(struct sm_state *sm, struct expression *mod_expr)
40 if (sm->state != &ok)
41 set_state(my_id, sm->name, sm->sym, &ok);
44 static void pre_merge_hook(struct sm_state *cur, struct sm_state *other)
46 if (is_impossible_path())
47 set_state(my_id, cur->name, cur->sym, &ok);
50 static struct smatch_state *unmatched_state(struct sm_state *sm)
52 struct smatch_state *state;
53 sval_t sval;
55 if (sm->state != &freed && sm->state != &maybe_freed)
56 return &undefined;
59 * If the parent is non-there count it as freed. This is
60 * a hack for tracking return states.
62 if (parent_is_null_var_sym(sm->name, sm->sym))
63 return sm->state;
65 state = get_state(SMATCH_EXTRA, sm->name, sm->sym);
66 if (!state)
67 return &undefined;
68 if (!estate_get_single_value(state, &sval) || sval.value != 0)
69 return &undefined;
70 /* It makes it easier to consider NULL pointers as freed. */
71 return &freed;
74 struct smatch_state *merge_frees(struct smatch_state *s1, struct smatch_state *s2)
76 if (s1 == &freed && s2 == &maybe_freed)
77 return &maybe_freed;
78 if (s1 == &maybe_freed && s2 == &freed)
79 return &maybe_freed;
80 return &merged;
83 static int is_freed(struct expression *expr)
85 struct sm_state *sm;
87 sm = get_sm_state_expr(my_id, expr);
88 if (sm && slist_has_state(sm->possible, &freed))
89 return 1;
90 return 0;
93 bool is_freed_var_sym(const char *name, struct symbol *sym)
95 struct smatch_state *state;
97 state = get_state(my_id, name, sym);
98 if (state == &freed || state == &maybe_freed)
99 return true;
101 return false;
104 static void match_symbol(struct expression *expr)
106 struct expression *parent;
107 char *name;
109 if (is_impossible_path())
110 return;
111 if (__in_fake_parameter_assign)
112 return;
114 parent = expr_get_parent_expr(expr);
115 while (parent && parent->type == EXPR_PREOP && parent->op == '(')
116 parent = expr_get_parent_expr(parent);
117 if (parent && parent->type == EXPR_PREOP && parent->op == '&')
118 return;
120 if (!is_freed(expr))
121 return;
122 name = expr_to_var(expr);
123 sm_warning("'%s' was already freed.", name);
124 free_string(name);
127 static void match_dereferences(struct expression *expr)
129 char *name;
131 if (expr->type != EXPR_PREOP)
132 return;
134 if (is_impossible_path())
135 return;
136 if (__in_fake_parameter_assign)
137 return;
139 expr = strip_expr(expr->unop);
140 if (!is_freed(expr))
141 return;
142 name = expr_to_var(expr);
143 sm_error("dereferencing freed memory '%s'", name);
144 set_state_expr(my_id, expr, &ok);
145 free_string(name);
148 static int ignored_params[16];
150 static void set_ignored_params(struct expression *call)
152 struct expression *arg;
153 const char *p;
154 int i;
156 memset(&ignored_params, 0, sizeof(ignored_params));
158 i = -1;
159 FOR_EACH_PTR(call->args, arg) {
160 i++;
161 if (arg->type != EXPR_STRING)
162 continue;
163 goto found;
164 } END_FOR_EACH_PTR(arg);
166 return;
168 found:
169 i++;
170 p = arg->string->data;
171 while ((p = strchr(p, '%'))) {
172 if (i >= ARRAY_SIZE(ignored_params))
173 return;
174 p++;
175 if (*p == '%') {
176 p++;
177 continue;
179 if (*p == '.')
180 p++;
181 if (*p == '*')
182 i++;
183 if (*p == 'p')
184 ignored_params[i] = 1;
185 i++;
189 static int is_free_func(struct expression *fn)
191 char *name;
192 int ret = 0;
194 name = expr_to_str(fn);
195 if (!name)
196 return 0;
197 if (strstr(name, "free"))
198 ret = 1;
199 free_string(name);
201 return ret;
204 static void match_call(struct expression *expr)
206 struct expression *arg;
207 char *name;
208 int i;
210 if (is_impossible_path())
211 return;
213 set_ignored_params(expr);
215 i = -1;
216 FOR_EACH_PTR(expr->args, arg) {
217 i++;
218 if (!is_pointer(arg))
219 continue;
220 if (!is_freed(arg))
221 continue;
222 if (ignored_params[i])
223 continue;
225 name = expr_to_var(arg);
226 if (is_free_func(expr->fn))
227 sm_error("double free of '%s'", name);
228 else
229 sm_warning("passing freed memory '%s'", name);
230 set_state_expr(my_id, arg, &ok);
231 free_string(name);
232 } END_FOR_EACH_PTR(arg);
235 static void match_return(struct expression *expr)
237 char *name;
239 if (is_impossible_path())
240 return;
242 if (!expr)
243 return;
244 if (!is_freed(expr))
245 return;
247 name = expr_to_var(expr);
248 sm_warning("returning freed memory '%s'", name);
249 set_state_expr(my_id, expr, &ok);
250 free_string(name);
253 static int counter_was_inced(struct expression *expr)
255 char *name;
256 struct symbol *sym;
257 char buf[256];
258 int ret = 0;
260 name = expr_to_var_sym(expr, &sym);
261 if (!name || !sym)
262 goto free;
264 snprintf(buf, sizeof(buf), "%s->users.counter", name);
265 ret = was_inced(buf, sym);
266 free:
267 free_string(name);
268 return ret;
271 void set_other_states_name_sym(int owner, const char *name, struct symbol *sym, struct smatch_state *state)
273 struct expression *tmp;
274 struct sm_state *sm;
276 FOR_EACH_MY_SM(check_assigned_expr_id, __get_cur_stree(), sm) {
277 tmp = sm->state->data;
278 if (!tmp)
279 continue;
280 if (tmp->type != EXPR_SYMBOL)
281 continue;
282 if (tmp->symbol != sym)
283 continue;
284 if (!tmp->symbol_name)
285 continue;
286 if (strcmp(tmp->symbol_name->name, name) != 0)
287 continue;
288 set_state(owner, tmp->symbol_name->name, tmp->symbol, state);
289 } END_FOR_EACH_SM(sm);
291 tmp = get_assigned_expr_name_sym(name, sym);
292 if (tmp)
293 set_state_expr(owner, tmp, state);
296 void set_other_states(int owner, struct expression *expr, struct smatch_state *state)
298 struct symbol *sym;
299 char *name;
301 name = expr_to_var_sym(expr, &sym);
302 if (!name || !sym)
303 goto free;
305 set_other_states_name_sym(owner, name, sym, state);
307 free:
308 free_string(name);
311 static void match_free(const char *fn, struct expression *expr, void *param)
313 struct expression *arg;
315 if (is_impossible_path())
316 return;
318 arg = get_argument_from_call_expr(expr->args, PTR_INT(param));
319 if (!arg)
320 return;
321 if (strcmp(fn, "kfree_skb") == 0 && counter_was_inced(arg))
322 return;
323 if (is_freed(arg)) {
324 char *name = expr_to_var(arg);
326 sm_error("double free of '%s'", name);
327 free_string(name);
329 track_freed_param(arg, &freed);
330 set_state_expr(my_id, arg, &freed);
331 set_other_states(my_id, arg, &freed);
334 static void match_kobject_put(const char *fn, struct expression *expr, void *param)
336 struct expression *arg;
338 arg = get_argument_from_call_expr(expr->args, PTR_INT(param));
339 if (!arg)
340 return;
341 /* kobject_put(&cdev->kobj); */
342 if (arg->type != EXPR_PREOP || arg->op != '&')
343 return;
344 arg = strip_expr(arg->unop);
345 if (arg->type != EXPR_DEREF)
346 return;
347 arg = strip_expr(arg->deref);
348 if (arg->type != EXPR_PREOP || arg->op != '*')
349 return;
350 arg = strip_expr(arg->unop);
351 track_freed_param(arg, &maybe_freed);
352 set_state_expr(my_id, arg, &maybe_freed);
355 struct string_list *handled;
356 static bool is_handled_func(struct expression *fn)
358 if (!fn || fn->type != EXPR_SYMBOL || !fn->symbol->ident)
359 return false;
361 return list_has_string(handled, fn->symbol->ident->name);
364 static void set_param_helper(struct expression *expr, int param,
365 char *key, char *value,
366 struct smatch_state *state)
368 struct expression *arg;
369 char *name;
370 struct symbol *sym;
371 struct sm_state *sm;
373 while (expr->type == EXPR_ASSIGNMENT)
374 expr = strip_expr(expr->right);
375 if (expr->type != EXPR_CALL)
376 return;
378 if (is_handled_func(expr->fn))
379 return;
381 arg = get_argument_from_call_expr(expr->args, param);
382 if (!arg)
383 return;
384 name = get_variable_from_key(arg, key, &sym);
385 if (!name || !sym)
386 goto free;
388 if (state == &freed && !is_impossible_path()) {
389 sm = get_sm_state(my_id, name, sym);
390 if (sm && slist_has_state(sm->possible, &freed)) {
391 sm_warning("'%s' double freed", name);
392 set_state(my_id, name, sym, &ok); /* fixme: doesn't silence anything. I know */
396 track_freed_param_var_sym(name, sym, state);
397 set_state(my_id, name, sym, state);
398 set_other_states_name_sym(my_id, name, sym, state);
399 free:
400 free_string(name);
403 static void set_param_freed(struct expression *expr, int param, char *key, char *value)
405 set_param_helper(expr, param, key, value, &freed);
408 static void set_param_maybe_freed(struct expression *expr, int param, char *key, char *value)
410 set_param_helper(expr, param, key, value, &maybe_freed);
413 int parent_is_free_var_sym_strict(const char *name, struct symbol *sym)
415 char buf[256];
416 char *start;
417 char *end;
418 char orig;
419 struct smatch_state *state;
421 strncpy(buf, name, sizeof(buf) - 1);
422 buf[sizeof(buf) - 1] = '\0';
424 start = &buf[0];
425 while ((*start == '&'))
426 start++;
428 end = start;
429 while ((end = strrchr(end, '-'))) {
430 orig = *end;
431 *end = '\0';
433 state = __get_state(my_id, start, sym);
434 if (state == &freed)
435 return 1;
436 *end = orig;
437 end++;
439 return 0;
442 int parent_is_free_strict(struct expression *expr)
444 struct symbol *sym;
445 char *var;
446 int ret = 0;
448 expr = strip_expr(expr);
449 var = expr_to_var_sym(expr, &sym);
450 if (!var || !sym)
451 goto free;
452 ret = parent_is_free_var_sym_strict(var, sym);
453 free:
454 free_string(var);
455 return ret;
458 static void match_untracked(struct expression *call, int param)
460 struct state_list *slist = NULL;
461 struct expression *arg;
462 struct sm_state *sm;
463 char *name;
464 char buf[64];
465 int len;
467 arg = get_argument_from_call_expr(call->args, param);
468 if (!arg)
469 return;
471 name = expr_to_var(arg);
472 if (!name)
473 return;
474 snprintf(buf, sizeof(buf), "%s->", name);
475 free_string(name);
476 len = strlen(buf);
478 FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
479 if (strncmp(sm->name, buf, len) == 0)
480 add_ptr_list(&slist, sm);
481 } END_FOR_EACH_SM(sm);
483 FOR_EACH_PTR(slist, sm) {
484 set_state(sm->owner, sm->name, sm->sym, &ok);
485 } END_FOR_EACH_PTR(sm);
487 free_slist(&slist);
490 void add_free_hook(const char *func, func_hook *call_back, int param)
492 insert_string(&handled, func);
493 add_function_hook(func, call_back, INT_PTR(param));
496 void check_free_strict(int id)
498 my_id = id;
500 if (option_project != PROJ_KERNEL)
501 return;
503 add_free_hook("free", &match_free, 0);
504 add_free_hook("kfree", &match_free, 0);
505 add_free_hook("vfree", &match_free, 0);
506 add_free_hook("kzfree", &match_free, 0);
507 add_free_hook("kvfree", &match_free, 0);
508 add_free_hook("kmem_cache_free", &match_free, 1);
509 add_free_hook("kfree_skb", &match_free, 0);
510 add_free_hook("kfree_skbmem", &match_free, 0);
511 add_free_hook("dma_pool_free", &match_free, 1);
512 // add_free_hook("spi_unregister_controller", &match_free, 0);
513 add_free_hook("netif_rx_internal", &match_free, 0);
514 add_free_hook("netif_rx", &match_free, 0);
515 add_free_hook("enqueue_to_backlog", &match_free, 0);
517 add_free_hook("brelse", &match_free, 0);
518 add_free_hook("kobject_put", &match_kobject_put, 0);
519 add_free_hook("kref_put", &match_kobject_put, 0);
520 add_free_hook("put_device", &match_kobject_put, 0);
522 add_free_hook("dma_free_coherent", match_free, 2);
524 if (option_spammy)
525 add_hook(&match_symbol, SYM_HOOK);
526 add_hook(&match_dereferences, DEREF_HOOK);
527 add_hook(&match_call, FUNCTION_CALL_HOOK);
528 add_hook(&match_return, RETURN_HOOK);
530 add_modification_hook_late(my_id, &ok_to_use);
531 add_pre_merge_hook(my_id, &pre_merge_hook);
532 add_unmatched_state_hook(my_id, &unmatched_state);
533 add_merge_hook(my_id, &merge_frees);
535 select_return_states_hook(PARAM_FREED, &set_param_freed);
536 select_return_states_hook(MAYBE_FREED, &set_param_maybe_freed);
537 add_untracked_param_hook(&match_untracked);