Print this page
new smatch
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/tools/smatch/src/check_uninitialized.c
+++ new/usr/src/tools/smatch/src/check_uninitialized.c
1 1 /*
2 2 * Copyright (C) 2014 Oracle.
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 */
↓ open down ↓ |
16 lines elided |
↑ open up ↑ |
17 17
18 18 #include "smatch.h"
19 19 #include "smatch_slist.h"
20 20 #include "smatch_extra.h"
21 21
22 22 static int my_id;
23 23
24 24 STATE(uninitialized);
25 25 STATE(initialized);
26 26
27 -static void pre_merge_hook(struct sm_state *sm)
27 +static void pre_merge_hook(struct sm_state *cur, struct sm_state *other)
28 28 {
29 29 if (is_impossible_path())
30 - set_state(my_id, sm->name, sm->sym, &initialized);
30 + set_state(my_id, cur->name, cur->sym, &initialized);
31 31 }
32 32
33 33 static void mark_members_uninitialized(struct symbol *sym)
34 34 {
35 35 struct symbol *struct_type, *tmp, *base_type;
36 36 char buf[256];
37 37
38 38 struct_type = get_real_base_type(sym);
39 39 FOR_EACH_PTR(struct_type->symbol_list, tmp) {
40 40 if (!tmp->ident)
41 41 continue;
42 42 base_type = get_real_base_type(tmp);
43 43 if (!base_type ||
44 44 base_type->type == SYM_STRUCT ||
45 45 base_type->type == SYM_ARRAY ||
46 46 base_type->type == SYM_UNION)
47 47 continue;
48 48 snprintf(buf, sizeof(buf), "%s.%s", sym->ident->name, tmp->ident->name);
49 49 set_state(my_id, buf, sym, &uninitialized);
50 50 } END_FOR_EACH_PTR(tmp);
51 51 }
52 52
53 53 static void match_declarations(struct symbol *sym)
54 54 {
55 55 struct symbol *type;
56 56
57 57 if (sym->initializer)
58 58 return;
59 59
60 60 type = get_real_base_type(sym);
61 61 /* Smatch is crap at tracking arrays */
62 62 if (type->type == SYM_ARRAY)
63 63 return;
64 64 if (type->type == SYM_UNION)
65 65 return;
66 66 if (sym->ctype.modifiers & MOD_STATIC)
67 67 return;
68 68
69 69 if (!sym->ident)
70 70 return;
71 71
72 72 if (type->type == SYM_STRUCT) {
73 73 mark_members_uninitialized(sym);
74 74 return;
75 75 }
76 76
77 77 set_state(my_id, sym->ident->name, sym, &uninitialized);
78 78 }
79 79
80 80 static void extra_mod_hook(const char *name, struct symbol *sym, struct expression *expr, struct smatch_state *state)
81 81 {
82 82 if (!sym || !sym->ident)
83 83 return;
84 84 if (strcmp(name, sym->ident->name) != 0)
85 85 return;
86 86 set_state(my_id, name, sym, &initialized);
87 87 }
88 88
89 89 static void match_assign(struct expression *expr)
90 90 {
91 91 struct expression *right;
92 92
93 93 right = strip_expr(expr->right);
94 94 if (right->type == EXPR_PREOP && right->op == '&')
95 95 set_state_expr(my_id, right->unop, &initialized);
96 96 }
97 97
98 98 static void match_negative_comparison(struct expression *expr)
99 99 {
100 100 struct expression *success;
101 101 struct sm_state *sm;
102 102 sval_t max;
103 103
104 104 /*
105 105 * In the kernel, people don't use "if (ret) {" and "if (ret < 0) {"
↓ open down ↓ |
65 lines elided |
↑ open up ↑ |
106 106 * consistently. Ideally Smatch would know the return but often it
107 107 * doesn't.
108 108 *
109 109 */
110 110
111 111 if (option_project != PROJ_KERNEL)
112 112 return;
113 113
114 114 if (expr->type != EXPR_COMPARE || expr->op != '<')
115 115 return;
116 - if (!is_zero(expr->right))
116 + if (!expr_is_zero(expr->right))
117 117 return;
118 118 if (get_implied_max(expr->left, &max) && max.value == 0)
119 119 return;
120 120
121 121 success = compare_expression(expr->left, SPECIAL_EQUAL, expr->right);
122 122 if (!assume(success))
123 123 return;
124 124
125 125 FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
126 126 if (sm->state == &initialized)
127 127 set_true_false_states(my_id, sm->name, sm->sym, NULL, &initialized);
128 128 } END_FOR_EACH_SM(sm);
129 129
130 130 end_assume();
131 131 }
132 132
133 133 static int is_initialized(struct expression *expr)
134 134 {
135 135 struct sm_state *sm;
136 136
137 137 expr = strip_expr(expr);
138 138 if (expr->type != EXPR_SYMBOL)
139 139 return 1;
140 140 sm = get_sm_state_expr(my_id, expr);
141 141 if (!sm)
142 142 return 1;
143 143 if (!slist_has_state(sm->possible, &uninitialized))
144 144 return 1;
145 145 return 0;
146 146 }
147 147
148 148 static void match_dereferences(struct expression *expr)
149 149 {
150 150 char *name;
151 151
152 152 if (implications_off || parse_error)
153 153 return;
154 154
155 155 if (expr->type != EXPR_PREOP)
156 156 return;
157 157 if (is_impossible_path())
158 158 return;
159 159 if (is_initialized(expr->unop))
160 160 return;
161 161
162 162 name = expr_to_str(expr->unop);
163 163 sm_error("potentially dereferencing uninitialized '%s'.", name);
164 164 free_string(name);
165 165
166 166 set_state_expr(my_id, expr->unop, &initialized);
167 167 }
168 168
169 169 static void match_condition(struct expression *expr)
170 170 {
171 171 char *name;
172 172
173 173 if (implications_off || parse_error)
174 174 return;
175 175
176 176 if (is_impossible_path())
177 177 return;
178 178
179 179 if (is_initialized(expr))
180 180 return;
181 181
182 182 name = expr_to_str(expr);
183 183 sm_error("potentially using uninitialized '%s'.", name);
184 184 free_string(name);
185 185
186 186 set_state_expr(my_id, expr, &initialized);
187 187 }
188 188
189 189 static void match_call(struct expression *expr)
190 190 {
191 191 struct expression *arg;
192 192 char *name;
193 193
194 194 if (parse_error)
195 195 return;
196 196
197 197 if (is_impossible_path())
198 198 return;
199 199
200 200 FOR_EACH_PTR(expr->args, arg) {
201 201 if (is_initialized(arg))
202 202 continue;
203 203
204 204 name = expr_to_str(arg);
205 205 sm_warning("passing uninitialized '%s'", name);
206 206 free_string(name);
207 207
208 208 set_state_expr(my_id, arg, &initialized);
209 209 } END_FOR_EACH_PTR(arg);
210 210 }
211 211
212 212 static int param_used_callback(void *found, int argc, char **argv, char **azColName)
213 213 {
214 214 *(int *)found = 1;
215 215 return 0;
216 216 }
217 217
218 218 static int member_is_used(struct expression *call, int param, char *printed_name)
219 219 {
220 220 int found;
221 221
222 222 /* for function pointers assume everything is used */
223 223 if (call->fn->type != EXPR_SYMBOL)
224 224 return 0;
225 225
226 226 found = 0;
227 227 run_sql(¶m_used_callback, &found,
228 228 "select * from return_implies where %s and type = %d and parameter = %d and key = '%s';",
229 229 get_static_filter(call->fn->symbol), PARAM_USED, param, printed_name);
230 230 return found;
231 231 }
232 232
233 233 static void match_call_struct_members(struct expression *expr)
234 234 {
235 235 struct symbol *type, *sym;
236 236 struct expression *arg;
237 237 struct sm_state *sm;
238 238 char *arg_name;
239 239 char buf[256];
240 240 int param;
241 241
242 242 return;
243 243
244 244 if (parse_error)
245 245 return;
246 246
247 247 param = -1;
248 248 FOR_EACH_PTR(expr->args, arg) {
249 249 param++;
250 250 if (arg->type != EXPR_PREOP || arg->op != '&')
251 251 continue;
252 252 type = get_type(arg->unop);
253 253 if (!type || type->type != SYM_STRUCT)
254 254 continue;
255 255 arg_name = expr_to_var_sym(arg->unop, &sym);
256 256 if (!arg_name || !sym)
257 257 goto free;
258 258 FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
259 259 if (sm->sym != sym)
260 260 continue;
261 261 if (!slist_has_state(sm->possible, &uninitialized))
262 262 continue;
263 263 snprintf(buf, sizeof(buf), "$->%s", sm->name + strlen(arg_name) + 1);
264 264 if (!member_is_used(expr, param, buf))
265 265 goto free;
266 266 sm_warning("struct member %s is uninitialized", sm->name);
267 267 } END_FOR_EACH_SM(sm);
268 268
269 269 free:
270 270 free_string(arg_name);
271 271 } END_FOR_EACH_PTR(arg);
272 272 }
273 273
274 274 static int is_being_modified(struct expression *expr)
275 275 {
276 276 struct expression *parent;
277 277 struct statement *stmt;
278 278
279 279 parent = expr_get_parent_expr(expr);
280 280 if (!parent)
281 281 return 0;
282 282 while (parent->type == EXPR_PREOP && parent->op == '(') {
283 283 parent = expr_get_parent_expr(parent);
284 284 if (!parent)
285 285 return 0;
286 286 }
287 287 if (parent->type == EXPR_PREOP && parent->op == '&')
288 288 return 1;
289 289 if (parent->type == EXPR_ASSIGNMENT && expr_equiv(parent->left, expr))
290 290 return 1;
291 291
292 292 stmt = last_ptr_list((struct ptr_list *)big_statement_stack);
293 293 if (stmt && stmt->type == STMT_ASM)
294 294 return 1;
295 295
296 296 return 0;
297 297 }
298 298
299 299 static void match_symbol(struct expression *expr)
300 300 {
301 301 char *name;
302 302
303 303 if (implications_off || parse_error)
304 304 return;
305 305
306 306 if (is_impossible_path())
307 307 return;
308 308
309 309 if (is_initialized(expr))
310 310 return;
311 311
312 312 if (is_being_modified(expr))
313 313 return;
314 314
315 315 name = expr_to_str(expr);
316 316 sm_error("uninitialized symbol '%s'.", name);
317 317 free_string(name);
318 318
319 319 set_state_expr(my_id, expr, &initialized);
320 320 }
321 321
322 322 static void match_untracked(struct expression *call, int param)
323 323 {
324 324 struct expression *arg;
325 325
326 326 arg = get_argument_from_call_expr(call->args, param);
327 327 arg = strip_expr(arg);
328 328 if (!arg || arg->type != EXPR_PREOP || arg->op != '&')
329 329 return;
330 330 arg = strip_expr(arg->unop);
331 331 set_state_expr(my_id, arg, &initialized);
332 332 }
333 333
334 334 static void match_ignore_param(const char *fn, struct expression *expr, void *_arg_nr)
335 335 {
336 336 int arg_nr = PTR_INT(_arg_nr);
337 337 struct expression *arg;
338 338
339 339 arg = get_argument_from_call_expr(expr->args, arg_nr);
340 340 arg = strip_expr(arg);
341 341 if (!arg)
342 342 return;
343 343 if (arg->type != EXPR_PREOP || arg->op != '&')
344 344 return;
345 345 arg = strip_expr(arg->unop);
346 346 set_state_expr(my_id, arg, &initialized);
347 347 }
348 348
349 349 static void register_ignored_params_from_file(void)
350 350 {
351 351 char name[256];
352 352 struct token *token;
353 353 const char *func;
354 354 char prev_func[256];
355 355 int param;
356 356
357 357 memset(prev_func, 0, sizeof(prev_func));
358 358 snprintf(name, 256, "%s.ignore_uninitialized_param", option_project_str);
359 359 name[255] = '\0';
360 360 token = get_tokens_file(name);
361 361 if (!token)
362 362 return;
363 363 if (token_type(token) != TOKEN_STREAMBEGIN)
364 364 return;
365 365 token = token->next;
366 366 while (token_type(token) != TOKEN_STREAMEND) {
367 367 if (token_type(token) != TOKEN_IDENT)
368 368 return;
369 369 func = show_ident(token->ident);
370 370
371 371 token = token->next;
372 372 if (token_type(token) != TOKEN_NUMBER)
373 373 return;
374 374 param = atoi(token->number);
375 375
376 376 add_function_hook(func, &match_ignore_param, INT_PTR(param));
377 377
378 378 token = token->next;
379 379 }
380 380 clear_token_alloc();
381 381 }
382 382
383 383 void check_uninitialized(int id)
384 384 {
385 385 my_id = id;
386 386
387 387 add_hook(&match_declarations, DECLARATION_HOOK);
388 388 add_extra_mod_hook(&extra_mod_hook);
389 389 add_hook(&match_assign, ASSIGNMENT_HOOK);
390 390 add_hook(&match_negative_comparison, CONDITION_HOOK);
391 391 add_untracked_param_hook(&match_untracked);
392 392 add_pre_merge_hook(my_id, &pre_merge_hook);
393 393
394 394 add_hook(&match_dereferences, DEREF_HOOK);
395 395 add_hook(&match_condition, CONDITION_HOOK);
396 396 add_hook(&match_call, FUNCTION_CALL_HOOK);
397 397 add_hook(&match_call_struct_members, FUNCTION_CALL_HOOK);
398 398 add_hook(&match_symbol, SYM_HOOK);
399 399
400 400 register_ignored_params_from_file();
401 401 }
↓ open down ↓ |
275 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX