1*1f5207b7SJohn Levon /*
2*1f5207b7SJohn Levon  * Copyright (C) 2012 Oracle.
3*1f5207b7SJohn Levon  *
4*1f5207b7SJohn Levon  * This program is free software; you can redistribute it and/or
5*1f5207b7SJohn Levon  * modify it under the terms of the GNU General Public License
6*1f5207b7SJohn Levon  * as published by the Free Software Foundation; either version 2
7*1f5207b7SJohn Levon  * of the License, or (at your option) any later version.
8*1f5207b7SJohn Levon  *
9*1f5207b7SJohn Levon  * This program is distributed in the hope that it will be useful,
10*1f5207b7SJohn Levon  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11*1f5207b7SJohn Levon  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12*1f5207b7SJohn Levon  * GNU General Public License for more details.
13*1f5207b7SJohn Levon  *
14*1f5207b7SJohn Levon  * You should have received a copy of the GNU General Public License
15*1f5207b7SJohn Levon  * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
16*1f5207b7SJohn Levon  */
17*1f5207b7SJohn Levon 
18*1f5207b7SJohn Levon /*
19*1f5207b7SJohn Levon  * This works together with smatch_clear_buffer.c.  This one is only for
20*1f5207b7SJohn Levon  * tracking the information and smatch_clear_buffer.c changes SMATCH_EXTRA.
21*1f5207b7SJohn Levon  *
22*1f5207b7SJohn Levon  * This tracks functions like memset() which clear out a chunk of memory.
23*1f5207b7SJohn Levon  * It fills in a gap that smatch_param_set.c can't handle.  It only handles
24*1f5207b7SJohn Levon  * void pointers because smatch_param_set.c should handle the rest.  Oh.  And
25*1f5207b7SJohn Levon  * also it handles arrays because Smatch sucks at handling arrays.
26*1f5207b7SJohn Levon  */
27*1f5207b7SJohn Levon 
28*1f5207b7SJohn Levon #include "scope.h"
29*1f5207b7SJohn Levon #include "smatch.h"
30*1f5207b7SJohn Levon #include "smatch_slist.h"
31*1f5207b7SJohn Levon #include "smatch_extra.h"
32*1f5207b7SJohn Levon 
33*1f5207b7SJohn Levon static int my_id;
34*1f5207b7SJohn Levon 
35*1f5207b7SJohn Levon STATE(cleared);
36*1f5207b7SJohn Levon STATE(zeroed);
37*1f5207b7SJohn Levon 
db_param_cleared(struct expression * expr,int param,char * key,char * value)38*1f5207b7SJohn Levon static void db_param_cleared(struct expression *expr, int param, char *key, char *value)
39*1f5207b7SJohn Levon {
40*1f5207b7SJohn Levon 	struct expression *arg;
41*1f5207b7SJohn Levon 	char *name;
42*1f5207b7SJohn Levon 	struct symbol *sym;
43*1f5207b7SJohn Levon 
44*1f5207b7SJohn Levon 	while (expr->type == EXPR_ASSIGNMENT)
45*1f5207b7SJohn Levon 		expr = strip_expr(expr->right);
46*1f5207b7SJohn Levon 	if (expr->type != EXPR_CALL)
47*1f5207b7SJohn Levon 		return;
48*1f5207b7SJohn Levon 
49*1f5207b7SJohn Levon 	arg = get_argument_from_call_expr(expr->args, param);
50*1f5207b7SJohn Levon 	arg = strip_expr(arg);
51*1f5207b7SJohn Levon 	name = get_variable_from_key(arg, key, &sym);
52*1f5207b7SJohn Levon 	if (!name || !sym)
53*1f5207b7SJohn Levon 		goto free;
54*1f5207b7SJohn Levon 
55*1f5207b7SJohn Levon 	if (strcmp(value, "0") == 0)
56*1f5207b7SJohn Levon 		set_state(my_id, name, sym, &zeroed);
57*1f5207b7SJohn Levon 	else
58*1f5207b7SJohn Levon 		set_state(my_id, name, sym, &cleared);
59*1f5207b7SJohn Levon free:
60*1f5207b7SJohn Levon 	free_string(name);
61*1f5207b7SJohn Levon }
62*1f5207b7SJohn Levon 
match_memset(const char * fn,struct expression * expr,void * arg)63*1f5207b7SJohn Levon static void match_memset(const char *fn, struct expression *expr, void *arg)
64*1f5207b7SJohn Levon {
65*1f5207b7SJohn Levon 	db_param_cleared(expr, PTR_INT(arg), (char *)"$", (char *)"0");
66*1f5207b7SJohn Levon }
67*1f5207b7SJohn Levon 
match_memcpy(const char * fn,struct expression * expr,void * arg)68*1f5207b7SJohn Levon static void match_memcpy(const char *fn, struct expression *expr, void *arg)
69*1f5207b7SJohn Levon {
70*1f5207b7SJohn Levon 	db_param_cleared(expr, PTR_INT(arg), (char *)"$", (char *)"");
71*1f5207b7SJohn Levon }
72*1f5207b7SJohn Levon 
print_return_value_param(int return_id,char * return_ranges,struct expression * expr)73*1f5207b7SJohn Levon static void print_return_value_param(int return_id, char *return_ranges, struct expression *expr)
74*1f5207b7SJohn Levon {
75*1f5207b7SJohn Levon 	struct stree *stree;
76*1f5207b7SJohn Levon 	struct sm_state *sm;
77*1f5207b7SJohn Levon 	int param;
78*1f5207b7SJohn Levon 	const char *param_name;
79*1f5207b7SJohn Levon 
80*1f5207b7SJohn Levon 	stree = __get_cur_stree();
81*1f5207b7SJohn Levon 
82*1f5207b7SJohn Levon 	FOR_EACH_MY_SM(my_id, stree, sm) {
83*1f5207b7SJohn Levon 		param = get_param_num_from_sym(sm->sym);
84*1f5207b7SJohn Levon 		if (param < 0)
85*1f5207b7SJohn Levon 			continue;
86*1f5207b7SJohn Levon 
87*1f5207b7SJohn Levon 		param_name = get_param_name(sm);
88*1f5207b7SJohn Levon 		if (!param_name)
89*1f5207b7SJohn Levon 			continue;
90*1f5207b7SJohn Levon 
91*1f5207b7SJohn Levon 		if (sm->state == &zeroed) {
92*1f5207b7SJohn Levon 			sql_insert_return_states(return_id, return_ranges,
93*1f5207b7SJohn Levon 						 PARAM_CLEARED, param, param_name, "0");
94*1f5207b7SJohn Levon 		}
95*1f5207b7SJohn Levon 
96*1f5207b7SJohn Levon 		if (sm->state == &cleared) {
97*1f5207b7SJohn Levon 			sql_insert_return_states(return_id, return_ranges,
98*1f5207b7SJohn Levon 						 PARAM_CLEARED, param, param_name, "");
99*1f5207b7SJohn Levon 		}
100*1f5207b7SJohn Levon 	} END_FOR_EACH_SM(sm);
101*1f5207b7SJohn Levon }
102*1f5207b7SJohn Levon 
register_clears_param(void)103*1f5207b7SJohn Levon static void register_clears_param(void)
104*1f5207b7SJohn Levon {
105*1f5207b7SJohn Levon 	struct token *token;
106*1f5207b7SJohn Levon 	char name[256];
107*1f5207b7SJohn Levon 	const char *function;
108*1f5207b7SJohn Levon 	int param;
109*1f5207b7SJohn Levon 
110*1f5207b7SJohn Levon 	if (option_project == PROJ_NONE)
111*1f5207b7SJohn Levon 		return;
112*1f5207b7SJohn Levon 
113*1f5207b7SJohn Levon 	snprintf(name, 256, "%s.clears_argument", option_project_str);
114*1f5207b7SJohn Levon 
115*1f5207b7SJohn Levon 	token = get_tokens_file(name);
116*1f5207b7SJohn Levon 	if (!token)
117*1f5207b7SJohn Levon 		return;
118*1f5207b7SJohn Levon 	if (token_type(token) != TOKEN_STREAMBEGIN)
119*1f5207b7SJohn Levon 		return;
120*1f5207b7SJohn Levon 	token = token->next;
121*1f5207b7SJohn Levon 	while (token_type(token) != TOKEN_STREAMEND) {
122*1f5207b7SJohn Levon 		if (token_type(token) != TOKEN_IDENT)
123*1f5207b7SJohn Levon 			return;
124*1f5207b7SJohn Levon 		function = show_ident(token->ident);
125*1f5207b7SJohn Levon 		token = token->next;
126*1f5207b7SJohn Levon 		if (token_type(token) != TOKEN_NUMBER)
127*1f5207b7SJohn Levon 			return;
128*1f5207b7SJohn Levon 		param = atoi(token->number);
129*1f5207b7SJohn Levon 		add_function_hook(function, &match_memcpy, INT_PTR(param));
130*1f5207b7SJohn Levon 		token = token->next;
131*1f5207b7SJohn Levon 	}
132*1f5207b7SJohn Levon 	clear_token_alloc();
133*1f5207b7SJohn Levon }
134*1f5207b7SJohn Levon 
135*1f5207b7SJohn Levon #define USB_DIR_IN 0x80
match_usb_control_msg(const char * fn,struct expression * expr,void * _size_arg)136*1f5207b7SJohn Levon static void match_usb_control_msg(const char *fn, struct expression *expr, void *_size_arg)
137*1f5207b7SJohn Levon {
138*1f5207b7SJohn Levon 	struct expression *inout;
139*1f5207b7SJohn Levon 	sval_t sval;
140*1f5207b7SJohn Levon 
141*1f5207b7SJohn Levon 	inout = get_argument_from_call_expr(expr->args, 3);
142*1f5207b7SJohn Levon 
143*1f5207b7SJohn Levon 	if (get_value(inout, &sval) && !(sval.uvalue & USB_DIR_IN))
144*1f5207b7SJohn Levon 		return;
145*1f5207b7SJohn Levon 
146*1f5207b7SJohn Levon 	db_param_cleared(expr, 6, (char *)"$", (char *)"");
147*1f5207b7SJohn Levon }
148*1f5207b7SJohn Levon 
match_assign(struct expression * expr)149*1f5207b7SJohn Levon static void match_assign(struct expression *expr)
150*1f5207b7SJohn Levon {
151*1f5207b7SJohn Levon 	struct symbol *type;
152*1f5207b7SJohn Levon 
153*1f5207b7SJohn Levon 	/*
154*1f5207b7SJohn Levon 	 * If we have struct foo x, y; and we say that x = y; then it
155*1f5207b7SJohn Levon 	 * initializes the struct holes.  So we record that here.
156*1f5207b7SJohn Levon 	 */
157*1f5207b7SJohn Levon 	type = get_type(expr->left);
158*1f5207b7SJohn Levon 	if (!type || type->type != SYM_STRUCT)
159*1f5207b7SJohn Levon 		return;
160*1f5207b7SJohn Levon 	set_state_expr(my_id, expr->left, &cleared);
161*1f5207b7SJohn Levon }
162*1f5207b7SJohn Levon 
match_array_assign(struct expression * expr)163*1f5207b7SJohn Levon static void match_array_assign(struct expression *expr)
164*1f5207b7SJohn Levon {
165*1f5207b7SJohn Levon 	struct expression *array_expr;
166*1f5207b7SJohn Levon 
167*1f5207b7SJohn Levon 	if (!is_array(expr->left))
168*1f5207b7SJohn Levon 		return;
169*1f5207b7SJohn Levon 
170*1f5207b7SJohn Levon 	array_expr = get_array_base(expr->left);
171*1f5207b7SJohn Levon 	set_state_expr(my_id, array_expr, &cleared);
172*1f5207b7SJohn Levon }
173*1f5207b7SJohn Levon 
register_param_cleared(int id)174*1f5207b7SJohn Levon void register_param_cleared(int id)
175*1f5207b7SJohn Levon {
176*1f5207b7SJohn Levon 	my_id = id;
177*1f5207b7SJohn Levon 
178*1f5207b7SJohn Levon 	add_function_hook("memset", &match_memset, INT_PTR(0));
179*1f5207b7SJohn Levon 	add_function_hook("memzero", &match_memset, INT_PTR(0));
180*1f5207b7SJohn Levon 	add_function_hook("__memset", &match_memset, INT_PTR(0));
181*1f5207b7SJohn Levon 	add_function_hook("__memzero", &match_memset, INT_PTR(0));
182*1f5207b7SJohn Levon 
183*1f5207b7SJohn Levon 	add_function_hook("memcpy", &match_memcpy, INT_PTR(0));
184*1f5207b7SJohn Levon 	add_function_hook("memmove", &match_memcpy, INT_PTR(0));
185*1f5207b7SJohn Levon 	add_function_hook("__memcpy", &match_memcpy, INT_PTR(0));
186*1f5207b7SJohn Levon 	add_function_hook("__memmove", &match_memcpy, INT_PTR(0));
187*1f5207b7SJohn Levon 	add_function_hook("strcpy", &match_memcpy, INT_PTR(0));
188*1f5207b7SJohn Levon 	add_function_hook("strncpy", &match_memcpy, INT_PTR(0));
189*1f5207b7SJohn Levon 	add_function_hook("sprintf", &match_memcpy, INT_PTR(0));
190*1f5207b7SJohn Levon 	add_function_hook("snprintf", &match_memcpy, INT_PTR(0));
191*1f5207b7SJohn Levon 
192*1f5207b7SJohn Levon 	add_hook(&match_assign, ASSIGNMENT_HOOK);
193*1f5207b7SJohn Levon 	add_hook(&match_array_assign, ASSIGNMENT_HOOK);
194*1f5207b7SJohn Levon 
195*1f5207b7SJohn Levon 	register_clears_param();
196*1f5207b7SJohn Levon 
197*1f5207b7SJohn Levon 	select_return_states_hook(PARAM_CLEARED, &db_param_cleared);
198*1f5207b7SJohn Levon 	add_split_return_callback(&print_return_value_param);
199*1f5207b7SJohn Levon 
200*1f5207b7SJohn Levon 	if (option_project == PROJ_KERNEL) {
201*1f5207b7SJohn Levon 		add_function_hook("usb_control_msg", &match_usb_control_msg, NULL);
202*1f5207b7SJohn Levon 	}
203*1f5207b7SJohn Levon 
204*1f5207b7SJohn Levon }
205*1f5207b7SJohn Levon 
206