check_kernel: add support for with_intel_display()
[smatch.git] / check_free_strict.c
blobeb42e99f2ecbc84bfcd0e75aa97fca42d385ef96
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 int counter_was_inced_name_sym(const char *name, struct symbol *sym, const char *counter_str)
421 char buf[256];
423 snprintf(buf, sizeof(buf), "%s%s", name, counter_str);
424 return was_inced(buf, sym);
427 static int counter_was_inced(struct expression *expr, const char *counter_str)
429 char *name;
430 struct symbol *sym;
431 int ret = 0;
433 name = expr_to_var_sym(expr, &sym);
434 if (!name || !sym)
435 goto free;
437 ret = counter_was_inced_name_sym(name, sym, counter_str);
438 free:
439 free_string(name);
440 return ret;
443 static bool is_ptr_to(struct expression *expr, const char *type)
445 struct symbol *sym;
447 sym = get_type(expr);
448 if (!is_ptr_type(sym))
449 return false;
450 sym = get_real_base_type(sym);
451 if (sym && sym->ident && strcmp(sym->ident->name, type) == 0)
452 return true;
453 return false;
456 static void match_free(struct expression *expr, const char *name, struct symbol *sym, void *data)
458 struct expression *arg;
460 if (is_impossible_path())
461 return;
463 arg = gen_expression_from_name_sym(name, sym);
464 if (!arg)
465 return;
466 if (is_ptr_to(arg, "sk_buff") &&
467 counter_was_inced(arg, "->users.refs.counter"))
468 return;
469 if (is_ptr_to(arg, "buffer_head") &&
470 counter_was_inced(arg, "->b_count.counter"))
471 return;
472 if (is_freed(arg))
473 sm_error("double free of '%s'", name);
475 track_freed_param(arg, &freed);
476 call_free_call_backs_name_sym(name, sym);
477 set_state_expr(my_id, arg, &freed);
481 static void match_kobject_put(struct expression *expr, const char *name, struct symbol *sym, void *data)
483 struct expression *arg;
485 arg = gen_expression_from_name_sym(name, sym);
486 if (!arg)
487 return;
488 /* kobject_put(&cdev->kobj); */
489 if (arg->type != EXPR_PREOP || arg->op != '&')
490 return;
491 arg = strip_expr(arg->unop);
492 if (arg->type != EXPR_DEREF)
493 return;
494 arg = strip_expr(arg->deref);
495 if (arg->type != EXPR_PREOP || arg->op != '*')
496 return;
497 arg = strip_expr(arg->unop);
498 track_freed_param(arg, &maybe_freed);
499 set_state_expr(my_id, arg, &maybe_freed);
502 static void match___skb_pad(struct expression *expr, const char *name, struct symbol *sym, void *data)
504 struct expression *arg, *skb;
505 struct smatch_state *state;
506 sval_t sval;
508 while (expr && expr->type == EXPR_ASSIGNMENT)
509 expr = strip_expr(expr->right);
510 if (!expr || expr->type != EXPR_CALL)
511 return;
513 arg = get_argument_from_call_expr(expr->args, 2);
514 if (expr_is_zero(arg))
515 return;
516 state = &maybe_freed;
517 if (get_implied_value(arg, &sval) && sval.value != 0)
518 state = &freed;
520 skb = get_argument_from_call_expr(expr->args, 0);
521 track_freed_param(skb, state);
522 set_state_expr(my_id, skb, state);
525 struct string_list *handled;
526 static bool is_handled_func(struct expression *fn)
528 if (!fn || fn->type != EXPR_SYMBOL || !fn->symbol->ident)
529 return false;
531 return list_has_string(handled, fn->symbol->ident->name);
534 static void set_param_helper(struct expression *expr, int param,
535 char *key, char *value,
536 struct smatch_state *state)
538 struct expression *arg;
539 char *name;
540 struct symbol *sym;
541 struct sm_state *sm;
543 while (expr->type == EXPR_ASSIGNMENT)
544 expr = strip_expr(expr->right);
545 if (expr->type != EXPR_CALL)
546 return;
548 if (is_handled_func(expr->fn))
549 return;
551 arg = get_argument_from_call_expr(expr->args, param);
552 if (!arg)
553 return;
554 name = get_variable_from_key(arg, key, &sym);
555 if (!name || !sym)
556 goto free;
558 /* skbs are not free if we called skb_get(). */
559 if (counter_was_inced_name_sym(name, sym, "->users.refs.counter"))
560 goto free;
562 if (state == &freed && !is_impossible_path()) {
563 sm = get_sm_state(my_id, name, sym);
564 if (sm && slist_has_state(sm->possible, &freed)) {
565 sm_warning("'%s' double freed", name);
566 set_state(my_id, name, sym, &ok); /* fixme: doesn't silence anything. I know */
570 track_freed_param_var_sym(name, sym, state);
571 if (state == &freed)
572 call_free_call_backs_name_sym(name, sym);
573 set_state(my_id, name, sym, state);
574 free:
575 free_string(name);
578 static void set_param_freed(struct expression *expr, int param, char *key, char *value)
580 set_param_helper(expr, param, key, value, &freed);
583 static void set_param_maybe_freed(struct expression *expr, int param, char *key, char *value)
585 set_param_helper(expr, param, key, value, &maybe_freed);
588 int parent_is_free_var_sym_strict(const char *name, struct symbol *sym)
590 char buf[256];
591 char *start;
592 char *end;
593 char orig;
594 struct smatch_state *state;
596 strncpy(buf, name, sizeof(buf) - 1);
597 buf[sizeof(buf) - 1] = '\0';
599 start = &buf[0];
600 while ((*start == '&'))
601 start++;
603 end = start;
604 while ((end = strrchr(end, '-'))) {
605 orig = *end;
606 *end = '\0';
608 state = __get_state(my_id, start, sym);
609 if (state == &freed)
610 return 1;
611 *end = orig;
612 end++;
614 return 0;
617 int parent_is_free_strict(struct expression *expr)
619 struct symbol *sym;
620 char *var;
621 int ret = 0;
623 expr = strip_expr(expr);
624 var = expr_to_var_sym(expr, &sym);
625 if (!var || !sym)
626 goto free;
627 ret = parent_is_free_var_sym_strict(var, sym);
628 free:
629 free_string(var);
630 return ret;
633 static void match_untracked(struct expression *call, int param)
635 struct state_list *slist = NULL;
636 struct expression *arg;
637 struct sm_state *sm;
638 char *name;
639 char buf[64];
640 int len;
642 arg = get_argument_from_call_expr(call->args, param);
643 if (!arg)
644 return;
646 name = expr_to_var(arg);
647 if (!name)
648 return;
649 snprintf(buf, sizeof(buf), "%s->", name);
650 free_string(name);
651 len = strlen(buf);
653 FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
654 if (strncmp(sm->name, buf, len) == 0)
655 add_ptr_list(&slist, sm);
656 } END_FOR_EACH_SM(sm);
658 FOR_EACH_PTR(slist, sm) {
659 set_state(sm->owner, sm->name, sm->sym, &ok);
660 } END_FOR_EACH_PTR(sm);
662 free_slist(&slist);
665 void check_free_strict(int id)
667 struct func_info *info;
668 param_key_hook *cb;
669 int i;
671 my_id = id;
673 if (option_project != PROJ_KERNEL)
674 return;
676 for (i = 0; i < ARRAY_SIZE(func_table); i++) {
677 info = &func_table[i];
679 insert_string(&handled, info->name);
681 if (info->call_back)
682 cb = info->call_back;
683 else
684 cb = &match_free;
686 if (info->implies_start) {
687 return_implies_param_key(info->name,
688 *info->implies_start, *info->implies_end,
689 cb, info->param, info->key, info);
690 } else {
691 add_function_param_key_hook(info->name, cb,
692 info->param, info->key, info);
696 if (option_spammy)
697 add_hook(&match_symbol, SYM_HOOK);
698 add_hook(&match_dereferences, DEREF_HOOK);
699 add_hook(&match_call, FUNCTION_CALL_HOOK);
700 add_hook(&match_return, RETURN_HOOK);
702 add_modification_hook_late(my_id, &ok_to_use);
703 add_pre_merge_hook(my_id, &pre_merge_hook);
704 add_unmatched_state_hook(my_id, &unmatched_state);
705 add_merge_hook(my_id, &merge_frees);
707 select_return_states_hook(PARAM_FREED, &set_param_freed);
708 select_return_states_hook(MAYBE_FREED, &set_param_maybe_freed);
709 add_untracked_param_hook(&match_untracked);