2 * smatch/smatch_clear_structs.c
4 * Copyright (C) 2013 Oracle.
6 * Licensed under the Open Software License version 1.1
11 #include "smatch_slist.h"
12 #include "smatch_extra.h"
19 static int type_sym_array(struct expression
*expr
)
23 /* remove casting the array to a pointer */
24 expr
= strip_expr(expr
);
25 type
= get_type(expr
);
26 if (type
&& type
->type
== SYM_ARRAY
)
31 static void set_members_uninitialized(struct expression
*expr
)
33 struct symbol
*type
, *sym
, *tmp
;
37 type
= get_type(expr
);
41 if (type
->type
!= SYM_PTR
)
43 type
= get_real_base_type(type
);
45 name
= expr_to_var_sym(expr
, &sym
);
49 FOR_EACH_PTR(type
->symbol_list
, tmp
) {
52 snprintf(buf
, sizeof(buf
), "%s->%s", name
, tmp
->ident
->name
);
53 set_state(my_id
, buf
, sym
, &uninitialized
);
54 } END_FOR_EACH_PTR(tmp
);
60 static void initialize_struct_members(struct symbol
*type
, struct expression
*expr
, struct expression
*to
)
63 struct expression
*member
;
64 struct expression
*assign
;
67 if (expr
->type
== EXPR_PREOP
&& expr
->op
== '&') {
68 expr
= strip_expr(expr
->unop
);
72 FOR_EACH_PTR(type
->symbol_list
, tmp
) {
75 member
= member_expression(expr
, op
, tmp
->ident
);
76 if (type_sym_array(member
))
80 * FIXME: the problem here is that sometimes we have:
81 * memset(&my_struct, 0xff, sizeof(my_struct));
82 * and my_struct->foo is a 1 bit bitfield. There is a check
83 * which complains that "255 doesn't fit in ->foo".
85 * For now I just have this ugly hack. But really it's not
86 * handling the memset(..., 0xff, ...) correctly at all so one
87 * more hack barely makes a difference.
90 if (to
&& type_positive_bits(get_type(member
)) >= type_positive_bits(get_type(to
)))
91 assign
= assign_expression(member
, to
);
93 assign
= assign_expression(member
, member
);
96 } END_FOR_EACH_PTR(tmp
);
99 static void initialize_base_type(struct symbol
*type
, struct expression
*expr
,
100 struct expression
*to
)
102 struct expression
*assign
;
104 if (type
== &void_ctype
)
106 if (expr
->type
== EXPR_PREOP
&& expr
->op
== '&')
107 expr
= strip_expr(expr
->unop
);
109 expr
= deref_expression(expr
);
112 /* FIXME: see the FIXME in initialize_struct_members() */
113 if (type_positive_bits(get_type(expr
)) < type_positive_bits(get_type(to
)))
115 assign
= assign_expression(expr
, to
);
116 __split_expr(assign
);
119 void set_initialized(struct expression
*expr
, struct expression
*to
)
123 expr
= strip_expr(expr
);
125 type
= get_type(expr
);
126 if (!type
|| type
->type
!= SYM_PTR
)
128 type
= get_real_base_type(type
);
131 if (type
->type
== SYM_BASETYPE
)
132 initialize_base_type(type
, expr
, to
);
133 if (type
->type
== SYM_STRUCT
) {
134 if (expr
->type
!= EXPR_PREOP
|| expr
->op
!= '&')
135 expr
= deref_expression(expr
);
136 initialize_struct_members(type
, expr
, to
);
140 int is_uninitialized(struct expression
*expr
)
144 sm
= get_sm_state_expr(my_id
, expr
);
147 return slist_has_state(sm
->possible
, &uninitialized
);
150 int has_uninitialized_members(struct expression
*expr
)
158 sym
= get_type(expr
);
162 if (sym
->type
== SYM_PTR
)
163 sym
= get_real_base_type(sym
);
165 name
= expr_to_var(expr
);
169 FOR_EACH_PTR(sym
->symbol_list
, tmp
) {
172 snprintf(buf
, sizeof(buf
), "%s->%s", name
, tmp
->ident
->name
);
173 sm
= get_sm_state(my_id
, buf
, sym
);
176 if (slist_has_state(sm
->possible
, &uninitialized
))
178 } END_FOR_EACH_PTR(tmp
);
184 static void match_assign(struct expression
*expr
)
188 type
= get_type(expr
->left
);
189 if (!type
|| type
->type
!= SYM_STRUCT
)
191 initialize_struct_members(type
, expr
->left
, NULL
);
194 static void match_alloc(const char *fn
, struct expression
*expr
, void *_size_arg
)
196 set_members_uninitialized(expr
->left
);
199 static void db_param_cleared(struct expression
*expr
, int param
, char *key
, char *value
)
201 struct expression
*arg
;
203 while (expr
->type
== EXPR_ASSIGNMENT
)
204 expr
= strip_expr(expr
->right
);
205 if (expr
->type
!= EXPR_CALL
)
208 arg
= get_argument_from_call_expr(expr
->args
, param
);
212 if (strcmp(value
, "0") == 0)
213 set_initialized(arg
, zero_expr());
215 set_initialized(arg
, NULL
);
218 static void match_memset(const char *fn
, struct expression
*expr
, void *_size_arg
)
220 struct expression
*buf
;
221 struct expression
*val
;
223 buf
= get_argument_from_call_expr(expr
->args
, 0);
224 val
= get_argument_from_call_expr(expr
->args
, 1);
226 set_initialized(buf
, val
);
229 static void match_memcpy(const char *fn
, struct expression
*expr
, void *_arg
)
231 struct expression
*buf
;
232 int arg
= PTR_INT(_arg
);
234 buf
= get_argument_from_call_expr(expr
->args
, arg
);
236 set_initialized(buf
, NULL
);
239 static void reset_initialized(struct sm_state
*sm
)
241 set_state(my_id
, sm
->name
, sm
->sym
, &initialized
);
244 #define USB_DIR_IN 0x80
245 static void match_usb_control_msg(const char *fn
, struct expression
*expr
, void *_size_arg
)
247 struct expression
*inout
;
248 struct expression
*buf
;
251 inout
= get_argument_from_call_expr(expr
->args
, 3);
252 buf
= get_argument_from_call_expr(expr
->args
, 6);
254 if (get_value(inout
, &sval
) && !(sval
.uvalue
& USB_DIR_IN
))
257 set_initialized(buf
, NULL
);
260 static void register_clears_param(void)
264 const char *function
;
267 if (option_project
== PROJ_NONE
)
270 snprintf(name
, 256, "%s.clears_argument", option_project_str
);
272 token
= get_tokens_file(name
);
275 if (token_type(token
) != TOKEN_STREAMBEGIN
)
278 while (token_type(token
) != TOKEN_STREAMEND
) {
279 if (token_type(token
) != TOKEN_IDENT
)
281 function
= show_ident(token
->ident
);
283 if (token_type(token
) != TOKEN_NUMBER
)
285 param
= atoi(token
->number
);
286 add_function_hook(function
, &match_memcpy
, INT_PTR(param
));
292 void register_clear_buffer(int id
)
295 if (option_project
== PROJ_KERNEL
) {
296 add_function_assign_hook("kmalloc", &match_alloc
, NULL
);
297 add_function_hook("usb_control_msg", &match_usb_control_msg
, NULL
);
299 add_modification_hook(my_id
, &reset_initialized
);
300 add_hook(&match_assign
, ASSIGNMENT_HOOK
);
301 add_function_hook("memset", &match_memset
, NULL
);
302 add_function_hook("memcpy", &match_memcpy
, INT_PTR(0));
303 add_function_hook("memmove", &match_memcpy
, INT_PTR(0));
304 register_clears_param();
306 add_db_return_states_callback(PARAM_CLEARED
, &db_param_cleared
);