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 ok_to_use(struct sm_state
*sm
, struct expression
*mod_expr
)
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
;
55 if (sm
->state
!= &freed
&& sm
->state
!= &maybe_freed
)
58 if (get_param_num_from_sym(sm
->sym
) < 0)
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
))
68 state
= get_state(SMATCH_EXTRA
, sm
->name
, sm
->sym
);
71 if (!estate_get_single_value(state
, &sval
) || sval
.value
!= 0)
73 /* It makes it easier to consider NULL pointers as freed. */
77 struct smatch_state
*merge_frees(struct smatch_state
*s1
, struct smatch_state
*s2
)
79 if (s1
== &freed
&& s2
== &maybe_freed
)
81 if (s1
== &maybe_freed
&& s2
== &freed
)
86 static int is_freed(struct expression
*expr
)
90 sm
= get_sm_state_expr(my_id
, expr
);
91 if (sm
&& slist_has_state(sm
->possible
, &freed
))
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
)
107 static void match_symbol(struct expression
*expr
)
109 struct expression
*parent
;
112 if (is_impossible_path())
114 if (__in_fake_parameter_assign
)
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
== '&')
125 name
= expr_to_var(expr
);
126 sm_warning("'%s' was already freed.", name
);
130 static void match_dereferences(struct expression
*expr
)
134 if (expr
->type
!= EXPR_PREOP
)
137 if (is_impossible_path())
139 if (__in_fake_parameter_assign
)
142 expr
= strip_expr(expr
->unop
);
145 name
= expr_to_var(expr
);
146 sm_error("dereferencing freed memory '%s'", name
);
147 set_state_expr(my_id
, expr
, &ok
);
151 static int ignored_params
[16];
153 static void set_ignored_params(struct expression
*call
)
155 struct expression
*arg
;
159 memset(&ignored_params
, 0, sizeof(ignored_params
));
162 FOR_EACH_PTR(call
->args
, arg
) {
164 if (arg
->type
!= EXPR_STRING
)
167 } END_FOR_EACH_PTR(arg
);
173 p
= arg
->string
->data
;
174 while ((p
= strchr(p
, '%'))) {
175 if (i
>= ARRAY_SIZE(ignored_params
))
187 ignored_params
[i
] = 1;
192 static int is_free_func(struct expression
*fn
)
197 name
= expr_to_str(fn
);
200 if (strstr(name
, "free"))
207 static void match_call(struct expression
*expr
)
209 struct expression
*arg
;
213 if (is_impossible_path())
216 set_ignored_params(expr
);
219 FOR_EACH_PTR(expr
->args
, arg
) {
221 if (!is_pointer(arg
))
225 if (ignored_params
[i
])
228 name
= expr_to_var(arg
);
229 if (is_free_func(expr
->fn
))
230 sm_error("double free of '%s'", name
);
232 sm_warning("passing freed memory '%s'", name
);
233 set_state_expr(my_id
, arg
, &ok
);
235 } END_FOR_EACH_PTR(arg
);
238 static void match_return(struct expression
*expr
)
242 if (is_impossible_path())
250 name
= expr_to_var(expr
);
251 sm_warning("returning freed memory '%s'", name
);
252 set_state_expr(my_id
, expr
, &ok
);
256 static int counter_was_inced_name_sym(const char *name
, struct symbol
*sym
)
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
)
270 name
= expr_to_var_sym(expr
, &sym
);
274 ret
= counter_was_inced_name_sym(name
, sym
);
280 void set_other_states_name_sym(int owner
, const char *name
, struct symbol
*sym
, struct smatch_state
*state
)
282 struct expression
*tmp
;
285 FOR_EACH_MY_SM(check_assigned_expr_id
, __get_cur_stree(), sm
) {
286 tmp
= sm
->state
->data
;
289 if (tmp
->type
!= EXPR_SYMBOL
)
291 if (tmp
->symbol
!= sym
)
293 if (!tmp
->symbol_name
)
295 if (strcmp(tmp
->symbol_name
->name
, name
) != 0)
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
);
302 set_state_expr(owner
, tmp
, state
);
305 void set_other_states(int owner
, struct expression
*expr
, struct smatch_state
*state
)
310 name
= expr_to_var_sym(expr
, &sym
);
314 set_other_states_name_sym(owner
, name
, sym
, state
);
320 static bool sk_buff_pointer(struct expression
*expr
)
324 type
= get_type(expr
);
325 if (!is_ptr_type(type
))
327 type
= get_real_base_type(type
);
328 if (type
&& type
->ident
&& strcmp(type
->ident
->name
, "sk_buff") == 0)
333 static void match_free(const char *fn
, struct expression
*expr
, void *param
)
335 struct expression
*arg
;
337 if (is_impossible_path())
340 arg
= get_argument_from_call_expr(expr
->args
, PTR_INT(param
));
343 if (sk_buff_pointer(arg
) && counter_was_inced(arg
))
346 char *name
= expr_to_var(arg
);
348 sm_error("double free of '%s'", 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
));
363 /* kobject_put(&cdev->kobj); */
364 if (arg
->type
!= EXPR_PREOP
|| arg
->op
!= '&')
366 arg
= strip_expr(arg
->unop
);
367 if (arg
->type
!= EXPR_DEREF
)
369 arg
= strip_expr(arg
->deref
);
370 if (arg
->type
!= EXPR_PREOP
|| arg
->op
!= '*')
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
)
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
;
395 while (expr
->type
== EXPR_ASSIGNMENT
)
396 expr
= strip_expr(expr
->right
);
397 if (expr
->type
!= EXPR_CALL
)
400 if (is_handled_func(expr
->fn
))
403 arg
= get_argument_from_call_expr(expr
->args
, param
);
406 name
= get_variable_from_key(arg
, key
, &sym
);
410 /* skbs are not free if we called skb_get(). */
411 if (counter_was_inced_name_sym(name
, sym
))
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
);
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
)
445 struct smatch_state
*state
;
447 strncpy(buf
, name
, sizeof(buf
) - 1);
448 buf
[sizeof(buf
) - 1] = '\0';
451 while ((*start
== '&'))
455 while ((end
= strrchr(end
, '-'))) {
459 state
= __get_state(my_id
, start
, sym
);
468 int parent_is_free_strict(struct expression
*expr
)
474 expr
= strip_expr(expr
);
475 var
= expr_to_var_sym(expr
, &sym
);
478 ret
= parent_is_free_var_sym_strict(var
, sym
);
484 static void match_untracked(struct expression
*call
, int param
)
486 struct state_list
*slist
= NULL
;
487 struct expression
*arg
;
493 arg
= get_argument_from_call_expr(call
->args
, param
);
497 name
= expr_to_var(arg
);
500 snprintf(buf
, sizeof(buf
), "%s->", name
);
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
);
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
)
526 if (option_project
!= PROJ_KERNEL
)
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);
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
);