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"
21 /* If we pass a parent to a function that sets all the
22 children to assigned. frob(x) means x->data is assigned. */
25 struct tracker_list
*children
;
27 ALLOCATOR(parent
, "parents");
28 DECLARE_PTR_LIST(parent_list
, struct parent
);
29 static struct parent_list
*parents
;
31 static const char *allocation_funcs
[] = {
37 static void add_parent_to_parents(char *name
, struct symbol
*sym
)
41 FOR_EACH_PTR(parents
, tmp
) {
42 if (tmp
->sym
== sym
) {
43 add_tracker(&tmp
->children
, name
, my_id
, sym
);
46 } END_FOR_EACH_PTR(tmp
);
48 tmp
= __alloc_parent(0);
51 add_tracker(&tmp
->children
, name
, my_id
, sym
);
52 add_ptr_list(&parents
, tmp
);
55 static void set_list_assigned(struct tracker_list
*children
)
57 struct tracker
*child
;
59 FOR_EACH_PTR(children
, child
) {
60 set_state(child
->name
, my_id
, child
->sym
, &assigned
);
61 } END_FOR_EACH_PTR(child
);
64 static struct tracker_list
*get_children(struct symbol
*sym
)
68 FOR_EACH_PTR(parents
, tmp
) {
69 if (tmp
->sym
== sym
) {
72 } END_FOR_EACH_PTR(tmp
);
76 static void set_children_assigned(struct symbol
*sym
)
78 struct tracker_list
*children
;
80 if ((children
= get_children(sym
))) {
81 set_list_assigned(children
);
85 static int is_allocation(struct expression
*expr
)
90 if (expr
->type
!= EXPR_CALL
)
93 if (!(fn_name
= get_variable_from_expr(expr
->fn
, NULL
)))
96 for (i
= 0; allocation_funcs
[i
]; i
++) {
97 if (!strcmp(fn_name
, allocation_funcs
[i
])) {
102 free_string(fn_name
);
106 static int is_freed(const char *name
, struct symbol
*sym
)
108 struct state_list
*slist
;
110 slist
= get_possible_states(name
, my_id
, sym
);
111 if (slist_has_state(slist
, &isfree
)) {
117 static void match_assign(struct expression
*expr
)
119 struct expression
*left
, *right
;
120 char *left_name
, *right_name
;
121 struct symbol
*left_sym
, *right_sym
;
122 struct smatch_state
*state
;
124 left
= strip_expr(expr
->left
);
125 left_name
= get_variable_from_expr(left
, &left_sym
);
129 free_string(left_name
);
133 right
= strip_expr(expr
->right
);
134 if (is_allocation(right
) && !(left_sym
->ctype
.modifiers
&
135 (MOD_NONLOCAL
| MOD_STATIC
| MOD_ADDRESSABLE
))) {
136 set_state(left_name
, my_id
, left_sym
, &allocated
);
137 add_parent_to_parents(left_name
, left_sym
);
138 free_string(left_name
);
142 right_name
= get_variable_from_expr(right
, &right_sym
);
143 if (right_name
&& (state
= get_state(right_name
, my_id
, right_sym
))) {
144 if (state
== &isfree
)
145 smatch_msg("assigning freed pointer");
146 set_state(right_name
, my_id
, right_sym
, &assigned
);
148 free_string(right_name
);
150 if (is_freed(left_name
, left_sym
)) {
151 set_state(left_name
, my_id
, left_sym
, &unfree
);
153 free_string(left_name
);
156 static int is_null(char *name
, struct symbol
*sym
)
158 struct smatch_state
*state
;
161 * FIXME. Ha ha ha... This is so wrong.
162 * I'm pulling in data from the check_null_deref script.
163 * I just happen to know that its ID is 3.
164 * The correct approved way to do this is to get the data from
165 * smatch_extra. But right now smatch_extra doesn't track it.
167 state
= get_state(name
, 3, sym
);
168 if (state
&& !strcmp(state
->name
, "isnull"))
173 static void match_kfree(struct expression
*expr
)
175 struct expression
*ptr_expr
;
177 struct symbol
*ptr_sym
;
179 ptr_expr
= get_argument_from_call_expr(expr
->args
, 0);
180 ptr_name
= get_variable_from_expr(ptr_expr
, &ptr_sym
);
181 if (is_freed(ptr_name
, ptr_sym
) && !is_null(ptr_name
, ptr_sym
)) {
182 smatch_msg("double free of %s", ptr_name
);
184 set_state(ptr_name
, my_id
, ptr_sym
, &isfree
);
185 free_string(ptr_name
);
188 static int possibly_allocated(struct state_list
*slist
)
190 struct sm_state
*tmp
;
192 FOR_EACH_PTR(slist
, tmp
) {
193 if (tmp
->state
== &allocated
)
195 } END_FOR_EACH_PTR(tmp
);
199 static void check_for_allocated()
201 struct state_list
*slist
;
202 struct sm_state
*tmp
;
206 slist
= get_all_states(my_id
);
207 FOR_EACH_PTR(slist
, tmp
) {
208 if (possibly_allocated(tmp
->possible
) &&
209 !is_null(tmp
->name
, tmp
->sym
))
210 smatch_msg("possible memery leak of %s", tmp
->name
);
211 } END_FOR_EACH_PTR(tmp
);
215 static void match_return(struct statement
*stmt
)
219 struct smatch_state
*state
;
221 name
= get_variable_from_expr(stmt
->ret_value
, &sym
);
222 if ((state
= get_state(name
, my_id
, sym
))) {
223 set_state(name
, my_id
, sym
, &assigned
);
226 check_for_allocated();
229 static void match_function_call(struct expression
*expr
)
231 struct expression
*tmp
;
235 struct smatch_state
*state
;
237 fn_name
= get_variable_from_expr(expr
->fn
, NULL
);
239 if (!strcmp(fn_name
, "kfree")) {
243 FOR_EACH_PTR(expr
->args
, tmp
) {
244 tmp
= strip_expr(tmp
);
245 name
= get_variable_from_expr(tmp
, &sym
);
248 if ((state
= get_state(name
, my_id
, sym
))) {
249 if (state
== &allocated
) {
250 set_state(name
, my_id
, sym
, &assigned
);
253 set_children_assigned(sym
);
254 /* get parent. set children to assigned */
255 } END_FOR_EACH_PTR(tmp
);
258 static void free_the_parents()
262 FOR_EACH_PTR(parents
, tmp
) {
263 free_trackers_and_list(&tmp
->children
);
264 } END_FOR_EACH_PTR(tmp
);
265 __free_ptr_list((struct ptr_list
**)&parents
);
268 static void match_end_func(struct symbol
*sym
)
270 check_for_allocated();
274 void register_memory(int id
)
277 add_hook(&match_function_call
, FUNCTION_CALL_HOOK
);
278 add_hook(&match_assign
, ASSIGNMENT_HOOK
);
279 add_hook(&match_return
, RETURN_HOOK
);
280 add_hook(&match_end_func
, END_FUNC_HOOK
);