2 * Copyright (C) 2012 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 * This works together with smatch_clear_buffer.c. This one is only for
20 * tracking the information and smatch_clear_buffer.c changes SMATCH_EXTRA.
22 * This tracks functions like memset() which clear out a chunk of memory.
23 * It fills in a gap that smatch_param_set.c can't handle. It only handles
24 * void pointers because smatch_param_set.c should handle the rest. Oh. And
25 * also it handles arrays because Smatch sucks at handling arrays.
30 #include "smatch_slist.h"
31 #include "smatch_extra.h"
38 static void db_param_cleared(struct expression
*expr
, int param
, char *key
, char *value
)
40 struct expression
*arg
;
44 while (expr
->type
== EXPR_ASSIGNMENT
)
45 expr
= strip_expr(expr
->right
);
46 if (expr
->type
!= EXPR_CALL
)
49 arg
= get_argument_from_call_expr(expr
->args
, param
);
50 arg
= strip_expr(arg
);
51 name
= get_variable_from_key(arg
, key
, &sym
);
55 if (strcmp(value
, "0") == 0)
56 set_state(my_id
, name
, sym
, &zeroed
);
58 set_state(my_id
, name
, sym
, &cleared
);
63 static void match_memset(const char *fn
, struct expression
*expr
, void *arg
)
65 db_param_cleared(expr
, PTR_INT(arg
), (char *)"$", (char *)"0");
68 static void match_memcpy(const char *fn
, struct expression
*expr
, void *arg
)
70 db_param_cleared(expr
, PTR_INT(arg
), (char *)"$", (char *)"");
73 static void print_return_value_param(int return_id
, char *return_ranges
, struct expression
*expr
)
78 const char *param_name
;
80 stree
= __get_cur_stree();
82 FOR_EACH_MY_SM(my_id
, stree
, sm
) {
83 param
= get_param_num_from_sym(sm
->sym
);
87 param_name
= get_param_name(sm
);
91 if (sm
->state
== &zeroed
) {
92 sql_insert_return_states(return_id
, return_ranges
,
93 PARAM_CLEARED
, param
, param_name
, "0");
96 if (sm
->state
== &cleared
) {
97 sql_insert_return_states(return_id
, return_ranges
,
98 PARAM_CLEARED
, param
, param_name
, "");
100 } END_FOR_EACH_SM(sm
);
103 bool parent_was_PARAM_CLEAR(const char *name
, struct symbol
*sym
)
113 if (len
>= sizeof(buf
))
114 len
= sizeof(buf
) - 1;
116 for (i
= len
- 2; i
>= 1; i
--) {
117 if (name
[i
] != '-' && name
[i
] != '.')
120 memcpy(buf
, name
, i
);
122 sm
= get_sm_state(my_id
, buf
, sym
);
123 if (sm
&& sm
->state
== &cleared
)
129 memcpy(buf
+ 1, name
, i
);
131 sm
= get_sm_state(my_id
, buf
, sym
);
132 if (sm
&& sm
->state
== &cleared
)
141 bool parent_was_PARAM_CLEAR_ZERO(const char *name
, struct symbol
*sym
)
151 if (len
>= sizeof(buf
))
152 len
= sizeof(buf
) - 1;
154 for (i
= len
- 2; i
>= 1; i
--) {
155 if (name
[i
] != '-' && name
[i
] != '.')
158 memcpy(buf
, name
, i
);
160 sm
= get_sm_state(my_id
, buf
, sym
);
161 if (sm
&& sm
->state
== &zeroed
)
167 memcpy(buf
+ 1, name
, i
);
169 sm
= get_sm_state(my_id
, buf
, sym
);
170 if (sm
&& sm
->state
== &zeroed
)
179 static void register_clears_param(void)
183 const char *function
;
186 if (option_project
== PROJ_NONE
)
189 snprintf(name
, 256, "%s.clears_argument", option_project_str
);
191 token
= get_tokens_file(name
);
194 if (token_type(token
) != TOKEN_STREAMBEGIN
)
197 while (token_type(token
) != TOKEN_STREAMEND
) {
198 if (token_type(token
) != TOKEN_IDENT
)
200 function
= show_ident(token
->ident
);
202 if (token_type(token
) != TOKEN_NUMBER
)
204 param
= atoi(token
->number
);
205 add_function_hook(function
, &match_memcpy
, INT_PTR(param
));
211 #define USB_DIR_IN 0x80
212 static void match_usb_control_msg(const char *fn
, struct expression
*expr
, void *_size_arg
)
214 struct expression
*inout
;
217 inout
= get_argument_from_call_expr(expr
->args
, 3);
219 if (get_value(inout
, &sval
) && !(sval
.uvalue
& USB_DIR_IN
))
222 db_param_cleared(expr
, 6, (char *)"$", (char *)"");
225 static void match_assign(struct expression
*expr
)
230 * If we have struct foo x, y; and we say that x = y; then it
231 * initializes the struct holes. So we record that here.
233 type
= get_type(expr
->left
);
234 if (!type
|| type
->type
!= SYM_STRUCT
)
236 set_state_expr(my_id
, expr
->left
, &cleared
);
239 static void match_array_assign(struct expression
*expr
)
241 struct expression
*array_expr
;
243 if (!is_array(expr
->left
))
246 array_expr
= get_array_base(expr
->left
);
247 set_state_expr(my_id
, array_expr
, &cleared
);
250 void register_param_cleared(int id
)
254 add_function_hook("memset", &match_memset
, INT_PTR(0));
255 add_function_hook("memzero", &match_memset
, INT_PTR(0));
256 add_function_hook("__memset", &match_memset
, INT_PTR(0));
257 add_function_hook("__memzero", &match_memset
, INT_PTR(0));
259 add_function_hook("memcpy", &match_memcpy
, INT_PTR(0));
260 add_function_hook("memmove", &match_memcpy
, INT_PTR(0));
261 add_function_hook("__memcpy", &match_memcpy
, INT_PTR(0));
262 add_function_hook("__memmove", &match_memcpy
, INT_PTR(0));
263 add_function_hook("strcpy", &match_memcpy
, INT_PTR(0));
264 add_function_hook("strncpy", &match_memcpy
, INT_PTR(0));
265 add_function_hook("sprintf", &match_memcpy
, INT_PTR(0));
266 add_function_hook("snprintf", &match_memcpy
, INT_PTR(0));
268 add_hook(&match_assign
, ASSIGNMENT_HOOK
);
269 add_hook(&match_array_assign
, ASSIGNMENT_HOOK
);
271 register_clears_param();
273 select_return_states_hook(PARAM_CLEARED
, &db_param_cleared
);
274 add_split_return_callback(&print_return_value_param
);
276 if (option_project
== PROJ_KERNEL
) {
277 add_function_hook("usb_control_msg", &match_usb_control_msg
, NULL
);