smatch_kernel_host_data: enable additional debug
[smatch.git] / check_free_strict.c
blobf34befde0b8d8d1e35a7eb79fe564f6c77fef43f
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;
58 if (get_param_num_from_sym(sm->sym) < 0)
59 return &undefined;
62 * If the parent is non-there count it as freed. This is
63 * a hack for tracking return states.
65 if (parent_is_null_var_sym(sm->name, sm->sym))
66 return sm->state;
68 state = get_state(SMATCH_EXTRA, sm->name, sm->sym);
69 if (!state)
70 return &undefined;
71 if (!estate_get_single_value(state, &sval) || sval.value != 0)
72 return &undefined;
73 /* It makes it easier to consider NULL pointers as freed. */
74 return &freed;
77 struct smatch_state *merge_frees(struct smatch_state *s1, struct smatch_state *s2)
79 if (s1 == &freed && s2 == &maybe_freed)
80 return &maybe_freed;
81 if (s1 == &maybe_freed && s2 == &freed)
82 return &maybe_freed;
83 return &merged;
86 static int is_freed(struct expression *expr)
88 struct sm_state *sm;
90 sm = get_sm_state_expr(my_id, expr);
91 if (sm && slist_has_state(sm->possible, &freed))
92 return 1;
93 return 0;
96 bool is_freed_var_sym(const char *name, struct symbol *sym)
98 struct smatch_state *state;
100 state = get_state(my_id, name, sym);
101 if (state == &freed || state == &maybe_freed)
102 return true;
104 return false;
107 static bool expr_is_condition(struct expression *expr)
109 struct statement *stmt;
111 stmt = expr_get_parent_stmt(expr);
112 if (!stmt)
113 return false;
114 if (stmt->type == STMT_IF || stmt->type == STMT_ITERATOR)
115 return true;
116 return false;
119 bool is_part_of_condition(struct expression *expr)
121 struct expression *parent;
123 if (expr_is_condition(expr))
124 return true;
126 parent = expr_get_parent_expr(expr);
127 if (!parent)
128 return false;
129 if (parent->type == EXPR_LOGICAL || parent->type == EXPR_COMPARE)
130 return true;
131 if (parent->type == EXPR_SELECT || parent->type == EXPR_CONDITIONAL)
132 return true;
133 if (parent->type == EXPR_PREOP && parent->op == '!')
134 return true;
136 return false;
139 static bool is_percent_p(struct expression *str_expr, int idx)
141 char *p;
142 int cnt = 0;
144 p = str_expr->string->data;
145 while (p[0]) {
146 if (p[0] == '%' && p[1] == '%') {
147 p += 2;
148 continue;
150 if (p[0] == '%') {
151 cnt++;
152 if (idx == cnt && p[1] == 'p')
153 return true;
155 p++;
157 return false;
160 bool is_percent_p_print(struct expression *expr)
162 struct expression *parent, *arg;
163 int expr_idx, string_idx;
165 parent = expr_get_parent_expr(expr);
166 if (!parent || parent->type != EXPR_CALL)
167 return false;
169 expr_idx = -1;
170 FOR_EACH_PTR(parent->args, arg) {
171 expr_idx++;
172 if (arg == expr)
173 goto found;
174 } END_FOR_EACH_PTR(arg);
176 return false;
177 found:
179 string_idx = -1;
180 FOR_EACH_PTR(parent->args, arg) {
181 string_idx++;
182 if (arg->type != EXPR_STRING)
183 continue;
184 if (is_percent_p(arg, expr_idx - string_idx))
185 return true;
186 } END_FOR_EACH_PTR(arg);
188 return false;
191 static void match_symbol(struct expression *expr)
193 struct expression *parent;
194 char *name;
196 if (is_impossible_path())
197 return;
198 if (__in_fake_parameter_assign)
199 return;
201 if (is_part_of_condition(expr))
202 return;
204 /* This ignores stuff like "get_new_ptr(&foo);" */
205 parent = expr_get_parent_expr(expr);
206 while (parent && parent->type == EXPR_PREOP && parent->op == '(')
207 parent = expr_get_parent_expr(parent);
208 if (parent && parent->type == EXPR_PREOP && parent->op == '&')
209 return;
211 if (!is_freed(expr))
212 return;
214 if (is_percent_p_print(expr))
215 return;
217 name = expr_to_var(expr);
218 sm_warning("'%s' was already freed.", name);
219 free_string(name);
222 static void match_dereferences(struct expression *expr)
224 char *name;
226 if (expr->type != EXPR_PREOP)
227 return;
229 if (is_impossible_path())
230 return;
231 if (__in_fake_parameter_assign)
232 return;
234 expr = strip_expr(expr->unop);
235 if (!is_freed(expr))
236 return;
237 name = expr_to_var(expr);
238 sm_error("dereferencing freed memory '%s'", name);
239 set_state_expr(my_id, expr, &ok);
240 free_string(name);
243 static int ignored_params[16];
245 static void set_ignored_params(struct expression *call)
247 struct expression *arg;
248 const char *p;
249 int i;
251 memset(&ignored_params, 0, sizeof(ignored_params));
253 i = -1;
254 FOR_EACH_PTR(call->args, arg) {
255 i++;
256 if (arg->type != EXPR_STRING)
257 continue;
258 goto found;
259 } END_FOR_EACH_PTR(arg);
261 return;
263 found:
264 i++;
265 p = arg->string->data;
266 while ((p = strchr(p, '%'))) {
267 if (i >= ARRAY_SIZE(ignored_params))
268 return;
269 p++;
270 if (*p == '%') {
271 p++;
272 continue;
274 if (*p == '.')
275 p++;
276 if (*p == '*')
277 i++;
278 if (*p == 'p')
279 ignored_params[i] = 1;
280 i++;
284 static int is_free_func(struct expression *fn)
286 char *name;
287 int ret = 0;
289 name = expr_to_str(fn);
290 if (!name)
291 return 0;
292 if (strstr(name, "free"))
293 ret = 1;
294 free_string(name);
296 return ret;
299 static void match_call(struct expression *expr)
301 struct expression *arg;
302 char *name;
303 int i;
305 if (is_impossible_path())
306 return;
308 set_ignored_params(expr);
310 i = -1;
311 FOR_EACH_PTR(expr->args, arg) {
312 i++;
313 if (!is_pointer(arg))
314 continue;
315 if (!is_freed(arg))
316 continue;
317 if (ignored_params[i])
318 continue;
319 if (is_percent_p_print(arg))
320 continue;
322 name = expr_to_var(arg);
323 if (is_free_func(expr->fn))
324 sm_error("double free of '%s'", name);
325 else
326 sm_warning("passing freed memory '%s'", name);
327 set_state_expr(my_id, arg, &ok);
328 free_string(name);
329 } END_FOR_EACH_PTR(arg);
332 static void match_return(struct expression *expr)
334 char *name;
336 if (is_impossible_path())
337 return;
339 if (!expr)
340 return;
341 if (!is_freed(expr))
342 return;
344 name = expr_to_var(expr);
345 sm_warning("returning freed memory '%s'", name);
346 set_state_expr(my_id, expr, &ok);
347 free_string(name);
350 static int counter_was_inced_name_sym(const char *name, struct symbol *sym, const char *counter_str)
352 char buf[256];
354 snprintf(buf, sizeof(buf), "%s%s", name, counter_str);
355 return was_inced(buf, sym);
358 static int counter_was_inced(struct expression *expr, const char *counter_str)
360 char *name;
361 struct symbol *sym;
362 int ret = 0;
364 name = expr_to_var_sym(expr, &sym);
365 if (!name || !sym)
366 goto free;
368 ret = counter_was_inced_name_sym(name, sym, counter_str);
369 free:
370 free_string(name);
371 return ret;
374 void set_other_states_name_sym(int owner, const char *name, struct symbol *sym, struct smatch_state *state)
376 struct expression *tmp;
377 struct sm_state *sm;
379 FOR_EACH_MY_SM(check_assigned_expr_id, __get_cur_stree(), sm) {
380 tmp = sm->state->data;
381 if (!tmp)
382 continue;
383 if (tmp->type != EXPR_SYMBOL)
384 continue;
385 if (tmp->symbol != sym)
386 continue;
387 if (!tmp->symbol_name)
388 continue;
389 if (strcmp(tmp->symbol_name->name, name) != 0)
390 continue;
391 set_state(owner, tmp->symbol_name->name, tmp->symbol, state);
392 } END_FOR_EACH_SM(sm);
394 tmp = get_assigned_expr_name_sym(name, sym);
395 if (tmp)
396 set_state_expr(owner, tmp, state);
399 void set_other_states(int owner, struct expression *expr, struct smatch_state *state)
401 struct symbol *sym;
402 char *name;
404 name = expr_to_var_sym(expr, &sym);
405 if (!name || !sym)
406 goto free;
408 set_other_states_name_sym(owner, name, sym, state);
410 free:
411 free_string(name);
414 static bool is_ptr_to(struct expression *expr, const char *type)
416 struct symbol *sym;
418 sym = get_type(expr);
419 if (!is_ptr_type(sym))
420 return false;
421 sym = get_real_base_type(sym);
422 if (sym && sym->ident && strcmp(sym->ident->name, type) == 0)
423 return true;
424 return false;
427 static void match_free(const char *fn, struct expression *expr, void *param)
429 struct expression *arg;
431 if (is_impossible_path())
432 return;
434 arg = get_argument_from_call_expr(expr->args, PTR_INT(param));
435 if (!arg)
436 return;
437 if (is_ptr_to(arg, "sk_buff") &&
438 counter_was_inced(arg, "->users.refs.counter"))
439 return;
440 if (is_ptr_to(arg, "buffer_head") &&
441 counter_was_inced(arg, "->b_count.counter"))
442 return;
443 if (is_freed(arg)) {
444 char *name = expr_to_var(arg);
446 sm_error("double free of '%s'", name);
447 free_string(name);
449 track_freed_param(arg, &freed);
450 set_state_expr(my_id, arg, &freed);
451 set_other_states(my_id, arg, &freed);
454 static void match_kobject_put(const char *fn, struct expression *expr, void *param)
456 struct expression *arg;
458 arg = get_argument_from_call_expr(expr->args, PTR_INT(param));
459 if (!arg)
460 return;
461 /* kobject_put(&cdev->kobj); */
462 if (arg->type != EXPR_PREOP || arg->op != '&')
463 return;
464 arg = strip_expr(arg->unop);
465 if (arg->type != EXPR_DEREF)
466 return;
467 arg = strip_expr(arg->deref);
468 if (arg->type != EXPR_PREOP || arg->op != '*')
469 return;
470 arg = strip_expr(arg->unop);
471 track_freed_param(arg, &maybe_freed);
472 set_state_expr(my_id, arg, &maybe_freed);
475 struct string_list *handled;
476 static bool is_handled_func(struct expression *fn)
478 if (!fn || fn->type != EXPR_SYMBOL || !fn->symbol->ident)
479 return false;
481 return list_has_string(handled, fn->symbol->ident->name);
484 static void set_param_helper(struct expression *expr, int param,
485 char *key, char *value,
486 struct smatch_state *state)
488 struct expression *arg;
489 char *name;
490 struct symbol *sym;
491 struct sm_state *sm;
493 while (expr->type == EXPR_ASSIGNMENT)
494 expr = strip_expr(expr->right);
495 if (expr->type != EXPR_CALL)
496 return;
498 if (is_handled_func(expr->fn))
499 return;
501 arg = get_argument_from_call_expr(expr->args, param);
502 if (!arg)
503 return;
504 name = get_variable_from_key(arg, key, &sym);
505 if (!name || !sym)
506 goto free;
508 /* skbs are not free if we called skb_get(). */
509 if (counter_was_inced_name_sym(name, sym, "->users.refs.counter"))
510 goto free;
512 if (state == &freed && !is_impossible_path()) {
513 sm = get_sm_state(my_id, name, sym);
514 if (sm && slist_has_state(sm->possible, &freed)) {
515 sm_warning("'%s' double freed", name);
516 set_state(my_id, name, sym, &ok); /* fixme: doesn't silence anything. I know */
520 track_freed_param_var_sym(name, sym, state);
521 set_state(my_id, name, sym, state);
522 set_other_states_name_sym(my_id, name, sym, state);
523 free:
524 free_string(name);
527 static void set_param_freed(struct expression *expr, int param, char *key, char *value)
529 set_param_helper(expr, param, key, value, &freed);
532 static void set_param_maybe_freed(struct expression *expr, int param, char *key, char *value)
534 set_param_helper(expr, param, key, value, &maybe_freed);
537 int parent_is_free_var_sym_strict(const char *name, struct symbol *sym)
539 char buf[256];
540 char *start;
541 char *end;
542 char orig;
543 struct smatch_state *state;
545 strncpy(buf, name, sizeof(buf) - 1);
546 buf[sizeof(buf) - 1] = '\0';
548 start = &buf[0];
549 while ((*start == '&'))
550 start++;
552 end = start;
553 while ((end = strrchr(end, '-'))) {
554 orig = *end;
555 *end = '\0';
557 state = __get_state(my_id, start, sym);
558 if (state == &freed)
559 return 1;
560 *end = orig;
561 end++;
563 return 0;
566 int parent_is_free_strict(struct expression *expr)
568 struct symbol *sym;
569 char *var;
570 int ret = 0;
572 expr = strip_expr(expr);
573 var = expr_to_var_sym(expr, &sym);
574 if (!var || !sym)
575 goto free;
576 ret = parent_is_free_var_sym_strict(var, sym);
577 free:
578 free_string(var);
579 return ret;
582 static void match_untracked(struct expression *call, int param)
584 struct state_list *slist = NULL;
585 struct expression *arg;
586 struct sm_state *sm;
587 char *name;
588 char buf[64];
589 int len;
591 arg = get_argument_from_call_expr(call->args, param);
592 if (!arg)
593 return;
595 name = expr_to_var(arg);
596 if (!name)
597 return;
598 snprintf(buf, sizeof(buf), "%s->", name);
599 free_string(name);
600 len = strlen(buf);
602 FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
603 if (strncmp(sm->name, buf, len) == 0)
604 add_ptr_list(&slist, sm);
605 } END_FOR_EACH_SM(sm);
607 FOR_EACH_PTR(slist, sm) {
608 set_state(sm->owner, sm->name, sm->sym, &ok);
609 } END_FOR_EACH_PTR(sm);
611 free_slist(&slist);
614 void add_free_hook(const char *func, func_hook *call_back, int param)
616 insert_string(&handled, func);
617 add_function_hook(func, call_back, INT_PTR(param));
620 void check_free_strict(int id)
622 my_id = id;
624 if (option_project != PROJ_KERNEL)
625 return;
627 add_free_hook("free", &match_free, 0);
628 add_free_hook("kfree", &match_free, 0);
629 add_free_hook("vfree", &match_free, 0);
630 add_free_hook("kzfree", &match_free, 0);
631 add_free_hook("kvfree", &match_free, 0);
632 add_free_hook("kmem_cache_free", &match_free, 1);
633 add_free_hook("mempool_free", &match_free, 0);
634 add_free_hook("kfree_skb", &match_free, 0);
635 add_free_hook("kfree_skbmem", &match_free, 0);
636 add_free_hook("dma_pool_free", &match_free, 1);
637 // add_free_hook("spi_unregister_controller", &match_free, 0);
638 add_free_hook("netif_rx_internal", &match_free, 0);
639 add_free_hook("netif_rx", &match_free, 0);
640 add_free_hook("enqueue_to_backlog", &match_free, 0);
642 add_free_hook("brelse", &match_free, 0);
643 add_free_hook("kobject_put", &match_kobject_put, 0);
644 add_free_hook("kref_put", &match_kobject_put, 0);
645 add_free_hook("put_device", &match_kobject_put, 0);
647 add_free_hook("dma_free_coherent", match_free, 2);
649 if (option_spammy)
650 add_hook(&match_symbol, SYM_HOOK);
651 add_hook(&match_dereferences, DEREF_HOOK);
652 add_hook(&match_call, FUNCTION_CALL_HOOK);
653 add_hook(&match_return, RETURN_HOOK);
655 add_modification_hook_late(my_id, &ok_to_use);
656 add_pre_merge_hook(my_id, &pre_merge_hook);
657 add_unmatched_state_hook(my_id, &unmatched_state);
658 add_merge_hook(my_id, &merge_frees);
660 select_return_states_hook(PARAM_FREED, &set_param_freed);
661 select_return_states_hook(MAYBE_FREED, &set_param_maybe_freed);
662 add_untracked_param_hook(&match_untracked);