Print this page
11506 smatch resync
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/tools/smatch/src/check_free_strict.c
+++ new/usr/src/tools/smatch/src/check_free_strict.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 (expr->type != EXPR_PREOP)
83 83 return;
84 84
85 85 if (is_impossible_path())
86 86 return;
87 87 if (__in_fake_parameter_assign)
88 88 return;
89 89
90 90 expr = strip_expr(expr->unop);
91 91 if (!is_freed(expr))
92 92 return;
93 93 name = expr_to_var(expr);
94 94 sm_error("dereferencing freed memory '%s'", name);
95 95 set_state_expr(my_id, expr, &ok);
96 96 free_string(name);
97 97 }
98 98
99 99 static int ignored_params[16];
100 100
101 101 static void set_ignored_params(struct expression *call)
102 102 {
103 103 struct expression *arg;
104 104 const char *p;
105 105 int i;
106 106
107 107 memset(&ignored_params, 0, sizeof(ignored_params));
108 108
109 109 i = -1;
110 110 FOR_EACH_PTR(call->args, arg) {
111 111 i++;
112 112 if (arg->type != EXPR_STRING)
113 113 continue;
114 114 goto found;
115 115 } END_FOR_EACH_PTR(arg);
116 116
117 117 return;
118 118
119 119 found:
120 120 i++;
121 121 p = arg->string->data;
122 122 while ((p = strchr(p, '%'))) {
123 123 if (i >= ARRAY_SIZE(ignored_params))
124 124 return;
125 125 p++;
126 126 if (*p == '%') {
127 127 p++;
128 128 continue;
129 129 }
130 130 if (*p == '.')
131 131 p++;
132 132 if (*p == '*')
133 133 i++;
134 134 if (*p == 'p')
135 135 ignored_params[i] = 1;
136 136 i++;
137 137 }
138 138 }
139 139
140 140 static int is_free_func(struct expression *fn)
141 141 {
142 142 char *name;
143 143 int ret = 0;
144 144
145 145 name = expr_to_str(fn);
146 146 if (!name)
147 147 return 0;
148 148 if (strstr(name, "free"))
149 149 ret = 1;
150 150 free_string(name);
151 151
152 152 return ret;
153 153 }
154 154
155 155 static void match_call(struct expression *expr)
156 156 {
157 157 struct expression *arg;
158 158 char *name;
159 159 int i;
160 160
161 161 if (is_impossible_path())
162 162 return;
163 163
164 164 set_ignored_params(expr);
165 165
166 166 i = -1;
167 167 FOR_EACH_PTR(expr->args, arg) {
168 168 i++;
169 169 if (!is_pointer(arg))
170 170 continue;
171 171 if (!is_freed(arg))
172 172 continue;
173 173 if (ignored_params[i])
174 174 continue;
175 175
176 176 name = expr_to_var(arg);
177 177 if (is_free_func(expr->fn))
178 178 sm_error("double free of '%s'", name);
179 179 else
180 180 sm_warning("passing freed memory '%s'", name);
181 181 set_state_expr(my_id, arg, &ok);
182 182 free_string(name);
183 183 } END_FOR_EACH_PTR(arg);
184 184 }
185 185
186 186 static void match_return(struct expression *expr)
187 187 {
188 188 char *name;
189 189
190 190 if (is_impossible_path())
191 191 return;
192 192
193 193 if (!expr)
194 194 return;
195 195 if (!is_freed(expr))
196 196 return;
197 197
198 198 name = expr_to_var(expr);
199 199 sm_warning("returning freed memory '%s'", name);
200 200 set_state_expr(my_id, expr, &ok);
201 201 free_string(name);
202 202 }
203 203
204 204 static void match_free(const char *fn, struct expression *expr, void *param)
205 205 {
206 206 struct expression *arg;
207 207
208 208 if (is_impossible_path())
209 209 return;
210 210
211 211 arg = get_argument_from_call_expr(expr->args, PTR_INT(param));
212 212 if (!arg)
213 213 return;
214 214 if (is_freed(arg)) {
215 215 char *name = expr_to_var(arg);
216 216
217 217 sm_error("double free of '%s'", name);
218 218 free_string(name);
219 219 }
220 220 set_state_expr(my_id, arg, &freed);
221 221 }
222 222
223 223 static void set_param_freed(struct expression *expr, int param, char *key, char *value)
224 224 {
225 225 struct expression *arg;
226 226 char *name;
227 227 struct symbol *sym;
228 228 struct sm_state *sm;
229 229
230 230 while (expr->type == EXPR_ASSIGNMENT)
231 231 expr = strip_expr(expr->right);
232 232 if (expr->type != EXPR_CALL)
233 233 return;
234 234
235 235 arg = get_argument_from_call_expr(expr->args, param);
236 236 if (!arg)
237 237 return;
238 238 name = get_variable_from_key(arg, key, &sym);
239 239 if (!name || !sym)
240 240 goto free;
241 241
242 242 if (!is_impossible_path()) {
243 243 sm = get_sm_state(my_id, name, sym);
244 244 if (sm && slist_has_state(sm->possible, &freed)) {
245 245 sm_warning("'%s' double freed", name);
246 246 set_state(my_id, name, sym, &ok); /* fixme: doesn't silence anything. I know */
247 247 }
248 248 }
249 249
250 250 set_state(my_id, name, sym, &freed);
251 251 free:
252 252 free_string(name);
253 253 }
254 254
255 255 int parent_is_free_var_sym_strict(const char *name, struct symbol *sym)
256 256 {
257 257 char buf[256];
258 258 char *start;
259 259 char *end;
260 260 struct smatch_state *state;
261 261
262 262 strncpy(buf, name, sizeof(buf) - 1);
263 263 buf[sizeof(buf) - 1] = '\0';
264 264
265 265 start = &buf[0];
266 266 while ((*start == '&'))
267 267 start++;
268 268
269 269 while ((end = strrchr(start, '-'))) {
270 270 *end = '\0';
271 271 state = __get_state(my_id, start, sym);
272 272 if (state == &freed)
273 273 return 1;
274 274 }
275 275 return 0;
276 276 }
277 277
278 278 int parent_is_free_strict(struct expression *expr)
279 279 {
280 280 struct symbol *sym;
281 281 char *var;
282 282 int ret = 0;
283 283
↓ open down ↓ |
283 lines elided |
↑ open up ↑ |
284 284 expr = strip_expr(expr);
285 285 var = expr_to_var_sym(expr, &sym);
286 286 if (!var || !sym)
287 287 goto free;
288 288 ret = parent_is_free_var_sym_strict(var, sym);
289 289 free:
290 290 free_string(var);
291 291 return ret;
292 292 }
293 293
294 +static void match_untracked(struct expression *call, int param)
295 +{
296 + struct state_list *slist = NULL;
297 + struct expression *arg;
298 + struct sm_state *sm;
299 + char *name;
300 + char buf[64];
301 + int len;
302 +
303 + arg = get_argument_from_call_expr(call->args, param);
304 + if (!arg)
305 + return;
306 +
307 + name = expr_to_var(arg);
308 + if (!name)
309 + return;
310 + snprintf(buf, sizeof(buf), "%s->", name);
311 + free_string(name);
312 + len = strlen(buf);
313 +
314 + FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
315 + if (strncmp(sm->name, buf, len) == 0)
316 + add_ptr_list(&slist, sm);
317 + } END_FOR_EACH_SM(sm);
318 +
319 + FOR_EACH_PTR(slist, sm) {
320 + set_state(sm->owner, sm->name, sm->sym, &ok);
321 + } END_FOR_EACH_PTR(sm);
322 +
323 + free_slist(&slist);
324 +}
325 +
294 326 void check_free_strict(int id)
295 327 {
296 328 my_id = id;
297 329
298 330 if (option_project != PROJ_KERNEL)
299 331 return;
300 332
301 333 add_function_hook("kfree", &match_free, INT_PTR(0));
302 334 add_function_hook("kmem_cache_free", &match_free, INT_PTR(1));
303 335
304 336 if (option_spammy)
305 337 add_hook(&match_symbol, SYM_HOOK);
306 338 add_hook(&match_dereferences, DEREF_HOOK);
307 339 add_hook(&match_call, FUNCTION_CALL_HOOK);
308 340 add_hook(&match_return, RETURN_HOOK);
309 341
310 342 add_modification_hook_late(my_id, &ok_to_use);
311 343 add_pre_merge_hook(my_id, &pre_merge_hook);
312 344
313 345 select_return_states_hook(PARAM_FREED, &set_param_freed);
346 + add_untracked_param_hook(&match_untracked);
314 347 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX