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
*sm
)
29 if (is_impossible_path())
30 set_state(my_id
, sm
->name
, sm
->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 int is_initialized(struct expression
*expr
)
102 expr
= strip_expr(expr
);
103 if (expr
->type
!= EXPR_SYMBOL
)
105 sm
= get_sm_state_expr(my_id
, expr
);
108 if (!slist_has_state(sm
->possible
, &uninitialized
))
113 static void match_dereferences(struct expression
*expr
)
120 if (expr
->type
!= EXPR_PREOP
)
122 if (is_impossible_path())
124 if (is_initialized(expr
->unop
))
127 name
= expr_to_str(expr
->unop
);
128 sm_msg("error: potentially dereferencing uninitialized '%s'.", name
);
131 set_state_expr(my_id
, expr
->unop
, &initialized
);
134 static void match_condition(struct expression
*expr
)
141 if (is_impossible_path())
144 if (is_initialized(expr
))
147 name
= expr_to_str(expr
);
148 sm_msg("error: potentially using uninitialized '%s'.", name
);
151 set_state_expr(my_id
, expr
, &initialized
);
154 static void match_call(struct expression
*expr
)
156 struct expression
*arg
;
162 if (is_impossible_path())
165 FOR_EACH_PTR(expr
->args
, arg
) {
166 if (is_initialized(arg
))
169 name
= expr_to_str(arg
);
170 sm_msg("warn: passing uninitialized '%s'", name
);
173 set_state_expr(my_id
, arg
, &initialized
);
174 } END_FOR_EACH_PTR(arg
);
177 static int param_used_callback(void *found
, int argc
, char **argv
, char **azColName
)
183 static int member_is_used(struct expression
*call
, int param
, char *printed_name
)
187 /* for function pointers assume everything is used */
188 if (call
->fn
->type
!= EXPR_SYMBOL
)
192 run_sql(¶m_used_callback
, &found
,
193 "select * from call_implies where %s and type = %d and parameter = %d and key = '%s';",
194 get_static_filter(call
->fn
->symbol
), PARAM_USED
, param
, printed_name
);
198 static void match_call_struct_members(struct expression
*expr
)
200 struct symbol
*type
, *sym
;
201 struct expression
*arg
;
213 FOR_EACH_PTR(expr
->args
, arg
) {
215 if (arg
->type
!= EXPR_PREOP
|| arg
->op
!= '&')
217 type
= get_type(arg
->unop
);
218 if (!type
|| type
->type
!= SYM_STRUCT
)
220 arg_name
= expr_to_var_sym(arg
->unop
, &sym
);
221 if (!arg_name
|| !sym
)
223 FOR_EACH_MY_SM(my_id
, __get_cur_stree(), sm
) {
226 if (!slist_has_state(sm
->possible
, &uninitialized
))
228 snprintf(buf
, sizeof(buf
), "$->%s", sm
->name
+ strlen(arg_name
) + 1);
229 if (!member_is_used(expr
, param
, buf
))
231 sm_msg("warn: struct member %s is uninitialized", sm
->name
);
232 } END_FOR_EACH_SM(sm
);
235 free_string(arg_name
);
236 } END_FOR_EACH_PTR(arg
);
239 static int is_being_modified(struct expression
*expr
)
241 struct expression
*parent
;
242 struct statement
*stmt
;
244 parent
= expr_get_parent_expr(expr
);
247 while (parent
->type
== EXPR_PREOP
&& parent
->op
== '(')
248 parent
= expr_get_parent_expr(parent
);
249 if (parent
->type
== EXPR_PREOP
&& parent
->op
== '&')
251 if (parent
->type
== EXPR_ASSIGNMENT
&& expr_equiv(parent
->left
, expr
))
254 stmt
= last_ptr_list((struct ptr_list
*)big_statement_stack
);
255 if (stmt
&& stmt
->type
== STMT_ASM
)
261 static void match_symbol(struct expression
*expr
)
268 if (is_impossible_path())
271 if (is_initialized(expr
))
274 if (is_being_modified(expr
))
277 name
= expr_to_str(expr
);
278 sm_msg("error: uninitialized symbol '%s'.", name
);
281 set_state_expr(my_id
, expr
, &initialized
);
284 static void match_untracked(struct expression
*call
, int param
)
286 struct expression
*arg
;
288 arg
= get_argument_from_call_expr(call
->args
, param
);
289 arg
= strip_expr(arg
);
290 if (!arg
|| arg
->type
!= EXPR_PREOP
|| arg
->op
!= '&')
292 arg
= strip_expr(arg
->unop
);
293 set_state_expr(my_id
, arg
, &initialized
);
296 static void match_ignore_param(const char *fn
, struct expression
*expr
, void *_arg_nr
)
298 int arg_nr
= PTR_INT(_arg_nr
);
299 struct expression
*arg
;
301 arg
= get_argument_from_call_expr(expr
->args
, arg_nr
);
302 arg
= strip_expr(arg
);
305 if (arg
->type
!= EXPR_PREOP
|| arg
->op
!= '&')
307 arg
= strip_expr(arg
->unop
);
308 set_state_expr(my_id
, arg
, &initialized
);
311 static void register_ignored_params_from_file(void)
319 memset(prev_func
, 0, sizeof(prev_func
));
320 snprintf(name
, 256, "%s.ignore_uninitialized_param", option_project_str
);
322 token
= get_tokens_file(name
);
325 if (token_type(token
) != TOKEN_STREAMBEGIN
)
328 while (token_type(token
) != TOKEN_STREAMEND
) {
329 if (token_type(token
) != TOKEN_IDENT
)
331 func
= show_ident(token
->ident
);
334 if (token_type(token
) != TOKEN_NUMBER
)
336 param
= atoi(token
->number
);
338 add_function_hook(func
, &match_ignore_param
, INT_PTR(param
));
345 void check_uninitialized(int id
)
349 add_hook(&match_declarations
, DECLARATION_HOOK
);
350 add_extra_mod_hook(&extra_mod_hook
);
351 add_hook(&match_assign
, ASSIGNMENT_HOOK
);
352 add_untracked_param_hook(&match_untracked
);
353 add_pre_merge_hook(my_id
, &pre_merge_hook
);
355 add_hook(&match_dereferences
, DEREF_HOOK
);
356 add_hook(&match_condition
, CONDITION_HOOK
);
357 add_hook(&match_call
, FUNCTION_CALL_HOOK
);
358 add_hook(&match_call_struct_members
, FUNCTION_CALL_HOOK
);
359 add_hook(&match_symbol
, SYM_HOOK
);
361 register_ignored_params_from_file();