param_key: fix container of when no struct member is referenced
[smatch.git] / check_free_strict.c
blob2a61608451929e5899f1b8c62f5fba2b2e7a7175
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 match_kobject_put(struct expression *expr, const char *name, struct symbol *sym, void *data);
40 struct func_info {
41 const char *name;
42 int type;
43 int param;
44 const char *key;
45 const sval_t *implies_start, *implies_end;
46 param_key_hook *call_back;
49 static struct func_info func_table[] = {
50 { "free", PARAM_FREED, 0, "$" },
51 { "kfree", PARAM_FREED, 0, "$" },
52 { "vfree", PARAM_FREED, 0, "$" },
53 { "kzfree", PARAM_FREED, 0, "$" },
54 { "kvfree", PARAM_FREED, 0, "$" },
56 { "kfree_skb", PARAM_FREED, 0, "$" },
57 { "kfree_skbmem", PARAM_FREED, 0, "$" },
59 { "mempool_free", PARAM_FREED, 0, "$" },
60 { "kmem_cache_free", PARAM_FREED, 1, "$" },
61 { "dma_pool_free", PARAM_FREED, 1, "$" },
63 { "memstick_free_host", PARAM_FREED, 0, "$" },
64 // { "spi_unregister_controller", PARAM_FREED, 0, "$" },
65 { "netif_rx_internal", PARAM_FREED, 0, "$" },
66 { "netif_rx", PARAM_FREED, 0, "$" },
68 { "enqueue_to_backlog", PARAM_FREED, 0, "$" },
70 { "brelse", PARAM_FREED, 0, "$" },
71 { "dma_free_coherent", PARAM_FREED, 2, "$" },
72 { "free_netdev", PARAM_FREED, 0, "$" },
74 { "kobject_put", PARAM_FREED, 0, "$", NULL, NULL, &match_kobject_put },
75 { "kref_put", PARAM_FREED, 0, "$", NULL, NULL, &match_kobject_put },
76 { "put_device", PARAM_FREED, 0, "$", NULL, NULL, &match_kobject_put },
79 static struct name_sym_fn_list *free_hooks;
81 void add_free_hook(name_sym_hook *hook)
83 add_ptr_list(&free_hooks, hook);
86 static void call_free_call_backs_name_sym(struct expression *expr, const char *name, struct symbol *sym)
88 name_sym_hook *hook;
90 if (!expr)
91 expr = gen_expression_from_name_sym(name, sym);
93 FOR_EACH_PTR(free_hooks, hook) {
94 hook(expr, name, sym);
95 } END_FOR_EACH_PTR(hook);
98 static void ok_to_use(struct sm_state *sm, struct expression *mod_expr)
100 if (sm->state != &ok)
101 set_state(my_id, sm->name, sm->sym, &ok);
104 static void pre_merge_hook(struct sm_state *cur, struct sm_state *other)
106 if (is_impossible_path())
107 set_state(my_id, cur->name, cur->sym, &ok);
110 static struct smatch_state *unmatched_state(struct sm_state *sm)
112 struct smatch_state *state;
113 sval_t sval;
115 if (sm->state != &freed && sm->state != &maybe_freed)
116 return &undefined;
118 if (get_param_num_from_sym(sm->sym) < 0)
119 return &undefined;
122 * If the parent is non-there count it as freed. This is
123 * a hack for tracking return states.
125 if (parent_is_null_var_sym(sm->name, sm->sym))
126 return sm->state;
128 state = get_state(SMATCH_EXTRA, sm->name, sm->sym);
129 if (!state)
130 return &undefined;
131 if (!estate_get_single_value(state, &sval) || sval.value != 0)
132 return &undefined;
133 /* It makes it easier to consider NULL pointers as freed. */
134 return &freed;
137 struct smatch_state *merge_frees(struct smatch_state *s1, struct smatch_state *s2)
139 if (s1 == &freed && s2 == &maybe_freed)
140 return &maybe_freed;
141 if (s1 == &maybe_freed && s2 == &freed)
142 return &maybe_freed;
143 return &merged;
146 static int is_freed(struct expression *expr)
148 struct sm_state *sm;
150 sm = get_sm_state_expr(my_id, expr);
151 if (sm && slist_has_state(sm->possible, &freed))
152 return 1;
153 return 0;
156 bool is_freed_var_sym(const char *name, struct symbol *sym)
158 struct smatch_state *state;
160 state = get_state(my_id, name, sym);
161 if (state == &freed || state == &maybe_freed)
162 return true;
164 return false;
167 static bool expr_is_condition(struct expression *expr)
169 struct statement *stmt;
171 stmt = expr_get_parent_stmt(expr);
172 if (!stmt)
173 return false;
174 if (stmt->type == STMT_IF || stmt->type == STMT_ITERATOR)
175 return true;
176 return false;
179 bool is_part_of_condition(struct expression *expr)
181 struct expression *parent;
183 if (expr_is_condition(expr))
184 return true;
186 parent = expr_get_parent_expr(expr);
187 if (!parent)
188 return false;
189 if (parent->type == EXPR_LOGICAL || parent->type == EXPR_COMPARE)
190 return true;
191 if (parent->type == EXPR_SELECT || parent->type == EXPR_CONDITIONAL)
192 return true;
193 if (parent->type == EXPR_PREOP && parent->op == '!')
194 return true;
196 return false;
199 static bool is_percent_p(struct expression *str_expr, int idx)
201 char *p;
202 int cnt = 0;
204 p = str_expr->string->data;
205 while (p[0]) {
206 if (p[0] == '%' && p[1] == '%') {
207 p += 2;
208 continue;
210 /* If we have print("%.*s %p", prec, str, p); then it takes 2 params */
211 if ((p[0] == '%' && p[1] == '*') ||
212 (p[0] == '%' && p[1] == '.' && p[2] == '*'))
213 cnt++;
214 if (p[0] == '%') {
215 cnt++;
216 if (idx == cnt && p[1] == 'p')
217 return true;
219 p++;
221 return false;
224 bool is_percent_p_print(struct expression *expr)
226 struct expression *parent, *arg;
227 int expr_idx, string_idx;
229 parent = expr_get_parent_expr(expr);
230 if (!parent || parent->type != EXPR_CALL)
231 return false;
233 expr_idx = -1;
234 FOR_EACH_PTR(parent->args, arg) {
235 expr_idx++;
236 if (arg == expr)
237 goto found;
238 } END_FOR_EACH_PTR(arg);
240 return false;
241 found:
243 string_idx = -1;
244 FOR_EACH_PTR(parent->args, arg) {
245 string_idx++;
246 if (arg->type != EXPR_STRING)
247 continue;
248 if (is_percent_p(arg, expr_idx - string_idx))
249 return true;
250 } END_FOR_EACH_PTR(arg);
252 return false;
255 static void match_symbol(struct expression *expr)
257 struct expression *parent;
258 char *name;
260 if (is_impossible_path())
261 return;
262 if (__in_fake_parameter_assign)
263 return;
265 if (is_part_of_condition(expr))
266 return;
268 /* This ignores stuff like "get_new_ptr(&foo);" */
269 parent = expr_get_parent_expr(expr);
270 while (parent && parent->type == EXPR_PREOP && parent->op == '(')
271 parent = expr_get_parent_expr(parent);
272 if (parent && parent->type == EXPR_PREOP && parent->op == '&')
273 return;
275 if (!is_freed(expr))
276 return;
278 if (is_percent_p_print(expr))
279 return;
281 name = expr_to_var(expr);
282 sm_warning("'%s' was already freed.", name);
283 free_string(name);
286 static void match_dereferences(struct expression *expr)
288 char *name;
290 if (expr->type != EXPR_PREOP)
291 return;
293 if (is_impossible_path())
294 return;
295 if (__in_fake_parameter_assign)
296 return;
298 expr = strip_expr(expr->unop);
299 if (!is_freed(expr))
300 return;
301 name = expr_to_var(expr);
302 sm_error("dereferencing freed memory '%s'", name);
303 set_state_expr(my_id, expr, &ok);
304 free_string(name);
307 static int ignored_params[16];
309 static void set_ignored_params(struct expression *call)
311 struct expression *arg;
312 const char *p;
313 int i;
315 memset(&ignored_params, 0, sizeof(ignored_params));
317 i = -1;
318 FOR_EACH_PTR(call->args, arg) {
319 i++;
320 if (arg->type != EXPR_STRING)
321 continue;
322 goto found;
323 } END_FOR_EACH_PTR(arg);
325 return;
327 found:
328 i++;
329 p = arg->string->data;
330 while ((p = strchr(p, '%'))) {
331 if (i >= ARRAY_SIZE(ignored_params))
332 return;
333 p++;
334 if (*p == '%') {
335 p++;
336 continue;
338 if (*p == '.')
339 p++;
340 if (*p == '*')
341 i++;
342 if (*p == 'p')
343 ignored_params[i] = 1;
344 i++;
348 static int is_free_func(struct expression *fn)
350 char *name;
351 int ret = 0;
353 name = expr_to_str(fn);
354 if (!name)
355 return 0;
356 if (strstr(name, "free"))
357 ret = 1;
358 free_string(name);
360 return ret;
363 static void match_call(struct expression *expr)
365 struct expression *arg;
366 char *name;
367 int i;
369 if (is_impossible_path())
370 return;
372 set_ignored_params(expr);
374 i = -1;
375 FOR_EACH_PTR(expr->args, arg) {
376 i++;
377 if (!is_pointer(arg))
378 continue;
379 if (!is_freed(arg))
380 continue;
381 if (ignored_params[i])
382 continue;
383 if (is_percent_p_print(arg))
384 continue;
386 name = expr_to_var(arg);
387 if (is_free_func(expr->fn))
388 sm_error("double free of '%s'", name);
389 else
390 sm_warning("passing freed memory '%s'", name);
391 set_state_expr(my_id, arg, &ok);
392 free_string(name);
393 } END_FOR_EACH_PTR(arg);
396 static void match_return(struct expression *expr)
398 char *name;
400 if (is_impossible_path())
401 return;
403 if (!expr)
404 return;
405 if (!is_freed(expr))
406 return;
408 name = expr_to_var(expr);
409 sm_warning("returning freed memory '%s'", name);
410 set_state_expr(my_id, expr, &ok);
411 free_string(name);
414 static int counter_was_inced_name_sym(const char *name, struct symbol *sym, const char *counter_str)
416 char buf[256];
418 snprintf(buf, sizeof(buf), "%s%s", name, counter_str);
419 return was_inced(buf, sym);
422 static int counter_was_inced(struct expression *expr, const char *counter_str)
424 char *name;
425 struct symbol *sym;
426 int ret = 0;
428 name = expr_to_var_sym(expr, &sym);
429 if (!name || !sym)
430 goto free;
432 ret = counter_was_inced_name_sym(name, sym, counter_str);
433 free:
434 free_string(name);
435 return ret;
438 static bool is_ptr_to(struct expression *expr, const char *type)
440 struct symbol *sym;
442 sym = get_type(expr);
443 if (!is_ptr_type(sym))
444 return false;
445 sym = get_real_base_type(sym);
446 if (sym && sym->ident && strcmp(sym->ident->name, type) == 0)
447 return true;
448 return false;
451 static void match_free(struct expression *expr, const char *name, struct symbol *sym, void *data)
453 struct expression *arg;
455 if (is_impossible_path())
456 return;
458 arg = gen_expression_from_name_sym(name, sym);
459 if (!arg)
460 return;
461 if (is_ptr_to(arg, "sk_buff") &&
462 counter_was_inced(arg, "->users.refs.counter"))
463 return;
464 if (is_ptr_to(arg, "buffer_head") &&
465 counter_was_inced(arg, "->b_count.counter"))
466 return;
467 if (is_freed(arg))
468 sm_error("double free of '%s'", name);
470 track_freed_param(arg, &freed);
471 call_free_call_backs_name_sym(expr, name, sym);
472 set_state_expr(my_id, arg, &freed);
476 static void match_kobject_put(struct expression *expr, const char *name, struct symbol *sym, void *data)
478 struct expression *arg;
480 arg = gen_expression_from_name_sym(name, sym);
481 if (!arg)
482 return;
483 /* kobject_put(&cdev->kobj); */
484 if (arg->type != EXPR_PREOP || arg->op != '&')
485 return;
486 arg = strip_expr(arg->unop);
487 if (arg->type != EXPR_DEREF)
488 return;
489 arg = strip_expr(arg->deref);
490 if (arg->type != EXPR_PREOP || arg->op != '*')
491 return;
492 arg = strip_expr(arg->unop);
493 track_freed_param(arg, &maybe_freed);
494 set_state_expr(my_id, arg, &maybe_freed);
497 struct string_list *handled;
498 static bool is_handled_func(struct expression *fn)
500 if (!fn || fn->type != EXPR_SYMBOL || !fn->symbol->ident)
501 return false;
503 return list_has_string(handled, fn->symbol->ident->name);
506 static void set_param_helper(struct expression *expr, int param,
507 char *key, char *value,
508 struct smatch_state *state)
510 struct expression *arg;
511 char *name;
512 struct symbol *sym;
513 struct sm_state *sm;
515 while (expr->type == EXPR_ASSIGNMENT)
516 expr = strip_expr(expr->right);
517 if (expr->type != EXPR_CALL)
518 return;
520 if (is_handled_func(expr->fn))
521 return;
523 arg = get_argument_from_call_expr(expr->args, param);
524 if (!arg)
525 return;
526 name = get_variable_from_key(arg, key, &sym);
527 if (!name || !sym)
528 goto free;
530 /* skbs are not free if we called skb_get(). */
531 if (counter_was_inced_name_sym(name, sym, "->users.refs.counter"))
532 goto free;
534 if (state == &freed && !is_impossible_path()) {
535 sm = get_sm_state(my_id, name, sym);
536 if (sm && slist_has_state(sm->possible, &freed)) {
537 sm_warning("'%s' double freed", name);
538 set_state(my_id, name, sym, &ok); /* fixme: doesn't silence anything. I know */
542 track_freed_param_var_sym(name, sym, state);
543 if (state == &freed)
544 call_free_call_backs_name_sym(NULL, name, sym);
545 set_state(my_id, name, sym, state);
546 free:
547 free_string(name);
550 static void set_param_freed(struct expression *expr, int param, char *key, char *value)
552 set_param_helper(expr, param, key, value, &freed);
555 static void set_param_maybe_freed(struct expression *expr, int param, char *key, char *value)
557 set_param_helper(expr, param, key, value, &maybe_freed);
560 int parent_is_free_var_sym_strict(const char *name, struct symbol *sym)
562 char buf[256];
563 char *start;
564 char *end;
565 char orig;
566 struct smatch_state *state;
568 strncpy(buf, name, sizeof(buf) - 1);
569 buf[sizeof(buf) - 1] = '\0';
571 start = &buf[0];
572 while ((*start == '&'))
573 start++;
575 end = start;
576 while ((end = strrchr(end, '-'))) {
577 orig = *end;
578 *end = '\0';
580 state = __get_state(my_id, start, sym);
581 if (state == &freed)
582 return 1;
583 *end = orig;
584 end++;
586 return 0;
589 int parent_is_free_strict(struct expression *expr)
591 struct symbol *sym;
592 char *var;
593 int ret = 0;
595 expr = strip_expr(expr);
596 var = expr_to_var_sym(expr, &sym);
597 if (!var || !sym)
598 goto free;
599 ret = parent_is_free_var_sym_strict(var, sym);
600 free:
601 free_string(var);
602 return ret;
605 static void match_untracked(struct expression *call, int param)
607 struct state_list *slist = NULL;
608 struct expression *arg;
609 struct sm_state *sm;
610 char *name;
611 char buf[64];
612 int len;
614 arg = get_argument_from_call_expr(call->args, param);
615 if (!arg)
616 return;
618 name = expr_to_var(arg);
619 if (!name)
620 return;
621 snprintf(buf, sizeof(buf), "%s->", name);
622 free_string(name);
623 len = strlen(buf);
625 FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
626 if (strncmp(sm->name, buf, len) == 0)
627 add_ptr_list(&slist, sm);
628 } END_FOR_EACH_SM(sm);
630 FOR_EACH_PTR(slist, sm) {
631 set_state(sm->owner, sm->name, sm->sym, &ok);
632 } END_FOR_EACH_PTR(sm);
634 free_slist(&slist);
637 void check_free_strict(int id)
639 struct func_info *info;
640 param_key_hook *cb;
641 int i;
643 my_id = id;
645 if (option_project != PROJ_KERNEL)
646 return;
648 for (i = 0; i < ARRAY_SIZE(func_table); i++) {
649 info = &func_table[i];
651 insert_string(&handled, info->name);
653 if (info->call_back)
654 cb = info->call_back;
655 else
656 cb = &match_free;
658 if (info->implies_start) {
659 return_implies_param_key(info->name,
660 *info->implies_start, *info->implies_end,
661 cb, info->param, info->key, info);
662 } else {
663 add_function_param_key_hook(info->name, cb,
664 info->param, info->key, info);
668 if (option_spammy)
669 add_hook(&match_symbol, SYM_HOOK);
670 add_hook(&match_dereferences, DEREF_HOOK);
671 add_hook(&match_call, FUNCTION_CALL_HOOK);
672 add_hook(&match_return, RETURN_HOOK);
674 add_modification_hook_late(my_id, &ok_to_use);
675 add_pre_merge_hook(my_id, &pre_merge_hook);
676 add_unmatched_state_hook(my_id, &unmatched_state);
677 add_merge_hook(my_id, &merge_frees);
679 select_return_states_hook(PARAM_FREED, &set_param_freed);
680 select_return_states_hook(MAYBE_FREED, &set_param_maybe_freed);
681 add_untracked_param_hook(&match_untracked);