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
29 #include "smatch_slist.h"
30 #include "smatch_extra.h"
38 static void match_kobject_put(struct expression
*expr
, const char *name
, struct symbol
*sym
, void *data
);
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
)
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
;
115 if (sm
->state
!= &freed
&& sm
->state
!= &maybe_freed
)
118 if (get_param_num_from_sym(sm
->sym
) < 0)
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
))
128 state
= get_state(SMATCH_EXTRA
, sm
->name
, sm
->sym
);
131 if (!estate_get_single_value(state
, &sval
) || sval
.value
!= 0)
133 /* It makes it easier to consider NULL pointers as freed. */
137 struct smatch_state
*merge_frees(struct smatch_state
*s1
, struct smatch_state
*s2
)
139 if (s1
== &freed
&& s2
== &maybe_freed
)
141 if (s1
== &maybe_freed
&& s2
== &freed
)
146 static int is_freed(struct expression
*expr
)
150 sm
= get_sm_state_expr(my_id
, expr
);
151 if (sm
&& slist_has_state(sm
->possible
, &freed
))
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
)
167 static bool expr_is_condition(struct expression
*expr
)
169 struct statement
*stmt
;
171 stmt
= expr_get_parent_stmt(expr
);
174 if (stmt
->type
== STMT_IF
|| stmt
->type
== STMT_ITERATOR
)
179 bool is_part_of_condition(struct expression
*expr
)
181 struct expression
*parent
;
183 if (expr_is_condition(expr
))
186 parent
= expr_get_parent_expr(expr
);
189 if (parent
->type
== EXPR_LOGICAL
|| parent
->type
== EXPR_COMPARE
)
191 if (parent
->type
== EXPR_SELECT
|| parent
->type
== EXPR_CONDITIONAL
)
193 if (parent
->type
== EXPR_PREOP
&& parent
->op
== '!')
199 static bool is_percent_p(struct expression
*str_expr
, int idx
)
204 p
= str_expr
->string
->data
;
206 if (p
[0] == '%' && p
[1] == '%') {
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] == '*'))
216 if (idx
== cnt
&& p
[1] == 'p')
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
)
234 FOR_EACH_PTR(parent
->args
, arg
) {
238 } END_FOR_EACH_PTR(arg
);
244 FOR_EACH_PTR(parent
->args
, arg
) {
246 if (arg
->type
!= EXPR_STRING
)
248 if (is_percent_p(arg
, expr_idx
- string_idx
))
250 } END_FOR_EACH_PTR(arg
);
255 static void match_symbol(struct expression
*expr
)
257 struct expression
*parent
;
260 if (is_impossible_path())
262 if (__in_fake_parameter_assign
)
265 if (is_part_of_condition(expr
))
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
== '&')
278 if (is_percent_p_print(expr
))
281 name
= expr_to_var(expr
);
282 sm_warning("'%s' was already freed.", name
);
286 static void match_dereferences(struct expression
*expr
)
290 if (expr
->type
!= EXPR_PREOP
)
293 if (is_impossible_path())
295 if (__in_fake_parameter_assign
)
298 expr
= strip_expr(expr
->unop
);
301 name
= expr_to_var(expr
);
302 sm_error("dereferencing freed memory '%s'", name
);
303 set_state_expr(my_id
, expr
, &ok
);
307 static int ignored_params
[16];
309 static void set_ignored_params(struct expression
*call
)
311 struct expression
*arg
;
315 memset(&ignored_params
, 0, sizeof(ignored_params
));
318 FOR_EACH_PTR(call
->args
, arg
) {
320 if (arg
->type
!= EXPR_STRING
)
323 } END_FOR_EACH_PTR(arg
);
329 p
= arg
->string
->data
;
330 while ((p
= strchr(p
, '%'))) {
331 if (i
>= ARRAY_SIZE(ignored_params
))
343 ignored_params
[i
] = 1;
348 static int is_free_func(struct expression
*fn
)
353 name
= expr_to_str(fn
);
356 if (strstr(name
, "free"))
363 static void match_call(struct expression
*expr
)
365 struct expression
*arg
;
369 if (is_impossible_path())
372 set_ignored_params(expr
);
375 FOR_EACH_PTR(expr
->args
, arg
) {
377 if (!is_pointer(arg
))
381 if (ignored_params
[i
])
383 if (is_percent_p_print(arg
))
386 name
= expr_to_var(arg
);
387 if (is_free_func(expr
->fn
))
388 sm_error("double free of '%s'", name
);
390 sm_warning("passing freed memory '%s'", name
);
391 set_state_expr(my_id
, arg
, &ok
);
393 } END_FOR_EACH_PTR(arg
);
396 static void match_return(struct expression
*expr
)
400 if (is_impossible_path())
408 name
= expr_to_var(expr
);
409 sm_warning("returning freed memory '%s'", name
);
410 set_state_expr(my_id
, expr
, &ok
);
414 static int counter_was_inced_name_sym(const char *name
, struct symbol
*sym
, const char *counter_str
)
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
)
428 name
= expr_to_var_sym(expr
, &sym
);
432 ret
= counter_was_inced_name_sym(name
, sym
, counter_str
);
438 static bool is_ptr_to(struct expression
*expr
, const char *type
)
442 sym
= get_type(expr
);
443 if (!is_ptr_type(sym
))
445 sym
= get_real_base_type(sym
);
446 if (sym
&& sym
->ident
&& strcmp(sym
->ident
->name
, type
) == 0)
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())
458 arg
= gen_expression_from_name_sym(name
, sym
);
461 if (is_ptr_to(arg
, "sk_buff") &&
462 counter_was_inced(arg
, "->users.refs.counter"))
464 if (is_ptr_to(arg
, "buffer_head") &&
465 counter_was_inced(arg
, "->b_count.counter"))
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
);
483 /* kobject_put(&cdev->kobj); */
484 if (arg
->type
!= EXPR_PREOP
|| arg
->op
!= '&')
486 arg
= strip_expr(arg
->unop
);
487 if (arg
->type
!= EXPR_DEREF
)
489 arg
= strip_expr(arg
->deref
);
490 if (arg
->type
!= EXPR_PREOP
|| arg
->op
!= '*')
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
)
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
;
515 while (expr
->type
== EXPR_ASSIGNMENT
)
516 expr
= strip_expr(expr
->right
);
517 if (expr
->type
!= EXPR_CALL
)
520 if (is_handled_func(expr
->fn
))
523 arg
= get_argument_from_call_expr(expr
->args
, param
);
526 name
= get_variable_from_key(arg
, key
, &sym
);
530 /* skbs are not free if we called skb_get(). */
531 if (counter_was_inced_name_sym(name
, sym
, "->users.refs.counter"))
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
);
544 call_free_call_backs_name_sym(NULL
, name
, sym
);
545 set_state(my_id
, name
, sym
, state
);
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
)
566 struct smatch_state
*state
;
568 strncpy(buf
, name
, sizeof(buf
) - 1);
569 buf
[sizeof(buf
) - 1] = '\0';
572 while ((*start
== '&'))
576 while ((end
= strrchr(end
, '-'))) {
580 state
= __get_state(my_id
, start
, sym
);
589 int parent_is_free_strict(struct expression
*expr
)
595 expr
= strip_expr(expr
);
596 var
= expr_to_var_sym(expr
, &sym
);
599 ret
= parent_is_free_var_sym_strict(var
, sym
);
605 static void match_untracked(struct expression
*call
, int param
)
607 struct state_list
*slist
= NULL
;
608 struct expression
*arg
;
614 arg
= get_argument_from_call_expr(call
->args
, param
);
618 name
= expr_to_var(arg
);
621 snprintf(buf
, sizeof(buf
), "%s->", name
);
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
);
637 void check_free_strict(int id
)
639 struct func_info
*info
;
645 if (option_project
!= PROJ_KERNEL
)
648 for (i
= 0; i
< ARRAY_SIZE(func_table
); i
++) {
649 info
= &func_table
[i
];
651 insert_string(&handled
, info
->name
);
654 cb
= info
->call_back
;
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
);
663 add_function_param_key_hook(info
->name
, cb
,
664 info
->param
, info
->key
, info
);
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
);