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 (__in_fake_struct_assign
)
84 if (expr
&& expr
->smatch_flags
& Fake
)
86 if (!sym
|| !sym
->ident
)
88 if (strcmp(name
, sym
->ident
->name
) != 0)
90 set_state(my_id
, name
, sym
, &initialized
);
93 static void match_assign(struct expression
*expr
)
95 struct expression
*right
;
97 right
= strip_expr(expr
->right
);
98 if (right
->type
== EXPR_PREOP
&& right
->op
== '&')
99 set_state_expr(my_id
, right
->unop
, &initialized
);
102 static void match_negative_comparison(struct expression
*expr
)
104 struct expression
*success
;
109 * In the kernel, people don't use "if (ret) {" and "if (ret < 0) {"
110 * consistently. Ideally Smatch would know the return but often it
115 if (option_project
!= PROJ_KERNEL
)
118 if (expr
->type
!= EXPR_COMPARE
|| expr
->op
!= '<')
120 if (!expr_is_zero(expr
->right
))
122 if (get_implied_max(expr
->left
, &max
) && max
.value
== 0)
125 success
= compare_expression(expr
->left
, SPECIAL_EQUAL
, expr
->right
);
126 if (!assume(success
))
129 FOR_EACH_MY_SM(my_id
, __get_cur_stree(), sm
) {
130 if (sm
->state
== &initialized
)
131 set_true_false_states(my_id
, sm
->name
, sm
->sym
, NULL
, &initialized
);
132 } END_FOR_EACH_SM(sm
);
137 static int is_initialized(struct expression
*expr
)
141 expr
= strip_expr(expr
);
142 if (expr
->type
!= EXPR_SYMBOL
)
144 sm
= get_sm_state_expr(my_id
, expr
);
147 if (!slist_has_state(sm
->possible
, &uninitialized
))
152 static void match_dereferences(struct expression
*expr
)
156 if (implications_off
|| parse_error
)
159 if (expr
->type
!= EXPR_PREOP
)
161 if (is_impossible_path())
163 if (is_initialized(expr
->unop
))
166 name
= expr_to_str(expr
->unop
);
167 sm_error("potentially dereferencing uninitialized '%s'.", name
);
170 set_state_expr(my_id
, expr
->unop
, &initialized
);
173 static void match_condition(struct expression
*expr
)
177 if (implications_off
|| parse_error
)
180 if (is_impossible_path())
183 if (is_initialized(expr
))
186 name
= expr_to_str(expr
);
187 sm_error("potentially using uninitialized '%s'.", name
);
190 set_state_expr(my_id
, expr
, &initialized
);
193 static void match_call(struct expression
*expr
)
195 struct expression
*arg
;
201 if (is_impossible_path())
204 FOR_EACH_PTR(expr
->args
, arg
) {
205 if (is_initialized(arg
))
208 name
= expr_to_str(arg
);
209 sm_warning("passing uninitialized '%s'", name
);
212 set_state_expr(my_id
, arg
, &initialized
);
213 } END_FOR_EACH_PTR(arg
);
216 static int param_used_callback(void *found
, int argc
, char **argv
, char **azColName
)
222 static int member_is_used(struct expression
*call
, int param
, char *printed_name
)
226 /* for function pointers assume everything is used */
227 if (call
->fn
->type
!= EXPR_SYMBOL
)
231 run_sql(¶m_used_callback
, &found
,
232 "select * from return_implies where %s and type = %d and parameter = %d and key = '%s';",
233 get_static_filter(call
->fn
->symbol
), PARAM_USED
, param
, printed_name
);
237 static void match_call_struct_members(struct expression
*expr
)
239 struct symbol
*type
, *sym
;
240 struct expression
*arg
;
252 FOR_EACH_PTR(expr
->args
, arg
) {
254 if (arg
->type
!= EXPR_PREOP
|| arg
->op
!= '&')
256 type
= get_type(arg
->unop
);
257 if (!type
|| type
->type
!= SYM_STRUCT
)
259 arg_name
= expr_to_var_sym(arg
->unop
, &sym
);
260 if (!arg_name
|| !sym
)
262 FOR_EACH_MY_SM(my_id
, __get_cur_stree(), sm
) {
265 if (!slist_has_state(sm
->possible
, &uninitialized
))
267 snprintf(buf
, sizeof(buf
), "$->%s", sm
->name
+ strlen(arg_name
) + 1);
268 if (!member_is_used(expr
, param
, buf
))
270 sm_warning("struct member %s is uninitialized", sm
->name
);
271 } END_FOR_EACH_SM(sm
);
274 free_string(arg_name
);
275 } END_FOR_EACH_PTR(arg
);
278 static int is_being_modified(struct expression
*expr
)
280 struct expression
*parent
;
281 struct statement
*stmt
;
283 parent
= expr_get_parent_expr(expr
);
286 while (parent
->type
== EXPR_PREOP
&& parent
->op
== '(') {
287 parent
= expr_get_parent_expr(parent
);
291 if (parent
->type
== EXPR_PREOP
&& parent
->op
== '&')
293 if (parent
->type
== EXPR_ASSIGNMENT
&& expr_equiv(parent
->left
, expr
))
296 stmt
= last_ptr_list((struct ptr_list
*)big_statement_stack
);
297 if (stmt
&& stmt
->type
== STMT_ASM
)
303 static void match_symbol(struct expression
*expr
)
307 if (implications_off
|| parse_error
)
310 if (is_impossible_path())
313 if (is_initialized(expr
))
316 if (is_being_modified(expr
))
319 name
= expr_to_str(expr
);
320 sm_error("uninitialized symbol '%s'.", name
);
323 set_state_expr(my_id
, expr
, &initialized
);
326 static void match_untracked(struct expression
*call
, int param
)
328 struct expression
*arg
;
330 arg
= get_argument_from_call_expr(call
->args
, param
);
331 arg
= strip_expr(arg
);
332 if (!arg
|| arg
->type
!= EXPR_PREOP
|| arg
->op
!= '&')
334 arg
= strip_expr(arg
->unop
);
335 set_state_expr(my_id
, arg
, &initialized
);
338 static void match_ignore_param(const char *fn
, struct expression
*expr
, void *_arg_nr
)
340 int arg_nr
= PTR_INT(_arg_nr
);
341 struct expression
*arg
;
343 arg
= get_argument_from_call_expr(expr
->args
, arg_nr
);
344 arg
= strip_expr(arg
);
347 if (arg
->type
!= EXPR_PREOP
|| arg
->op
!= '&')
349 arg
= strip_expr(arg
->unop
);
350 set_state_expr(my_id
, arg
, &initialized
);
353 static void register_ignored_params_from_file(void)
361 memset(prev_func
, 0, sizeof(prev_func
));
362 snprintf(name
, 256, "%s.ignore_uninitialized_param", option_project_str
);
364 token
= get_tokens_file(name
);
367 if (token_type(token
) != TOKEN_STREAMBEGIN
)
370 while (token_type(token
) != TOKEN_STREAMEND
) {
371 if (token_type(token
) != TOKEN_IDENT
)
373 func
= show_ident(token
->ident
);
376 if (token_type(token
) != TOKEN_NUMBER
)
378 param
= atoi(token
->number
);
380 add_function_hook(func
, &match_ignore_param
, INT_PTR(param
));
387 void check_uninitialized(int id
)
391 add_hook(&match_declarations
, DECLARATION_HOOK
);
392 add_extra_mod_hook(&extra_mod_hook
);
393 add_hook(&match_assign
, ASSIGNMENT_HOOK
);
394 add_hook(&match_negative_comparison
, CONDITION_HOOK
);
395 add_untracked_param_hook(&match_untracked
);
396 add_pre_merge_hook(my_id
, &pre_merge_hook
);
398 add_hook(&match_dereferences
, DEREF_HOOK
);
399 add_hook(&match_condition
, CONDITION_HOOK
);
400 add_hook(&match_call
, FUNCTION_CALL_HOOK
);
401 add_hook(&match_call_struct_members
, FUNCTION_CALL_HOOK
);
402 add_hook(&match_symbol
, SYM_HOOK
);
404 register_ignored_params_from_file();