kernel.return_fixes: add mipi_dsi_device_transfer(), timer_delete() and get_device()
[smatch.git] / check_free_strict.c
blob15fc7476877a5abb237eb2ec23d356c5963cd526
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);
39 static void match___skb_pad(struct expression *expr, const char *name, struct symbol *sym, void *data);
41 struct func_info {
42 const char *name;
43 int type;
44 int param;
45 const char *key;
46 const sval_t *implies_start, *implies_end;
47 param_key_hook *call_back;
50 static struct func_info func_table[] = {
51 { "free", PARAM_FREED, 0, "$" },
52 { "kfree", PARAM_FREED, 0, "$" },
53 { "vfree", PARAM_FREED, 0, "$" },
54 { "kzfree", PARAM_FREED, 0, "$" },
55 { "kvfree", PARAM_FREED, 0, "$" },
57 { "kfree_skb", PARAM_FREED, 0, "$" },
58 { "kfree_skbmem", PARAM_FREED, 0, "$" },
60 { "mempool_free", PARAM_FREED, 0, "$" },
61 { "kmem_cache_free", PARAM_FREED, 1, "$" },
62 { "dma_pool_free", PARAM_FREED, 1, "$" },
64 { "memstick_free_host", PARAM_FREED, 0, "$" },
65 // { "spi_unregister_controller", PARAM_FREED, 0, "$" },
66 { "netif_rx_internal", PARAM_FREED, 0, "$" },
67 { "netif_rx", PARAM_FREED, 0, "$" },
69 { "enqueue_to_backlog", PARAM_FREED, 0, "$" },
71 { "brelse", PARAM_FREED, 0, "$" },
72 { "dma_free_coherent", PARAM_FREED, 2, "$" },
73 { "free_netdev", PARAM_FREED, 0, "$" },
74 { "sock_release", PARAM_FREED, 0, "$" },
76 { "qdisc_enqueue", PARAM_FREED, 0, "$" },
78 { "kobject_put", PARAM_FREED, 0, "$", NULL, NULL, &match_kobject_put },
79 { "put_device", PARAM_FREED, 0, "$", NULL, NULL, &match_kobject_put },
81 { "__skb_pad", PARAM_FREED, 0, "$", &err_min, &err_max, &match___skb_pad },
84 static struct name_sym_fn_list *free_hooks;
86 void add_free_hook(name_sym_hook *hook)
88 add_ptr_list(&free_hooks, hook);
91 static void call_free_call_backs_name_sym(const char *name, struct symbol *sym)
93 struct expression *expr;
94 name_sym_hook *hook;
96 expr = gen_expression_from_name_sym(name, sym);
98 FOR_EACH_PTR(free_hooks, hook) {
99 hook(expr, name, sym);
100 } END_FOR_EACH_PTR(hook);
103 static void ok_to_use(struct sm_state *sm, struct expression *mod_expr)
105 if (sm->state != &ok)
106 set_state(my_id, sm->name, sm->sym, &ok);
109 static void pre_merge_hook(struct sm_state *cur, struct sm_state *other)
111 if (is_impossible_path())
112 set_state(my_id, cur->name, cur->sym, &ok);
115 static struct smatch_state *unmatched_state(struct sm_state *sm)
117 struct smatch_state *state;
118 sval_t sval;
120 if (sm->state != &freed && sm->state != &maybe_freed)
121 return &undefined;
123 if (get_param_num_from_sym(sm->sym) < 0)
124 return &undefined;
127 * If the parent is non-there count it as freed. This is
128 * a hack for tracking return states.
130 if (parent_is_null_var_sym(sm->name, sm->sym))
131 return sm->state;
133 state = get_state(SMATCH_EXTRA, sm->name, sm->sym);
134 if (!state)
135 return &undefined;
136 if (!estate_get_single_value(state, &sval) || sval.value != 0)
137 return &undefined;
138 /* It makes it easier to consider NULL pointers as freed. */
139 return sm->state;
142 struct smatch_state *merge_frees(struct smatch_state *s1, struct smatch_state *s2)
144 if (s1 == &freed && s2 == &maybe_freed)
145 return &maybe_freed;
146 if (s1 == &maybe_freed && s2 == &freed)
147 return &maybe_freed;
148 return &merged;
151 static int is_freed(struct expression *expr)
153 struct sm_state *sm;
155 sm = get_sm_state_expr(my_id, expr);
156 if (sm && slist_has_state(sm->possible, &freed))
157 return 1;
158 return 0;
161 bool is_freed_var_sym(const char *name, struct symbol *sym)
163 struct smatch_state *state;
165 state = get_state(my_id, name, sym);
166 if (state == &freed || state == &maybe_freed)
167 return true;
169 return false;
172 static bool expr_is_condition(struct expression *expr)
174 struct statement *stmt;
176 stmt = expr_get_parent_stmt(expr);
177 if (!stmt)
178 return false;
179 if (stmt->type == STMT_IF || stmt->type == STMT_ITERATOR)
180 return true;
181 return false;
184 bool is_part_of_condition(struct expression *expr)
186 struct expression *parent;
188 if (expr_is_condition(expr))
189 return true;
191 parent = expr_get_parent_expr(expr);
192 if (!parent)
193 return false;
194 if (parent->type == EXPR_LOGICAL || parent->type == EXPR_COMPARE)
195 return true;
196 if (parent->type == EXPR_SELECT || parent->type == EXPR_CONDITIONAL)
197 return true;
198 if (parent->type == EXPR_PREOP && parent->op == '!')
199 return true;
201 return false;
204 static bool is_percent_p(struct expression *str_expr, int idx)
206 char *p;
207 int cnt = 0;
209 p = str_expr->string->data;
210 while (p[0]) {
211 if (p[0] == '%' && p[1] == '%') {
212 p += 2;
213 continue;
215 /* If we have print("%.*s %p", prec, str, p); then it takes 2 params */
216 if ((p[0] == '%' && p[1] == '*') ||
217 (p[0] == '%' && p[1] == '.' && p[2] == '*'))
218 cnt++;
219 if (p[0] == '%') {
220 cnt++;
221 if (idx == cnt && p[1] == 'p')
222 return true;
224 p++;
226 return false;
229 bool is_percent_p_print(struct expression *expr)
231 struct expression *parent, *arg;
232 int expr_idx, string_idx;
234 parent = expr_get_parent_expr(expr);
235 if (!parent || parent->type != EXPR_CALL)
236 return false;
238 expr_idx = -1;
239 FOR_EACH_PTR(parent->args, arg) {
240 expr_idx++;
241 if (arg == expr)
242 goto found;
243 } END_FOR_EACH_PTR(arg);
245 return false;
246 found:
248 string_idx = -1;
249 FOR_EACH_PTR(parent->args, arg) {
250 string_idx++;
251 if (arg->type != EXPR_STRING)
252 continue;
253 if (is_percent_p(arg, expr_idx - string_idx))
254 return true;
255 } END_FOR_EACH_PTR(arg);
257 return false;
260 static void match_symbol(struct expression *expr)
262 struct expression *parent;
263 char *name;
265 if (is_impossible_path())
266 return;
267 if (__in_fake_parameter_assign)
268 return;
270 if (is_part_of_condition(expr))
271 return;
273 /* This ignores stuff like "get_new_ptr(&foo);" */
274 parent = expr_get_parent_expr(expr);
275 while (parent && parent->type == EXPR_PREOP && parent->op == '(')
276 parent = expr_get_parent_expr(parent);
277 if (parent && parent->type == EXPR_PREOP && parent->op == '&')
278 return;
280 if (!is_freed(expr))
281 return;
283 if (is_percent_p_print(expr))
284 return;
286 name = expr_to_var(expr);
287 sm_warning("'%s' was already freed.", name);
288 free_string(name);
291 static void match_dereferences(struct expression *expr)
293 char *name;
295 if (expr->type != EXPR_PREOP)
296 return;
298 if (is_impossible_path())
299 return;
300 if (__in_fake_parameter_assign)
301 return;
303 expr = strip_expr(expr->unop);
304 if (!is_freed(expr))
305 return;
306 name = expr_to_var(expr);
307 sm_error("dereferencing freed memory '%s'", name);
308 set_state_expr(my_id, expr, &ok);
309 free_string(name);
312 static int ignored_params[16];
314 static void set_ignored_params(struct expression *call)
316 struct expression *arg;
317 const char *p;
318 int i;
320 memset(&ignored_params, 0, sizeof(ignored_params));
322 i = -1;
323 FOR_EACH_PTR(call->args, arg) {
324 i++;
325 if (arg->type != EXPR_STRING)
326 continue;
327 goto found;
328 } END_FOR_EACH_PTR(arg);
330 return;
332 found:
333 i++;
334 p = arg->string->data;
335 while ((p = strchr(p, '%'))) {
336 if (i >= ARRAY_SIZE(ignored_params))
337 return;
338 p++;
339 if (*p == '%') {
340 p++;
341 continue;
343 if (*p == '.')
344 p++;
345 if (*p == '*')
346 i++;
347 if (*p == 'p')
348 ignored_params[i] = 1;
349 i++;
353 static int is_free_func(struct expression *fn)
355 char *name;
356 int ret = 0;
358 name = expr_to_str(fn);
359 if (!name)
360 return 0;
361 if (strstr(name, "free"))
362 ret = 1;
363 free_string(name);
365 return ret;
368 static void match_call(struct expression *expr)
370 struct expression *arg;
371 char *name;
372 int i;
374 if (is_impossible_path())
375 return;
377 set_ignored_params(expr);
379 i = -1;
380 FOR_EACH_PTR(expr->args, arg) {
381 i++;
382 if (!is_pointer(arg))
383 continue;
384 if (!is_freed(arg))
385 continue;
386 if (ignored_params[i])
387 continue;
388 if (is_percent_p_print(arg))
389 continue;
391 name = expr_to_var(arg);
392 if (is_free_func(expr->fn))
393 sm_error("double free of '%s'", name);
394 else
395 sm_warning("passing freed memory '%s'", name);
396 set_state_expr(my_id, arg, &ok);
397 free_string(name);
398 } END_FOR_EACH_PTR(arg);
401 static void match_return(struct expression *expr)
403 char *name;
405 if (is_impossible_path())
406 return;
408 if (!expr)
409 return;
410 if (!is_freed(expr))
411 return;
413 name = expr_to_var(expr);
414 sm_warning("returning freed memory '%s'", name);
415 set_state_expr(my_id, expr, &ok);
416 free_string(name);
419 static bool is_ptr_to(struct expression *expr, const char *type)
421 struct symbol *sym;
423 sym = get_type(expr);
424 if (!is_ptr_type(sym))
425 return false;
426 sym = get_real_base_type(sym);
427 if (sym && sym->ident && strcmp(sym->ident->name, type) == 0)
428 return true;
429 return false;
432 static void match_free(struct expression *expr, const char *name, struct symbol *sym, void *data)
434 struct expression *arg;
436 if (is_impossible_path())
437 return;
439 arg = gen_expression_from_name_sym(name, sym);
440 if (!arg)
441 return;
442 if (is_ptr_to(arg, "sk_buff") &&
443 refcount_was_inced(arg, "->users.refs.counter"))
444 return;
445 if (is_ptr_to(arg, "buffer_head") &&
446 refcount_was_inced(arg, "->b_count.counter"))
447 return;
448 if (is_freed(arg))
449 sm_error("double free of '%s'", name);
451 track_freed_param(arg, &freed);
452 call_free_call_backs_name_sym(name, sym);
453 set_state_expr(my_id, arg, &freed);
457 static void match_kobject_put(struct expression *expr, const char *name, struct symbol *sym, void *data)
459 struct expression *arg;
461 arg = gen_expression_from_name_sym(name, sym);
462 if (!arg)
463 return;
464 /* kobject_put(&cdev->kobj); */
465 if (arg->type != EXPR_PREOP || arg->op != '&')
466 return;
467 arg = strip_expr(arg->unop);
468 if (arg->type != EXPR_DEREF)
469 return;
470 arg = strip_expr(arg->deref);
471 if (arg->type != EXPR_PREOP || arg->op != '*')
472 return;
473 arg = strip_expr(arg->unop);
474 track_freed_param(arg, &maybe_freed);
475 set_state_expr(my_id, arg, &maybe_freed);
478 static void match___skb_pad(struct expression *expr, const char *name, struct symbol *sym, void *data)
480 struct expression *arg, *skb;
481 struct smatch_state *state;
482 sval_t sval;
484 while (expr && expr->type == EXPR_ASSIGNMENT)
485 expr = strip_expr(expr->right);
486 if (!expr || expr->type != EXPR_CALL)
487 return;
489 arg = get_argument_from_call_expr(expr->args, 2);
490 if (expr_is_zero(arg))
491 return;
492 state = &maybe_freed;
493 if (get_implied_value(arg, &sval) && sval.value != 0)
494 state = &freed;
496 skb = get_argument_from_call_expr(expr->args, 0);
497 track_freed_param(skb, state);
498 set_state_expr(my_id, skb, state);
501 struct string_list *handled;
502 static bool is_handled_func(struct expression *fn)
504 if (!fn || fn->type != EXPR_SYMBOL || !fn->symbol->ident)
505 return false;
507 return list_has_string(handled, fn->symbol->ident->name);
510 static void set_param_helper(struct expression *expr, int param,
511 char *key, char *value,
512 struct smatch_state *state)
514 struct expression *arg;
515 char *name;
516 struct symbol *sym;
517 struct sm_state *sm;
519 while (expr->type == EXPR_ASSIGNMENT)
520 expr = strip_expr(expr->right);
521 if (expr->type != EXPR_CALL)
522 return;
524 if (is_handled_func(expr->fn))
525 return;
527 arg = get_argument_from_call_expr(expr->args, param);
528 if (!arg)
529 return;
530 name = get_variable_from_key(arg, key, &sym);
531 if (!name || !sym)
532 goto free;
534 /* skbs are not free if we called skb_get(). */
535 if (refcount_was_inced_name_sym(name, sym, "->users.refs.counter"))
536 goto free;
538 if (state == &freed && !is_impossible_path()) {
539 sm = get_sm_state(my_id, name, sym);
540 if (sm && slist_has_state(sm->possible, &freed)) {
541 sm_warning("'%s' double freed", name);
542 set_state(my_id, name, sym, &ok); /* fixme: doesn't silence anything. I know */
546 track_freed_param_var_sym(name, sym, state);
547 if (state == &freed)
548 call_free_call_backs_name_sym(name, sym);
549 set_state(my_id, name, sym, state);
550 free:
551 free_string(name);
554 static void set_param_freed(struct expression *expr, int param, char *key, char *value)
556 set_param_helper(expr, param, key, value, &freed);
559 static void set_param_maybe_freed(struct expression *expr, int param, char *key, char *value)
561 set_param_helper(expr, param, key, value, &maybe_freed);
564 int parent_is_free_var_sym_strict(const char *name, struct symbol *sym)
566 char buf[256];
567 char *start;
568 char *end;
569 char orig;
570 struct smatch_state *state;
572 strncpy(buf, name, sizeof(buf) - 1);
573 buf[sizeof(buf) - 1] = '\0';
575 start = &buf[0];
576 while ((*start == '&'))
577 start++;
579 end = start;
580 while ((end = strrchr(end, '-'))) {
581 orig = *end;
582 *end = '\0';
584 state = __get_state(my_id, start, sym);
585 if (state == &freed)
586 return 1;
587 *end = orig;
588 end++;
590 return 0;
593 int parent_is_free_strict(struct expression *expr)
595 struct symbol *sym;
596 char *var;
597 int ret = 0;
599 expr = strip_expr(expr);
600 var = expr_to_var_sym(expr, &sym);
601 if (!var || !sym)
602 goto free;
603 ret = parent_is_free_var_sym_strict(var, sym);
604 free:
605 free_string(var);
606 return ret;
609 static void match_untracked(struct expression *call, int param)
611 struct state_list *slist = NULL;
612 struct expression *arg;
613 struct sm_state *sm;
614 char *name;
615 char buf[64];
616 int len;
618 arg = get_argument_from_call_expr(call->args, param);
619 if (!arg)
620 return;
622 name = expr_to_var(arg);
623 if (!name)
624 return;
625 snprintf(buf, sizeof(buf), "%s->", name);
626 free_string(name);
627 len = strlen(buf);
629 FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
630 if (strncmp(sm->name, buf, len) == 0)
631 add_ptr_list(&slist, sm);
632 } END_FOR_EACH_SM(sm);
634 FOR_EACH_PTR(slist, sm) {
635 set_state(sm->owner, sm->name, sm->sym, &ok);
636 } END_FOR_EACH_PTR(sm);
638 free_slist(&slist);
641 void check_free_strict(int id)
643 struct func_info *info;
644 param_key_hook *cb;
645 int i;
647 my_id = id;
649 if (option_project != PROJ_KERNEL)
650 return;
652 for (i = 0; i < ARRAY_SIZE(func_table); i++) {
653 info = &func_table[i];
655 insert_string(&handled, info->name);
657 if (info->call_back)
658 cb = info->call_back;
659 else
660 cb = &match_free;
662 if (info->implies_start) {
663 return_implies_param_key(info->name,
664 *info->implies_start, *info->implies_end,
665 cb, info->param, info->key, info);
666 } else {
667 add_function_param_key_hook(info->name, cb,
668 info->param, info->key, info);
672 if (option_spammy)
673 add_hook(&match_symbol, SYM_HOOK);
674 add_hook(&match_dereferences, DEREF_HOOK);
675 add_hook(&match_call, FUNCTION_CALL_HOOK);
676 add_hook(&match_return, RETURN_HOOK);
678 add_modification_hook_late(my_id, &ok_to_use);
679 add_pre_merge_hook(my_id, &pre_merge_hook);
680 add_unmatched_state_hook(my_id, &unmatched_state);
681 add_merge_hook(my_id, &merge_frees);
683 select_return_states_hook(PARAM_FREED, &set_param_freed);
684 select_return_states_hook(MAYBE_FREED, &set_param_maybe_freed);
685 add_untracked_param_hook(&match_untracked);