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 static const char *allocation_funcs
[] = {
39 static struct smatch_state
*merge_func(const char *name
, struct symbol
*sym
,
40 struct smatch_state
*s1
,
41 struct smatch_state
*s2
)
43 if (!strcmp(name
, "-"))
45 /* this is normal merge */
51 static void assign_parent(struct symbol
*sym
)
53 set_state("-", my_id
, sym
, &assigned
);
56 static int parent_is_assigned(struct symbol
*sym
)
58 struct smatch_state
*state
;
60 state
= get_state("-", my_id
, sym
);
61 if (state
== &assigned
)
66 static int is_allocation(struct expression
*expr
)
71 if (expr
->type
!= EXPR_CALL
)
74 if (!(fn_name
= get_variable_from_expr(expr
->fn
, NULL
)))
77 for (i
= 0; allocation_funcs
[i
]; i
++) {
78 if (!strcmp(fn_name
, allocation_funcs
[i
])) {
87 static int is_freed(const char *name
, struct symbol
*sym
)
89 struct state_list
*slist
;
91 slist
= get_possible_states(name
, my_id
, sym
);
92 if (slist_has_state(slist
, &isfree
)) {
98 static int is_argument(struct symbol
*sym
)
102 FOR_EACH_PTR(arguments
, arg
) {
105 } END_FOR_EACH_PTR(arg
);
109 static void match_function_def(struct symbol
*sym
)
113 FOR_EACH_PTR(sym
->ctype
.base_type
->arguments
, arg
) {
114 add_tracker(&arguments
, (arg
->ident
?arg
->ident
->name
:"NULL"), my_id
, arg
);
115 } END_FOR_EACH_PTR(arg
);
118 static void match_declarations(struct symbol
*sym
)
122 if ((get_base_type(sym
))->type
== SYM_ARRAY
) {
126 name
= sym
->ident
->name
;
128 if (sym
->initializer
) {
129 if (is_allocation(sym
->initializer
)) {
130 set_state(name
, my_id
, sym
, &malloced
);
137 static int is_parent(struct expression
*expr
)
139 if (expr
->type
== EXPR_DEREF
)
144 static int assign_seen
;
145 static int handle_double_assign(struct expression
*expr
)
150 if (expr
->right
->type
!= EXPR_ASSIGNMENT
)
154 name
= get_variable_from_expr(expr
->left
, &sym
);
155 if (name
&& is_parent(expr
->left
))
158 name
= get_variable_from_expr(expr
->right
->left
, &sym
);
159 if (name
&& is_parent(expr
->right
->left
))
162 name
= get_variable_from_expr(expr
->right
->right
, &sym
);
163 if (name
&& is_parent(expr
->right
->right
))
169 static void match_assign(struct expression
*expr
)
171 struct expression
*left
, *right
;
172 char *left_name
= NULL
;
173 char *right_name
= NULL
;
174 struct symbol
*left_sym
, *right_sym
;
175 struct smatch_state
*state
;
182 if (handle_double_assign(expr
)) {
186 left
= strip_expr(expr
->left
);
187 left_name
= get_variable_from_expr_complex(left
, &left_sym
);
189 right
= strip_expr(expr
->right
);
190 if (left_name
&& left_sym
&& is_allocation(right
) &&
191 !(left_sym
->ctype
.modifiers
&
192 (MOD_NONLOCAL
| MOD_STATIC
| MOD_ADDRESSABLE
)) &&
193 !parent_is_assigned(left_sym
)) {
194 set_state(left_name
, my_id
, left_sym
, &malloced
);
198 right_name
= get_variable_from_expr_complex(right
, &right_sym
);
200 if (right_name
&& (state
= get_state(right_name
, my_id
, right_sym
))) {
201 if (state
== &isfree
)
202 smatch_msg("error: assigning freed pointer");
203 set_state(right_name
, my_id
, right_sym
, &assigned
);
206 if (is_freed(left_name
, left_sym
)) {
207 set_state(left_name
, my_id
, left_sym
, &unfree
);
209 if (left_name
&& is_parent(left
))
210 assign_parent(left_sym
);
211 if (right_name
&& is_parent(right
))
212 assign_parent(right_sym
);
214 free_string(left_name
);
215 free_string(right_name
);
218 static int is_null(char *name
, struct symbol
*sym
)
220 struct smatch_state
*state
;
223 * FIXME. Ha ha ha... This is so wrong.
224 * I'm pulling in data from the check_null_deref script.
225 * I just happen to know that its ID is 3.
226 * The correct approved way to do this is to get the data from
227 * smatch_extra. But right now smatch_extra doesn't track it.
229 state
= get_state(name
, my_id
, sym
);
230 if (state
&& !strcmp(state
->name
, "isnull"))
235 static void match_kfree(struct expression
*expr
)
237 struct expression
*ptr_expr
;
239 struct symbol
*ptr_sym
;
241 ptr_expr
= get_argument_from_call_expr(expr
->args
, 0);
242 ptr_name
= get_variable_from_expr(ptr_expr
, &ptr_sym
);
243 if (is_freed(ptr_name
, ptr_sym
) && !is_null(ptr_name
, ptr_sym
)) {
244 smatch_msg("error: double free of %s", ptr_name
);
246 set_state(ptr_name
, my_id
, ptr_sym
, &isfree
);
247 free_string(ptr_name
);
250 static int possibly_allocated(struct state_list
*slist
)
252 struct sm_state
*tmp
;
254 FOR_EACH_PTR(slist
, tmp
) {
255 if (tmp
->state
== &allocated
)
257 if (tmp
->state
== &malloced
)
259 } END_FOR_EACH_PTR(tmp
);
263 static void check_for_allocated()
265 struct state_list
*slist
;
266 struct sm_state
*tmp
;
268 slist
= get_all_states(my_id
);
269 FOR_EACH_PTR(slist
, tmp
) {
270 if (possibly_allocated(tmp
->possible
) &&
271 !is_null(tmp
->name
, tmp
->sym
) &&
272 !is_argument(tmp
->sym
) &&
273 !parent_is_assigned(tmp
->sym
))
274 smatch_msg("error: memery leak of %s", tmp
->name
);
275 } END_FOR_EACH_PTR(tmp
);
279 static void match_return(struct statement
*stmt
)
284 name
= get_variable_from_expr(stmt
->ret_value
, &sym
);
288 check_for_allocated();
291 static void set_new_true_false_paths(const char *name
, struct symbol
*sym
)
293 struct smatch_state
*tmp
;
295 tmp
= get_state(name
, my_id
, sym
);
301 if (tmp
== &isfree
) {
302 smatch_msg("warn: why do you care about freed memory?");
305 if (tmp
== &assigned
) {
306 /* we don't care about assigned pointers any more */
309 set_true_false_states(name
, my_id
, sym
, &allocated
, &isnull
);
312 static void match_condition(struct expression
*expr
)
317 expr
= strip_expr(expr
);
322 name
= get_variable_from_expr(expr
, &sym
);
325 set_new_true_false_paths(name
, sym
);
328 case EXPR_ASSIGNMENT
:
330 /* You have to deal with stuff like if (a = b = c) */
331 match_condition(expr
->right
);
332 match_condition(expr
->left
);
339 static void match_function_call(struct expression
*expr
)
341 struct expression
*tmp
;
345 struct sm_state
*state
;
347 fn_name
= get_variable_from_expr(expr
->fn
, NULL
);
349 if (fn_name
&& !strcmp(fn_name
, "kfree")) {
353 FOR_EACH_PTR(expr
->args
, tmp
) {
354 tmp
= strip_expr(tmp
);
355 name
= get_variable_from_expr(tmp
, &sym
);
358 if ((state
= get_sm_state(name
, my_id
, sym
))) {
359 if (possibly_allocated(state
->possible
)) {
360 set_state(name
, my_id
, sym
, &assigned
);
364 } END_FOR_EACH_PTR(tmp
);
367 static void match_end_func(struct symbol
*sym
)
369 check_for_allocated();
370 free_trackers_and_list(&arguments
);
373 void register_memory(int id
)
376 add_merge_hook(my_id
, &merge_func
);
377 add_hook(&match_function_def
, FUNC_DEF_HOOK
);
378 add_hook(&match_declarations
, DECLARATION_HOOK
);
379 add_hook(&match_function_call
, FUNCTION_CALL_HOOK
);
380 add_hook(&match_condition
, CONDITION_HOOK
);
381 add_hook(&match_assign
, ASSIGNMENT_HOOK
);
382 add_hook(&match_return
, RETURN_HOOK
);
383 add_hook(&match_end_func
, END_FUNC_HOOK
);