4 * Copyright (C) 2010 Dan Carpenter.
6 * Licensed under the Open Software License version 1.1
11 * The point of this check is to look for leaks.
12 * foo = malloc(); // <- mark it as allocated.
13 * A variable becomes &ok if we:
14 * 1) assign it to another variable.
15 * 2) pass it to a function.
17 * One complication is dealing with stuff like:
18 * foo->bar = malloc();
19 * foo->baz = malloc();
22 * The work around is that for now what this check only
23 * checks simple expressions and doesn't check whether
32 #include "smatch_slist.h"
39 static void set_parent(struct expression
*expr
, struct smatch_state
*state
);
41 static const char *allocation_funcs
[] = {
48 static char *alloc_parent_str(struct symbol
*sym
)
52 if (!sym
|| !sym
->ident
)
55 snprintf(buf
, 255, "%s", sym
->ident
->name
);
57 return alloc_string(buf
);
60 static char *get_parent_from_expr(struct expression
*expr
, struct symbol
**sym
)
64 expr
= strip_expr(expr
);
66 name
= expr_to_str_sym(expr
, sym
);
68 if (!name
|| !*sym
|| !(*sym
)->ident
) {
72 return alloc_parent_str(*sym
);
75 static int is_local(struct expression
*expr
)
81 name
= expr_to_str_sym(expr
, &sym
);
84 if (sym
->ctype
.modifiers
& (MOD_NONLOCAL
| MOD_STATIC
| MOD_ADDRESSABLE
))
92 static int is_param(struct expression
*expr
)
99 name
= expr_to_str_sym(expr
, &sym
);
102 FOR_EACH_PTR(cur_func_sym
->ctype
.base_type
->arguments
, tmp
) {
107 } END_FOR_EACH_PTR(tmp
);
114 static void match_alloc(const char *fn
, struct expression
*expr
, void *unused
)
116 if (!is_local(expr
->left
))
118 if (is_param(expr
->left
))
120 if (expr
->left
->type
!= EXPR_SYMBOL
)
122 set_state_expr(my_id
, expr
->left
, &allocated
);
125 static void match_condition(struct expression
*expr
)
129 expr
= strip_expr(expr
);
131 switch (expr
->type
) {
135 sm
= get_sm_state_expr(my_id
, expr
);
136 if (sm
&& slist_has_state(sm
->possible
, &allocated
))
137 set_true_false_states_expr(my_id
, expr
, &allocated
, &ok
);
139 case EXPR_ASSIGNMENT
:
140 /* You have to deal with stuff like if (a = b = c) */
141 match_condition(expr
->left
);
148 static void set_parent(struct expression
*expr
, struct smatch_state
*state
)
153 name
= get_parent_from_expr(expr
, &sym
);
156 if (state
== &ok
&& !get_state(my_id
, name
, sym
))
158 set_state(my_id
, name
, sym
, state
);
163 static void match_function_call(struct expression
*expr
)
165 struct expression
*tmp
;
167 FOR_EACH_PTR(expr
->args
, tmp
) {
168 set_parent(tmp
, &ok
);
169 } END_FOR_EACH_PTR(tmp
);
172 static void warn_if_allocated(struct expression
*expr
)
177 sm
= get_sm_state_expr(my_id
, expr
);
180 if (!slist_has_state(sm
->possible
, &allocated
))
183 name
= expr_to_var(expr
);
184 sm_msg("warn: overwrite may leak '%s'", name
);
187 /* silence further warnings */
188 set_state_expr(my_id
, expr
, &ok
);
191 static void match_assign(struct expression
*expr
)
193 struct expression
*right
;
197 while (right
->type
== EXPR_ASSIGNMENT
)
200 warn_if_allocated(expr
->left
);
201 set_parent(right
, &ok
);
204 static void check_for_allocated(void)
206 struct state_list
*slist
;
207 struct sm_state
*tmp
;
209 slist
= get_all_states(my_id
);
210 FOR_EACH_PTR(slist
, tmp
) {
211 if (!slist_has_state(tmp
->possible
, &allocated
))
213 sm_msg("warn: possible memory leak of '%s'", tmp
->name
);
214 } END_FOR_EACH_PTR(tmp
);
218 static void match_return(struct expression
*ret_value
)
222 set_parent(ret_value
, &ok
);
223 check_for_allocated();
226 static void match_end_func(struct symbol
*sym
)
230 check_for_allocated();
233 void check_leaks(int id
)
239 for (i
= 0; i
< ARRAY_SIZE(allocation_funcs
); i
++)
240 add_function_assign_hook(allocation_funcs
[i
], &match_alloc
, NULL
);
242 add_hook(&match_condition
, CONDITION_HOOK
);
244 add_hook(&match_function_call
, FUNCTION_CALL_HOOK
);
245 add_hook(&match_assign
, ASSIGNMENT_HOOK
);
247 add_hook(&match_return
, RETURN_HOOK
);
248 add_hook(&match_end_func
, END_FUNC_HOOK
);