db/fixup_kernel.sh: delete some impossible returns
[smatch.git] / check_free_strict.c
blobe52712eec2fd4d8e7d6efb9c99a7bc8cc9c15ecc
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 void match_symbol(struct expression *expr)
109 struct expression *parent;
110 char *name;
112 if (is_impossible_path())
113 return;
114 if (__in_fake_parameter_assign)
115 return;
117 parent = expr_get_parent_expr(expr);
118 while (parent && parent->type == EXPR_PREOP && parent->op == '(')
119 parent = expr_get_parent_expr(parent);
120 if (parent && parent->type == EXPR_PREOP && parent->op == '&')
121 return;
123 if (!is_freed(expr))
124 return;
125 name = expr_to_var(expr);
126 sm_warning("'%s' was already freed.", name);
127 free_string(name);
130 static void match_dereferences(struct expression *expr)
132 char *name;
134 if (expr->type != EXPR_PREOP)
135 return;
137 if (is_impossible_path())
138 return;
139 if (__in_fake_parameter_assign)
140 return;
142 expr = strip_expr(expr->unop);
143 if (!is_freed(expr))
144 return;
145 name = expr_to_var(expr);
146 sm_error("dereferencing freed memory '%s'", name);
147 set_state_expr(my_id, expr, &ok);
148 free_string(name);
151 static int ignored_params[16];
153 static void set_ignored_params(struct expression *call)
155 struct expression *arg;
156 const char *p;
157 int i;
159 memset(&ignored_params, 0, sizeof(ignored_params));
161 i = -1;
162 FOR_EACH_PTR(call->args, arg) {
163 i++;
164 if (arg->type != EXPR_STRING)
165 continue;
166 goto found;
167 } END_FOR_EACH_PTR(arg);
169 return;
171 found:
172 i++;
173 p = arg->string->data;
174 while ((p = strchr(p, '%'))) {
175 if (i >= ARRAY_SIZE(ignored_params))
176 return;
177 p++;
178 if (*p == '%') {
179 p++;
180 continue;
182 if (*p == '.')
183 p++;
184 if (*p == '*')
185 i++;
186 if (*p == 'p')
187 ignored_params[i] = 1;
188 i++;
192 static int is_free_func(struct expression *fn)
194 char *name;
195 int ret = 0;
197 name = expr_to_str(fn);
198 if (!name)
199 return 0;
200 if (strstr(name, "free"))
201 ret = 1;
202 free_string(name);
204 return ret;
207 static void match_call(struct expression *expr)
209 struct expression *arg;
210 char *name;
211 int i;
213 if (is_impossible_path())
214 return;
216 set_ignored_params(expr);
218 i = -1;
219 FOR_EACH_PTR(expr->args, arg) {
220 i++;
221 if (!is_pointer(arg))
222 continue;
223 if (!is_freed(arg))
224 continue;
225 if (ignored_params[i])
226 continue;
228 name = expr_to_var(arg);
229 if (is_free_func(expr->fn))
230 sm_error("double free of '%s'", name);
231 else
232 sm_warning("passing freed memory '%s'", name);
233 set_state_expr(my_id, arg, &ok);
234 free_string(name);
235 } END_FOR_EACH_PTR(arg);
238 static void match_return(struct expression *expr)
240 char *name;
242 if (is_impossible_path())
243 return;
245 if (!expr)
246 return;
247 if (!is_freed(expr))
248 return;
250 name = expr_to_var(expr);
251 sm_warning("returning freed memory '%s'", name);
252 set_state_expr(my_id, expr, &ok);
253 free_string(name);
256 static int counter_was_inced_name_sym(const char *name, struct symbol *sym)
258 char buf[256];
260 snprintf(buf, sizeof(buf), "%s->users.refs.counter", name);
261 return was_inced(buf, sym);
264 static int counter_was_inced(struct expression *expr)
266 char *name;
267 struct symbol *sym;
268 int ret = 0;
270 name = expr_to_var_sym(expr, &sym);
271 if (!name || !sym)
272 goto free;
274 ret = counter_was_inced_name_sym(name, sym);
275 free:
276 free_string(name);
277 return ret;
280 void set_other_states_name_sym(int owner, const char *name, struct symbol *sym, struct smatch_state *state)
282 struct expression *tmp;
283 struct sm_state *sm;
285 FOR_EACH_MY_SM(check_assigned_expr_id, __get_cur_stree(), sm) {
286 tmp = sm->state->data;
287 if (!tmp)
288 continue;
289 if (tmp->type != EXPR_SYMBOL)
290 continue;
291 if (tmp->symbol != sym)
292 continue;
293 if (!tmp->symbol_name)
294 continue;
295 if (strcmp(tmp->symbol_name->name, name) != 0)
296 continue;
297 set_state(owner, tmp->symbol_name->name, tmp->symbol, state);
298 } END_FOR_EACH_SM(sm);
300 tmp = get_assigned_expr_name_sym(name, sym);
301 if (tmp)
302 set_state_expr(owner, tmp, state);
305 void set_other_states(int owner, struct expression *expr, struct smatch_state *state)
307 struct symbol *sym;
308 char *name;
310 name = expr_to_var_sym(expr, &sym);
311 if (!name || !sym)
312 goto free;
314 set_other_states_name_sym(owner, name, sym, state);
316 free:
317 free_string(name);
320 static bool sk_buff_pointer(struct expression *expr)
322 struct symbol *type;
324 type = get_type(expr);
325 if (!is_ptr_type(type))
326 return false;
327 type = get_real_base_type(type);
328 if (type && type->ident && strcmp(type->ident->name, "sk_buff") == 0)
329 return true;
330 return false;
333 static void match_free(const char *fn, struct expression *expr, void *param)
335 struct expression *arg;
337 if (is_impossible_path())
338 return;
340 arg = get_argument_from_call_expr(expr->args, PTR_INT(param));
341 if (!arg)
342 return;
343 if (sk_buff_pointer(arg) && counter_was_inced(arg))
344 return;
345 if (is_freed(arg)) {
346 char *name = expr_to_var(arg);
348 sm_error("double free of '%s'", name);
349 free_string(name);
351 track_freed_param(arg, &freed);
352 set_state_expr(my_id, arg, &freed);
353 set_other_states(my_id, arg, &freed);
356 static void match_kobject_put(const char *fn, struct expression *expr, void *param)
358 struct expression *arg;
360 arg = get_argument_from_call_expr(expr->args, PTR_INT(param));
361 if (!arg)
362 return;
363 /* kobject_put(&cdev->kobj); */
364 if (arg->type != EXPR_PREOP || arg->op != '&')
365 return;
366 arg = strip_expr(arg->unop);
367 if (arg->type != EXPR_DEREF)
368 return;
369 arg = strip_expr(arg->deref);
370 if (arg->type != EXPR_PREOP || arg->op != '*')
371 return;
372 arg = strip_expr(arg->unop);
373 track_freed_param(arg, &maybe_freed);
374 set_state_expr(my_id, arg, &maybe_freed);
377 struct string_list *handled;
378 static bool is_handled_func(struct expression *fn)
380 if (!fn || fn->type != EXPR_SYMBOL || !fn->symbol->ident)
381 return false;
383 return list_has_string(handled, fn->symbol->ident->name);
386 static void set_param_helper(struct expression *expr, int param,
387 char *key, char *value,
388 struct smatch_state *state)
390 struct expression *arg;
391 char *name;
392 struct symbol *sym;
393 struct sm_state *sm;
395 while (expr->type == EXPR_ASSIGNMENT)
396 expr = strip_expr(expr->right);
397 if (expr->type != EXPR_CALL)
398 return;
400 if (is_handled_func(expr->fn))
401 return;
403 arg = get_argument_from_call_expr(expr->args, param);
404 if (!arg)
405 return;
406 name = get_variable_from_key(arg, key, &sym);
407 if (!name || !sym)
408 goto free;
410 /* skbs are not free if we called skb_get(). */
411 if (counter_was_inced_name_sym(name, sym))
412 goto free;
414 if (state == &freed && !is_impossible_path()) {
415 sm = get_sm_state(my_id, name, sym);
416 if (sm && slist_has_state(sm->possible, &freed)) {
417 sm_warning("'%s' double freed", name);
418 set_state(my_id, name, sym, &ok); /* fixme: doesn't silence anything. I know */
422 track_freed_param_var_sym(name, sym, state);
423 set_state(my_id, name, sym, state);
424 set_other_states_name_sym(my_id, name, sym, state);
425 free:
426 free_string(name);
429 static void set_param_freed(struct expression *expr, int param, char *key, char *value)
431 set_param_helper(expr, param, key, value, &freed);
434 static void set_param_maybe_freed(struct expression *expr, int param, char *key, char *value)
436 set_param_helper(expr, param, key, value, &maybe_freed);
439 int parent_is_free_var_sym_strict(const char *name, struct symbol *sym)
441 char buf[256];
442 char *start;
443 char *end;
444 char orig;
445 struct smatch_state *state;
447 strncpy(buf, name, sizeof(buf) - 1);
448 buf[sizeof(buf) - 1] = '\0';
450 start = &buf[0];
451 while ((*start == '&'))
452 start++;
454 end = start;
455 while ((end = strrchr(end, '-'))) {
456 orig = *end;
457 *end = '\0';
459 state = __get_state(my_id, start, sym);
460 if (state == &freed)
461 return 1;
462 *end = orig;
463 end++;
465 return 0;
468 int parent_is_free_strict(struct expression *expr)
470 struct symbol *sym;
471 char *var;
472 int ret = 0;
474 expr = strip_expr(expr);
475 var = expr_to_var_sym(expr, &sym);
476 if (!var || !sym)
477 goto free;
478 ret = parent_is_free_var_sym_strict(var, sym);
479 free:
480 free_string(var);
481 return ret;
484 static void match_untracked(struct expression *call, int param)
486 struct state_list *slist = NULL;
487 struct expression *arg;
488 struct sm_state *sm;
489 char *name;
490 char buf[64];
491 int len;
493 arg = get_argument_from_call_expr(call->args, param);
494 if (!arg)
495 return;
497 name = expr_to_var(arg);
498 if (!name)
499 return;
500 snprintf(buf, sizeof(buf), "%s->", name);
501 free_string(name);
502 len = strlen(buf);
504 FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
505 if (strncmp(sm->name, buf, len) == 0)
506 add_ptr_list(&slist, sm);
507 } END_FOR_EACH_SM(sm);
509 FOR_EACH_PTR(slist, sm) {
510 set_state(sm->owner, sm->name, sm->sym, &ok);
511 } END_FOR_EACH_PTR(sm);
513 free_slist(&slist);
516 void add_free_hook(const char *func, func_hook *call_back, int param)
518 insert_string(&handled, func);
519 add_function_hook(func, call_back, INT_PTR(param));
522 void check_free_strict(int id)
524 my_id = id;
526 if (option_project != PROJ_KERNEL)
527 return;
529 add_free_hook("free", &match_free, 0);
530 add_free_hook("kfree", &match_free, 0);
531 add_free_hook("vfree", &match_free, 0);
532 add_free_hook("kzfree", &match_free, 0);
533 add_free_hook("kvfree", &match_free, 0);
534 add_free_hook("kmem_cache_free", &match_free, 1);
535 add_free_hook("mempool_free", &match_free, 0);
536 add_free_hook("kfree_skb", &match_free, 0);
537 add_free_hook("kfree_skbmem", &match_free, 0);
538 add_free_hook("dma_pool_free", &match_free, 1);
539 // add_free_hook("spi_unregister_controller", &match_free, 0);
540 add_free_hook("netif_rx_internal", &match_free, 0);
541 add_free_hook("netif_rx", &match_free, 0);
542 add_free_hook("enqueue_to_backlog", &match_free, 0);
544 add_free_hook("brelse", &match_free, 0);
545 add_free_hook("kobject_put", &match_kobject_put, 0);
546 add_free_hook("kref_put", &match_kobject_put, 0);
547 add_free_hook("put_device", &match_kobject_put, 0);
549 add_free_hook("dma_free_coherent", match_free, 2);
551 if (option_spammy)
552 add_hook(&match_symbol, SYM_HOOK);
553 add_hook(&match_dereferences, DEREF_HOOK);
554 add_hook(&match_call, FUNCTION_CALL_HOOK);
555 add_hook(&match_return, RETURN_HOOK);
557 add_modification_hook_late(my_id, &ok_to_use);
558 add_pre_merge_hook(my_id, &pre_merge_hook);
559 add_unmatched_state_hook(my_id, &unmatched_state);
560 add_merge_hook(my_id, &merge_frees);
562 select_return_states_hook(PARAM_FREED, &set_param_freed);
563 select_return_states_hook(MAYBE_FREED, &set_param_maybe_freed);
564 add_untracked_param_hook(&match_untracked);