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 { "qdisc_enqueue", PARAM_FREED
, 0, "$" },
76 { "kobject_put", PARAM_FREED
, 0, "$", NULL
, NULL
, &match_kobject_put
},
77 { "kref_put", PARAM_FREED
, 0, "$", NULL
, NULL
, &match_kobject_put
},
78 { "put_device", PARAM_FREED
, 0, "$", NULL
, NULL
, &match_kobject_put
},
81 static struct name_sym_fn_list
*free_hooks
;
83 void add_free_hook(name_sym_hook
*hook
)
85 add_ptr_list(&free_hooks
, hook
);
88 static void call_free_call_backs_name_sym(struct expression
*expr
, const char *name
, struct symbol
*sym
)
93 expr
= gen_expression_from_name_sym(name
, sym
);
95 FOR_EACH_PTR(free_hooks
, hook
) {
96 hook(expr
, name
, sym
);
97 } END_FOR_EACH_PTR(hook
);
100 static void ok_to_use(struct sm_state
*sm
, struct expression
*mod_expr
)
102 if (sm
->state
!= &ok
)
103 set_state(my_id
, sm
->name
, sm
->sym
, &ok
);
106 static void pre_merge_hook(struct sm_state
*cur
, struct sm_state
*other
)
108 if (is_impossible_path())
109 set_state(my_id
, cur
->name
, cur
->sym
, &ok
);
112 static struct smatch_state
*unmatched_state(struct sm_state
*sm
)
114 struct smatch_state
*state
;
117 if (sm
->state
!= &freed
&& sm
->state
!= &maybe_freed
)
120 if (get_param_num_from_sym(sm
->sym
) < 0)
124 * If the parent is non-there count it as freed. This is
125 * a hack for tracking return states.
127 if (parent_is_null_var_sym(sm
->name
, sm
->sym
))
130 state
= get_state(SMATCH_EXTRA
, sm
->name
, sm
->sym
);
133 if (!estate_get_single_value(state
, &sval
) || sval
.value
!= 0)
135 /* It makes it easier to consider NULL pointers as freed. */
139 struct smatch_state
*merge_frees(struct smatch_state
*s1
, struct smatch_state
*s2
)
141 if (s1
== &freed
&& s2
== &maybe_freed
)
143 if (s1
== &maybe_freed
&& s2
== &freed
)
148 static int is_freed(struct expression
*expr
)
152 sm
= get_sm_state_expr(my_id
, expr
);
153 if (sm
&& slist_has_state(sm
->possible
, &freed
))
158 bool is_freed_var_sym(const char *name
, struct symbol
*sym
)
160 struct smatch_state
*state
;
162 state
= get_state(my_id
, name
, sym
);
163 if (state
== &freed
|| state
== &maybe_freed
)
169 static bool expr_is_condition(struct expression
*expr
)
171 struct statement
*stmt
;
173 stmt
= expr_get_parent_stmt(expr
);
176 if (stmt
->type
== STMT_IF
|| stmt
->type
== STMT_ITERATOR
)
181 bool is_part_of_condition(struct expression
*expr
)
183 struct expression
*parent
;
185 if (expr_is_condition(expr
))
188 parent
= expr_get_parent_expr(expr
);
191 if (parent
->type
== EXPR_LOGICAL
|| parent
->type
== EXPR_COMPARE
)
193 if (parent
->type
== EXPR_SELECT
|| parent
->type
== EXPR_CONDITIONAL
)
195 if (parent
->type
== EXPR_PREOP
&& parent
->op
== '!')
201 static bool is_percent_p(struct expression
*str_expr
, int idx
)
206 p
= str_expr
->string
->data
;
208 if (p
[0] == '%' && p
[1] == '%') {
212 /* If we have print("%.*s %p", prec, str, p); then it takes 2 params */
213 if ((p
[0] == '%' && p
[1] == '*') ||
214 (p
[0] == '%' && p
[1] == '.' && p
[2] == '*'))
218 if (idx
== cnt
&& p
[1] == 'p')
226 bool is_percent_p_print(struct expression
*expr
)
228 struct expression
*parent
, *arg
;
229 int expr_idx
, string_idx
;
231 parent
= expr_get_parent_expr(expr
);
232 if (!parent
|| parent
->type
!= EXPR_CALL
)
236 FOR_EACH_PTR(parent
->args
, arg
) {
240 } END_FOR_EACH_PTR(arg
);
246 FOR_EACH_PTR(parent
->args
, arg
) {
248 if (arg
->type
!= EXPR_STRING
)
250 if (is_percent_p(arg
, expr_idx
- string_idx
))
252 } END_FOR_EACH_PTR(arg
);
257 static void match_symbol(struct expression
*expr
)
259 struct expression
*parent
;
262 if (is_impossible_path())
264 if (__in_fake_parameter_assign
)
267 if (is_part_of_condition(expr
))
270 /* This ignores stuff like "get_new_ptr(&foo);" */
271 parent
= expr_get_parent_expr(expr
);
272 while (parent
&& parent
->type
== EXPR_PREOP
&& parent
->op
== '(')
273 parent
= expr_get_parent_expr(parent
);
274 if (parent
&& parent
->type
== EXPR_PREOP
&& parent
->op
== '&')
280 if (is_percent_p_print(expr
))
283 name
= expr_to_var(expr
);
284 sm_warning("'%s' was already freed.", name
);
288 static void match_dereferences(struct expression
*expr
)
292 if (expr
->type
!= EXPR_PREOP
)
295 if (is_impossible_path())
297 if (__in_fake_parameter_assign
)
300 expr
= strip_expr(expr
->unop
);
303 name
= expr_to_var(expr
);
304 sm_error("dereferencing freed memory '%s'", name
);
305 set_state_expr(my_id
, expr
, &ok
);
309 static int ignored_params
[16];
311 static void set_ignored_params(struct expression
*call
)
313 struct expression
*arg
;
317 memset(&ignored_params
, 0, sizeof(ignored_params
));
320 FOR_EACH_PTR(call
->args
, arg
) {
322 if (arg
->type
!= EXPR_STRING
)
325 } END_FOR_EACH_PTR(arg
);
331 p
= arg
->string
->data
;
332 while ((p
= strchr(p
, '%'))) {
333 if (i
>= ARRAY_SIZE(ignored_params
))
345 ignored_params
[i
] = 1;
350 static int is_free_func(struct expression
*fn
)
355 name
= expr_to_str(fn
);
358 if (strstr(name
, "free"))
365 static void match_call(struct expression
*expr
)
367 struct expression
*arg
;
371 if (is_impossible_path())
374 set_ignored_params(expr
);
377 FOR_EACH_PTR(expr
->args
, arg
) {
379 if (!is_pointer(arg
))
383 if (ignored_params
[i
])
385 if (is_percent_p_print(arg
))
388 name
= expr_to_var(arg
);
389 if (is_free_func(expr
->fn
))
390 sm_error("double free of '%s'", name
);
392 sm_warning("passing freed memory '%s'", name
);
393 set_state_expr(my_id
, arg
, &ok
);
395 } END_FOR_EACH_PTR(arg
);
398 static void match_return(struct expression
*expr
)
402 if (is_impossible_path())
410 name
= expr_to_var(expr
);
411 sm_warning("returning freed memory '%s'", name
);
412 set_state_expr(my_id
, expr
, &ok
);
416 static int counter_was_inced_name_sym(const char *name
, struct symbol
*sym
, const char *counter_str
)
420 snprintf(buf
, sizeof(buf
), "%s%s", name
, counter_str
);
421 return was_inced(buf
, sym
);
424 static int counter_was_inced(struct expression
*expr
, const char *counter_str
)
430 name
= expr_to_var_sym(expr
, &sym
);
434 ret
= counter_was_inced_name_sym(name
, sym
, counter_str
);
440 static bool is_ptr_to(struct expression
*expr
, const char *type
)
444 sym
= get_type(expr
);
445 if (!is_ptr_type(sym
))
447 sym
= get_real_base_type(sym
);
448 if (sym
&& sym
->ident
&& strcmp(sym
->ident
->name
, type
) == 0)
453 static void match_free(struct expression
*expr
, const char *name
, struct symbol
*sym
, void *data
)
455 struct expression
*arg
;
457 if (is_impossible_path())
460 arg
= gen_expression_from_name_sym(name
, sym
);
463 if (is_ptr_to(arg
, "sk_buff") &&
464 counter_was_inced(arg
, "->users.refs.counter"))
466 if (is_ptr_to(arg
, "buffer_head") &&
467 counter_was_inced(arg
, "->b_count.counter"))
470 sm_error("double free of '%s'", name
);
472 track_freed_param(arg
, &freed
);
473 call_free_call_backs_name_sym(expr
, name
, sym
);
474 set_state_expr(my_id
, arg
, &freed
);
478 static void match_kobject_put(struct expression
*expr
, const char *name
, struct symbol
*sym
, void *data
)
480 struct expression
*arg
;
482 arg
= gen_expression_from_name_sym(name
, sym
);
485 /* kobject_put(&cdev->kobj); */
486 if (arg
->type
!= EXPR_PREOP
|| arg
->op
!= '&')
488 arg
= strip_expr(arg
->unop
);
489 if (arg
->type
!= EXPR_DEREF
)
491 arg
= strip_expr(arg
->deref
);
492 if (arg
->type
!= EXPR_PREOP
|| arg
->op
!= '*')
494 arg
= strip_expr(arg
->unop
);
495 track_freed_param(arg
, &maybe_freed
);
496 set_state_expr(my_id
, arg
, &maybe_freed
);
499 struct string_list
*handled
;
500 static bool is_handled_func(struct expression
*fn
)
502 if (!fn
|| fn
->type
!= EXPR_SYMBOL
|| !fn
->symbol
->ident
)
505 return list_has_string(handled
, fn
->symbol
->ident
->name
);
508 static void set_param_helper(struct expression
*expr
, int param
,
509 char *key
, char *value
,
510 struct smatch_state
*state
)
512 struct expression
*arg
;
517 while (expr
->type
== EXPR_ASSIGNMENT
)
518 expr
= strip_expr(expr
->right
);
519 if (expr
->type
!= EXPR_CALL
)
522 if (is_handled_func(expr
->fn
))
525 arg
= get_argument_from_call_expr(expr
->args
, param
);
528 name
= get_variable_from_key(arg
, key
, &sym
);
532 /* skbs are not free if we called skb_get(). */
533 if (counter_was_inced_name_sym(name
, sym
, "->users.refs.counter"))
536 if (state
== &freed
&& !is_impossible_path()) {
537 sm
= get_sm_state(my_id
, name
, sym
);
538 if (sm
&& slist_has_state(sm
->possible
, &freed
)) {
539 sm_warning("'%s' double freed", name
);
540 set_state(my_id
, name
, sym
, &ok
); /* fixme: doesn't silence anything. I know */
544 track_freed_param_var_sym(name
, sym
, state
);
546 call_free_call_backs_name_sym(NULL
, name
, sym
);
547 set_state(my_id
, name
, sym
, state
);
552 static void set_param_freed(struct expression
*expr
, int param
, char *key
, char *value
)
554 set_param_helper(expr
, param
, key
, value
, &freed
);
557 static void set_param_maybe_freed(struct expression
*expr
, int param
, char *key
, char *value
)
559 set_param_helper(expr
, param
, key
, value
, &maybe_freed
);
562 int parent_is_free_var_sym_strict(const char *name
, struct symbol
*sym
)
568 struct smatch_state
*state
;
570 strncpy(buf
, name
, sizeof(buf
) - 1);
571 buf
[sizeof(buf
) - 1] = '\0';
574 while ((*start
== '&'))
578 while ((end
= strrchr(end
, '-'))) {
582 state
= __get_state(my_id
, start
, sym
);
591 int parent_is_free_strict(struct expression
*expr
)
597 expr
= strip_expr(expr
);
598 var
= expr_to_var_sym(expr
, &sym
);
601 ret
= parent_is_free_var_sym_strict(var
, sym
);
607 static void match_untracked(struct expression
*call
, int param
)
609 struct state_list
*slist
= NULL
;
610 struct expression
*arg
;
616 arg
= get_argument_from_call_expr(call
->args
, param
);
620 name
= expr_to_var(arg
);
623 snprintf(buf
, sizeof(buf
), "%s->", name
);
627 FOR_EACH_MY_SM(my_id
, __get_cur_stree(), sm
) {
628 if (strncmp(sm
->name
, buf
, len
) == 0)
629 add_ptr_list(&slist
, sm
);
630 } END_FOR_EACH_SM(sm
);
632 FOR_EACH_PTR(slist
, sm
) {
633 set_state(sm
->owner
, sm
->name
, sm
->sym
, &ok
);
634 } END_FOR_EACH_PTR(sm
);
639 void check_free_strict(int id
)
641 struct func_info
*info
;
647 if (option_project
!= PROJ_KERNEL
)
650 for (i
= 0; i
< ARRAY_SIZE(func_table
); i
++) {
651 info
= &func_table
[i
];
653 insert_string(&handled
, info
->name
);
656 cb
= info
->call_back
;
660 if (info
->implies_start
) {
661 return_implies_param_key(info
->name
,
662 *info
->implies_start
, *info
->implies_end
,
663 cb
, info
->param
, info
->key
, info
);
665 add_function_param_key_hook(info
->name
, cb
,
666 info
->param
, info
->key
, info
);
671 add_hook(&match_symbol
, SYM_HOOK
);
672 add_hook(&match_dereferences
, DEREF_HOOK
);
673 add_hook(&match_call
, FUNCTION_CALL_HOOK
);
674 add_hook(&match_return
, RETURN_HOOK
);
676 add_modification_hook_late(my_id
, &ok_to_use
);
677 add_pre_merge_hook(my_id
, &pre_merge_hook
);
678 add_unmatched_state_hook(my_id
, &unmatched_state
);
679 add_merge_hook(my_id
, &merge_frees
);
681 select_return_states_hook(PARAM_FREED
, &set_param_freed
);
682 select_return_states_hook(MAYBE_FREED
, &set_param_maybe_freed
);
683 add_untracked_param_hook(&match_untracked
);