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",
68 static void check_for_allocated(void)
70 struct state_list
*slist
;
73 slist
= get_all_states(my_id
);
74 FOR_EACH_PTR(slist
, tmp
) {
76 } END_FOR_EACH_PTR(tmp
);
80 static void match_allocation(const char *fn
, struct expression
*expr
,
83 char *left_name
= NULL
;
84 struct symbol
*left_sym
;
86 left_name
= get_variable_from_expr(expr
->left
, &left_sym
);
87 if (!left_name
|| !left_sym
)
89 if (is_argument(left_sym
))
91 if (left_sym
->ctype
.modifiers
&
92 (MOD_NONLOCAL
| MOD_STATIC
| MOD_ADDRESSABLE
))
94 set_state(left_name
, my_id
, left_sym
, &allocated
);
96 free_string(left_name
);
99 static void match_free(const char *fn
, struct expression
*expr
, void *data
)
101 struct expression
*ptr_expr
;
103 struct symbol
*ptr_sym
;
104 int arg_num
= (int)data
;
106 ptr_expr
= get_argument_from_call_expr(expr
->args
, arg_num
);
107 ptr_name
= get_variable_from_expr(ptr_expr
, &ptr_sym
);
110 if (!get_state(ptr_name
, my_id
, ptr_sym
))
112 set_state(ptr_name
, my_id
, ptr_sym
, &freed
);
113 free_string(ptr_name
);
116 static void check_slist(struct state_list
*slist
)
119 struct sm_state
*poss
;
121 FOR_EACH_PTR(slist
, sm
) {
122 if (sm
->owner
!= my_id
)
124 FOR_EACH_PTR(sm
->possible
, poss
) {
125 if (poss
->state
== &allocated
)
126 smatch_msg("warn: '%s' possibly leaked on error"
127 "path (implied from line %d)",
128 sm
->name
, poss
->line
);
129 } END_FOR_EACH_PTR(poss
);
130 } END_FOR_EACH_PTR(sm
);
133 static void do_implication_check(struct expression
*expr
)
135 struct state_list
*lt_zero
= NULL
;
136 struct state_list
*ge_zero
= NULL
;
140 name
= get_variable_from_expr(expr
, &sym
);
143 get_implications(name
, sym
, '<', 0, <_zero
, &ge_zero
);
144 check_slist(lt_zero
);
146 free_slist(&ge_zero
);
147 free_slist(<_zero
);
151 static void match_return(struct statement
*stmt
)
155 ret_val
= get_value(stmt
->ret_value
);
156 if (ret_val
== UNDEFINED
) {
157 do_implication_check(stmt
->ret_value
);
162 check_for_allocated();
165 static void set_new_true_false_paths(const char *name
, struct symbol
*sym
)
167 if (!get_state(name
, my_id
, sym
))
169 set_true_false_states(name
, my_id
, sym
, &allocated
, &isnull
);
172 static void match_condition(struct expression
*expr
)
177 expr
= strip_expr(expr
);
182 name
= get_variable_from_expr(expr
, &sym
);
185 set_new_true_false_paths(name
, sym
);
188 case EXPR_ASSIGNMENT
:
189 match_condition(expr
->left
);
196 static void match_end_func(struct symbol
*sym
)
198 free_trackers_and_list(&arguments
);
201 static void register_funcs_from_file(void)
207 token
= get_tokens_file("kernel.frees_argument");
210 if (token_type(token
) != TOKEN_STREAMBEGIN
)
213 while (token_type(token
) != TOKEN_STREAMEND
) {
214 if (token_type(token
) != TOKEN_IDENT
)
216 func
= show_ident(token
->ident
);
218 if (token_type(token
) != TOKEN_NUMBER
)
220 arg
= atoi(token
->number
);
221 add_function_hook(func
, &match_free
, (void *)arg
);
227 static void register_allocation_funcs(void)
232 token
= get_tokens_file("kernel.allocation_funcs");
235 if (token_type(token
) != TOKEN_STREAMBEGIN
)
238 while (token_type(token
) != TOKEN_STREAMEND
) {
239 if (token_type(token
) != TOKEN_IDENT
)
241 func
= show_ident(token
->ident
);
242 add_function_assign_hook(func
, &match_allocation
, NULL
);
248 void check_leaks(int id
)
253 add_hook(&match_function_def
, FUNC_DEF_HOOK
);
254 add_hook(&match_condition
, CONDITION_HOOK
);
255 add_hook(&match_return
, RETURN_HOOK
);
256 add_hook(&match_end_func
, END_FUNC_HOOK
);
257 add_function_hook("kfree", &match_free
, (void *)0);
258 register_funcs_from_file();
259 for(i
= 0; allocation_funcs
[i
]; i
++) {
260 add_function_assign_hook(allocation_funcs
[i
],
261 &match_allocation
, NULL
);
263 register_allocation_funcs();