xref: /illumos-gate/usr/src/tools/smatch/src/smatch_buf_comparison.c (revision 1f5207b7604fb44407eb4342aff613f7c4508508)
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  * The point here is to store that a buffer has x bytes even if we don't know
20*1f5207b7SJohn Levon  * the value of x.
21*1f5207b7SJohn Levon  *
22*1f5207b7SJohn Levon  */
23*1f5207b7SJohn Levon 
24*1f5207b7SJohn Levon #include "smatch.h"
25*1f5207b7SJohn Levon #include "smatch_extra.h"
26*1f5207b7SJohn Levon #include "smatch_slist.h"
27*1f5207b7SJohn Levon 
28*1f5207b7SJohn Levon static int size_id;
29*1f5207b7SJohn Levon static int link_id;
30*1f5207b7SJohn Levon 
31*1f5207b7SJohn Levon /*
32*1f5207b7SJohn Levon  * We need this for code which does:
33*1f5207b7SJohn Levon  *
34*1f5207b7SJohn Levon  *     if (size)
35*1f5207b7SJohn Levon  *         foo = malloc(size);
36*1f5207b7SJohn Levon  *
37*1f5207b7SJohn Levon  * We want to record that the size of "foo" is "size" even after the merge.
38*1f5207b7SJohn Levon  *
39*1f5207b7SJohn Levon  */
40*1f5207b7SJohn Levon static struct smatch_state *unmatched_state(struct sm_state *sm)
41*1f5207b7SJohn Levon {
42*1f5207b7SJohn Levon 	struct expression *size_expr;
43*1f5207b7SJohn Levon 	sval_t sval;
44*1f5207b7SJohn Levon 
45*1f5207b7SJohn Levon 	if (!sm->state->data)
46*1f5207b7SJohn Levon 		return &undefined;
47*1f5207b7SJohn Levon 	size_expr = sm->state->data;
48*1f5207b7SJohn Levon 	if (!get_implied_value(size_expr, &sval) || sval.value != 0)
49*1f5207b7SJohn Levon 		return &undefined;
50*1f5207b7SJohn Levon 	return sm->state;
51*1f5207b7SJohn Levon }
52*1f5207b7SJohn Levon 
53*1f5207b7SJohn Levon static struct smatch_state *merge_links(struct smatch_state *s1, struct smatch_state *s2)
54*1f5207b7SJohn Levon {
55*1f5207b7SJohn Levon 	struct expression *expr1, *expr2;
56*1f5207b7SJohn Levon 
57*1f5207b7SJohn Levon 	expr1 = s1->data;
58*1f5207b7SJohn Levon 	expr2 = s2->data;
59*1f5207b7SJohn Levon 
60*1f5207b7SJohn Levon 	if (expr1 && expr2 && expr_equiv(expr1, expr2))
61*1f5207b7SJohn Levon 		return s1;
62*1f5207b7SJohn Levon 	return &merged;
63*1f5207b7SJohn Levon }
64*1f5207b7SJohn Levon 
65*1f5207b7SJohn Levon static void match_link_modify(struct sm_state *sm, struct expression *mod_expr)
66*1f5207b7SJohn Levon {
67*1f5207b7SJohn Levon 	struct expression *expr;
68*1f5207b7SJohn Levon 	struct sm_state *tmp;
69*1f5207b7SJohn Levon 
70*1f5207b7SJohn Levon 	expr = sm->state->data;
71*1f5207b7SJohn Levon 	if (expr) {
72*1f5207b7SJohn Levon 		set_state_expr(size_id, expr, &undefined);
73*1f5207b7SJohn Levon 		set_state(link_id, sm->name, sm->sym, &undefined);
74*1f5207b7SJohn Levon 		return;
75*1f5207b7SJohn Levon 	}
76*1f5207b7SJohn Levon 
77*1f5207b7SJohn Levon 	FOR_EACH_PTR(sm->possible, tmp) {
78*1f5207b7SJohn Levon 		expr = tmp->state->data;
79*1f5207b7SJohn Levon 		if (expr)
80*1f5207b7SJohn Levon 			set_state_expr(size_id, expr, &undefined);
81*1f5207b7SJohn Levon 	} END_FOR_EACH_PTR(tmp);
82*1f5207b7SJohn Levon 	set_state(link_id, sm->name, sm->sym, &undefined);
83*1f5207b7SJohn Levon }
84*1f5207b7SJohn Levon 
85*1f5207b7SJohn Levon static struct smatch_state *alloc_expr_state(struct expression *expr)
86*1f5207b7SJohn Levon {
87*1f5207b7SJohn Levon 	struct smatch_state *state;
88*1f5207b7SJohn Levon 	char *name;
89*1f5207b7SJohn Levon 
90*1f5207b7SJohn Levon 	state = __alloc_smatch_state(0);
91*1f5207b7SJohn Levon 	expr = strip_expr(expr);
92*1f5207b7SJohn Levon 	name = expr_to_str(expr);
93*1f5207b7SJohn Levon 	state->name = alloc_sname(name);
94*1f5207b7SJohn Levon 	free_string(name);
95*1f5207b7SJohn Levon 	state->data = expr;
96*1f5207b7SJohn Levon 	return state;
97*1f5207b7SJohn Levon }
98*1f5207b7SJohn Levon 
99*1f5207b7SJohn Levon static int bytes_per_element(struct expression *expr)
100*1f5207b7SJohn Levon {
101*1f5207b7SJohn Levon 	struct symbol *type;
102*1f5207b7SJohn Levon 
103*1f5207b7SJohn Levon 	type = get_type(expr);
104*1f5207b7SJohn Levon 	if (!type)
105*1f5207b7SJohn Levon 		return 0;
106*1f5207b7SJohn Levon 
107*1f5207b7SJohn Levon 	if (type->type != SYM_PTR && type->type != SYM_ARRAY)
108*1f5207b7SJohn Levon 		return 0;
109*1f5207b7SJohn Levon 
110*1f5207b7SJohn Levon 	type = get_base_type(type);
111*1f5207b7SJohn Levon 	return type_bytes(type);
112*1f5207b7SJohn Levon }
113*1f5207b7SJohn Levon 
114*1f5207b7SJohn Levon static void db_save_type_links(struct expression *array, struct expression *size)
115*1f5207b7SJohn Levon {
116*1f5207b7SJohn Levon 	const char *array_name;
117*1f5207b7SJohn Levon 
118*1f5207b7SJohn Levon 	array_name = get_data_info_name(array);
119*1f5207b7SJohn Levon 	if (!array_name)
120*1f5207b7SJohn Levon 		array_name = "";
121*1f5207b7SJohn Levon 	sql_insert_data_info(size, ARRAY_LEN, array_name);
122*1f5207b7SJohn Levon }
123*1f5207b7SJohn Levon 
124*1f5207b7SJohn Levon static void match_alloc_helper(struct expression *pointer, struct expression *size)
125*1f5207b7SJohn Levon {
126*1f5207b7SJohn Levon 	struct expression *tmp;
127*1f5207b7SJohn Levon 	struct sm_state *sm;
128*1f5207b7SJohn Levon 	sval_t sval;
129*1f5207b7SJohn Levon 	int cnt = 0;
130*1f5207b7SJohn Levon 
131*1f5207b7SJohn Levon 	pointer = strip_expr(pointer);
132*1f5207b7SJohn Levon 	size = strip_expr(size);
133*1f5207b7SJohn Levon 	if (!size || !pointer)
134*1f5207b7SJohn Levon 		return;
135*1f5207b7SJohn Levon 
136*1f5207b7SJohn Levon 	while ((tmp = get_assigned_expr(size))) {
137*1f5207b7SJohn Levon 		size = strip_expr(tmp);
138*1f5207b7SJohn Levon 		if (cnt++ > 5)
139*1f5207b7SJohn Levon 			break;
140*1f5207b7SJohn Levon 	}
141*1f5207b7SJohn Levon 
142*1f5207b7SJohn Levon 	if (size->type == EXPR_BINOP && size->op == '*') {
143*1f5207b7SJohn Levon 		struct expression *mult_left, *mult_right;
144*1f5207b7SJohn Levon 
145*1f5207b7SJohn Levon 		mult_left = strip_expr(size->left);
146*1f5207b7SJohn Levon 		mult_right = strip_expr(size->right);
147*1f5207b7SJohn Levon 
148*1f5207b7SJohn Levon 		if (get_implied_value(mult_left, &sval) &&
149*1f5207b7SJohn Levon 		    sval.value == bytes_per_element(pointer))
150*1f5207b7SJohn Levon 			size = mult_right;
151*1f5207b7SJohn Levon 		else if (get_implied_value(mult_right, &sval) &&
152*1f5207b7SJohn Levon 		    sval.value == bytes_per_element(pointer))
153*1f5207b7SJohn Levon 			size = mult_left;
154*1f5207b7SJohn Levon 		else
155*1f5207b7SJohn Levon 			return;
156*1f5207b7SJohn Levon 	}
157*1f5207b7SJohn Levon 
158*1f5207b7SJohn Levon 	/* Only save links to variables, not fixed sizes */
159*1f5207b7SJohn Levon 	if (get_value(size, &sval))
160*1f5207b7SJohn Levon 		return;
161*1f5207b7SJohn Levon 
162*1f5207b7SJohn Levon 	db_save_type_links(pointer, size);
163*1f5207b7SJohn Levon 	sm = set_state_expr(size_id, pointer, alloc_expr_state(size));
164*1f5207b7SJohn Levon 	if (!sm)
165*1f5207b7SJohn Levon 		return;
166*1f5207b7SJohn Levon 	set_state_expr(link_id, size, alloc_expr_state(pointer));
167*1f5207b7SJohn Levon }
168*1f5207b7SJohn Levon 
169*1f5207b7SJohn Levon static void match_alloc(const char *fn, struct expression *expr, void *_size_arg)
170*1f5207b7SJohn Levon {
171*1f5207b7SJohn Levon 	int size_arg = PTR_INT(_size_arg);
172*1f5207b7SJohn Levon 	struct expression *pointer, *call, *arg;
173*1f5207b7SJohn Levon 
174*1f5207b7SJohn Levon 	pointer = strip_expr(expr->left);
175*1f5207b7SJohn Levon 	call = strip_expr(expr->right);
176*1f5207b7SJohn Levon 	arg = get_argument_from_call_expr(call->args, size_arg);
177*1f5207b7SJohn Levon 	match_alloc_helper(pointer, arg);
178*1f5207b7SJohn Levon }
179*1f5207b7SJohn Levon 
180*1f5207b7SJohn Levon static void match_calloc(const char *fn, struct expression *expr, void *_start_arg)
181*1f5207b7SJohn Levon {
182*1f5207b7SJohn Levon 	int start_arg = PTR_INT(_start_arg);
183*1f5207b7SJohn Levon 	struct expression *pointer, *call, *arg;
184*1f5207b7SJohn Levon 	struct sm_state *tmp;
185*1f5207b7SJohn Levon 	sval_t sval;
186*1f5207b7SJohn Levon 
187*1f5207b7SJohn Levon 	pointer = strip_expr(expr->left);
188*1f5207b7SJohn Levon 	call = strip_expr(expr->right);
189*1f5207b7SJohn Levon 	arg = get_argument_from_call_expr(call->args, start_arg);
190*1f5207b7SJohn Levon 	if (get_implied_value(arg, &sval) &&
191*1f5207b7SJohn Levon 	    sval.value == bytes_per_element(pointer))
192*1f5207b7SJohn Levon 		arg = get_argument_from_call_expr(call->args, start_arg + 1);
193*1f5207b7SJohn Levon 
194*1f5207b7SJohn Levon 	db_save_type_links(pointer, arg);
195*1f5207b7SJohn Levon 	tmp = set_state_expr(size_id, pointer, alloc_expr_state(arg));
196*1f5207b7SJohn Levon 	if (!tmp)
197*1f5207b7SJohn Levon 		return;
198*1f5207b7SJohn Levon 	set_state_expr(link_id, arg, alloc_expr_state(pointer));
199*1f5207b7SJohn Levon }
200*1f5207b7SJohn Levon 
201*1f5207b7SJohn Levon struct expression *get_size_variable(struct expression *buf)
202*1f5207b7SJohn Levon {
203*1f5207b7SJohn Levon 	struct smatch_state *state;
204*1f5207b7SJohn Levon 
205*1f5207b7SJohn Levon 	state = get_state_expr(size_id, buf);
206*1f5207b7SJohn Levon 	if (state)
207*1f5207b7SJohn Levon 		return state->data;
208*1f5207b7SJohn Levon 	return NULL;
209*1f5207b7SJohn Levon }
210*1f5207b7SJohn Levon 
211*1f5207b7SJohn Levon struct expression *get_array_variable(struct expression *size)
212*1f5207b7SJohn Levon {
213*1f5207b7SJohn Levon 	struct smatch_state *state;
214*1f5207b7SJohn Levon 
215*1f5207b7SJohn Levon 	state = get_state_expr(link_id, size);
216*1f5207b7SJohn Levon 	if (state)
217*1f5207b7SJohn Levon 		return state->data;
218*1f5207b7SJohn Levon 	return NULL;
219*1f5207b7SJohn Levon }
220*1f5207b7SJohn Levon 
221*1f5207b7SJohn Levon static void array_check(struct expression *expr)
222*1f5207b7SJohn Levon {
223*1f5207b7SJohn Levon 	struct expression *array;
224*1f5207b7SJohn Levon 	struct expression *size;
225*1f5207b7SJohn Levon 	struct expression *offset;
226*1f5207b7SJohn Levon 	char *array_str, *offset_str;
227*1f5207b7SJohn Levon 
228*1f5207b7SJohn Levon 	expr = strip_expr(expr);
229*1f5207b7SJohn Levon 	if (!is_array(expr))
230*1f5207b7SJohn Levon 		return;
231*1f5207b7SJohn Levon 
232*1f5207b7SJohn Levon 	array = get_array_base(expr);
233*1f5207b7SJohn Levon 	size = get_size_variable(array);
234*1f5207b7SJohn Levon 	if (!size)
235*1f5207b7SJohn Levon 		return;
236*1f5207b7SJohn Levon 	offset = get_array_offset(expr);
237*1f5207b7SJohn Levon 	if (!possible_comparison(size, SPECIAL_EQUAL, offset))
238*1f5207b7SJohn Levon 		return;
239*1f5207b7SJohn Levon 
240*1f5207b7SJohn Levon 	array_str = expr_to_str(array);
241*1f5207b7SJohn Levon 	offset_str = expr_to_str(offset);
242*1f5207b7SJohn Levon 	sm_warning("potentially one past the end of array '%s[%s]'", array_str, offset_str);
243*1f5207b7SJohn Levon 	free_string(array_str);
244*1f5207b7SJohn Levon 	free_string(offset_str);
245*1f5207b7SJohn Levon }
246*1f5207b7SJohn Levon 
247*1f5207b7SJohn Levon struct db_info {
248*1f5207b7SJohn Levon 	char *name;
249*1f5207b7SJohn Levon 	int ret;
250*1f5207b7SJohn Levon };
251*1f5207b7SJohn Levon 
252*1f5207b7SJohn Levon static int db_limitter_callback(void *_info, int argc, char **argv, char **azColName)
253*1f5207b7SJohn Levon {
254*1f5207b7SJohn Levon 	struct db_info *info = _info;
255*1f5207b7SJohn Levon 
256*1f5207b7SJohn Levon 	/*
257*1f5207b7SJohn Levon 	 * If possible the limitters are tied to the struct they limit.  If we
258*1f5207b7SJohn Levon 	 * aren't sure which struct they limit then we use them as limitters for
259*1f5207b7SJohn Levon 	 * everything.
260*1f5207b7SJohn Levon 	 */
261*1f5207b7SJohn Levon 	if (!info->name || argv[0][0] == '\0' || strcmp(info->name, argv[0]) == 0)
262*1f5207b7SJohn Levon 		info->ret = 1;
263*1f5207b7SJohn Levon 	return 0;
264*1f5207b7SJohn Levon }
265*1f5207b7SJohn Levon 
266*1f5207b7SJohn Levon static char *vsl_to_data_info_name(const char *name, struct var_sym_list *vsl)
267*1f5207b7SJohn Levon {
268*1f5207b7SJohn Levon 	struct var_sym *vs;
269*1f5207b7SJohn Levon 	struct symbol *type;
270*1f5207b7SJohn Levon 	static char buf[80];
271*1f5207b7SJohn Levon 	const char *p;
272*1f5207b7SJohn Levon 
273*1f5207b7SJohn Levon 	if (ptr_list_size((struct ptr_list *)vsl) != 1)
274*1f5207b7SJohn Levon 		return NULL;
275*1f5207b7SJohn Levon 	vs = first_ptr_list((struct ptr_list *)vsl);
276*1f5207b7SJohn Levon 
277*1f5207b7SJohn Levon 	type = get_real_base_type(vs->sym);
278*1f5207b7SJohn Levon 	if (!type || type->type != SYM_PTR)
279*1f5207b7SJohn Levon 		goto top_level_name;
280*1f5207b7SJohn Levon 	type = get_real_base_type(type);
281*1f5207b7SJohn Levon 	if (!type || type->type != SYM_STRUCT)
282*1f5207b7SJohn Levon 		goto top_level_name;
283*1f5207b7SJohn Levon 	if (!type->ident)
284*1f5207b7SJohn Levon 		goto top_level_name;
285*1f5207b7SJohn Levon 
286*1f5207b7SJohn Levon 	p = name;
287*1f5207b7SJohn Levon 	while ((name = strstr(p, "->")))
288*1f5207b7SJohn Levon 		p = name + 2;
289*1f5207b7SJohn Levon 
290*1f5207b7SJohn Levon 	snprintf(buf, sizeof(buf),"(struct %s)->%s", type->ident->name, p);
291*1f5207b7SJohn Levon 	return alloc_sname(buf);
292*1f5207b7SJohn Levon 
293*1f5207b7SJohn Levon top_level_name:
294*1f5207b7SJohn Levon 	if (!(vs->sym->ctype.modifiers & MOD_TOPLEVEL))
295*1f5207b7SJohn Levon 		return NULL;
296*1f5207b7SJohn Levon 	if (vs->sym->ctype.modifiers & MOD_STATIC)
297*1f5207b7SJohn Levon 		snprintf(buf, sizeof(buf),"static %s", name);
298*1f5207b7SJohn Levon 	else
299*1f5207b7SJohn Levon 		snprintf(buf, sizeof(buf),"global %s", name);
300*1f5207b7SJohn Levon 	return alloc_sname(buf);
301*1f5207b7SJohn Levon }
302*1f5207b7SJohn Levon 
303*1f5207b7SJohn Levon int db_var_is_array_limit(struct expression *array, const char *name, struct var_sym_list *vsl)
304*1f5207b7SJohn Levon {
305*1f5207b7SJohn Levon 	char *size_name;
306*1f5207b7SJohn Levon 	char *array_name = get_data_info_name(array);
307*1f5207b7SJohn Levon 	struct db_info db_info = {.name = array_name,};
308*1f5207b7SJohn Levon 
309*1f5207b7SJohn Levon 	size_name = vsl_to_data_info_name(name, vsl);
310*1f5207b7SJohn Levon 	if (!size_name)
311*1f5207b7SJohn Levon 		return 0;
312*1f5207b7SJohn Levon 
313*1f5207b7SJohn Levon 	run_sql(db_limitter_callback, &db_info,
314*1f5207b7SJohn Levon 		"select value from data_info where type = %d and data = '%s';",
315*1f5207b7SJohn Levon 		ARRAY_LEN, size_name);
316*1f5207b7SJohn Levon 
317*1f5207b7SJohn Levon 	return db_info.ret;
318*1f5207b7SJohn Levon }
319*1f5207b7SJohn Levon 
320*1f5207b7SJohn Levon static int known_access_ok_comparison(struct expression *expr)
321*1f5207b7SJohn Levon {
322*1f5207b7SJohn Levon 	struct expression *array;
323*1f5207b7SJohn Levon 	struct expression *size;
324*1f5207b7SJohn Levon 	struct expression *offset;
325*1f5207b7SJohn Levon 	int comparison;
326*1f5207b7SJohn Levon 
327*1f5207b7SJohn Levon 	array = get_array_base(expr);
328*1f5207b7SJohn Levon 	size = get_size_variable(array);
329*1f5207b7SJohn Levon 	if (!size)
330*1f5207b7SJohn Levon 		return 0;
331*1f5207b7SJohn Levon 	offset = get_array_offset(expr);
332*1f5207b7SJohn Levon 	comparison = get_comparison(size, offset);
333*1f5207b7SJohn Levon 	if (comparison == '>' || comparison == SPECIAL_UNSIGNED_GT)
334*1f5207b7SJohn Levon 		return 1;
335*1f5207b7SJohn Levon 
336*1f5207b7SJohn Levon 	return 0;
337*1f5207b7SJohn Levon }
338*1f5207b7SJohn Levon 
339*1f5207b7SJohn Levon static int known_access_ok_numbers(struct expression *expr)
340*1f5207b7SJohn Levon {
341*1f5207b7SJohn Levon 	struct expression *array;
342*1f5207b7SJohn Levon 	struct expression *offset;
343*1f5207b7SJohn Levon 	sval_t max;
344*1f5207b7SJohn Levon 	int size;
345*1f5207b7SJohn Levon 
346*1f5207b7SJohn Levon 	array = get_array_base(expr);
347*1f5207b7SJohn Levon 	offset = get_array_offset(expr);
348*1f5207b7SJohn Levon 
349*1f5207b7SJohn Levon 	size = get_array_size(array);
350*1f5207b7SJohn Levon 	if (size <= 0)
351*1f5207b7SJohn Levon 		return 0;
352*1f5207b7SJohn Levon 
353*1f5207b7SJohn Levon 	get_absolute_max(offset, &max);
354*1f5207b7SJohn Levon 	if (max.uvalue < size)
355*1f5207b7SJohn Levon 		return 1;
356*1f5207b7SJohn Levon 	return 0;
357*1f5207b7SJohn Levon }
358*1f5207b7SJohn Levon 
359*1f5207b7SJohn Levon static void array_check_data_info(struct expression *expr)
360*1f5207b7SJohn Levon {
361*1f5207b7SJohn Levon 	struct expression *array;
362*1f5207b7SJohn Levon 	struct expression *offset;
363*1f5207b7SJohn Levon 	struct state_list *slist;
364*1f5207b7SJohn Levon 	struct sm_state *sm;
365*1f5207b7SJohn Levon 	struct compare_data *comp;
366*1f5207b7SJohn Levon 	char *offset_name;
367*1f5207b7SJohn Levon 	const char *equal_name = NULL;
368*1f5207b7SJohn Levon 
369*1f5207b7SJohn Levon 	expr = strip_expr(expr);
370*1f5207b7SJohn Levon 	if (!is_array(expr))
371*1f5207b7SJohn Levon 		return;
372*1f5207b7SJohn Levon 
373*1f5207b7SJohn Levon 	if (known_access_ok_numbers(expr))
374*1f5207b7SJohn Levon 		return;
375*1f5207b7SJohn Levon 	if (known_access_ok_comparison(expr))
376*1f5207b7SJohn Levon 		return;
377*1f5207b7SJohn Levon 
378*1f5207b7SJohn Levon 	array = get_array_base(expr);
379*1f5207b7SJohn Levon 	offset = get_array_offset(expr);
380*1f5207b7SJohn Levon 	offset_name = expr_to_var(offset);
381*1f5207b7SJohn Levon 	if (!offset_name)
382*1f5207b7SJohn Levon 		return;
383*1f5207b7SJohn Levon 	slist = get_all_possible_equal_comparisons(offset);
384*1f5207b7SJohn Levon 	if (!slist)
385*1f5207b7SJohn Levon 		goto free;
386*1f5207b7SJohn Levon 
387*1f5207b7SJohn Levon 	FOR_EACH_PTR(slist, sm) {
388*1f5207b7SJohn Levon 		comp = sm->state->data;
389*1f5207b7SJohn Levon 		if (strcmp(comp->left_var, offset_name) == 0) {
390*1f5207b7SJohn Levon 			if (db_var_is_array_limit(array, comp->right_var, comp->right_vsl)) {
391*1f5207b7SJohn Levon 				equal_name = comp->right_var;
392*1f5207b7SJohn Levon 				break;
393*1f5207b7SJohn Levon 			}
394*1f5207b7SJohn Levon 		} else if (strcmp(comp->right_var, offset_name) == 0) {
395*1f5207b7SJohn Levon 			if (db_var_is_array_limit(array, comp->left_var, comp->left_vsl)) {
396*1f5207b7SJohn Levon 				equal_name = comp->left_var;
397*1f5207b7SJohn Levon 				break;
398*1f5207b7SJohn Levon 			}
399*1f5207b7SJohn Levon 		}
400*1f5207b7SJohn Levon 	} END_FOR_EACH_PTR(sm);
401*1f5207b7SJohn Levon 
402*1f5207b7SJohn Levon 	if (equal_name) {
403*1f5207b7SJohn Levon 		char *array_name = expr_to_str(array);
404*1f5207b7SJohn Levon 
405*1f5207b7SJohn Levon 		sm_warning("potential off by one '%s[]' limit '%s'", array_name, equal_name);
406*1f5207b7SJohn Levon 		free_string(array_name);
407*1f5207b7SJohn Levon 	}
408*1f5207b7SJohn Levon 
409*1f5207b7SJohn Levon free:
410*1f5207b7SJohn Levon 	free_slist(&slist);
411*1f5207b7SJohn Levon 	free_string(offset_name);
412*1f5207b7SJohn Levon }
413*1f5207b7SJohn Levon 
414*1f5207b7SJohn Levon static void add_allocation_function(const char *func, void *call_back, int param)
415*1f5207b7SJohn Levon {
416*1f5207b7SJohn Levon 	add_function_assign_hook(func, call_back, INT_PTR(param));
417*1f5207b7SJohn Levon }
418*1f5207b7SJohn Levon 
419*1f5207b7SJohn Levon static char *buf_size_param_comparison(struct expression *array, struct expression_list *args)
420*1f5207b7SJohn Levon {
421*1f5207b7SJohn Levon 	struct expression *arg;
422*1f5207b7SJohn Levon 	struct expression *size;
423*1f5207b7SJohn Levon 	static char buf[32];
424*1f5207b7SJohn Levon 	int i;
425*1f5207b7SJohn Levon 
426*1f5207b7SJohn Levon 	size = get_size_variable(array);
427*1f5207b7SJohn Levon 	if (!size)
428*1f5207b7SJohn Levon 		return NULL;
429*1f5207b7SJohn Levon 
430*1f5207b7SJohn Levon 	i = -1;
431*1f5207b7SJohn Levon 	FOR_EACH_PTR(args, arg) {
432*1f5207b7SJohn Levon 		i++;
433*1f5207b7SJohn Levon 		if (arg == array)
434*1f5207b7SJohn Levon 			continue;
435*1f5207b7SJohn Levon 		if (!expr_equiv(arg, size))
436*1f5207b7SJohn Levon 			continue;
437*1f5207b7SJohn Levon 		snprintf(buf, sizeof(buf), "==$%d", i);
438*1f5207b7SJohn Levon 		return buf;
439*1f5207b7SJohn Levon 	} END_FOR_EACH_PTR(arg);
440*1f5207b7SJohn Levon 
441*1f5207b7SJohn Levon 	return NULL;
442*1f5207b7SJohn Levon }
443*1f5207b7SJohn Levon 
444*1f5207b7SJohn Levon static void match_call(struct expression *call)
445*1f5207b7SJohn Levon {
446*1f5207b7SJohn Levon 	struct expression *arg;
447*1f5207b7SJohn Levon 	char *compare;
448*1f5207b7SJohn Levon 	int param;
449*1f5207b7SJohn Levon 
450*1f5207b7SJohn Levon 	param = -1;
451*1f5207b7SJohn Levon 	FOR_EACH_PTR(call->args, arg) {
452*1f5207b7SJohn Levon 		param++;
453*1f5207b7SJohn Levon 		if (!is_pointer(arg))
454*1f5207b7SJohn Levon 			continue;
455*1f5207b7SJohn Levon 		compare = buf_size_param_comparison(arg, call->args);
456*1f5207b7SJohn Levon 		if (!compare)
457*1f5207b7SJohn Levon 			continue;
458*1f5207b7SJohn Levon 		sql_insert_caller_info(call, ARRAY_LEN, param, "$", compare);
459*1f5207b7SJohn Levon 	} END_FOR_EACH_PTR(arg);
460*1f5207b7SJohn Levon }
461*1f5207b7SJohn Levon 
462*1f5207b7SJohn Levon static int get_param(int param, char **name, struct symbol **sym)
463*1f5207b7SJohn Levon {
464*1f5207b7SJohn Levon 	struct symbol *arg;
465*1f5207b7SJohn Levon 	int i;
466*1f5207b7SJohn Levon 
467*1f5207b7SJohn Levon 	i = 0;
468*1f5207b7SJohn Levon 	FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, arg) {
469*1f5207b7SJohn Levon 		/*
470*1f5207b7SJohn Levon 		 * this is a temporary hack to work around a bug (I think in sparse?)
471*1f5207b7SJohn Levon 		 * 2.6.37-rc1:fs/reiserfs/journal.o
472*1f5207b7SJohn Levon 		 * If there is a function definition without parameter name found
473*1f5207b7SJohn Levon 		 * after a function implementation then it causes a crash.
474*1f5207b7SJohn Levon 		 * int foo() {}
475*1f5207b7SJohn Levon 		 * int bar(char *);
476*1f5207b7SJohn Levon 		 */
477*1f5207b7SJohn Levon 		if (arg->ident->name < (char *)100)
478*1f5207b7SJohn Levon 			continue;
479*1f5207b7SJohn Levon 		if (i == param) {
480*1f5207b7SJohn Levon 			*name = arg->ident->name;
481*1f5207b7SJohn Levon 			*sym = arg;
482*1f5207b7SJohn Levon 			return TRUE;
483*1f5207b7SJohn Levon 		}
484*1f5207b7SJohn Levon 		i++;
485*1f5207b7SJohn Levon 	} END_FOR_EACH_PTR(arg);
486*1f5207b7SJohn Levon 
487*1f5207b7SJohn Levon 	return FALSE;
488*1f5207b7SJohn Levon }
489*1f5207b7SJohn Levon 
490*1f5207b7SJohn Levon static void set_param_compare(const char *array_name, struct symbol *array_sym, char *key, char *value)
491*1f5207b7SJohn Levon {
492*1f5207b7SJohn Levon 	struct expression *array_expr;
493*1f5207b7SJohn Levon 	struct expression *size_expr;
494*1f5207b7SJohn Levon 	struct symbol *size_sym;
495*1f5207b7SJohn Levon 	char *size_name;
496*1f5207b7SJohn Levon 	long param;
497*1f5207b7SJohn Levon 	struct sm_state *tmp;
498*1f5207b7SJohn Levon 
499*1f5207b7SJohn Levon 	if (strncmp(value, "==$", 3) != 0)
500*1f5207b7SJohn Levon 		return;
501*1f5207b7SJohn Levon 	param = strtol(value + 3, NULL, 10);
502*1f5207b7SJohn Levon 	if (!get_param(param, &size_name, &size_sym))
503*1f5207b7SJohn Levon 		return;
504*1f5207b7SJohn Levon 	array_expr = symbol_expression(array_sym);
505*1f5207b7SJohn Levon 	size_expr = symbol_expression(size_sym);
506*1f5207b7SJohn Levon 
507*1f5207b7SJohn Levon 	tmp = set_state_expr(size_id, array_expr, alloc_expr_state(size_expr));
508*1f5207b7SJohn Levon 	if (!tmp)
509*1f5207b7SJohn Levon 		return;
510*1f5207b7SJohn Levon 	set_state_expr(link_id, size_expr, alloc_expr_state(array_expr));
511*1f5207b7SJohn Levon }
512*1f5207b7SJohn Levon 
513*1f5207b7SJohn Levon static void set_arraysize_arg(const char *array_name, struct symbol *array_sym, char *key, char *value)
514*1f5207b7SJohn Levon {
515*1f5207b7SJohn Levon 	struct expression *array_expr;
516*1f5207b7SJohn Levon 	struct expression *size_expr;
517*1f5207b7SJohn Levon 	struct symbol *size_sym;
518*1f5207b7SJohn Levon 	char *size_name;
519*1f5207b7SJohn Levon 	long param;
520*1f5207b7SJohn Levon 	struct sm_state *tmp;
521*1f5207b7SJohn Levon 
522*1f5207b7SJohn Levon 	param = strtol(key, NULL, 10);
523*1f5207b7SJohn Levon 	if (!get_param(param, &size_name, &size_sym))
524*1f5207b7SJohn Levon 		return;
525*1f5207b7SJohn Levon 	array_expr = symbol_expression(array_sym);
526*1f5207b7SJohn Levon 	size_expr = symbol_expression(size_sym);
527*1f5207b7SJohn Levon 
528*1f5207b7SJohn Levon 	tmp = set_state_expr(size_id, array_expr, alloc_expr_state(size_expr));
529*1f5207b7SJohn Levon 	if (!tmp)
530*1f5207b7SJohn Levon 		return;
531*1f5207b7SJohn Levon 	set_state_expr(link_id, size_expr, alloc_expr_state(array_expr));
532*1f5207b7SJohn Levon }
533*1f5207b7SJohn Levon 
534*1f5207b7SJohn Levon static void munge_start_states(struct statement *stmt)
535*1f5207b7SJohn Levon {
536*1f5207b7SJohn Levon 	struct state_list *slist = NULL;
537*1f5207b7SJohn Levon 	struct sm_state *sm;
538*1f5207b7SJohn Levon 	struct sm_state *poss;
539*1f5207b7SJohn Levon 
540*1f5207b7SJohn Levon 	FOR_EACH_MY_SM(size_id, __get_cur_stree(), sm) {
541*1f5207b7SJohn Levon 		if (sm->state != &merged)
542*1f5207b7SJohn Levon 			continue;
543*1f5207b7SJohn Levon 		/*
544*1f5207b7SJohn Levon 		 * screw it.  let's just assume that if one caller passes the
545*1f5207b7SJohn Levon 		 * size then they all do.
546*1f5207b7SJohn Levon 		 */
547*1f5207b7SJohn Levon 		FOR_EACH_PTR(sm->possible, poss) {
548*1f5207b7SJohn Levon 			if (poss->state != &merged &&
549*1f5207b7SJohn Levon 			    poss->state != &undefined) {
550*1f5207b7SJohn Levon 				add_ptr_list(&slist, poss);
551*1f5207b7SJohn Levon 				break;
552*1f5207b7SJohn Levon 			}
553*1f5207b7SJohn Levon 		} END_FOR_EACH_PTR(poss);
554*1f5207b7SJohn Levon 	} END_FOR_EACH_SM(sm);
555*1f5207b7SJohn Levon 
556*1f5207b7SJohn Levon 	FOR_EACH_PTR(slist, sm) {
557*1f5207b7SJohn Levon 		set_state(size_id, sm->name, sm->sym, sm->state);
558*1f5207b7SJohn Levon 	} END_FOR_EACH_PTR(sm);
559*1f5207b7SJohn Levon 
560*1f5207b7SJohn Levon 	free_slist(&slist);
561*1f5207b7SJohn Levon }
562*1f5207b7SJohn Levon 
563*1f5207b7SJohn Levon void register_buf_comparison(int id)
564*1f5207b7SJohn Levon {
565*1f5207b7SJohn Levon 	size_id = id;
566*1f5207b7SJohn Levon 
567*1f5207b7SJohn Levon 	add_unmatched_state_hook(size_id, &unmatched_state);
568*1f5207b7SJohn Levon 
569*1f5207b7SJohn Levon 	add_allocation_function("malloc", &match_alloc, 0);
570*1f5207b7SJohn Levon 	add_allocation_function("memdup", &match_alloc, 1);
571*1f5207b7SJohn Levon 	add_allocation_function("realloc", &match_alloc, 1);
572*1f5207b7SJohn Levon 	if (option_project == PROJ_KERNEL) {
573*1f5207b7SJohn Levon 		add_allocation_function("kmalloc", &match_alloc, 0);
574*1f5207b7SJohn Levon 		add_allocation_function("kzalloc", &match_alloc, 0);
575*1f5207b7SJohn Levon 		add_allocation_function("vmalloc", &match_alloc, 0);
576*1f5207b7SJohn Levon 		add_allocation_function("__vmalloc", &match_alloc, 0);
577*1f5207b7SJohn Levon 		add_allocation_function("sock_kmalloc", &match_alloc, 1);
578*1f5207b7SJohn Levon 		add_allocation_function("kmemdup", &match_alloc, 1);
579*1f5207b7SJohn Levon 		add_allocation_function("kmemdup_user", &match_alloc, 1);
580*1f5207b7SJohn Levon 		add_allocation_function("dma_alloc_attrs", &match_alloc, 1);
581*1f5207b7SJohn Levon 		add_allocation_function("pci_alloc_consistent", &match_alloc, 1);
582*1f5207b7SJohn Levon 		add_allocation_function("pci_alloc_coherent", &match_alloc, 1);
583*1f5207b7SJohn Levon 		add_allocation_function("devm_kmalloc", &match_alloc, 1);
584*1f5207b7SJohn Levon 		add_allocation_function("devm_kzalloc", &match_alloc, 1);
585*1f5207b7SJohn Levon 		add_allocation_function("kcalloc", &match_calloc, 0);
586*1f5207b7SJohn Levon 		add_allocation_function("devm_kcalloc", &match_calloc, 1);
587*1f5207b7SJohn Levon 		add_allocation_function("kmalloc_array", &match_calloc, 0);
588*1f5207b7SJohn Levon 		add_allocation_function("krealloc", &match_alloc, 1);
589*1f5207b7SJohn Levon 	}
590*1f5207b7SJohn Levon 
591*1f5207b7SJohn Levon 	add_hook(&array_check, OP_HOOK);
592*1f5207b7SJohn Levon 	add_hook(&array_check_data_info, OP_HOOK);
593*1f5207b7SJohn Levon 
594*1f5207b7SJohn Levon 	add_hook(&match_call, FUNCTION_CALL_HOOK);
595*1f5207b7SJohn Levon 	select_caller_info_hook(set_param_compare, ARRAY_LEN);
596*1f5207b7SJohn Levon 	select_caller_info_hook(set_arraysize_arg, ARRAYSIZE_ARG);
597*1f5207b7SJohn Levon 	add_hook(&munge_start_states, AFTER_DEF_HOOK);
598*1f5207b7SJohn Levon }
599*1f5207b7SJohn Levon 
600*1f5207b7SJohn Levon void register_buf_comparison_links(int id)
601*1f5207b7SJohn Levon {
602*1f5207b7SJohn Levon 	link_id = id;
603*1f5207b7SJohn Levon 	add_merge_hook(link_id, &merge_links);
604*1f5207b7SJohn Levon 	add_modification_hook(link_id, &match_link_modify);
605*1f5207b7SJohn Levon }
606