Print this page
smatch: check libld_* allocation functions
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/tools/smatch/src/check_free.c
+++ new/usr/src/tools/smatch/src/check_free.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 * check_memory() is getting too big and messy.
20 20 *
21 21 */
22 22
23 23 #include <string.h>
24 24 #include "smatch.h"
25 25 #include "smatch_slist.h"
26 26 #include "smatch_extra.h"
27 27
28 28 static int my_id;
29 29
30 30 STATE(freed);
31 31 STATE(ok);
32 32
33 33 static void ok_to_use(struct sm_state *sm, struct expression *mod_expr)
34 34 {
35 35 if (sm->state != &ok)
36 36 set_state(my_id, sm->name, sm->sym, &ok);
37 37 }
38 38
39 39 static void pre_merge_hook(struct sm_state *sm)
40 40 {
41 41 if (is_impossible_path())
42 42 set_state(my_id, sm->name, sm->sym, &ok);
43 43 }
44 44
45 45 static int is_freed(struct expression *expr)
46 46 {
47 47 struct sm_state *sm;
48 48
49 49 sm = get_sm_state_expr(my_id, expr);
50 50 if (sm && slist_has_state(sm->possible, &freed))
51 51 return 1;
52 52 return 0;
53 53 }
54 54
55 55 static void match_symbol(struct expression *expr)
56 56 {
57 57 struct expression *parent;
58 58 char *name;
59 59
60 60 if (is_impossible_path())
61 61 return;
62 62 if (__in_fake_parameter_assign)
63 63 return;
64 64
65 65 parent = expr_get_parent_expr(expr);
66 66 while (parent && parent->type == EXPR_PREOP && parent->op == '(')
67 67 parent = expr_get_parent_expr(parent);
68 68 if (parent && parent->type == EXPR_PREOP && parent->op == '&')
69 69 return;
70 70
71 71 if (!is_freed(expr))
72 72 return;
73 73 name = expr_to_var(expr);
74 74 sm_warning("'%s' was already freed.", name);
75 75 free_string(name);
76 76 }
77 77
78 78 static void match_dereferences(struct expression *expr)
79 79 {
80 80 char *name;
81 81
82 82 if (__in_fake_parameter_assign)
83 83 return;
84 84
85 85 if (expr->type != EXPR_PREOP)
86 86 return;
87 87
88 88 if (is_impossible_path())
89 89 return;
90 90
91 91 expr = strip_expr(expr->unop);
92 92 if (!is_freed(expr))
93 93 return;
94 94 name = expr_to_var(expr);
95 95 sm_error("dereferencing freed memory '%s'", name);
96 96 set_state_expr(my_id, expr, &ok);
97 97 free_string(name);
98 98 }
99 99
100 100 static int ignored_params[16];
101 101
102 102 static void set_ignored_params(struct expression *call)
103 103 {
104 104 struct expression *arg;
105 105 const char *p;
106 106 int i;
107 107
108 108 memset(&ignored_params, 0, sizeof(ignored_params));
109 109
110 110 i = -1;
111 111 FOR_EACH_PTR(call->args, arg) {
112 112 i++;
113 113 if (arg->type != EXPR_STRING)
114 114 continue;
115 115 goto found;
116 116 } END_FOR_EACH_PTR(arg);
117 117
118 118 return;
119 119
120 120 found:
121 121 i++;
122 122 p = arg->string->data;
123 123 while ((p = strchr(p, '%'))) {
124 124 if (i >= ARRAY_SIZE(ignored_params))
125 125 return;
126 126 p++;
127 127 if (*p == '%') {
128 128 p++;
129 129 continue;
130 130 }
131 131 if (*p == '.')
132 132 p++;
133 133 if (*p == '*')
134 134 i++;
135 135 if (*p == 'p')
136 136 ignored_params[i] = 1;
137 137 i++;
138 138 }
139 139 }
140 140
141 141 static int is_free_func(struct expression *fn)
142 142 {
143 143 char *name;
144 144 int ret = 0;
145 145
146 146 name = expr_to_str(fn);
147 147 if (!name)
148 148 return 0;
149 149 if (strstr(name, "free"))
150 150 ret = 1;
151 151 free_string(name);
152 152
153 153 return ret;
154 154 }
155 155
156 156 static void match_call(struct expression *expr)
157 157 {
158 158 struct expression *arg;
159 159 char *name;
160 160 int i;
161 161
162 162 if (is_impossible_path())
163 163 return;
164 164
165 165 set_ignored_params(expr);
166 166
167 167 i = -1;
168 168 FOR_EACH_PTR(expr->args, arg) {
169 169 i++;
170 170 if (!is_pointer(arg))
171 171 continue;
172 172 if (!is_freed(arg))
173 173 continue;
174 174 if (ignored_params[i])
175 175 continue;
176 176
177 177 name = expr_to_var(arg);
178 178 if (is_free_func(expr->fn))
179 179 sm_error("double free of '%s'", name);
180 180 else
181 181 sm_warning("passing freed memory '%s'", name);
182 182 set_state_expr(my_id, arg, &ok);
183 183 free_string(name);
184 184 } END_FOR_EACH_PTR(arg);
185 185 }
186 186
187 187 static void match_return(struct expression *expr)
188 188 {
189 189 char *name;
190 190
191 191 if (is_impossible_path())
192 192 return;
193 193 if (__in_fake_parameter_assign)
194 194 return;
195 195
196 196 if (!expr)
197 197 return;
198 198 if (!is_freed(expr))
199 199 return;
200 200
201 201 name = expr_to_var(expr);
202 202 sm_warning("returning freed memory '%s'", name);
203 203 set_state_expr(my_id, expr, &ok);
204 204 free_string(name);
205 205 }
206 206
207 207 static void match_free(const char *fn, struct expression *expr, void *param)
208 208 {
209 209 struct expression *arg;
210 210
211 211 if (is_impossible_path())
212 212 return;
213 213
214 214 arg = get_argument_from_call_expr(expr->args, PTR_INT(param));
215 215 if (!arg)
216 216 return;
217 217 if (is_freed(arg)) {
218 218 char *name = expr_to_var(arg);
219 219
220 220 sm_error("double free of '%s'", name);
221 221 free_string(name);
222 222 }
223 223 set_state_expr(my_id, arg, &freed);
224 224 }
225 225
226 226 static void set_param_freed(struct expression *call, struct expression *arg, char *key, char *unused)
227 227 {
228 228 struct symbol *sym;
229 229 char *name;
230 230
231 231 name = get_variable_from_key(arg, key, &sym);
232 232 if (!name || !sym)
233 233 goto free;
234 234
235 235 set_state(my_id, name, sym, &freed);
236 236 free:
237 237 free_string(name);
238 238 }
239 239
240 240 int parent_is_free_var_sym(const char *name, struct symbol *sym)
241 241 {
242 242 char buf[256];
243 243 char *start;
244 244 char *end;
245 245 struct smatch_state *state;
246 246
247 247 if (option_project == PROJ_KERNEL)
248 248 return parent_is_free_var_sym_strict(name, sym);
249 249
250 250 strncpy(buf, name, sizeof(buf) - 1);
251 251 buf[sizeof(buf) - 1] = '\0';
252 252
253 253 start = &buf[0];
254 254 while ((*start == '&'))
255 255 start++;
256 256
257 257 while ((end = strrchr(start, '-'))) {
258 258 *end = '\0';
259 259 state = __get_state(my_id, start, sym);
260 260 if (state == &freed)
261 261 return 1;
262 262 }
263 263 return 0;
264 264 }
265 265
266 266 int parent_is_free(struct expression *expr)
267 267 {
268 268 struct symbol *sym;
269 269 char *var;
270 270 int ret = 0;
271 271
272 272 expr = strip_expr(expr);
273 273 var = expr_to_var_sym(expr, &sym);
274 274 if (!var || !sym)
275 275 goto free;
276 276 ret = parent_is_free_var_sym(var, sym);
277 277 free:
278 278 free_string(var);
279 279 return ret;
280 280 }
281 281
282 282 void check_free(int id)
↓ open down ↓ |
282 lines elided |
↑ open up ↑ |
283 283 {
284 284 my_id = id;
285 285
286 286 if (option_project == PROJ_KERNEL) {
287 287 /* The kernel use check_free_strict.c */
288 288 return;
289 289 }
290 290
291 291 add_function_hook("free", &match_free, INT_PTR(0));
292 292
293 + if (option_project == PROJ_ILLUMOS_USER)
294 + add_function_hook("libld_free", &match_free, INT_PTR(0));
295 +
293 296 if (option_spammy)
294 297 add_hook(&match_symbol, SYM_HOOK);
295 298 add_hook(&match_dereferences, DEREF_HOOK);
296 299 add_hook(&match_call, FUNCTION_CALL_HOOK);
297 300 add_hook(&match_return, RETURN_HOOK);
298 301
299 302 add_modification_hook(my_id, &ok_to_use);
300 303 select_return_implies_hook(PARAM_FREED, &set_param_freed);
301 304 add_pre_merge_hook(my_id, &pre_merge_hook);
302 305 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX