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
*unmatched_state(struct sm_state
*sm
)
42 if (!strcmp(sm
->name
, "-"))
47 static void assign_parent(struct symbol
*sym
)
49 set_state("-", my_id
, sym
, &assigned
);
52 static int parent_is_assigned(struct symbol
*sym
)
54 struct smatch_state
*state
;
56 state
= get_state("-", my_id
, sym
);
57 if (state
== &assigned
)
62 static int is_allocation(struct expression
*expr
)
67 if (expr
->type
!= EXPR_CALL
)
70 if (!(fn_name
= get_variable_from_expr(expr
->fn
, NULL
)))
73 for (i
= 0; allocation_funcs
[i
]; i
++) {
74 if (!strcmp(fn_name
, allocation_funcs
[i
])) {
83 static int is_freed(const char *name
, struct symbol
*sym
)
85 struct state_list
*slist
;
87 slist
= get_possible_states(name
, my_id
, sym
);
88 if (slist_has_state(slist
, &isfree
)) {
94 static int is_argument(struct symbol
*sym
)
98 FOR_EACH_PTR(arguments
, arg
) {
101 } END_FOR_EACH_PTR(arg
);
105 static void match_function_def(struct symbol
*sym
)
109 FOR_EACH_PTR(sym
->ctype
.base_type
->arguments
, arg
) {
110 add_tracker(&arguments
, (arg
->ident
?arg
->ident
->name
:"NULL"), my_id
, arg
);
111 } END_FOR_EACH_PTR(arg
);
114 static void match_declarations(struct symbol
*sym
)
118 if ((get_base_type(sym
))->type
== SYM_ARRAY
) {
122 name
= sym
->ident
->name
;
124 if (sym
->initializer
) {
125 if (is_allocation(sym
->initializer
)) {
126 set_state(name
, my_id
, sym
, &malloced
);
133 static int is_parent(struct expression
*expr
)
135 if (expr
->type
== EXPR_DEREF
)
140 static int assign_seen
;
141 static int handle_double_assign(struct expression
*expr
)
146 if (expr
->right
->type
!= EXPR_ASSIGNMENT
)
150 name
= get_variable_from_expr_complex(expr
->left
, &sym
);
151 if (name
&& is_parent(expr
->left
))
154 name
= get_variable_from_expr_complex(expr
->right
->left
, &sym
);
155 if (name
&& is_parent(expr
->right
->left
))
158 name
= get_variable_from_expr_complex(expr
->right
->right
, &sym
);
159 if (name
&& is_parent(expr
->right
->right
))
165 static void match_assign(struct expression
*expr
)
167 struct expression
*left
, *right
;
168 char *left_name
= NULL
;
169 char *right_name
= NULL
;
170 struct symbol
*left_sym
, *right_sym
;
171 struct smatch_state
*state
;
178 if (handle_double_assign(expr
)) {
182 left
= strip_expr(expr
->left
);
183 left_name
= get_variable_from_expr_complex(left
, &left_sym
);
185 right
= strip_expr(expr
->right
);
186 if (left_name
&& left_sym
&& is_allocation(right
) &&
187 !(left_sym
->ctype
.modifiers
&
188 (MOD_NONLOCAL
| MOD_STATIC
| MOD_ADDRESSABLE
)) &&
189 !parent_is_assigned(left_sym
)) {
190 set_state(left_name
, my_id
, left_sym
, &malloced
);
194 right_name
= get_variable_from_expr_complex(right
, &right_sym
);
196 if (right_name
&& (state
= get_state(right_name
, my_id
, right_sym
))) {
197 if (state
== &isfree
)
198 smatch_msg("error: assigning freed pointer");
199 set_state(right_name
, my_id
, right_sym
, &assigned
);
202 if (is_freed(left_name
, left_sym
)) {
203 set_state(left_name
, my_id
, left_sym
, &unfree
);
205 if (left_name
&& is_parent(left
))
206 assign_parent(left_sym
);
207 if (right_name
&& is_parent(right
))
208 assign_parent(right_sym
);
210 free_string(left_name
);
211 free_string(right_name
);
214 static int is_null(char *name
, struct symbol
*sym
)
216 struct smatch_state
*state
;
219 * FIXME. Ha ha ha... This is so wrong.
220 * I'm pulling in data from the check_null_deref script.
221 * I just happen to know that its ID is 3.
222 * The correct approved way to do this is to get the data from
223 * smatch_extra. But right now smatch_extra doesn't track it.
225 state
= get_state(name
, my_id
, sym
);
226 if (state
&& !strcmp(state
->name
, "isnull"))
231 static void match_kfree(struct expression
*expr
)
233 struct expression
*ptr_expr
;
235 struct symbol
*ptr_sym
;
237 ptr_expr
= get_argument_from_call_expr(expr
->args
, 0);
238 ptr_name
= get_variable_from_expr_complex(ptr_expr
, &ptr_sym
);
239 if (is_freed(ptr_name
, ptr_sym
) && !is_null(ptr_name
, ptr_sym
)) {
240 smatch_msg("error: double free of %s", ptr_name
);
242 set_state(ptr_name
, my_id
, ptr_sym
, &isfree
);
243 free_string(ptr_name
);
246 static int possibly_allocated(struct state_list
*slist
)
248 struct sm_state
*tmp
;
250 FOR_EACH_PTR(slist
, tmp
) {
251 if (tmp
->state
== &allocated
)
253 if (tmp
->state
== &malloced
)
255 } END_FOR_EACH_PTR(tmp
);
259 static void check_for_allocated(void)
261 struct state_list
*slist
;
262 struct sm_state
*tmp
;
264 slist
= get_all_states(my_id
);
265 FOR_EACH_PTR(slist
, tmp
) {
266 if (possibly_allocated(tmp
->possible
) &&
267 !is_null(tmp
->name
, tmp
->sym
) &&
268 !is_argument(tmp
->sym
) &&
269 !parent_is_assigned(tmp
->sym
))
270 smatch_msg("error: memery leak of %s", tmp
->name
);
271 } END_FOR_EACH_PTR(tmp
);
275 static void match_return(struct statement
*stmt
)
280 name
= get_variable_from_expr_complex(stmt
->ret_value
, &sym
);
284 check_for_allocated();
287 static void set_new_true_false_paths(const char *name
, struct symbol
*sym
)
289 struct smatch_state
*tmp
;
291 tmp
= get_state(name
, my_id
, sym
);
297 if (tmp
== &isfree
) {
298 smatch_msg("warn: why do you care about freed memory?");
301 if (tmp
== &assigned
) {
302 /* we don't care about assigned pointers any more */
305 set_true_false_states(name
, my_id
, sym
, &allocated
, &isnull
);
308 static void match_condition(struct expression
*expr
)
313 expr
= strip_expr(expr
);
318 name
= get_variable_from_expr_complex(expr
, &sym
);
321 set_new_true_false_paths(name
, sym
);
324 case EXPR_ASSIGNMENT
:
326 /* You have to deal with stuff like if (a = b = c) */
327 match_condition(expr
->right
);
328 match_condition(expr
->left
);
335 static void match_function_call(struct expression
*expr
)
337 struct expression
*tmp
;
341 struct sm_state
*state
;
343 fn_name
= get_variable_from_expr(expr
->fn
, NULL
);
345 if (fn_name
&& !strcmp(fn_name
, "kfree")) {
349 FOR_EACH_PTR(expr
->args
, tmp
) {
350 tmp
= strip_expr(tmp
);
351 name
= get_variable_from_expr_complex(tmp
, &sym
);
354 if ((state
= get_sm_state(name
, my_id
, sym
))) {
355 if (possibly_allocated(state
->possible
)) {
356 set_state(name
, my_id
, sym
, &assigned
);
360 } END_FOR_EACH_PTR(tmp
);
363 static void match_end_func(struct symbol
*sym
)
365 check_for_allocated();
366 free_trackers_and_list(&arguments
);
369 void check_memory(int id
)
372 add_unmatched_state_hook(my_id
, &unmatched_state
);
373 add_hook(&match_function_def
, FUNC_DEF_HOOK
);
374 add_hook(&match_declarations
, DECLARATION_HOOK
);
375 add_hook(&match_function_call
, FUNCTION_CALL_HOOK
);
376 add_hook(&match_condition
, CONDITION_HOOK
);
377 add_hook(&match_assign
, ASSIGNMENT_HOOK
);
378 add_hook(&match_return
, RETURN_HOOK
);
379 add_hook(&match_end_func
, END_FUNC_HOOK
);