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 struct tracker_list
*arguments
;
33 /* If we pass a parent to a function that sets all the
34 children to assigned. frob(x) means x->data is assigned. */
37 struct tracker_list
*children
;
39 ALLOCATOR(parent
, "parents");
40 DECLARE_PTR_LIST(parent_list
, struct parent
);
41 static struct parent_list
*parents
;
43 static const char *allocation_funcs
[] = {
49 static void add_parent_to_parents(char *name
, struct symbol
*sym
)
53 FOR_EACH_PTR(parents
, tmp
) {
54 if (tmp
->sym
== sym
) {
55 add_tracker(&tmp
->children
, name
, my_id
, sym
);
58 } END_FOR_EACH_PTR(tmp
);
60 tmp
= __alloc_parent(0);
63 add_tracker(&tmp
->children
, name
, my_id
, sym
);
64 add_ptr_list(&parents
, tmp
);
67 static void set_list_assigned(struct tracker_list
*children
)
69 struct tracker
*child
;
71 FOR_EACH_PTR(children
, child
) {
72 set_state(child
->name
, my_id
, child
->sym
, &assigned
);
73 } END_FOR_EACH_PTR(child
);
76 static struct tracker_list
*get_children(struct symbol
*sym
)
80 FOR_EACH_PTR(parents
, tmp
) {
81 if (tmp
->sym
== sym
) {
84 } END_FOR_EACH_PTR(tmp
);
88 static void set_children_assigned(struct symbol
*sym
)
90 struct tracker_list
*children
;
92 if ((children
= get_children(sym
))) {
93 set_list_assigned(children
);
97 static int is_allocation(struct expression
*expr
)
102 if (expr
->type
!= EXPR_CALL
)
105 if (!(fn_name
= get_variable_from_expr(expr
->fn
, NULL
)))
108 for (i
= 0; allocation_funcs
[i
]; i
++) {
109 if (!strcmp(fn_name
, allocation_funcs
[i
])) {
110 free_string(fn_name
);
114 free_string(fn_name
);
118 static int is_freed(const char *name
, struct symbol
*sym
)
120 struct state_list
*slist
;
122 slist
= get_possible_states(name
, my_id
, sym
);
123 if (slist_has_state(slist
, &isfree
)) {
129 static int is_argument(struct symbol
*sym
)
133 FOR_EACH_PTR(arguments
, arg
) {
136 } END_FOR_EACH_PTR(arg
);
140 static void match_function_def(struct symbol
*sym
)
144 FOR_EACH_PTR(sym
->ctype
.base_type
->arguments
, arg
) {
145 add_tracker(&arguments
, arg
->ident
->name
, my_id
, arg
);
146 } END_FOR_EACH_PTR(arg
);
149 static void match_assign(struct expression
*expr
)
151 struct expression
*left
, *right
;
152 char *left_name
, *right_name
;
153 struct symbol
*left_sym
, *right_sym
;
154 struct smatch_state
*state
;
156 left
= strip_expr(expr
->left
);
157 left_name
= get_variable_from_expr(left
, &left_sym
);
161 free_string(left_name
);
165 right
= strip_expr(expr
->right
);
166 if (is_allocation(right
) && !(left_sym
->ctype
.modifiers
&
167 (MOD_NONLOCAL
| MOD_STATIC
| MOD_ADDRESSABLE
))) {
168 set_state(left_name
, my_id
, left_sym
, &malloced
);
169 add_parent_to_parents(left_name
, left_sym
);
170 free_string(left_name
);
174 right_name
= get_variable_from_expr(right
, &right_sym
);
175 if (right_name
&& (state
= get_state(right_name
, my_id
, right_sym
))) {
176 if (state
== &isfree
)
177 smatch_msg("error: assigning freed pointer");
178 set_state(right_name
, my_id
, right_sym
, &assigned
);
180 free_string(right_name
);
182 if (is_freed(left_name
, left_sym
)) {
183 set_state(left_name
, my_id
, left_sym
, &unfree
);
185 free_string(left_name
);
188 static int is_null(char *name
, struct symbol
*sym
)
190 struct smatch_state
*state
;
193 * FIXME. Ha ha ha... This is so wrong.
194 * I'm pulling in data from the check_null_deref script.
195 * I just happen to know that its ID is 3.
196 * The correct approved way to do this is to get the data from
197 * smatch_extra. But right now smatch_extra doesn't track it.
199 state
= get_state(name
, my_id
, sym
);
200 if (state
&& !strcmp(state
->name
, "isnull"))
205 static void match_kfree(struct expression
*expr
)
207 struct expression
*ptr_expr
;
209 struct symbol
*ptr_sym
;
211 ptr_expr
= get_argument_from_call_expr(expr
->args
, 0);
212 ptr_name
= get_variable_from_expr(ptr_expr
, &ptr_sym
);
213 if (is_freed(ptr_name
, ptr_sym
) && !is_null(ptr_name
, ptr_sym
)) {
214 smatch_msg("error: double free of %s", ptr_name
);
216 set_state(ptr_name
, my_id
, ptr_sym
, &isfree
);
217 free_string(ptr_name
);
220 static int possibly_allocated(struct state_list
*slist
)
222 struct sm_state
*tmp
;
224 FOR_EACH_PTR(slist
, tmp
) {
225 if (tmp
->state
== &allocated
)
227 if (tmp
->state
== &malloced
)
229 } END_FOR_EACH_PTR(tmp
);
233 static void check_for_allocated()
235 struct state_list
*slist
;
236 struct sm_state
*tmp
;
238 slist
= get_all_states(my_id
);
239 FOR_EACH_PTR(slist
, tmp
) {
240 if (possibly_allocated(tmp
->possible
) &&
241 !is_null(tmp
->name
, tmp
->sym
) &&
242 !is_argument(tmp
->sym
))
243 smatch_msg("error: memery leak of %s", tmp
->name
);
244 } END_FOR_EACH_PTR(tmp
);
248 static void match_return(struct statement
*stmt
)
252 struct smatch_state
*state
;
254 name
= get_variable_from_expr(stmt
->ret_value
, &sym
);
255 if ((state
= get_state(name
, my_id
, sym
))) {
256 set_state(name
, my_id
, sym
, &assigned
);
257 add_parent_to_parents(name
, sym
);
260 check_for_allocated();
263 static void set_new_true_false_paths(const char *name
, struct symbol
*sym
)
265 struct smatch_state
*tmp
;
267 tmp
= get_state(name
, my_id
, sym
);
273 if (tmp
== &isfree
) {
274 smatch_msg("warn: why do you care about freed memory?");
277 if (tmp
== &malloced
) {
278 set_true_false_states(name
, my_id
, sym
, &allocated
, &isnull
);
282 static void match_condition(struct expression
*expr
)
287 expr
= strip_expr(expr
);
292 name
= get_variable_from_expr(expr
, &sym
);
295 set_new_true_false_paths(name
, sym
);
303 static void match_function_call(struct expression
*expr
)
305 struct expression
*tmp
;
309 struct sm_state
*state
;
311 fn_name
= get_variable_from_expr(expr
->fn
, NULL
);
313 if (fn_name
&& !strcmp(fn_name
, "kfree")) {
317 FOR_EACH_PTR(expr
->args
, tmp
) {
318 tmp
= strip_expr(tmp
);
319 name
= get_variable_from_expr(tmp
, &sym
);
322 if ((state
= get_sm_state(name
, my_id
, sym
))) {
323 if (possibly_allocated(state
->possible
)) {
324 set_state(name
, my_id
, sym
, &assigned
);
327 set_children_assigned(sym
);
328 /* get parent. set children to assigned */
329 } END_FOR_EACH_PTR(tmp
);
332 static void free_the_parents()
336 FOR_EACH_PTR(parents
, tmp
) {
337 free_trackers_and_list(&tmp
->children
);
338 } END_FOR_EACH_PTR(tmp
);
339 __free_ptr_list((struct ptr_list
**)&parents
);
342 static void match_end_func(struct symbol
*sym
)
344 check_for_allocated();
348 void register_memory(int id
)
351 add_hook(&match_function_def
, FUNC_DEF_HOOK
);
352 add_hook(&match_function_call
, FUNCTION_CALL_HOOK
);
353 add_hook(&match_condition
, CONDITION_HOOK
);
354 add_hook(&match_assign
, ASSIGNMENT_HOOK
);
355 add_hook(&match_return
, RETURN_HOOK
);
356 add_hook(&match_end_func
, END_FUNC_HOOK
);