1 /*
2 * Copyright (C) 2010 Dan Carpenter.
3 *
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.
8 *
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.
13 *
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
16 */
17
18 /*
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.
24 *
25 * One complication is dealing with stuff like:
26 * foo->bar = malloc();
27 * foo->baz = malloc();
28 * foo = something();
29 *
30 * The work around is that for now what this check only
31 * checks simple expressions and doesn't check whether
32 * foo->bar is leaked.
33 *
34 */
35
36 #include <fcntl.h>
37 #include <unistd.h>
38 #include "parse.h"
39 #include "smatch.h"
40 #include "smatch_slist.h"
41
42 static int my_id;
43
44 STATE(allocated);
45 STATE(ok);
46
47 static void set_parent(struct expression *expr, struct smatch_state *state);
48
49 static const char *allocation_funcs[] = {
50 "malloc",
51 "kmalloc",
52 "kzalloc",
53 "kmemdup",
54 };
55
alloc_parent_str(struct symbol * sym)56 static char *alloc_parent_str(struct symbol *sym)
57 {
58 static char buf[256];
59
60 if (!sym || !sym->ident)
61 return NULL;
62
63 snprintf(buf, 255, "%s", sym->ident->name);
64 buf[255] = '\0';
65 return alloc_string(buf);
66 }
67
get_parent_from_expr(struct expression * expr,struct symbol ** sym)68 static char *get_parent_from_expr(struct expression *expr, struct symbol **sym)
69 {
70 char *name;
71
72 expr = strip_expr(expr);
73
74 name = expr_to_str_sym(expr, sym);
75 free_string(name);
76 if (!name || !*sym || !(*sym)->ident) {
77 *sym = NULL;
78 return NULL;
79 }
80 return alloc_parent_str(*sym);
81 }
82
is_local(struct expression * expr)83 static int is_local(struct expression *expr)
84 {
85 char *name;
86 struct symbol *sym;
87 int ret = 0;
88
89 name = expr_to_str_sym(expr, &sym);
90 if (!name || !sym)
91 goto out;
92 if (sym->ctype.modifiers & (MOD_NONLOCAL | MOD_STATIC | MOD_ADDRESSABLE))
93 goto out;
94 ret = 1;
95 out:
96 free_string(name);
97 return ret;
98 }
99
is_param(struct expression * expr)100 static int is_param(struct expression *expr)
101 {
102 char *name;
103 struct symbol *sym;
104 struct symbol *tmp;
105 int ret = 0;
106
107 name = expr_to_str_sym(expr, &sym);
108 if (!name || !sym)
109 goto out;
110 FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, tmp) {
111 if (tmp == sym) {
112 ret = 1;
113 goto out;
114 }
115 } END_FOR_EACH_PTR(tmp);
116 out:
117 free_string(name);
118 return ret;
119
120 }
121
match_alloc(const char * fn,struct expression * expr,void * unused)122 static void match_alloc(const char *fn, struct expression *expr, void *unused)
123 {
124 if (!is_local(expr->left))
125 return;
126 if (is_param(expr->left))
127 return;
128 if (expr->left->type != EXPR_SYMBOL)
129 return;
130 set_state_expr(my_id, expr->left, &allocated);
131 }
132
match_condition(struct expression * expr)133 static void match_condition(struct expression *expr)
134 {
135 struct sm_state *sm;
136
137 expr = strip_expr(expr);
138
139 switch (expr->type) {
140 case EXPR_PREOP:
141 case EXPR_SYMBOL:
142 case EXPR_DEREF:
143 sm = get_sm_state_expr(my_id, expr);
144 if (sm && slist_has_state(sm->possible, &allocated))
145 set_true_false_states_expr(my_id, expr, NULL, &ok);
146 return;
147 case EXPR_ASSIGNMENT:
148 /* You have to deal with stuff like if (a = b = c) */
149 match_condition(expr->left);
150 return;
151 default:
152 return;
153 }
154 }
155
set_parent(struct expression * expr,struct smatch_state * state)156 static void set_parent(struct expression *expr, struct smatch_state *state)
157 {
158 char *name;
159 struct symbol *sym;
160
161 expr = strip_expr(expr);
162 if (!expr)
163 return;
164 if (expr->type == EXPR_CONDITIONAL ||
165 expr->type == EXPR_SELECT) {
166 set_parent(expr->cond_true, state);
167 set_parent(expr->cond_false, state);
168 return;
169 }
170
171 name = get_parent_from_expr(expr, &sym);
172 if (!name || !sym)
173 goto free;
174 if (state == &ok && !get_state(my_id, name, sym))
175 goto free;
176 set_state(my_id, name, sym, state);
177 free:
178 free_string(name);
179 }
180
match_function_call(struct expression * expr)181 static void match_function_call(struct expression *expr)
182 {
183 struct expression *tmp;
184
185 FOR_EACH_PTR(expr->args, tmp) {
186 set_parent(tmp, &ok);
187 } END_FOR_EACH_PTR(tmp);
188 }
189
warn_if_allocated(struct expression * expr)190 static void warn_if_allocated(struct expression *expr)
191 {
192 struct sm_state *sm;
193 char *name;
194 sval_t sval;
195
196 if (get_implied_value(expr, &sval) && sval.value == 0)
197 return;
198
199 sm = get_sm_state_expr(my_id, expr);
200 if (!sm)
201 return;
202 if (!slist_has_state(sm->possible, &allocated))
203 return;
204
205 name = expr_to_var(expr);
206 sm_warning("overwrite may leak '%s'", name);
207 free_string(name);
208
209 /* silence further warnings */
210 set_state_expr(my_id, expr, &ok);
211 }
212
match_assign(struct expression * expr)213 static void match_assign(struct expression *expr)
214 {
215 struct expression *right;
216
217 right = expr->right;
218
219 while (right->type == EXPR_ASSIGNMENT)
220 right = right->left;
221
222 warn_if_allocated(expr->left);
223 set_parent(right, &ok);
224 }
225
check_for_allocated(void)226 static void check_for_allocated(void)
227 {
228 struct stree *stree;
229 struct sm_state *tmp;
230
231 stree = __get_cur_stree();
232 FOR_EACH_MY_SM(my_id, stree, tmp) {
233 if (!slist_has_state(tmp->possible, &allocated))
234 continue;
235 sm_warning("possible memory leak of '%s'", tmp->name);
236 } END_FOR_EACH_SM(tmp);
237 }
238
match_return(struct expression * ret_value)239 static void match_return(struct expression *ret_value)
240 {
241 if (__inline_fn)
242 return;
243 set_parent(ret_value, &ok);
244 check_for_allocated();
245 }
246
match_end_func(struct symbol * sym)247 static void match_end_func(struct symbol *sym)
248 {
249 if (__inline_fn)
250 return;
251 check_for_allocated();
252 }
253
check_leaks(int id)254 void check_leaks(int id)
255 {
256 int i;
257
258 my_id = id;
259
260 for (i = 0; i < ARRAY_SIZE(allocation_funcs); i++)
261 add_function_assign_hook(allocation_funcs[i], &match_alloc, NULL);
262
263 add_hook(&match_condition, CONDITION_HOOK);
264
265 add_hook(&match_function_call, FUNCTION_CALL_HOOK);
266 add_hook(&match_assign, ASSIGNMENT_HOOK);
267
268 add_hook(&match_return, RETURN_HOOK);
269 add_hook(&match_end_func, END_FUNC_HOOK);
270 }
271