2 * Copyright (C) 2010 Dan Carpenter.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
19 * The point of this check is to look for leaks.
20 * foo = malloc(); // <- mark it as allocated.
21 * A variable becomes &ok if we:
22 * 1) assign it to another variable.
23 * 2) pass it to a function.
25 * One complication is dealing with stuff like:
26 * foo->bar = malloc();
27 * foo->baz = malloc();
30 * The work around is that for now what this check only
31 * checks simple expressions and doesn't check whether
40 #include "smatch_slist.h"
47 static void set_parent(struct expression
*expr
, struct smatch_state
*state
);
49 static const char *allocation_funcs
[] = {
56 static char *alloc_parent_str(struct symbol
*sym
)
60 if (!sym
|| !sym
->ident
)
63 snprintf(buf
, 255, "%s", sym
->ident
->name
);
65 return alloc_string(buf
);
68 static char *get_parent_from_expr(struct expression
*expr
, struct symbol
**sym
)
72 expr
= strip_expr(expr
);
74 name
= expr_to_str_sym(expr
, sym
);
76 if (!name
|| !*sym
|| !(*sym
)->ident
) {
80 return alloc_parent_str(*sym
);
83 static int is_local(struct expression
*expr
)
89 name
= expr_to_str_sym(expr
, &sym
);
92 if (sym
->ctype
.modifiers
& (MOD_NONLOCAL
| MOD_STATIC
| MOD_ADDRESSABLE
))
100 static int is_param(struct expression
*expr
)
107 name
= expr_to_str_sym(expr
, &sym
);
110 FOR_EACH_PTR(cur_func_sym
->ctype
.base_type
->arguments
, tmp
) {
115 } END_FOR_EACH_PTR(tmp
);
121 static void match_alloc(const char *fn
, struct expression
*expr
, void *unused
)
123 if (is_fake_var_assign(expr
))
125 if (!is_local(expr
->left
))
127 if (is_param(expr
->left
))
129 if (has_cleanup(expr
->left
))
131 if (expr
->left
->type
!= EXPR_SYMBOL
)
133 set_state_expr(my_id
, expr
->left
, &allocated
);
136 static void match_condition(struct expression
*expr
)
140 expr
= strip_expr(expr
);
142 switch (expr
->type
) {
146 sm
= get_sm_state_expr(my_id
, expr
);
147 if (sm
&& slist_has_state(sm
->possible
, &allocated
))
148 set_true_false_states_expr(my_id
, expr
, NULL
, &ok
);
150 case EXPR_ASSIGNMENT
:
151 /* You have to deal with stuff like if (a = b = c) */
152 match_condition(expr
->left
);
159 static void set_parent(struct expression
*expr
, struct smatch_state
*state
)
164 expr
= strip_expr(expr
);
167 if (expr
->type
== EXPR_CONDITIONAL
||
168 expr
->type
== EXPR_SELECT
) {
169 set_parent(expr
->cond_true
, state
);
170 set_parent(expr
->cond_false
, state
);
174 name
= get_parent_from_expr(expr
, &sym
);
177 if (state
== &ok
&& !get_state(my_id
, name
, sym
))
179 set_state(my_id
, name
, sym
, state
);
184 static void match_function_call(struct expression
*expr
)
186 struct expression
*tmp
;
188 FOR_EACH_PTR(expr
->args
, tmp
) {
189 set_parent(tmp
, &ok
);
190 } END_FOR_EACH_PTR(tmp
);
193 static void warn_if_allocated(struct expression
*expr
)
199 sm
= get_sm_state_expr(my_id
, expr
);
202 if (!slist_has_state(sm
->possible
, &allocated
))
205 if (get_implied_value(expr
, &sval
) && sval
.value
== 0)
208 name
= expr_to_var(expr
);
209 sm_warning("overwrite may leak '%s'", name
);
212 /* silence further warnings */
213 set_state_expr(my_id
, expr
, &ok
);
216 static void match_assign(struct expression
*expr
)
218 struct expression
*right
;
222 while (right
->type
== EXPR_ASSIGNMENT
)
225 warn_if_allocated(expr
->left
);
226 set_parent(right
, &ok
);
229 static void check_for_allocated(void)
232 struct sm_state
*tmp
;
234 stree
= __get_cur_stree();
235 FOR_EACH_MY_SM(my_id
, stree
, tmp
) {
236 if (!slist_has_state(tmp
->possible
, &allocated
))
238 sm_warning("possible memory leak of '%s'", tmp
->name
);
239 } END_FOR_EACH_SM(tmp
);
242 static void match_return(struct expression
*ret_value
)
246 set_parent(ret_value
, &ok
);
247 check_for_allocated();
250 static void match_end_func(struct symbol
*sym
)
254 check_for_allocated();
257 void check_leaks(int id
)
263 for (i
= 0; i
< ARRAY_SIZE(allocation_funcs
); i
++)
264 add_function_assign_hook(allocation_funcs
[i
], &match_alloc
, NULL
);
266 add_hook(&match_condition
, CONDITION_HOOK
);
268 add_hook(&match_function_call
, FUNCTION_CALL_HOOK
);
269 add_hook(&match_assign
, ASSIGNMENT_HOOK
);
271 add_hook(&match_return
, RETURN_HOOK
);
272 add_hook(&match_end_func
, END_FUNC_HOOK
);