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"
23 The previous memory leak script found about 3 leaks. Almost all the leaks
24 it found were real though so that has to be said in it's favour.
26 The goal of this check is to find a lot more.
28 On this check, the plan is to look at return values. If the value is
29 negative we print an error for every local variable that is not freed.
32 static struct tracker_list
*arguments
;
34 static const char *allocation_funcs
[] = {
41 static int is_argument(struct symbol
*sym
)
45 FOR_EACH_PTR(arguments
, arg
) {
48 } END_FOR_EACH_PTR(arg
);
52 static void match_function_def(struct symbol
*sym
)
56 FOR_EACH_PTR(sym
->ctype
.base_type
->arguments
, arg
) {
57 add_tracker(&arguments
, (arg
->ident
?arg
->ident
->name
:"NULL"), my_id
, arg
);
58 } END_FOR_EACH_PTR(arg
);
61 static void check_allocated(struct sm_state
*sm
)
63 if (slist_has_state(sm
->possible
, &allocated
))
64 smatch_msg("warn: %s possibly leaked on error path", sm
->name
);
67 static void check_for_allocated(void)
69 struct state_list
*slist
;
72 slist
= get_all_states(my_id
);
73 FOR_EACH_PTR(slist
, tmp
) {
75 } END_FOR_EACH_PTR(tmp
);
79 static void match_allocation(const char *fn
, struct expression
*expr
,
82 char *left_name
= NULL
;
83 struct symbol
*left_sym
;
85 left_name
= get_variable_from_expr(expr
->left
, &left_sym
);
86 if (!left_name
|| !left_sym
)
88 if (is_argument(left_sym
))
90 if (left_sym
->ctype
.modifiers
&
91 (MOD_NONLOCAL
| MOD_STATIC
| MOD_ADDRESSABLE
))
93 set_state(left_name
, my_id
, left_sym
, &allocated
);
95 free_string(left_name
);
98 static void match_free(const char *fn
, struct expression
*expr
, void *data
)
100 struct expression
*ptr_expr
;
102 struct symbol
*ptr_sym
;
103 int arg_num
= (int)data
;
105 ptr_expr
= get_argument_from_call_expr(expr
->args
, arg_num
);
106 ptr_name
= get_variable_from_expr(ptr_expr
, &ptr_sym
);
109 if (!get_state(ptr_name
, my_id
, ptr_sym
))
111 set_state(ptr_name
, my_id
, ptr_sym
, &freed
);
112 free_string(ptr_name
);
115 static void check_slist(struct state_list
*slist
)
119 FOR_EACH_PTR(slist
, sm
) {
120 if (sm
->owner
!= my_id
)
122 if (slist_has_state(sm
->possible
, &allocated
))
123 smatch_msg("warn: %s possibly leaked on error path (implied)",
125 } END_FOR_EACH_PTR(sm
);
128 static void do_implication_check(struct expression
*expr
)
130 struct state_list
*lt_zero
= NULL
;
131 struct state_list
*ge_zero
= NULL
;
135 name
= get_variable_from_expr(expr
, &sym
);
138 get_implications(name
, sym
, '<', 0, <_zero
, &ge_zero
);
139 check_slist(lt_zero
);
141 free_slist(&ge_zero
);
142 free_slist(<_zero
);
146 static void match_return(struct statement
*stmt
)
150 ret_val
= get_value(stmt
->ret_value
);
151 if (ret_val
== UNDEFINED
) {
152 do_implication_check(stmt
->ret_value
);
157 check_for_allocated();
160 static void set_new_true_false_paths(const char *name
, struct symbol
*sym
)
162 if (!get_state(name
, my_id
, sym
))
164 set_true_false_states(name
, my_id
, sym
, &allocated
, &isnull
);
167 static void match_condition(struct expression
*expr
)
172 expr
= strip_expr(expr
);
177 name
= get_variable_from_expr(expr
, &sym
);
180 set_new_true_false_paths(name
, sym
);
183 case EXPR_ASSIGNMENT
:
184 match_condition(expr
->left
);
191 static void match_end_func(struct symbol
*sym
)
193 free_trackers_and_list(&arguments
);
196 static void register_funcs_from_file(void)
198 const char *filename
= "frees";
204 fd
= open(filename
, O_RDONLY
);
207 token
= tokenize(filename
, fd
, NULL
, NULL
);
209 if (token_type(token
) != TOKEN_STREAMBEGIN
)
212 while (token_type(token
) != TOKEN_STREAMEND
) {
213 if (token_type(token
) != TOKEN_IDENT
)
215 func
= show_ident(token
->ident
);
217 if (token_type(token
) != TOKEN_NUMBER
)
219 arg
= atoi(token
->number
);
220 add_function_hook(func
, &match_free
, (void *)arg
);
226 void check_leaks(int id
)
231 add_hook(&match_function_def
, FUNC_DEF_HOOK
);
232 add_hook(&match_condition
, CONDITION_HOOK
);
233 add_hook(&match_return
, RETURN_HOOK
);
234 add_hook(&match_end_func
, END_FUNC_HOOK
);
235 add_function_hook("kfree", &match_free
, (void *)0);
236 register_funcs_from_file();
237 for(i
= 0; allocation_funcs
[i
]; i
++) {
238 add_function_assign_hook(allocation_funcs
[i
],
239 &match_allocation
, NULL
);