redundant_null_check: silence some false positives
[smatch.git] / check_frees_param.c
blob3c4ec6fb48f39e52ee6d185bfcf246190d1ef92e
1 /*
2 * sparse/check_frees_param.c
4 * Copyright (C) 2014 Oracle.
6 * Licensed under the Open Software License version 1.1
8 * This file is sort of like check_dereferences_param.c. In theory the one
9 * difference should be that the param is NULL it should still be counted as a
10 * free. But for now I don't handle that case.
13 #include "smatch.h"
14 #include "smatch_extra.h"
15 #include "smatch_slist.h"
17 static int my_id;
19 STATE(freed);
20 STATE(ignore);
21 STATE(param);
23 static int is_arg(struct expression *expr)
25 struct symbol *arg;
27 if (expr->type != EXPR_SYMBOL)
28 return 0;
30 FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, arg) {
31 if (arg == expr->symbol)
32 return 1;
33 } END_FOR_EACH_PTR(arg);
34 return 0;
37 static void set_ignore(struct sm_state *sm, struct expression *mod_expr)
39 if (sm->state == &freed)
40 return;
41 set_state(my_id, sm->name, sm->sym, &ignore);
44 static void match_function_def(struct symbol *sym)
46 struct symbol *arg;
47 int i;
49 i = -1;
50 FOR_EACH_PTR(sym->ctype.base_type->arguments, arg) {
51 i++;
52 if (!arg->ident)
53 continue;
54 set_state(my_id, arg->ident->name, arg, &param);
55 } END_FOR_EACH_PTR(arg);
58 static void freed_variable(struct expression *expr)
60 struct sm_state *sm;
62 expr = strip_expr(expr);
63 if (!is_arg(expr))
64 return;
66 sm = get_sm_state_expr(my_id, expr);
67 if (sm && slist_has_state(sm->possible, &ignore))
68 return;
69 set_state_expr(my_id, expr, &freed);
72 static void match_free(const char *fn, struct expression *expr, void *param)
74 struct expression *arg;
76 arg = get_argument_from_call_expr(expr->args, PTR_INT(param));
77 if (!arg)
78 return;
79 freed_variable(arg);
82 static void set_param_freed(struct expression *arg, char *unused)
84 freed_variable(arg);
87 static void process_states(struct state_list *slist)
89 struct symbol *arg;
90 int i;
92 i = -1;
93 FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, arg) {
94 i++;
95 if (!arg->ident)
96 continue;
97 if (get_state_slist(slist, my_id, arg->ident->name, arg) == &freed)
98 sql_insert_call_implies(PARAM_FREED, i, 1);
99 } END_FOR_EACH_PTR(arg);
102 void check_frees_param(int id)
104 my_id = id;
106 add_hook(&match_function_def, FUNC_DEF_HOOK);
108 if (option_project == PROJ_KERNEL) {
109 add_function_hook("kfree", &match_free, INT_PTR(0));
110 add_function_hook("kmem_cache_free", &match_free, INT_PTR(1));
111 } else {
112 add_function_hook("free", &match_free, INT_PTR(0));
115 select_call_implies_hook(PARAM_FREED, &set_param_freed);
116 add_modification_hook(my_id, &set_ignore);
118 all_return_states_hook(&process_states);