2 * Copyright (C) 2014 Oracle.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
19 #include "smatch_slist.h"
20 #include "smatch_extra.h"
27 static void pre_merge_hook(struct sm_state
*cur
, struct sm_state
*other
)
29 if (is_impossible_path())
30 set_state(my_id
, cur
->name
, cur
->sym
, &initialized
);
33 static void mark_members_uninitialized(struct symbol
*sym
)
35 struct symbol
*struct_type
, *tmp
, *base_type
;
38 struct_type
= get_real_base_type(sym
);
39 FOR_EACH_PTR(struct_type
->symbol_list
, tmp
) {
42 base_type
= get_real_base_type(tmp
);
44 base_type
->type
== SYM_STRUCT
||
45 base_type
->type
== SYM_ARRAY
||
46 base_type
->type
== SYM_UNION
)
48 snprintf(buf
, sizeof(buf
), "%s.%s", sym
->ident
->name
, tmp
->ident
->name
);
49 set_state(my_id
, buf
, sym
, &uninitialized
);
50 } END_FOR_EACH_PTR(tmp
);
53 static void match_declarations(struct symbol
*sym
)
60 type
= get_real_base_type(sym
);
61 /* Smatch is crap at tracking arrays */
62 if (type
->type
== SYM_ARRAY
)
64 if (type
->type
== SYM_UNION
)
66 if (sym
->ctype
.modifiers
& MOD_STATIC
)
72 if (type
->type
== SYM_STRUCT
) {
73 mark_members_uninitialized(sym
);
77 set_state(my_id
, sym
->ident
->name
, sym
, &uninitialized
);
80 static void extra_mod_hook(const char *name
, struct symbol
*sym
, struct expression
*expr
, struct smatch_state
*state
)
82 if (!sym
|| !sym
->ident
)
84 if (strcmp(name
, sym
->ident
->name
) != 0)
86 set_state(my_id
, name
, sym
, &initialized
);
89 static void match_assign(struct expression
*expr
)
91 struct expression
*right
;
93 right
= strip_expr(expr
->right
);
94 if (right
->type
== EXPR_PREOP
&& right
->op
== '&')
95 set_state_expr(my_id
, right
->unop
, &initialized
);
98 static void match_negative_comparison(struct expression
*expr
)
100 struct expression
*success
;
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
111 if (option_project
!= PROJ_KERNEL
)
114 if (expr
->type
!= EXPR_COMPARE
|| expr
->op
!= '<')
116 if (!expr_is_zero(expr
->right
))
118 if (get_implied_max(expr
->left
, &max
) && max
.value
== 0)
121 success
= compare_expression(expr
->left
, SPECIAL_EQUAL
, expr
->right
);
122 if (!assume(success
))
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
);
133 static int is_initialized(struct expression
*expr
)
137 expr
= strip_expr(expr
);
138 if (expr
->type
!= EXPR_SYMBOL
)
140 sm
= get_sm_state_expr(my_id
, expr
);
143 if (!slist_has_state(sm
->possible
, &uninitialized
))
148 static void match_dereferences(struct expression
*expr
)
152 if (implications_off
|| parse_error
)
155 if (expr
->type
!= EXPR_PREOP
)
157 if (is_impossible_path())
159 if (is_initialized(expr
->unop
))
162 name
= expr_to_str(expr
->unop
);
163 sm_error("potentially dereferencing uninitialized '%s'.", name
);
166 set_state_expr(my_id
, expr
->unop
, &initialized
);
169 static void match_condition(struct expression
*expr
)
173 if (implications_off
|| parse_error
)
176 if (is_impossible_path())
179 if (is_initialized(expr
))
182 name
= expr_to_str(expr
);
183 sm_error("potentially using uninitialized '%s'.", name
);
186 set_state_expr(my_id
, expr
, &initialized
);
189 static void match_call(struct expression
*expr
)
191 struct expression
*arg
;
197 if (is_impossible_path())
200 FOR_EACH_PTR(expr
->args
, arg
) {
201 if (is_initialized(arg
))
204 name
= expr_to_str(arg
);
205 sm_warning("passing uninitialized '%s'", name
);
208 set_state_expr(my_id
, arg
, &initialized
);
209 } END_FOR_EACH_PTR(arg
);
212 static int param_used_callback(void *found
, int argc
, char **argv
, char **azColName
)
218 static int member_is_used(struct expression
*call
, int param
, char *printed_name
)
222 /* for function pointers assume everything is used */
223 if (call
->fn
->type
!= EXPR_SYMBOL
)
227 run_sql(¶m_used_callback
, &found
,
228 "select * from return_implies where %s and type = %d and parameter = %d and key = '%s';",
229 get_static_filter(call
->fn
->symbol
), PARAM_USED
, param
, printed_name
);
233 static void match_call_struct_members(struct expression
*expr
)
235 struct symbol
*type
, *sym
;
236 struct expression
*arg
;
248 FOR_EACH_PTR(expr
->args
, arg
) {
250 if (arg
->type
!= EXPR_PREOP
|| arg
->op
!= '&')
252 type
= get_type(arg
->unop
);
253 if (!type
|| type
->type
!= SYM_STRUCT
)
255 arg_name
= expr_to_var_sym(arg
->unop
, &sym
);
256 if (!arg_name
|| !sym
)
258 FOR_EACH_MY_SM(my_id
, __get_cur_stree(), sm
) {
261 if (!slist_has_state(sm
->possible
, &uninitialized
))
263 snprintf(buf
, sizeof(buf
), "$->%s", sm
->name
+ strlen(arg_name
) + 1);
264 if (!member_is_used(expr
, param
, buf
))
266 sm_warning("struct member %s is uninitialized", sm
->name
);
267 } END_FOR_EACH_SM(sm
);
270 free_string(arg_name
);
271 } END_FOR_EACH_PTR(arg
);
274 static int is_being_modified(struct expression
*expr
)
276 struct expression
*parent
;
277 struct statement
*stmt
;
279 parent
= expr_get_parent_expr(expr
);
282 while (parent
->type
== EXPR_PREOP
&& parent
->op
== '(') {
283 parent
= expr_get_parent_expr(parent
);
287 if (parent
->type
== EXPR_PREOP
&& parent
->op
== '&')
289 if (parent
->type
== EXPR_ASSIGNMENT
&& expr_equiv(parent
->left
, expr
))
292 stmt
= last_ptr_list((struct ptr_list
*)big_statement_stack
);
293 if (stmt
&& stmt
->type
== STMT_ASM
)
299 static void match_symbol(struct expression
*expr
)
303 if (implications_off
|| parse_error
)
306 if (is_impossible_path())
309 if (is_initialized(expr
))
312 if (is_being_modified(expr
))
315 name
= expr_to_str(expr
);
316 sm_error("uninitialized symbol '%s'.", name
);
319 set_state_expr(my_id
, expr
, &initialized
);
322 static void match_untracked(struct expression
*call
, int param
)
324 struct expression
*arg
;
326 arg
= get_argument_from_call_expr(call
->args
, param
);
327 arg
= strip_expr(arg
);
328 if (!arg
|| arg
->type
!= EXPR_PREOP
|| arg
->op
!= '&')
330 arg
= strip_expr(arg
->unop
);
331 set_state_expr(my_id
, arg
, &initialized
);
334 static void match_ignore_param(const char *fn
, struct expression
*expr
, void *_arg_nr
)
336 int arg_nr
= PTR_INT(_arg_nr
);
337 struct expression
*arg
;
339 arg
= get_argument_from_call_expr(expr
->args
, arg_nr
);
340 arg
= strip_expr(arg
);
343 if (arg
->type
!= EXPR_PREOP
|| arg
->op
!= '&')
345 arg
= strip_expr(arg
->unop
);
346 set_state_expr(my_id
, arg
, &initialized
);
349 static void register_ignored_params_from_file(void)
357 memset(prev_func
, 0, sizeof(prev_func
));
358 snprintf(name
, 256, "%s.ignore_uninitialized_param", option_project_str
);
360 token
= get_tokens_file(name
);
363 if (token_type(token
) != TOKEN_STREAMBEGIN
)
366 while (token_type(token
) != TOKEN_STREAMEND
) {
367 if (token_type(token
) != TOKEN_IDENT
)
369 func
= show_ident(token
->ident
);
372 if (token_type(token
) != TOKEN_NUMBER
)
374 param
= atoi(token
->number
);
376 add_function_hook(func
, &match_ignore_param
, INT_PTR(param
));
383 void check_uninitialized(int id
)
387 add_hook(&match_declarations
, DECLARATION_HOOK
);
388 add_extra_mod_hook(&extra_mod_hook
);
389 add_hook(&match_assign
, ASSIGNMENT_HOOK
);
390 add_hook(&match_negative_comparison
, CONDITION_HOOK
);
391 add_untracked_param_hook(&match_untracked
);
392 add_pre_merge_hook(my_id
, &pre_merge_hook
);
394 add_hook(&match_dereferences
, DEREF_HOOK
);
395 add_hook(&match_condition
, CONDITION_HOOK
);
396 add_hook(&match_call
, FUNCTION_CALL_HOOK
);
397 add_hook(&match_call_struct_members
, FUNCTION_CALL_HOOK
);
398 add_hook(&match_symbol
, SYM_HOOK
);
400 register_ignored_params_from_file();