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