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 static struct tracker_list
*arguments
;
33 static const char *allocation_funcs
[] = {
40 static struct smatch_state
*merge_func(const char *name
, struct symbol
*sym
,
41 struct smatch_state
*s1
,
42 struct smatch_state
*s2
)
44 if (!strcmp(name
, "-"))
46 /* this is normal merge */
52 static void assign_parent(struct symbol
*sym
)
54 set_state("-", my_id
, sym
, &assigned
);
57 static int parent_is_assigned(struct symbol
*sym
)
59 struct smatch_state
*state
;
61 state
= get_state("-", my_id
, sym
);
62 if (state
== &assigned
)
67 static int is_allocation(struct expression
*expr
)
72 if (expr
->type
!= EXPR_CALL
)
75 if (!(fn_name
= get_variable_from_expr(expr
->fn
, NULL
)))
78 for (i
= 0; allocation_funcs
[i
]; i
++) {
79 if (!strcmp(fn_name
, allocation_funcs
[i
])) {
88 static int is_freed(const char *name
, struct symbol
*sym
)
90 struct state_list
*slist
;
92 slist
= get_possible_states(name
, my_id
, sym
);
93 if (slist_has_state(slist
, &isfree
)) {
99 static int is_argument(struct symbol
*sym
)
103 FOR_EACH_PTR(arguments
, arg
) {
106 } END_FOR_EACH_PTR(arg
);
110 static void match_function_def(struct symbol
*sym
)
114 FOR_EACH_PTR(sym
->ctype
.base_type
->arguments
, arg
) {
115 add_tracker(&arguments
, (arg
->ident
?arg
->ident
->name
:"NULL"), my_id
, arg
);
116 } END_FOR_EACH_PTR(arg
);
119 static void match_declarations(struct symbol
*sym
)
123 if ((get_base_type(sym
))->type
== SYM_ARRAY
) {
127 name
= sym
->ident
->name
;
129 if (sym
->initializer
) {
130 if (is_allocation(sym
->initializer
)) {
131 set_state(name
, my_id
, sym
, &malloced
);
138 static int is_parent(struct expression
*expr
)
140 if (expr
->type
== EXPR_DEREF
)
145 static int assign_seen
;
146 static int handle_double_assign(struct expression
*expr
)
151 if (expr
->right
->type
!= EXPR_ASSIGNMENT
)
155 name
= get_variable_from_expr_complex(expr
->left
, &sym
);
156 if (name
&& is_parent(expr
->left
))
159 name
= get_variable_from_expr_complex(expr
->right
->left
, &sym
);
160 if (name
&& is_parent(expr
->right
->left
))
163 name
= get_variable_from_expr_complex(expr
->right
->right
, &sym
);
164 if (name
&& is_parent(expr
->right
->right
))
170 static void match_assign(struct expression
*expr
)
172 struct expression
*left
, *right
;
173 char *left_name
= NULL
;
174 char *right_name
= NULL
;
175 struct symbol
*left_sym
, *right_sym
;
176 struct smatch_state
*state
;
183 if (handle_double_assign(expr
)) {
187 left
= strip_expr(expr
->left
);
188 left_name
= get_variable_from_expr_complex(left
, &left_sym
);
190 right
= strip_expr(expr
->right
);
191 if (left_name
&& left_sym
&& is_allocation(right
) &&
192 !(left_sym
->ctype
.modifiers
&
193 (MOD_NONLOCAL
| MOD_STATIC
| MOD_ADDRESSABLE
)) &&
194 !parent_is_assigned(left_sym
)) {
195 set_state(left_name
, my_id
, left_sym
, &malloced
);
199 right_name
= get_variable_from_expr_complex(right
, &right_sym
);
201 if (right_name
&& (state
= get_state(right_name
, my_id
, right_sym
))) {
202 if (state
== &isfree
)
203 smatch_msg("error: assigning freed pointer");
204 set_state(right_name
, my_id
, right_sym
, &assigned
);
207 if (is_freed(left_name
, left_sym
)) {
208 set_state(left_name
, my_id
, left_sym
, &unfree
);
210 if (left_name
&& is_parent(left
))
211 assign_parent(left_sym
);
212 if (right_name
&& is_parent(right
))
213 assign_parent(right_sym
);
215 free_string(left_name
);
216 free_string(right_name
);
219 static int is_null(char *name
, struct symbol
*sym
)
221 struct smatch_state
*state
;
224 * FIXME. Ha ha ha... This is so wrong.
225 * I'm pulling in data from the check_null_deref script.
226 * I just happen to know that its ID is 3.
227 * The correct approved way to do this is to get the data from
228 * smatch_extra. But right now smatch_extra doesn't track it.
230 state
= get_state(name
, my_id
, sym
);
231 if (state
&& !strcmp(state
->name
, "isnull"))
236 static void match_kfree(struct expression
*expr
)
238 struct expression
*ptr_expr
;
240 struct symbol
*ptr_sym
;
242 ptr_expr
= get_argument_from_call_expr(expr
->args
, 0);
243 ptr_name
= get_variable_from_expr_complex(ptr_expr
, &ptr_sym
);
244 if (is_freed(ptr_name
, ptr_sym
) && !is_null(ptr_name
, ptr_sym
)) {
245 smatch_msg("error: double free of %s", ptr_name
);
247 set_state(ptr_name
, my_id
, ptr_sym
, &isfree
);
248 free_string(ptr_name
);
251 static int possibly_allocated(struct state_list
*slist
)
253 struct sm_state
*tmp
;
255 FOR_EACH_PTR(slist
, tmp
) {
256 if (tmp
->state
== &allocated
)
258 if (tmp
->state
== &malloced
)
260 } END_FOR_EACH_PTR(tmp
);
264 static void check_for_allocated()
266 struct state_list
*slist
;
267 struct sm_state
*tmp
;
269 slist
= get_all_states(my_id
);
270 FOR_EACH_PTR(slist
, tmp
) {
271 if (possibly_allocated(tmp
->possible
) &&
272 !is_null(tmp
->name
, tmp
->sym
) &&
273 !is_argument(tmp
->sym
) &&
274 !parent_is_assigned(tmp
->sym
))
275 smatch_msg("error: memery leak of %s", tmp
->name
);
276 } END_FOR_EACH_PTR(tmp
);
280 static void match_return(struct statement
*stmt
)
285 name
= get_variable_from_expr_complex(stmt
->ret_value
, &sym
);
289 check_for_allocated();
292 static void set_new_true_false_paths(const char *name
, struct symbol
*sym
)
294 struct smatch_state
*tmp
;
296 tmp
= get_state(name
, my_id
, sym
);
302 if (tmp
== &isfree
) {
303 smatch_msg("warn: why do you care about freed memory?");
306 if (tmp
== &assigned
) {
307 /* we don't care about assigned pointers any more */
310 set_true_false_states(name
, my_id
, sym
, &allocated
, &isnull
);
313 static void match_condition(struct expression
*expr
)
318 expr
= strip_expr(expr
);
323 name
= get_variable_from_expr_complex(expr
, &sym
);
326 set_new_true_false_paths(name
, sym
);
329 case EXPR_ASSIGNMENT
:
331 /* You have to deal with stuff like if (a = b = c) */
332 match_condition(expr
->right
);
333 match_condition(expr
->left
);
340 static void match_function_call(struct expression
*expr
)
342 struct expression
*tmp
;
346 struct sm_state
*state
;
348 fn_name
= get_variable_from_expr(expr
->fn
, NULL
);
350 if (fn_name
&& !strcmp(fn_name
, "kfree")) {
354 FOR_EACH_PTR(expr
->args
, tmp
) {
355 tmp
= strip_expr(tmp
);
356 name
= get_variable_from_expr_complex(tmp
, &sym
);
359 if ((state
= get_sm_state(name
, my_id
, sym
))) {
360 if (possibly_allocated(state
->possible
)) {
361 set_state(name
, my_id
, sym
, &assigned
);
365 } END_FOR_EACH_PTR(tmp
);
368 static void match_end_func(struct symbol
*sym
)
370 check_for_allocated();
371 free_trackers_and_list(&arguments
);
374 void check_memory(int id
)
377 add_merge_hook(my_id
, &merge_func
);
378 add_hook(&match_function_def
, FUNC_DEF_HOOK
);
379 add_hook(&match_declarations
, DECLARATION_HOOK
);
380 add_hook(&match_function_call
, FUNCTION_CALL_HOOK
);
381 add_hook(&match_condition
, CONDITION_HOOK
);
382 add_hook(&match_assign
, ASSIGNMENT_HOOK
);
383 add_hook(&match_return
, RETURN_HOOK
);
384 add_hook(&match_end_func
, END_FUNC_HOOK
);