Print this page
smatch: check libld_* allocation functions
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/tools/smatch/src/check_leaks.c
+++ new/usr/src/tools/smatch/src/check_leaks.c
1 1 /*
2 2 * Copyright (C) 2010 Dan Carpenter.
3 3 *
4 4 * This program is free software; you can redistribute it and/or
5 5 * modify it under the terms of the GNU General Public License
6 6 * as published by the Free Software Foundation; either version 2
7 7 * of the License, or (at your option) any later version.
8 8 *
9 9 * This program is distributed in the hope that it will be useful,
10 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 * GNU General Public License for more details.
13 13 *
14 14 * You should have received a copy of the GNU General Public License
15 15 * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
16 16 */
17 17
18 18 /*
19 19 * The point of this check is to look for leaks.
20 20 * foo = malloc(); // <- mark it as allocated.
21 21 * A variable becomes &ok if we:
22 22 * 1) assign it to another variable.
23 23 * 2) pass it to a function.
24 24 *
25 25 * One complication is dealing with stuff like:
26 26 * foo->bar = malloc();
27 27 * foo->baz = malloc();
28 28 * foo = something();
29 29 *
30 30 * The work around is that for now what this check only
31 31 * checks simple expressions and doesn't check whether
32 32 * foo->bar is leaked.
33 33 *
34 34 */
35 35
36 36 #include <fcntl.h>
37 37 #include <unistd.h>
38 38 #include "parse.h"
↓ open down ↓ |
38 lines elided |
↑ open up ↑ |
39 39 #include "smatch.h"
40 40 #include "smatch_slist.h"
41 41
42 42 static int my_id;
43 43
44 44 STATE(allocated);
45 45 STATE(ok);
46 46
47 47 static void set_parent(struct expression *expr, struct smatch_state *state);
48 48
49 -static const char *allocation_funcs[] = {
50 - "malloc",
51 - "kmalloc",
52 - "kzalloc",
53 - "kmemdup",
54 -};
55 -
56 49 static char *alloc_parent_str(struct symbol *sym)
57 50 {
58 51 static char buf[256];
59 52
60 53 if (!sym || !sym->ident)
61 54 return NULL;
62 55
63 56 snprintf(buf, 255, "%s", sym->ident->name);
64 57 buf[255] = '\0';
65 58 return alloc_string(buf);
66 59 }
67 60
68 61 static char *get_parent_from_expr(struct expression *expr, struct symbol **sym)
69 62 {
70 63 char *name;
71 64
72 65 expr = strip_expr(expr);
73 66
74 67 name = expr_to_str_sym(expr, sym);
75 68 free_string(name);
76 69 if (!name || !*sym || !(*sym)->ident) {
77 70 *sym = NULL;
78 71 return NULL;
79 72 }
80 73 return alloc_parent_str(*sym);
81 74 }
82 75
83 76 static int is_local(struct expression *expr)
84 77 {
85 78 char *name;
86 79 struct symbol *sym;
87 80 int ret = 0;
88 81
89 82 name = expr_to_str_sym(expr, &sym);
90 83 if (!name || !sym)
91 84 goto out;
92 85 if (sym->ctype.modifiers & (MOD_NONLOCAL | MOD_STATIC | MOD_ADDRESSABLE))
93 86 goto out;
94 87 ret = 1;
95 88 out:
96 89 free_string(name);
97 90 return ret;
98 91 }
99 92
100 93 static int is_param(struct expression *expr)
101 94 {
102 95 char *name;
103 96 struct symbol *sym;
104 97 struct symbol *tmp;
105 98 int ret = 0;
106 99
107 100 name = expr_to_str_sym(expr, &sym);
108 101 if (!name || !sym)
109 102 goto out;
110 103 FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, tmp) {
111 104 if (tmp == sym) {
112 105 ret = 1;
113 106 goto out;
114 107 }
115 108 } END_FOR_EACH_PTR(tmp);
116 109 out:
117 110 free_string(name);
118 111 return ret;
119 112
120 113 }
121 114
122 115 static void match_alloc(const char *fn, struct expression *expr, void *unused)
123 116 {
124 117 if (!is_local(expr->left))
125 118 return;
126 119 if (is_param(expr->left))
127 120 return;
128 121 if (expr->left->type != EXPR_SYMBOL)
129 122 return;
130 123 set_state_expr(my_id, expr->left, &allocated);
131 124 }
132 125
133 126 static void match_condition(struct expression *expr)
134 127 {
135 128 struct sm_state *sm;
136 129
137 130 expr = strip_expr(expr);
138 131
139 132 switch (expr->type) {
140 133 case EXPR_PREOP:
141 134 case EXPR_SYMBOL:
142 135 case EXPR_DEREF:
143 136 sm = get_sm_state_expr(my_id, expr);
144 137 if (sm && slist_has_state(sm->possible, &allocated))
145 138 set_true_false_states_expr(my_id, expr, NULL, &ok);
146 139 return;
147 140 case EXPR_ASSIGNMENT:
148 141 /* You have to deal with stuff like if (a = b = c) */
149 142 match_condition(expr->left);
150 143 return;
151 144 default:
152 145 return;
153 146 }
154 147 }
155 148
156 149 static void set_parent(struct expression *expr, struct smatch_state *state)
157 150 {
158 151 char *name;
159 152 struct symbol *sym;
160 153
161 154 expr = strip_expr(expr);
162 155 if (!expr)
163 156 return;
164 157 if (expr->type == EXPR_CONDITIONAL ||
165 158 expr->type == EXPR_SELECT) {
166 159 set_parent(expr->cond_true, state);
167 160 set_parent(expr->cond_false, state);
168 161 return;
169 162 }
170 163
171 164 name = get_parent_from_expr(expr, &sym);
172 165 if (!name || !sym)
173 166 goto free;
174 167 if (state == &ok && !get_state(my_id, name, sym))
175 168 goto free;
176 169 set_state(my_id, name, sym, state);
177 170 free:
178 171 free_string(name);
179 172 }
180 173
181 174 static void match_function_call(struct expression *expr)
182 175 {
183 176 struct expression *tmp;
184 177
185 178 FOR_EACH_PTR(expr->args, tmp) {
186 179 set_parent(tmp, &ok);
187 180 } END_FOR_EACH_PTR(tmp);
188 181 }
189 182
190 183 static void warn_if_allocated(struct expression *expr)
191 184 {
192 185 struct sm_state *sm;
193 186 char *name;
194 187 sval_t sval;
195 188
196 189 if (get_implied_value(expr, &sval) && sval.value == 0)
197 190 return;
198 191
199 192 sm = get_sm_state_expr(my_id, expr);
200 193 if (!sm)
201 194 return;
202 195 if (!slist_has_state(sm->possible, &allocated))
203 196 return;
204 197
205 198 name = expr_to_var(expr);
206 199 sm_warning("overwrite may leak '%s'", name);
207 200 free_string(name);
208 201
209 202 /* silence further warnings */
210 203 set_state_expr(my_id, expr, &ok);
211 204 }
212 205
213 206 static void match_assign(struct expression *expr)
214 207 {
215 208 struct expression *right;
216 209
217 210 right = expr->right;
218 211
219 212 while (right->type == EXPR_ASSIGNMENT)
220 213 right = right->left;
221 214
222 215 warn_if_allocated(expr->left);
223 216 set_parent(right, &ok);
224 217 }
225 218
226 219 static void check_for_allocated(void)
227 220 {
228 221 struct stree *stree;
229 222 struct sm_state *tmp;
230 223
231 224 stree = __get_cur_stree();
232 225 FOR_EACH_MY_SM(my_id, stree, tmp) {
233 226 if (!slist_has_state(tmp->possible, &allocated))
234 227 continue;
235 228 sm_warning("possible memory leak of '%s'", tmp->name);
236 229 } END_FOR_EACH_SM(tmp);
237 230 }
238 231
239 232 static void match_return(struct expression *ret_value)
240 233 {
241 234 if (__inline_fn)
242 235 return;
243 236 set_parent(ret_value, &ok);
244 237 check_for_allocated();
245 238 }
↓ open down ↓ |
180 lines elided |
↑ open up ↑ |
246 239
247 240 static void match_end_func(struct symbol *sym)
248 241 {
249 242 if (__inline_fn)
250 243 return;
251 244 check_for_allocated();
252 245 }
253 246
254 247 void check_leaks(int id)
255 248 {
256 - int i;
257 -
258 249 my_id = id;
259 250
260 - for (i = 0; i < ARRAY_SIZE(allocation_funcs); i++)
261 - add_function_assign_hook(allocation_funcs[i], &match_alloc, NULL);
262 -
251 + switch (option_project) {
252 + case PROJ_KERNEL:
253 + add_function_assign_hook("kmalloc", &match_alloc, NULL);
254 + add_function_assign_hook("kzalloc", &match_alloc, NULL);
255 + add_function_assign_hook("kmemdup", &match_alloc, NULL);
256 + break;
257 + case PROJ_ILLUMOS_USER:
258 + add_function_assign_hook("libld_malloc", &match_alloc, NULL);
259 + add_function_assign_hook("libld_calloc", &match_alloc, NULL);
260 + /* FALLTHROUGH */
261 + default:
262 + add_function_assign_hook("malloc", &match_alloc, NULL);
263 + add_function_assign_hook("calloc", &match_alloc, NULL);
264 + }
265 +
263 266 add_hook(&match_condition, CONDITION_HOOK);
264 267
265 268 add_hook(&match_function_call, FUNCTION_CALL_HOOK);
266 269 add_hook(&match_assign, ASSIGNMENT_HOOK);
267 270
268 271 add_hook(&match_return, RETURN_HOOK);
269 272 add_hook(&match_end_func, END_FUNC_HOOK);
270 273 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX