2 * sparse/check_memory.c
4 * Copyright (C) 2008 Dan Carpenter.
6 * Licensed under the Open Software License version 1.1
12 #include "smatch_slist.h"
24 malloced --> allocated --> assigned --> isfree +
25 \-> isnull. \-> isfree +
31 /* If we pass a parent to a function that sets all the
32 children to assigned. frob(x) means x->data is assigned. */
35 struct tracker_list
*children
;
37 ALLOCATOR(parent
, "parents");
38 DECLARE_PTR_LIST(parent_list
, struct parent
);
39 static struct parent_list
*parents
;
41 static const char *allocation_funcs
[] = {
47 static void add_parent_to_parents(char *name
, struct symbol
*sym
)
51 FOR_EACH_PTR(parents
, tmp
) {
52 if (tmp
->sym
== sym
) {
53 add_tracker(&tmp
->children
, name
, my_id
, sym
);
56 } END_FOR_EACH_PTR(tmp
);
58 tmp
= __alloc_parent(0);
61 add_tracker(&tmp
->children
, name
, my_id
, sym
);
62 add_ptr_list(&parents
, tmp
);
65 static void set_list_assigned(struct tracker_list
*children
)
67 struct tracker
*child
;
69 FOR_EACH_PTR(children
, child
) {
70 set_state(child
->name
, my_id
, child
->sym
, &assigned
);
71 } END_FOR_EACH_PTR(child
);
74 static struct tracker_list
*get_children(struct symbol
*sym
)
78 FOR_EACH_PTR(parents
, tmp
) {
79 if (tmp
->sym
== sym
) {
82 } END_FOR_EACH_PTR(tmp
);
86 static void set_children_assigned(struct symbol
*sym
)
88 struct tracker_list
*children
;
90 if ((children
= get_children(sym
))) {
91 set_list_assigned(children
);
95 static int is_allocation(struct expression
*expr
)
100 if (expr
->type
!= EXPR_CALL
)
103 if (!(fn_name
= get_variable_from_expr(expr
->fn
, NULL
)))
106 for (i
= 0; allocation_funcs
[i
]; i
++) {
107 if (!strcmp(fn_name
, allocation_funcs
[i
])) {
108 free_string(fn_name
);
112 free_string(fn_name
);
116 static int is_freed(const char *name
, struct symbol
*sym
)
118 struct state_list
*slist
;
120 slist
= get_possible_states(name
, my_id
, sym
);
121 if (slist_has_state(slist
, &isfree
)) {
127 static void match_assign(struct expression
*expr
)
129 struct expression
*left
, *right
;
130 char *left_name
, *right_name
;
131 struct symbol
*left_sym
, *right_sym
;
132 struct smatch_state
*state
;
134 left
= strip_expr(expr
->left
);
135 left_name
= get_variable_from_expr(left
, &left_sym
);
139 free_string(left_name
);
143 right
= strip_expr(expr
->right
);
144 if (is_allocation(right
) && !(left_sym
->ctype
.modifiers
&
145 (MOD_NONLOCAL
| MOD_STATIC
| MOD_ADDRESSABLE
))) {
146 set_state(left_name
, my_id
, left_sym
, &malloced
);
147 add_parent_to_parents(left_name
, left_sym
);
148 free_string(left_name
);
152 right_name
= get_variable_from_expr(right
, &right_sym
);
153 if (right_name
&& (state
= get_state(right_name
, my_id
, right_sym
))) {
154 if (state
== &isfree
)
155 smatch_msg("assigning freed pointer");
156 set_state(right_name
, my_id
, right_sym
, &assigned
);
158 free_string(right_name
);
160 if (is_freed(left_name
, left_sym
)) {
161 set_state(left_name
, my_id
, left_sym
, &unfree
);
163 free_string(left_name
);
166 static int is_null(char *name
, struct symbol
*sym
)
168 struct smatch_state
*state
;
171 * FIXME. Ha ha ha... This is so wrong.
172 * I'm pulling in data from the check_null_deref script.
173 * I just happen to know that its ID is 3.
174 * The correct approved way to do this is to get the data from
175 * smatch_extra. But right now smatch_extra doesn't track it.
177 state
= get_state(name
, my_id
, sym
);
178 if (state
&& !strcmp(state
->name
, "isnull"))
183 static void match_kfree(struct expression
*expr
)
185 struct expression
*ptr_expr
;
187 struct symbol
*ptr_sym
;
189 ptr_expr
= get_argument_from_call_expr(expr
->args
, 0);
190 ptr_name
= get_variable_from_expr(ptr_expr
, &ptr_sym
);
191 if (is_freed(ptr_name
, ptr_sym
) && !is_null(ptr_name
, ptr_sym
)) {
192 smatch_msg("double free of %s", ptr_name
);
194 set_state(ptr_name
, my_id
, ptr_sym
, &isfree
);
195 free_string(ptr_name
);
198 static int possibly_allocated(struct state_list
*slist
)
200 struct sm_state
*tmp
;
202 FOR_EACH_PTR(slist
, tmp
) {
203 if (tmp
->state
== &allocated
)
205 if (tmp
->state
== &malloced
)
207 } END_FOR_EACH_PTR(tmp
);
211 static void check_for_allocated()
213 struct state_list
*slist
;
214 struct sm_state
*tmp
;
218 slist
= get_all_states(my_id
);
219 FOR_EACH_PTR(slist
, tmp
) {
220 if (possibly_allocated(tmp
->possible
) &&
221 !is_null(tmp
->name
, tmp
->sym
))
222 smatch_msg("possible memery leak of %s", tmp
->name
);
223 } END_FOR_EACH_PTR(tmp
);
227 static void match_return(struct statement
*stmt
)
231 struct smatch_state
*state
;
233 name
= get_variable_from_expr(stmt
->ret_value
, &sym
);
234 if ((state
= get_state(name
, my_id
, sym
))) {
235 set_state(name
, my_id
, sym
, &assigned
);
238 check_for_allocated();
241 static void set_new_true_false_paths(const char *name
, struct symbol
*sym
)
243 struct smatch_state
*tmp
;
245 tmp
= get_state(name
, my_id
, sym
);
251 if (tmp
== &isfree
) {
252 smatch_msg("why do you care about freed memory?");
255 if (tmp
== &malloced
) {
256 set_true_false_states(name
, my_id
, sym
, &allocated
, &isnull
);
260 static void match_condition(struct expression
*expr
)
265 expr
= strip_expr(expr
);
270 name
= get_variable_from_expr(expr
, &sym
);
273 set_new_true_false_paths(name
, sym
);
281 static void match_function_call(struct expression
*expr
)
283 struct expression
*tmp
;
287 struct sm_state
*state
;
289 fn_name
= get_variable_from_expr(expr
->fn
, NULL
);
291 if (fn_name
&& !strcmp(fn_name
, "kfree")) {
295 FOR_EACH_PTR(expr
->args
, tmp
) {
296 tmp
= strip_expr(tmp
);
297 name
= get_variable_from_expr(tmp
, &sym
);
300 if ((state
= get_sm_state(name
, my_id
, sym
))) {
301 if (possibly_allocated(state
->possible
)) {
302 set_state(name
, my_id
, sym
, &assigned
);
305 set_children_assigned(sym
);
306 /* get parent. set children to assigned */
307 } END_FOR_EACH_PTR(tmp
);
310 static void free_the_parents()
314 FOR_EACH_PTR(parents
, tmp
) {
315 free_trackers_and_list(&tmp
->children
);
316 } END_FOR_EACH_PTR(tmp
);
317 __free_ptr_list((struct ptr_list
**)&parents
);
320 static void match_end_func(struct symbol
*sym
)
322 check_for_allocated();
326 void register_memory(int id
)
329 add_hook(&match_function_call
, FUNCTION_CALL_HOOK
);
330 add_hook(&match_condition
, CONDITION_HOOK
);
331 add_hook(&match_assign
, ASSIGNMENT_HOOK
);
332 add_hook(&match_return
, RETURN_HOOK
);
333 add_hook(&match_end_func
, END_FUNC_HOOK
);