2 * sparse/check_memory.c
4 * Copyright (C) 2008 Dan Carpenter.
6 * Licensed under the Open Software License version 1.1
14 #include "smatch_slist.h"
26 malloced --> allocated --> assigned --> isfree +
27 \-> isnull. \-> isfree +
33 static struct tracker_list
*arguments
;
35 static const char *allocation_funcs
[] = {
42 static struct smatch_state
*unmatched_state(struct sm_state
*sm
)
44 if (!strcmp(sm
->name
, "-"))
49 static void assign_parent(struct symbol
*sym
)
51 set_state("-", my_id
, sym
, &assigned
);
54 static int parent_is_assigned(struct symbol
*sym
)
56 struct smatch_state
*state
;
58 state
= get_state("-", my_id
, sym
);
59 if (state
== &assigned
)
64 static int is_allocation(struct expression
*expr
)
69 if (expr
->type
!= EXPR_CALL
)
72 if (!(fn_name
= get_variable_from_expr(expr
->fn
, NULL
)))
75 for (i
= 0; allocation_funcs
[i
]; i
++) {
76 if (!strcmp(fn_name
, allocation_funcs
[i
])) {
85 static int is_freed(const char *name
, struct symbol
*sym
)
87 struct state_list
*slist
;
89 slist
= get_possible_states(name
, my_id
, sym
);
90 if (slist_has_state(slist
, &isfree
)) {
96 static int is_argument(struct symbol
*sym
)
100 FOR_EACH_PTR(arguments
, arg
) {
103 } END_FOR_EACH_PTR(arg
);
107 static void match_function_def(struct symbol
*sym
)
111 FOR_EACH_PTR(sym
->ctype
.base_type
->arguments
, arg
) {
112 add_tracker(&arguments
, (arg
->ident
?arg
->ident
->name
:"NULL"), my_id
, arg
);
113 } END_FOR_EACH_PTR(arg
);
116 static void match_declarations(struct symbol
*sym
)
120 if ((get_base_type(sym
))->type
== SYM_ARRAY
) {
124 name
= sym
->ident
->name
;
126 if (sym
->initializer
) {
127 if (is_allocation(sym
->initializer
)) {
128 set_state(name
, my_id
, sym
, &malloced
);
135 static int is_parent(struct expression
*expr
)
137 if (expr
->type
== EXPR_DEREF
)
142 static int assign_seen
;
143 static int handle_double_assign(struct expression
*expr
)
148 if (expr
->right
->type
!= EXPR_ASSIGNMENT
)
152 name
= get_variable_from_expr_complex(expr
->left
, &sym
);
153 if (name
&& is_parent(expr
->left
))
156 name
= get_variable_from_expr_complex(expr
->right
->left
, &sym
);
157 if (name
&& is_parent(expr
->right
->left
))
160 name
= get_variable_from_expr_complex(expr
->right
->right
, &sym
);
161 if (name
&& is_parent(expr
->right
->right
))
167 static void match_assign(struct expression
*expr
)
169 struct expression
*left
, *right
;
170 char *left_name
= NULL
;
171 char *right_name
= NULL
;
172 struct symbol
*left_sym
, *right_sym
;
173 struct smatch_state
*state
;
180 if (handle_double_assign(expr
)) {
184 left
= strip_expr(expr
->left
);
185 left_name
= get_variable_from_expr_complex(left
, &left_sym
);
187 right
= strip_expr(expr
->right
);
188 if (left_name
&& left_sym
&& is_allocation(right
) &&
189 !(left_sym
->ctype
.modifiers
&
190 (MOD_NONLOCAL
| MOD_STATIC
| MOD_ADDRESSABLE
)) &&
191 !parent_is_assigned(left_sym
)) {
192 set_state(left_name
, my_id
, left_sym
, &malloced
);
196 right_name
= get_variable_from_expr_complex(right
, &right_sym
);
198 if (right_name
&& (state
= get_state(right_name
, my_id
, right_sym
))) {
199 if (state
== &isfree
)
200 smatch_msg("error: assigning freed pointer");
201 set_state(right_name
, my_id
, right_sym
, &assigned
);
204 if (is_freed(left_name
, left_sym
)) {
205 set_state(left_name
, my_id
, left_sym
, &unfree
);
207 if (left_name
&& is_parent(left
))
208 assign_parent(left_sym
);
209 if (right_name
&& is_parent(right
))
210 assign_parent(right_sym
);
212 free_string(left_name
);
213 free_string(right_name
);
216 static int is_null(char *name
, struct symbol
*sym
)
218 struct smatch_state
*state
;
220 state
= get_state(name
, my_id
, sym
);
221 if (state
&& !strcmp(state
->name
, "isnull"))
226 static void match_free_func(struct expression
*expr
, void *data
)
228 struct expression
*ptr_expr
;
230 struct symbol
*ptr_sym
;
231 int arg_num
= (int)data
;
233 ptr_expr
= get_argument_from_call_expr(expr
->args
, arg_num
);
234 ptr_name
= get_variable_from_expr_complex(ptr_expr
, &ptr_sym
);
235 if (is_freed(ptr_name
, ptr_sym
) && !is_null(ptr_name
, ptr_sym
)) {
236 smatch_msg("error: double free of %s", ptr_name
);
238 set_state(ptr_name
, my_id
, ptr_sym
, &isfree
);
239 free_string(ptr_name
);
242 static int possibly_allocated(struct state_list
*slist
)
244 struct sm_state
*tmp
;
246 FOR_EACH_PTR(slist
, tmp
) {
247 if (tmp
->state
== &allocated
)
249 if (tmp
->state
== &malloced
)
251 } END_FOR_EACH_PTR(tmp
);
255 static void check_for_allocated(void)
257 struct state_list
*slist
;
258 struct sm_state
*tmp
;
260 slist
= get_all_states(my_id
);
261 FOR_EACH_PTR(slist
, tmp
) {
262 if (possibly_allocated(tmp
->possible
) &&
263 !is_null(tmp
->name
, tmp
->sym
) &&
264 !is_argument(tmp
->sym
) &&
265 !parent_is_assigned(tmp
->sym
))
266 smatch_msg("error: memery leak of %s", tmp
->name
);
267 } END_FOR_EACH_PTR(tmp
);
271 static void match_return(struct statement
*stmt
)
276 name
= get_variable_from_expr_complex(stmt
->ret_value
, &sym
);
280 check_for_allocated();
283 static void set_new_true_false_paths(const char *name
, struct symbol
*sym
)
285 struct smatch_state
*tmp
;
287 tmp
= get_state(name
, my_id
, sym
);
293 if (tmp
== &isfree
) {
294 smatch_msg("warn: why do you care about freed memory?");
297 if (tmp
== &assigned
) {
298 /* we don't care about assigned pointers any more */
301 set_true_false_states(name
, my_id
, sym
, &allocated
, &isnull
);
304 static void match_condition(struct expression
*expr
)
309 expr
= strip_expr(expr
);
314 name
= get_variable_from_expr_complex(expr
, &sym
);
317 set_new_true_false_paths(name
, sym
);
320 case EXPR_ASSIGNMENT
:
322 /* You have to deal with stuff like if (a = b = c) */
323 match_condition(expr
->right
);
324 match_condition(expr
->left
);
331 static void match_function_call(struct expression
*expr
)
333 struct expression
*tmp
;
337 struct sm_state
*state
;
339 fn_name
= get_variable_from_expr(expr
->fn
, NULL
);
341 FOR_EACH_PTR(expr
->args
, tmp
) {
342 tmp
= strip_expr(tmp
);
343 name
= get_variable_from_expr_complex(tmp
, &sym
);
346 if ((state
= get_sm_state(name
, my_id
, sym
))) {
347 if (possibly_allocated(state
->possible
)) {
348 set_state(name
, my_id
, sym
, &assigned
);
352 } END_FOR_EACH_PTR(tmp
);
355 static void match_dereferences(struct expression
*expr
)
358 struct symbol
*sym
= NULL
;
360 deref
= get_variable_from_expr(expr
->deref
->unop
, &sym
);
363 if (is_freed(deref
, sym
)) {
364 smatch_msg("error: dereferencing freed memory '%s'\n", deref
);
365 set_state(deref
, my_id
, sym
, &unfree
);
370 static void match_end_func(struct symbol
*sym
)
372 check_for_allocated();
373 free_trackers_and_list(&arguments
);
376 static void register_funcs_from_file(void)
378 const char *filename
= "frees";
384 fd
= open(filename
, O_RDONLY
);
387 token
= tokenize(filename
, fd
, NULL
, NULL
);
389 if (token_type(token
) != TOKEN_STREAMBEGIN
)
392 while (token_type(token
) != TOKEN_STREAMEND
) {
393 if (token_type(token
) != TOKEN_IDENT
)
395 func
= show_ident(token
->ident
);
397 if (token_type(token
) != TOKEN_NUMBER
)
399 arg
= atoi(token
->number
);
400 add_function_hook(func
, &match_free_func
, (void *)arg
);
406 void check_memory(int id
)
409 add_unmatched_state_hook(my_id
, &unmatched_state
);
410 add_hook(&match_function_def
, FUNC_DEF_HOOK
);
411 add_hook(&match_declarations
, DECLARATION_HOOK
);
412 add_hook(&match_function_call
, FUNCTION_CALL_HOOK
);
413 add_hook(&match_condition
, CONDITION_HOOK
);
414 add_hook(&match_dereferences
, DEREF_HOOK
);
415 add_hook(&match_assign
, ASSIGNMENT_HOOK
);
416 add_hook(&match_return
, RETURN_HOOK
);
417 add_hook(&match_end_func
, END_FUNC_HOOK
);
418 add_function_hook("kfree", &match_free_func
, (void *)0);
419 register_funcs_from_file();