Print fewer Unclear locking messages.
[smatch.git] / check_memory.c
blob064a9643d62b2e794cfc373cda97a5f025803f39
1 /*
2 * sparse/check_memory.c
4 * Copyright (C) 2008 Dan Carpenter.
6 * Licensed under the Open Software License version 1.1
8 */
10 #include "parse.h"
11 #include "smatch.h"
12 #include "smatch_slist.h"
14 static int my_id;
16 STATE(allocated);
17 STATE(assigned);
18 STATE(isfree);
19 STATE(returned);
20 STATE(unfree);
22 static const char *allocation_funcs[] = {
23 "malloc",
24 "kmalloc",
25 NULL,
28 static int is_allocation(struct expression *expr)
30 char *fn_name;
31 int i;
33 if (expr->type != EXPR_CALL)
34 return 0;
36 if (!(fn_name = get_variable_from_expr(expr->fn, NULL)))
37 return 0;
39 for (i = 0; allocation_funcs[i]; i++) {
40 if (!strcmp(fn_name, allocation_funcs[i])) {
41 free_string(fn_name);
42 return 1;
45 free_string(fn_name);
46 return 0;
49 static int is_freed(const char *name, struct symbol *sym)
51 struct state_list *slist;
53 slist = get_possible_states(name, my_id, sym);
54 if (slist_has_state(slist, &isfree)) {
55 return 1;
57 return 0;
60 static void match_assign(struct expression *expr)
62 struct expression *left, *right;
63 char *left_name, *right_name;
64 struct symbol *left_sym, *right_sym;
65 struct smatch_state *state;
67 left = strip_expr(expr->left);
68 left_name = get_variable_from_expr(left, &left_sym);
69 if (!left_name)
70 return;
71 if (!left_sym) {
72 free_string(left_name);
73 return;
76 right = strip_expr(expr->right);
77 if (is_allocation(right) && !(left_sym->ctype.modifiers &
78 (MOD_NONLOCAL | MOD_STATIC | MOD_ADDRESSABLE))) {
79 set_state(left_name, my_id, left_sym, &allocated);
80 return;
83 right_name = get_variable_from_expr(right, &right_sym);
84 if (right_name && (state = get_state(right_name, my_id, right_sym))) {
85 if (state == &isfree)
86 smatch_msg("assigning freed pointer");
87 set_state(right_name, my_id, right_sym, &assigned);
89 free_string(right_name);
91 if (is_freed(left_name, left_sym)) {
92 set_state(left_name, my_id, left_sym, &unfree);
96 static int is_null(char *name, struct symbol *sym)
98 struct smatch_state *state;
101 * FIXME. Ha ha ha... This is so wrong.
102 * I'm pulling in data from the check_null_deref script.
103 * I just happen to know that its ID is 3.
104 * The correct approved way to do this is to get the data from
105 * smatch_extra. But right now smatch_extra doesn't track it.
107 state = get_state(name, 3, sym);
108 if (state && !strcmp(state->name, "isnull"))
109 return 1;
110 return 0;
113 static void match_kfree(struct expression *expr)
115 struct expression *ptr_expr;
116 char *fn_name;
117 char *ptr_name;
118 struct symbol *ptr_sym;
121 fn_name = get_variable_from_expr(expr->fn, NULL);
123 if (!fn_name || strcmp(fn_name, "kfree"))
124 return;
126 ptr_expr = get_argument_from_call_expr(expr->args, 0);
127 ptr_name = get_variable_from_expr(ptr_expr, &ptr_sym);
128 if (is_freed(ptr_name, ptr_sym) && !is_null(ptr_name, ptr_sym)) {
129 smatch_msg("double free of %s", ptr_name);
131 set_state(ptr_name, my_id, ptr_sym, &isfree);
133 free_string(fn_name);
136 static int possibly_allocated(struct state_list *slist)
138 struct sm_state *tmp;
140 FOR_EACH_PTR(slist, tmp) {
141 if (tmp->state == &allocated)
142 return 1;
143 } END_FOR_EACH_PTR(tmp);
144 return 0;
147 static void check_for_allocated()
149 struct state_list *slist;
150 struct sm_state *tmp;
152 return;
154 slist = get_all_states(my_id);
155 FOR_EACH_PTR(slist, tmp) {
156 if (possibly_allocated(tmp->possible) &&
157 !is_null(tmp->name, tmp->sym))
158 smatch_msg("possible memery leak of %s", tmp->name);
159 } END_FOR_EACH_PTR(tmp);
163 static void match_return(struct statement *stmt)
165 char *name;
166 struct symbol *sym;
167 struct smatch_state *state;
169 name = get_variable_from_expr(stmt->ret_value, &sym);
170 if ((state = get_state(name, my_id, sym))) {
171 set_state(name, my_id, sym, &returned);
174 check_for_allocated();
177 static void match_function_call(struct expression *expr)
184 static void match_end_func(struct symbol *sym)
186 check_for_allocated();
189 void register_memory(int id)
191 my_id = id;
192 add_hook(&match_kfree, FUNCTION_CALL_HOOK);
193 add_hook(&match_assign, ASSIGNMENT_HOOK);
194 add_hook(&match_return, RETURN_HOOK);
195 add_hook(&match_end_func, END_FUNC_HOOK);