xref: /illumos-gate/usr/src/tools/smatch/src/smatch_buf_comparison.c (revision efe51d0cc2398b9ac179568b63a44e4bf295b8e2)
11f5207b7SJohn Levon /*
21f5207b7SJohn Levon  * Copyright (C) 2012 Oracle.
31f5207b7SJohn Levon  *
41f5207b7SJohn Levon  * This program is free software; you can redistribute it and/or
51f5207b7SJohn Levon  * modify it under the terms of the GNU General Public License
61f5207b7SJohn Levon  * as published by the Free Software Foundation; either version 2
71f5207b7SJohn Levon  * of the License, or (at your option) any later version.
81f5207b7SJohn Levon  *
91f5207b7SJohn Levon  * This program is distributed in the hope that it will be useful,
101f5207b7SJohn Levon  * but WITHOUT ANY WARRANTY; without even the implied warranty of
111f5207b7SJohn Levon  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
121f5207b7SJohn Levon  * GNU General Public License for more details.
131f5207b7SJohn Levon  *
141f5207b7SJohn Levon  * You should have received a copy of the GNU General Public License
151f5207b7SJohn Levon  * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
161f5207b7SJohn Levon  */
171f5207b7SJohn Levon 
181f5207b7SJohn Levon /*
191f5207b7SJohn Levon  * The point here is to store that a buffer has x bytes even if we don't know
201f5207b7SJohn Levon  * the value of x.
211f5207b7SJohn Levon  *
221f5207b7SJohn Levon  */
231f5207b7SJohn Levon 
241f5207b7SJohn Levon #include "smatch.h"
251f5207b7SJohn Levon #include "smatch_extra.h"
261f5207b7SJohn Levon #include "smatch_slist.h"
271f5207b7SJohn Levon 
281f5207b7SJohn Levon static int size_id;
291f5207b7SJohn Levon static int link_id;
301f5207b7SJohn Levon 
311f5207b7SJohn Levon /*
32*efe51d0cSJohn Levon  * There is a bunch of code which does this:
331f5207b7SJohn Levon  *
341f5207b7SJohn Levon  *     if (size)
351f5207b7SJohn Levon  *         foo = malloc(size);
361f5207b7SJohn Levon  *
37*efe51d0cSJohn Levon  * So if "size" is non-zero then the size of "foo" is size.  But really it's
38*efe51d0cSJohn Levon  * also true if size is zero.  It's just better to assume to not trample over
39*efe51d0cSJohn Levon  * the data that we have by merging &undefined states.
401f5207b7SJohn Levon  *
411f5207b7SJohn Levon  */
421f5207b7SJohn Levon static struct smatch_state *unmatched_state(struct sm_state *sm)
431f5207b7SJohn Levon {
441f5207b7SJohn Levon 	return sm->state;
451f5207b7SJohn Levon }
461f5207b7SJohn Levon 
471f5207b7SJohn Levon static struct smatch_state *merge_links(struct smatch_state *s1, struct smatch_state *s2)
481f5207b7SJohn Levon {
491f5207b7SJohn Levon 	struct expression *expr1, *expr2;
501f5207b7SJohn Levon 
511f5207b7SJohn Levon 	expr1 = s1->data;
521f5207b7SJohn Levon 	expr2 = s2->data;
531f5207b7SJohn Levon 
541f5207b7SJohn Levon 	if (expr1 && expr2 && expr_equiv(expr1, expr2))
551f5207b7SJohn Levon 		return s1;
561f5207b7SJohn Levon 	return &merged;
571f5207b7SJohn Levon }
581f5207b7SJohn Levon 
591f5207b7SJohn Levon static void match_link_modify(struct sm_state *sm, struct expression *mod_expr)
601f5207b7SJohn Levon {
611f5207b7SJohn Levon 	struct expression *expr;
621f5207b7SJohn Levon 	struct sm_state *tmp;
631f5207b7SJohn Levon 
641f5207b7SJohn Levon 	expr = sm->state->data;
651f5207b7SJohn Levon 	if (expr) {
661f5207b7SJohn Levon 		set_state_expr(size_id, expr, &undefined);
671f5207b7SJohn Levon 		set_state(link_id, sm->name, sm->sym, &undefined);
681f5207b7SJohn Levon 		return;
691f5207b7SJohn Levon 	}
701f5207b7SJohn Levon 
711f5207b7SJohn Levon 	FOR_EACH_PTR(sm->possible, tmp) {
721f5207b7SJohn Levon 		expr = tmp->state->data;
731f5207b7SJohn Levon 		if (expr)
741f5207b7SJohn Levon 			set_state_expr(size_id, expr, &undefined);
751f5207b7SJohn Levon 	} END_FOR_EACH_PTR(tmp);
761f5207b7SJohn Levon 	set_state(link_id, sm->name, sm->sym, &undefined);
771f5207b7SJohn Levon }
781f5207b7SJohn Levon 
79*efe51d0cSJohn Levon static const char *limit_map[] = {
80*efe51d0cSJohn Levon 	"byte_count",
81*efe51d0cSJohn Levon 	"elem_count",
82*efe51d0cSJohn Levon 	"elem_last",
83*efe51d0cSJohn Levon 	"used_count",
84*efe51d0cSJohn Levon 	"used_last",
85*efe51d0cSJohn Levon };
86*efe51d0cSJohn Levon 
87*efe51d0cSJohn Levon int state_to_limit(struct smatch_state *state)
88*efe51d0cSJohn Levon {
89*efe51d0cSJohn Levon 	int i;
90*efe51d0cSJohn Levon 
91*efe51d0cSJohn Levon 	if (!state || !state->data)
92*efe51d0cSJohn Levon 		return -1;
93*efe51d0cSJohn Levon 
94*efe51d0cSJohn Levon 	for (i = 0; i < ARRAY_SIZE(limit_map); i++) {
95*efe51d0cSJohn Levon 		if (strncmp(state->name, limit_map[i], strlen(limit_map[i])) == 0)
96*efe51d0cSJohn Levon 			return i + BYTE_COUNT;
97*efe51d0cSJohn Levon 	}
98*efe51d0cSJohn Levon 
99*efe51d0cSJohn Levon 	return -1;
100*efe51d0cSJohn Levon }
101*efe51d0cSJohn Levon 
102*efe51d0cSJohn Levon const char *limit_type_str(unsigned int limit_type)
103*efe51d0cSJohn Levon {
104*efe51d0cSJohn Levon 	if (limit_type - BYTE_COUNT >= ARRAY_SIZE(limit_map)) {
105*efe51d0cSJohn Levon 		sm_msg("internal: wrong size type %u", limit_type);
106*efe51d0cSJohn Levon 		return "unknown";
107*efe51d0cSJohn Levon 	}
108*efe51d0cSJohn Levon 
109*efe51d0cSJohn Levon 	return limit_map[limit_type - BYTE_COUNT];
110*efe51d0cSJohn Levon }
111*efe51d0cSJohn Levon 
112*efe51d0cSJohn Levon static struct smatch_state *alloc_compare_size(int limit_type, struct expression *expr)
1131f5207b7SJohn Levon {
1141f5207b7SJohn Levon 	struct smatch_state *state;
1151f5207b7SJohn Levon 	char *name;
116*efe51d0cSJohn Levon 	char buf[256];
1171f5207b7SJohn Levon 
1181f5207b7SJohn Levon 	state = __alloc_smatch_state(0);
1191f5207b7SJohn Levon 	expr = strip_expr(expr);
1201f5207b7SJohn Levon 	name = expr_to_str(expr);
121*efe51d0cSJohn Levon 	snprintf(buf, sizeof(buf), "%s %s", limit_type_str(limit_type), name);
122*efe51d0cSJohn Levon 	state->name = alloc_sname(buf);
1231f5207b7SJohn Levon 	free_string(name);
1241f5207b7SJohn Levon 	state->data = expr;
1251f5207b7SJohn Levon 	return state;
1261f5207b7SJohn Levon }
1271f5207b7SJohn Levon 
1281f5207b7SJohn Levon static int bytes_per_element(struct expression *expr)
1291f5207b7SJohn Levon {
1301f5207b7SJohn Levon 	struct symbol *type;
1311f5207b7SJohn Levon 
1321f5207b7SJohn Levon 	type = get_type(expr);
1331f5207b7SJohn Levon 	if (!type)
1341f5207b7SJohn Levon 		return 0;
1351f5207b7SJohn Levon 
1361f5207b7SJohn Levon 	if (type->type != SYM_PTR && type->type != SYM_ARRAY)
1371f5207b7SJohn Levon 		return 0;
1381f5207b7SJohn Levon 
1391f5207b7SJohn Levon 	type = get_base_type(type);
1401f5207b7SJohn Levon 	return type_bytes(type);
1411f5207b7SJohn Levon }
1421f5207b7SJohn Levon 
143*efe51d0cSJohn Levon static void db_save_type_links(struct expression *array, int type_limit, struct expression *size)
1441f5207b7SJohn Levon {
1451f5207b7SJohn Levon 	const char *array_name;
1461f5207b7SJohn Levon 
1471f5207b7SJohn Levon 	array_name = get_data_info_name(array);
1481f5207b7SJohn Levon 	if (!array_name)
1491f5207b7SJohn Levon 		array_name = "";
150*efe51d0cSJohn Levon 	sql_insert_data_info(size, type_limit, array_name);
1511f5207b7SJohn Levon }
1521f5207b7SJohn Levon 
1531f5207b7SJohn Levon static void match_alloc_helper(struct expression *pointer, struct expression *size)
1541f5207b7SJohn Levon {
1551f5207b7SJohn Levon 	struct expression *tmp;
1561f5207b7SJohn Levon 	struct sm_state *sm;
157*efe51d0cSJohn Levon 	int limit_type = ELEM_COUNT;
1581f5207b7SJohn Levon 	sval_t sval;
1591f5207b7SJohn Levon 	int cnt = 0;
1601f5207b7SJohn Levon 
1611f5207b7SJohn Levon 	pointer = strip_expr(pointer);
1621f5207b7SJohn Levon 	size = strip_expr(size);
1631f5207b7SJohn Levon 	if (!size || !pointer)
1641f5207b7SJohn Levon 		return;
1651f5207b7SJohn Levon 
1661f5207b7SJohn Levon 	while ((tmp = get_assigned_expr(size))) {
1671f5207b7SJohn Levon 		size = strip_expr(tmp);
1681f5207b7SJohn Levon 		if (cnt++ > 5)
1691f5207b7SJohn Levon 			break;
1701f5207b7SJohn Levon 	}
1711f5207b7SJohn Levon 
1721f5207b7SJohn Levon 	if (size->type == EXPR_BINOP && size->op == '*') {
1731f5207b7SJohn Levon 		struct expression *mult_left, *mult_right;
1741f5207b7SJohn Levon 
1751f5207b7SJohn Levon 		mult_left = strip_expr(size->left);
1761f5207b7SJohn Levon 		mult_right = strip_expr(size->right);
1771f5207b7SJohn Levon 
1781f5207b7SJohn Levon 		if (get_implied_value(mult_left, &sval) &&
1791f5207b7SJohn Levon 		    sval.value == bytes_per_element(pointer))
1801f5207b7SJohn Levon 			size = mult_right;
1811f5207b7SJohn Levon 		else if (get_implied_value(mult_right, &sval) &&
1821f5207b7SJohn Levon 		    sval.value == bytes_per_element(pointer))
1831f5207b7SJohn Levon 			size = mult_left;
1841f5207b7SJohn Levon 		else
1851f5207b7SJohn Levon 			return;
1861f5207b7SJohn Levon 	}
1871f5207b7SJohn Levon 
1881f5207b7SJohn Levon 	/* Only save links to variables, not fixed sizes */
1891f5207b7SJohn Levon 	if (get_value(size, &sval))
1901f5207b7SJohn Levon 		return;
1911f5207b7SJohn Levon 
192*efe51d0cSJohn Levon 	if (size->type == EXPR_BINOP && size->op == '+' &&
193*efe51d0cSJohn Levon 	    get_value(size->right, &sval) && sval.value == 1) {
194*efe51d0cSJohn Levon 		size = size->left;
195*efe51d0cSJohn Levon 		limit_type = ELEM_LAST;
196*efe51d0cSJohn Levon 	}
197*efe51d0cSJohn Levon 
198*efe51d0cSJohn Levon 	db_save_type_links(pointer, limit_type, size);
199*efe51d0cSJohn Levon 	sm = set_state_expr(size_id, pointer, alloc_compare_size(limit_type, size));
2001f5207b7SJohn Levon 	if (!sm)
2011f5207b7SJohn Levon 		return;
202*efe51d0cSJohn Levon 	set_state_expr(link_id, size, alloc_state_expr(pointer));
2031f5207b7SJohn Levon }
2041f5207b7SJohn Levon 
2051f5207b7SJohn Levon static void match_alloc(const char *fn, struct expression *expr, void *_size_arg)
2061f5207b7SJohn Levon {
2071f5207b7SJohn Levon 	int size_arg = PTR_INT(_size_arg);
2081f5207b7SJohn Levon 	struct expression *pointer, *call, *arg;
2091f5207b7SJohn Levon 
2101f5207b7SJohn Levon 	pointer = strip_expr(expr->left);
2111f5207b7SJohn Levon 	call = strip_expr(expr->right);
2121f5207b7SJohn Levon 	arg = get_argument_from_call_expr(call->args, size_arg);
2131f5207b7SJohn Levon 	match_alloc_helper(pointer, arg);
2141f5207b7SJohn Levon }
2151f5207b7SJohn Levon 
2161f5207b7SJohn Levon static void match_calloc(const char *fn, struct expression *expr, void *_start_arg)
2171f5207b7SJohn Levon {
2181f5207b7SJohn Levon 	int start_arg = PTR_INT(_start_arg);
2191f5207b7SJohn Levon 	struct expression *pointer, *call, *arg;
2201f5207b7SJohn Levon 	struct sm_state *tmp;
221*efe51d0cSJohn Levon 	int limit_type = ELEM_COUNT;
2221f5207b7SJohn Levon 	sval_t sval;
2231f5207b7SJohn Levon 
2241f5207b7SJohn Levon 	pointer = strip_expr(expr->left);
2251f5207b7SJohn Levon 	call = strip_expr(expr->right);
2261f5207b7SJohn Levon 	arg = get_argument_from_call_expr(call->args, start_arg);
2271f5207b7SJohn Levon 	if (get_implied_value(arg, &sval) &&
2281f5207b7SJohn Levon 	    sval.value == bytes_per_element(pointer))
2291f5207b7SJohn Levon 		arg = get_argument_from_call_expr(call->args, start_arg + 1);
2301f5207b7SJohn Levon 
231*efe51d0cSJohn Levon 	if (arg->type == EXPR_BINOP && arg->op == '+' &&
232*efe51d0cSJohn Levon 	    get_value(arg->right, &sval) && sval.value == 1) {
233*efe51d0cSJohn Levon 		arg = arg->left;
234*efe51d0cSJohn Levon 		limit_type = ELEM_LAST;
235*efe51d0cSJohn Levon 	}
236*efe51d0cSJohn Levon 
237*efe51d0cSJohn Levon 	db_save_type_links(pointer, limit_type, arg);
238*efe51d0cSJohn Levon 	tmp = set_state_expr(size_id, pointer, alloc_compare_size(limit_type, arg));
2391f5207b7SJohn Levon 	if (!tmp)
2401f5207b7SJohn Levon 		return;
241*efe51d0cSJohn Levon 	set_state_expr(link_id, arg, alloc_state_expr(pointer));
2421f5207b7SJohn Levon }
2431f5207b7SJohn Levon 
244*efe51d0cSJohn Levon struct expression *get_size_variable(struct expression *buf, int *limit_type)
2451f5207b7SJohn Levon {
2461f5207b7SJohn Levon 	struct smatch_state *state;
2471f5207b7SJohn Levon 
2481f5207b7SJohn Levon 	state = get_state_expr(size_id, buf);
249*efe51d0cSJohn Levon 	if (!state)
250*efe51d0cSJohn Levon 		return NULL;
251*efe51d0cSJohn Levon 	*limit_type = state_to_limit(state);
252*efe51d0cSJohn Levon 	return state->data;
2531f5207b7SJohn Levon }
2541f5207b7SJohn Levon 
2551f5207b7SJohn Levon struct expression *get_array_variable(struct expression *size)
2561f5207b7SJohn Levon {
2571f5207b7SJohn Levon 	struct smatch_state *state;
2581f5207b7SJohn Levon 
2591f5207b7SJohn Levon 	state = get_state_expr(link_id, size);
2601f5207b7SJohn Levon 	if (state)
2611f5207b7SJohn Levon 		return state->data;
2621f5207b7SJohn Levon 	return NULL;
2631f5207b7SJohn Levon }
2641f5207b7SJohn Levon 
2651f5207b7SJohn Levon static void array_check(struct expression *expr)
2661f5207b7SJohn Levon {
2671f5207b7SJohn Levon 	struct expression *array;
2681f5207b7SJohn Levon 	struct expression *size;
2691f5207b7SJohn Levon 	struct expression *offset;
2701f5207b7SJohn Levon 	char *array_str, *offset_str;
271*efe51d0cSJohn Levon 	int limit_type;
2721f5207b7SJohn Levon 
2731f5207b7SJohn Levon 	expr = strip_expr(expr);
2741f5207b7SJohn Levon 	if (!is_array(expr))
2751f5207b7SJohn Levon 		return;
2761f5207b7SJohn Levon 
2771f5207b7SJohn Levon 	array = get_array_base(expr);
278*efe51d0cSJohn Levon 	size = get_size_variable(array, &limit_type);
2791f5207b7SJohn Levon 	if (!size)
2801f5207b7SJohn Levon 		return;
281*efe51d0cSJohn Levon 	if (limit_type != ELEM_COUNT)
282*efe51d0cSJohn Levon 		return;
2831f5207b7SJohn Levon 	offset = get_array_offset(expr);
2841f5207b7SJohn Levon 	if (!possible_comparison(size, SPECIAL_EQUAL, offset))
2851f5207b7SJohn Levon 		return;
2861f5207b7SJohn Levon 
2871f5207b7SJohn Levon 	array_str = expr_to_str(array);
2881f5207b7SJohn Levon 	offset_str = expr_to_str(offset);
2891f5207b7SJohn Levon 	sm_warning("potentially one past the end of array '%s[%s]'", array_str, offset_str);
2901f5207b7SJohn Levon 	free_string(array_str);
2911f5207b7SJohn Levon 	free_string(offset_str);
2921f5207b7SJohn Levon }
2931f5207b7SJohn Levon 
2941f5207b7SJohn Levon struct db_info {
2951f5207b7SJohn Levon 	char *name;
2961f5207b7SJohn Levon 	int ret;
2971f5207b7SJohn Levon };
2981f5207b7SJohn Levon 
2991f5207b7SJohn Levon static int db_limitter_callback(void *_info, int argc, char **argv, char **azColName)
3001f5207b7SJohn Levon {
3011f5207b7SJohn Levon 	struct db_info *info = _info;
3021f5207b7SJohn Levon 
3031f5207b7SJohn Levon 	/*
3041f5207b7SJohn Levon 	 * If possible the limitters are tied to the struct they limit.  If we
3051f5207b7SJohn Levon 	 * aren't sure which struct they limit then we use them as limitters for
3061f5207b7SJohn Levon 	 * everything.
3071f5207b7SJohn Levon 	 */
3081f5207b7SJohn Levon 	if (!info->name || argv[0][0] == '\0' || strcmp(info->name, argv[0]) == 0)
3091f5207b7SJohn Levon 		info->ret = 1;
3101f5207b7SJohn Levon 	return 0;
3111f5207b7SJohn Levon }
3121f5207b7SJohn Levon 
3131f5207b7SJohn Levon static char *vsl_to_data_info_name(const char *name, struct var_sym_list *vsl)
3141f5207b7SJohn Levon {
3151f5207b7SJohn Levon 	struct var_sym *vs;
3161f5207b7SJohn Levon 	struct symbol *type;
3171f5207b7SJohn Levon 	static char buf[80];
3181f5207b7SJohn Levon 	const char *p;
3191f5207b7SJohn Levon 
3201f5207b7SJohn Levon 	if (ptr_list_size((struct ptr_list *)vsl) != 1)
3211f5207b7SJohn Levon 		return NULL;
3221f5207b7SJohn Levon 	vs = first_ptr_list((struct ptr_list *)vsl);
3231f5207b7SJohn Levon 
3241f5207b7SJohn Levon 	type = get_real_base_type(vs->sym);
3251f5207b7SJohn Levon 	if (!type || type->type != SYM_PTR)
3261f5207b7SJohn Levon 		goto top_level_name;
3271f5207b7SJohn Levon 	type = get_real_base_type(type);
3281f5207b7SJohn Levon 	if (!type || type->type != SYM_STRUCT)
3291f5207b7SJohn Levon 		goto top_level_name;
3301f5207b7SJohn Levon 	if (!type->ident)
3311f5207b7SJohn Levon 		goto top_level_name;
3321f5207b7SJohn Levon 
3331f5207b7SJohn Levon 	p = name;
3341f5207b7SJohn Levon 	while ((name = strstr(p, "->")))
3351f5207b7SJohn Levon 		p = name + 2;
3361f5207b7SJohn Levon 
3371f5207b7SJohn Levon 	snprintf(buf, sizeof(buf),"(struct %s)->%s", type->ident->name, p);
3381f5207b7SJohn Levon 	return alloc_sname(buf);
3391f5207b7SJohn Levon 
3401f5207b7SJohn Levon top_level_name:
3411f5207b7SJohn Levon 	if (!(vs->sym->ctype.modifiers & MOD_TOPLEVEL))
3421f5207b7SJohn Levon 		return NULL;
3431f5207b7SJohn Levon 	if (vs->sym->ctype.modifiers & MOD_STATIC)
3441f5207b7SJohn Levon 		snprintf(buf, sizeof(buf),"static %s", name);
3451f5207b7SJohn Levon 	else
3461f5207b7SJohn Levon 		snprintf(buf, sizeof(buf),"global %s", name);
3471f5207b7SJohn Levon 	return alloc_sname(buf);
3481f5207b7SJohn Levon }
3491f5207b7SJohn Levon 
3501f5207b7SJohn Levon int db_var_is_array_limit(struct expression *array, const char *name, struct var_sym_list *vsl)
3511f5207b7SJohn Levon {
3521f5207b7SJohn Levon 	char *size_name;
3531f5207b7SJohn Levon 	char *array_name = get_data_info_name(array);
3541f5207b7SJohn Levon 	struct db_info db_info = {.name = array_name,};
3551f5207b7SJohn Levon 
3561f5207b7SJohn Levon 	size_name = vsl_to_data_info_name(name, vsl);
3571f5207b7SJohn Levon 	if (!size_name)
3581f5207b7SJohn Levon 		return 0;
3591f5207b7SJohn Levon 
3601f5207b7SJohn Levon 	run_sql(db_limitter_callback, &db_info,
3611f5207b7SJohn Levon 		"select value from data_info where type = %d and data = '%s';",
3621f5207b7SJohn Levon 		ARRAY_LEN, size_name);
3631f5207b7SJohn Levon 
3641f5207b7SJohn Levon 	return db_info.ret;
3651f5207b7SJohn Levon }
3661f5207b7SJohn Levon 
367*efe51d0cSJohn Levon int buf_comparison_index_ok(struct expression *expr)
3681f5207b7SJohn Levon {
3691f5207b7SJohn Levon 	struct expression *array;
3701f5207b7SJohn Levon 	struct expression *size;
3711f5207b7SJohn Levon 	struct expression *offset;
372*efe51d0cSJohn Levon 	int limit_type;
3731f5207b7SJohn Levon 	int comparison;
3741f5207b7SJohn Levon 
3751f5207b7SJohn Levon 	array = get_array_base(expr);
376*efe51d0cSJohn Levon 	size = get_size_variable(array, &limit_type);
3771f5207b7SJohn Levon 	if (!size)
3781f5207b7SJohn Levon 		return 0;
3791f5207b7SJohn Levon 	offset = get_array_offset(expr);
380*efe51d0cSJohn Levon 	comparison = get_comparison(offset, size);
381*efe51d0cSJohn Levon 	if (!comparison)
382*efe51d0cSJohn Levon 		return 0;
383*efe51d0cSJohn Levon 
384*efe51d0cSJohn Levon 	if ((limit_type == ELEM_COUNT || limit_type == ELEM_LAST) &&
385*efe51d0cSJohn Levon 	    (comparison == '<' || comparison == SPECIAL_UNSIGNED_LT))
386*efe51d0cSJohn Levon 		return 1;
387*efe51d0cSJohn Levon 	if (limit_type == ELEM_LAST &&
388*efe51d0cSJohn Levon 	    (comparison == SPECIAL_LTE ||
389*efe51d0cSJohn Levon 	     comparison == SPECIAL_UNSIGNED_LTE ||
390*efe51d0cSJohn Levon 	     comparison == SPECIAL_EQUAL))
3911f5207b7SJohn Levon 		return 1;
3921f5207b7SJohn Levon 
3931f5207b7SJohn Levon 	return 0;
3941f5207b7SJohn Levon }
3951f5207b7SJohn Levon 
3961f5207b7SJohn Levon static int known_access_ok_numbers(struct expression *expr)
3971f5207b7SJohn Levon {
3981f5207b7SJohn Levon 	struct expression *array;
3991f5207b7SJohn Levon 	struct expression *offset;
4001f5207b7SJohn Levon 	sval_t max;
4011f5207b7SJohn Levon 	int size;
4021f5207b7SJohn Levon 
4031f5207b7SJohn Levon 	array = get_array_base(expr);
4041f5207b7SJohn Levon 	offset = get_array_offset(expr);
4051f5207b7SJohn Levon 
4061f5207b7SJohn Levon 	size = get_array_size(array);
4071f5207b7SJohn Levon 	if (size <= 0)
4081f5207b7SJohn Levon 		return 0;
4091f5207b7SJohn Levon 
4101f5207b7SJohn Levon 	get_absolute_max(offset, &max);
4111f5207b7SJohn Levon 	if (max.uvalue < size)
4121f5207b7SJohn Levon 		return 1;
4131f5207b7SJohn Levon 	return 0;
4141f5207b7SJohn Levon }
4151f5207b7SJohn Levon 
4161f5207b7SJohn Levon static void array_check_data_info(struct expression *expr)
4171f5207b7SJohn Levon {
4181f5207b7SJohn Levon 	struct expression *array;
4191f5207b7SJohn Levon 	struct expression *offset;
4201f5207b7SJohn Levon 	struct state_list *slist;
4211f5207b7SJohn Levon 	struct sm_state *sm;
4221f5207b7SJohn Levon 	struct compare_data *comp;
4231f5207b7SJohn Levon 	char *offset_name;
4241f5207b7SJohn Levon 	const char *equal_name = NULL;
4251f5207b7SJohn Levon 
4261f5207b7SJohn Levon 	expr = strip_expr(expr);
4271f5207b7SJohn Levon 	if (!is_array(expr))
4281f5207b7SJohn Levon 		return;
4291f5207b7SJohn Levon 
4301f5207b7SJohn Levon 	if (known_access_ok_numbers(expr))
4311f5207b7SJohn Levon 		return;
432*efe51d0cSJohn Levon 	if (buf_comparison_index_ok(expr))
4331f5207b7SJohn Levon 		return;
4341f5207b7SJohn Levon 
4351f5207b7SJohn Levon 	array = get_array_base(expr);
4361f5207b7SJohn Levon 	offset = get_array_offset(expr);
4371f5207b7SJohn Levon 	offset_name = expr_to_var(offset);
4381f5207b7SJohn Levon 	if (!offset_name)
4391f5207b7SJohn Levon 		return;
4401f5207b7SJohn Levon 	slist = get_all_possible_equal_comparisons(offset);
4411f5207b7SJohn Levon 	if (!slist)
4421f5207b7SJohn Levon 		goto free;
4431f5207b7SJohn Levon 
4441f5207b7SJohn Levon 	FOR_EACH_PTR(slist, sm) {
4451f5207b7SJohn Levon 		comp = sm->state->data;
4461f5207b7SJohn Levon 		if (strcmp(comp->left_var, offset_name) == 0) {
4471f5207b7SJohn Levon 			if (db_var_is_array_limit(array, comp->right_var, comp->right_vsl)) {
4481f5207b7SJohn Levon 				equal_name = comp->right_var;
4491f5207b7SJohn Levon 				break;
4501f5207b7SJohn Levon 			}
4511f5207b7SJohn Levon 		} else if (strcmp(comp->right_var, offset_name) == 0) {
4521f5207b7SJohn Levon 			if (db_var_is_array_limit(array, comp->left_var, comp->left_vsl)) {
4531f5207b7SJohn Levon 				equal_name = comp->left_var;
4541f5207b7SJohn Levon 				break;
4551f5207b7SJohn Levon 			}
4561f5207b7SJohn Levon 		}
4571f5207b7SJohn Levon 	} END_FOR_EACH_PTR(sm);
4581f5207b7SJohn Levon 
4591f5207b7SJohn Levon 	if (equal_name) {
4601f5207b7SJohn Levon 		char *array_name = expr_to_str(array);
4611f5207b7SJohn Levon 
4621f5207b7SJohn Levon 		sm_warning("potential off by one '%s[]' limit '%s'", array_name, equal_name);
4631f5207b7SJohn Levon 		free_string(array_name);
4641f5207b7SJohn Levon 	}
4651f5207b7SJohn Levon 
4661f5207b7SJohn Levon free:
4671f5207b7SJohn Levon 	free_slist(&slist);
4681f5207b7SJohn Levon 	free_string(offset_name);
4691f5207b7SJohn Levon }
4701f5207b7SJohn Levon 
4711f5207b7SJohn Levon static void add_allocation_function(const char *func, void *call_back, int param)
4721f5207b7SJohn Levon {
4731f5207b7SJohn Levon 	add_function_assign_hook(func, call_back, INT_PTR(param));
4741f5207b7SJohn Levon }
4751f5207b7SJohn Levon 
476*efe51d0cSJohn Levon static int is_sizeof(struct expression *expr)
4771f5207b7SJohn Levon {
478*efe51d0cSJohn Levon 	const char *name;
479*efe51d0cSJohn Levon 
480*efe51d0cSJohn Levon 	if (expr->type == EXPR_SIZEOF)
481*efe51d0cSJohn Levon 		return 1;
482*efe51d0cSJohn Levon 	name = pos_ident(expr->pos);
483*efe51d0cSJohn Levon 	if (name && strcmp(name, "sizeof") == 0)
484*efe51d0cSJohn Levon 		return 1;
485*efe51d0cSJohn Levon 	return 0;
486*efe51d0cSJohn Levon }
487*efe51d0cSJohn Levon 
488*efe51d0cSJohn Levon static int match_size_binop(struct expression *size, struct expression *expr, int *limit_type)
489*efe51d0cSJohn Levon {
490*efe51d0cSJohn Levon 	int orig_type = *limit_type;
491*efe51d0cSJohn Levon 	struct expression *left;
492*efe51d0cSJohn Levon 	sval_t sval;
493*efe51d0cSJohn Levon 
494*efe51d0cSJohn Levon 	left = expr->left;
495*efe51d0cSJohn Levon 	if (!expr_equiv(size, left))
496*efe51d0cSJohn Levon 		return 0;
497*efe51d0cSJohn Levon 
498*efe51d0cSJohn Levon 	if (expr->op == '-' &&
499*efe51d0cSJohn Levon 	    get_value(expr->right, &sval) &&
500*efe51d0cSJohn Levon 	    sval.value == 1 &&
501*efe51d0cSJohn Levon 	    orig_type == ELEM_COUNT) {
502*efe51d0cSJohn Levon 		*limit_type = ELEM_LAST;
503*efe51d0cSJohn Levon 		return 1;
504*efe51d0cSJohn Levon 	}
505*efe51d0cSJohn Levon 
506*efe51d0cSJohn Levon 	if (expr->op == '+' &&
507*efe51d0cSJohn Levon 	    get_value(expr->right, &sval) &&
508*efe51d0cSJohn Levon 	    sval.value == 1 &&
509*efe51d0cSJohn Levon 	    orig_type == ELEM_LAST) {
510*efe51d0cSJohn Levon 		*limit_type = ELEM_COUNT;
511*efe51d0cSJohn Levon 		return 1;
512*efe51d0cSJohn Levon 	}
513*efe51d0cSJohn Levon 
514*efe51d0cSJohn Levon 	if (expr->op == '*' &&
515*efe51d0cSJohn Levon 	    is_sizeof(expr->right) &&
516*efe51d0cSJohn Levon 	    orig_type == ELEM_COUNT) {
517*efe51d0cSJohn Levon 		*limit_type = BYTE_COUNT;
518*efe51d0cSJohn Levon 		return 1;
519*efe51d0cSJohn Levon 	}
520*efe51d0cSJohn Levon 
521*efe51d0cSJohn Levon 	if (expr->op == '/' &&
522*efe51d0cSJohn Levon 	    is_sizeof(expr->right) &&
523*efe51d0cSJohn Levon 	    orig_type == BYTE_COUNT) {
524*efe51d0cSJohn Levon 		*limit_type = ELEM_COUNT;
525*efe51d0cSJohn Levon 		return 1;
526*efe51d0cSJohn Levon 	}
527*efe51d0cSJohn Levon 
528*efe51d0cSJohn Levon 	return 0;
529*efe51d0cSJohn Levon }
530*efe51d0cSJohn Levon 
531*efe51d0cSJohn Levon static char *buf_size_param_comparison(struct expression *array, struct expression_list *args, int *limit_type)
532*efe51d0cSJohn Levon {
533*efe51d0cSJohn Levon 	struct expression *tmp, *arg;
5341f5207b7SJohn Levon 	struct expression *size;
5351f5207b7SJohn Levon 	static char buf[32];
5361f5207b7SJohn Levon 	int i;
5371f5207b7SJohn Levon 
538*efe51d0cSJohn Levon 	size = get_size_variable(array, limit_type);
5391f5207b7SJohn Levon 	if (!size)
5401f5207b7SJohn Levon 		return NULL;
5411f5207b7SJohn Levon 
542*efe51d0cSJohn Levon 	if (*limit_type == USED_LAST)
543*efe51d0cSJohn Levon 		*limit_type = ELEM_LAST;
544*efe51d0cSJohn Levon 	if (*limit_type == USED_COUNT)
545*efe51d0cSJohn Levon 		*limit_type = ELEM_COUNT;
546*efe51d0cSJohn Levon 
5471f5207b7SJohn Levon 	i = -1;
548*efe51d0cSJohn Levon 	FOR_EACH_PTR(args, tmp) {
5491f5207b7SJohn Levon 		i++;
550*efe51d0cSJohn Levon 		arg = tmp;
5511f5207b7SJohn Levon 		if (arg == array)
5521f5207b7SJohn Levon 			continue;
553*efe51d0cSJohn Levon 		if (expr_equiv(arg, size) ||
554*efe51d0cSJohn Levon 		    (arg->type == EXPR_BINOP &&
555*efe51d0cSJohn Levon 		     match_size_binop(size, arg, limit_type))) {
556*efe51d0cSJohn Levon 			snprintf(buf, sizeof(buf), "==$%d", i);
557*efe51d0cSJohn Levon 			return buf;
558*efe51d0cSJohn Levon 		}
559*efe51d0cSJohn Levon 	} END_FOR_EACH_PTR(tmp);
5601f5207b7SJohn Levon 
5611f5207b7SJohn Levon 	return NULL;
5621f5207b7SJohn Levon }
5631f5207b7SJohn Levon 
5641f5207b7SJohn Levon static void match_call(struct expression *call)
5651f5207b7SJohn Levon {
5661f5207b7SJohn Levon 	struct expression *arg;
5671f5207b7SJohn Levon 	char *compare;
5681f5207b7SJohn Levon 	int param;
569*efe51d0cSJohn Levon 	char buf[5];
570*efe51d0cSJohn Levon 	int limit_type;
5711f5207b7SJohn Levon 
5721f5207b7SJohn Levon 	param = -1;
5731f5207b7SJohn Levon 	FOR_EACH_PTR(call->args, arg) {
5741f5207b7SJohn Levon 		param++;
5751f5207b7SJohn Levon 		if (!is_pointer(arg))
5761f5207b7SJohn Levon 			continue;
577*efe51d0cSJohn Levon 		compare = buf_size_param_comparison(arg, call->args, &limit_type);
5781f5207b7SJohn Levon 		if (!compare)
5791f5207b7SJohn Levon 			continue;
580*efe51d0cSJohn Levon 		snprintf(buf, sizeof(buf), "%d", limit_type);
581*efe51d0cSJohn Levon 		sql_insert_caller_info(call, limit_type, param, compare, buf);
5821f5207b7SJohn Levon 	} END_FOR_EACH_PTR(arg);
5831f5207b7SJohn Levon }
5841f5207b7SJohn Levon 
5851f5207b7SJohn Levon static int get_param(int param, char **name, struct symbol **sym)
5861f5207b7SJohn Levon {
5871f5207b7SJohn Levon 	struct symbol *arg;
5881f5207b7SJohn Levon 	int i;
5891f5207b7SJohn Levon 
5901f5207b7SJohn Levon 	i = 0;
5911f5207b7SJohn Levon 	FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, arg) {
5921f5207b7SJohn Levon 		/*
5931f5207b7SJohn Levon 		 * this is a temporary hack to work around a bug (I think in sparse?)
5941f5207b7SJohn Levon 		 * 2.6.37-rc1:fs/reiserfs/journal.o
5951f5207b7SJohn Levon 		 * If there is a function definition without parameter name found
5961f5207b7SJohn Levon 		 * after a function implementation then it causes a crash.
5971f5207b7SJohn Levon 		 * int foo() {}
5981f5207b7SJohn Levon 		 * int bar(char *);
5991f5207b7SJohn Levon 		 */
6001f5207b7SJohn Levon 		if (arg->ident->name < (char *)100)
6011f5207b7SJohn Levon 			continue;
6021f5207b7SJohn Levon 		if (i == param) {
6031f5207b7SJohn Levon 			*name = arg->ident->name;
6041f5207b7SJohn Levon 			*sym = arg;
6051f5207b7SJohn Levon 			return TRUE;
6061f5207b7SJohn Levon 		}
6071f5207b7SJohn Levon 		i++;
6081f5207b7SJohn Levon 	} END_FOR_EACH_PTR(arg);
6091f5207b7SJohn Levon 
6101f5207b7SJohn Levon 	return FALSE;
6111f5207b7SJohn Levon }
6121f5207b7SJohn Levon 
6131f5207b7SJohn Levon static void set_param_compare(const char *array_name, struct symbol *array_sym, char *key, char *value)
6141f5207b7SJohn Levon {
6151f5207b7SJohn Levon 	struct expression *array_expr;
6161f5207b7SJohn Levon 	struct expression *size_expr;
6171f5207b7SJohn Levon 	struct symbol *size_sym;
6181f5207b7SJohn Levon 	char *size_name;
6191f5207b7SJohn Levon 	long param;
6201f5207b7SJohn Levon 	struct sm_state *tmp;
621*efe51d0cSJohn Levon 	int limit_type;
6221f5207b7SJohn Levon 
623*efe51d0cSJohn Levon 	if (strncmp(key, "==$", 3) != 0)
6241f5207b7SJohn Levon 		return;
625*efe51d0cSJohn Levon 	param = strtol(key + 3, NULL, 10);
6261f5207b7SJohn Levon 	if (!get_param(param, &size_name, &size_sym))
6271f5207b7SJohn Levon 		return;
6281f5207b7SJohn Levon 	array_expr = symbol_expression(array_sym);
6291f5207b7SJohn Levon 	size_expr = symbol_expression(size_sym);
630*efe51d0cSJohn Levon 	limit_type = strtol(value, NULL, 10);
6311f5207b7SJohn Levon 
632*efe51d0cSJohn Levon 	tmp = set_state_expr(size_id, array_expr, alloc_compare_size(limit_type, size_expr));
6331f5207b7SJohn Levon 	if (!tmp)
6341f5207b7SJohn Levon 		return;
635*efe51d0cSJohn Levon 	set_state_expr(link_id, size_expr, alloc_state_expr(array_expr));
6361f5207b7SJohn Levon }
6371f5207b7SJohn Levon 
638*efe51d0cSJohn Levon static void set_implied(struct expression *call, struct expression *array_expr, char *key, char *value)
6391f5207b7SJohn Levon {
6401f5207b7SJohn Levon 	struct expression *size_expr;
6411f5207b7SJohn Levon 	struct symbol *size_sym;
6421f5207b7SJohn Levon 	char *size_name;
6431f5207b7SJohn Levon 	long param;
6441f5207b7SJohn Levon 	struct sm_state *tmp;
645*efe51d0cSJohn Levon 	int limit_type;
6461f5207b7SJohn Levon 
647*efe51d0cSJohn Levon 	if (strncmp(key, "==$", 3) != 0)
648*efe51d0cSJohn Levon 		return;
649*efe51d0cSJohn Levon 	param = strtol(key + 3, NULL, 10);
6501f5207b7SJohn Levon 	if (!get_param(param, &size_name, &size_sym))
6511f5207b7SJohn Levon 		return;
6521f5207b7SJohn Levon 	size_expr = symbol_expression(size_sym);
6531f5207b7SJohn Levon 
654*efe51d0cSJohn Levon 	limit_type = strtol(value, NULL, 10);
655*efe51d0cSJohn Levon 	tmp = set_state_expr(size_id, array_expr, alloc_compare_size(limit_type, size_expr));
6561f5207b7SJohn Levon 	if (!tmp)
6571f5207b7SJohn Levon 		return;
658*efe51d0cSJohn Levon 	set_state_expr(link_id, size_expr, alloc_state_expr(array_expr));
6591f5207b7SJohn Levon }
6601f5207b7SJohn Levon 
6611f5207b7SJohn Levon static void munge_start_states(struct statement *stmt)
6621f5207b7SJohn Levon {
6631f5207b7SJohn Levon 	struct state_list *slist = NULL;
6641f5207b7SJohn Levon 	struct sm_state *sm;
6651f5207b7SJohn Levon 	struct sm_state *poss;
6661f5207b7SJohn Levon 
6671f5207b7SJohn Levon 	FOR_EACH_MY_SM(size_id, __get_cur_stree(), sm) {
6681f5207b7SJohn Levon 		if (sm->state != &merged)
6691f5207b7SJohn Levon 			continue;
6701f5207b7SJohn Levon 		/*
6711f5207b7SJohn Levon 		 * screw it.  let's just assume that if one caller passes the
6721f5207b7SJohn Levon 		 * size then they all do.
6731f5207b7SJohn Levon 		 */
6741f5207b7SJohn Levon 		FOR_EACH_PTR(sm->possible, poss) {
6751f5207b7SJohn Levon 			if (poss->state != &merged &&
6761f5207b7SJohn Levon 			    poss->state != &undefined) {
6771f5207b7SJohn Levon 				add_ptr_list(&slist, poss);
6781f5207b7SJohn Levon 				break;
6791f5207b7SJohn Levon 			}
6801f5207b7SJohn Levon 		} END_FOR_EACH_PTR(poss);
6811f5207b7SJohn Levon 	} END_FOR_EACH_SM(sm);
6821f5207b7SJohn Levon 
6831f5207b7SJohn Levon 	FOR_EACH_PTR(slist, sm) {
6841f5207b7SJohn Levon 		set_state(size_id, sm->name, sm->sym, sm->state);
6851f5207b7SJohn Levon 	} END_FOR_EACH_PTR(sm);
6861f5207b7SJohn Levon 
6871f5207b7SJohn Levon 	free_slist(&slist);
6881f5207b7SJohn Levon }
6891f5207b7SJohn Levon 
690*efe51d0cSJohn Levon static void set_used(struct expression *expr)
691*efe51d0cSJohn Levon {
692*efe51d0cSJohn Levon 	struct expression *parent;
693*efe51d0cSJohn Levon 	struct expression *array;
694*efe51d0cSJohn Levon 	struct expression *offset;
695*efe51d0cSJohn Levon 	struct sm_state *tmp;
696*efe51d0cSJohn Levon 	int limit_type;
697*efe51d0cSJohn Levon 
698*efe51d0cSJohn Levon 	if (expr->op != SPECIAL_INCREMENT)
699*efe51d0cSJohn Levon 		return;
700*efe51d0cSJohn Levon 
701*efe51d0cSJohn Levon 	limit_type = USED_LAST;
702*efe51d0cSJohn Levon 	if (expr->type == EXPR_POSTOP)
703*efe51d0cSJohn Levon 		limit_type = USED_COUNT;
704*efe51d0cSJohn Levon 
705*efe51d0cSJohn Levon 	parent = expr_get_parent_expr(expr);
706*efe51d0cSJohn Levon 	if (!parent || parent->type != EXPR_BINOP)
707*efe51d0cSJohn Levon 		return;
708*efe51d0cSJohn Levon 	parent = expr_get_parent_expr(parent);
709*efe51d0cSJohn Levon 	if (!parent || !is_array(parent))
710*efe51d0cSJohn Levon 		return;
711*efe51d0cSJohn Levon 
712*efe51d0cSJohn Levon 	array = get_array_base(parent);
713*efe51d0cSJohn Levon 	offset = get_array_offset(parent);
714*efe51d0cSJohn Levon 	if (offset != expr)
715*efe51d0cSJohn Levon 		return;
716*efe51d0cSJohn Levon 
717*efe51d0cSJohn Levon 	tmp = set_state_expr(size_id, array, alloc_compare_size(limit_type, offset->unop));
718*efe51d0cSJohn Levon 	if (!tmp)
719*efe51d0cSJohn Levon 		return;
720*efe51d0cSJohn Levon 	set_state_expr(link_id, offset->unop, alloc_state_expr(array));
721*efe51d0cSJohn Levon }
722*efe51d0cSJohn Levon 
723*efe51d0cSJohn Levon static int match_assign_array(struct expression *expr)
724*efe51d0cSJohn Levon {
725*efe51d0cSJohn Levon 	// FIXME: implement
726*efe51d0cSJohn Levon 	return 0;
727*efe51d0cSJohn Levon }
728*efe51d0cSJohn Levon 
729*efe51d0cSJohn Levon static int match_assign_size(struct expression *expr)
730*efe51d0cSJohn Levon {
731*efe51d0cSJohn Levon 	struct expression *right, *size, *array;
732*efe51d0cSJohn Levon 	struct smatch_state *state;
733*efe51d0cSJohn Levon 	struct sm_state *tmp;
734*efe51d0cSJohn Levon 	int limit_type;
735*efe51d0cSJohn Levon 
736*efe51d0cSJohn Levon 	right = expr->right;
737*efe51d0cSJohn Levon 	size = right;
738*efe51d0cSJohn Levon 	if (size->type == EXPR_BINOP)
739*efe51d0cSJohn Levon 		size = size->left;
740*efe51d0cSJohn Levon 
741*efe51d0cSJohn Levon 	array = get_array_variable(size);
742*efe51d0cSJohn Levon 	if (!array)
743*efe51d0cSJohn Levon 		return 0;
744*efe51d0cSJohn Levon 	state = get_state_expr(size_id, array);
745*efe51d0cSJohn Levon 	if (!state || !state->data)
746*efe51d0cSJohn Levon 		return 0;
747*efe51d0cSJohn Levon 
748*efe51d0cSJohn Levon 	limit_type = state_to_limit(state);
749*efe51d0cSJohn Levon 	if (limit_type < 0)
750*efe51d0cSJohn Levon 		return 0;
751*efe51d0cSJohn Levon 
752*efe51d0cSJohn Levon 	if (right->type == EXPR_BINOP && !match_size_binop(size, right, &limit_type))
753*efe51d0cSJohn Levon 		return 0;
754*efe51d0cSJohn Levon 
755*efe51d0cSJohn Levon 	tmp = set_state_expr(size_id, array, alloc_compare_size(limit_type, expr->left));
756*efe51d0cSJohn Levon 	if (!tmp)
757*efe51d0cSJohn Levon 		return 0;
758*efe51d0cSJohn Levon 	set_state_expr(link_id, expr->left, alloc_state_expr(array));
759*efe51d0cSJohn Levon 	return 1;
760*efe51d0cSJohn Levon }
761*efe51d0cSJohn Levon 
762*efe51d0cSJohn Levon static void match_assign(struct expression *expr)
763*efe51d0cSJohn Levon {
764*efe51d0cSJohn Levon 	if (expr->op != '=')
765*efe51d0cSJohn Levon 		return;
766*efe51d0cSJohn Levon 
767*efe51d0cSJohn Levon 	if (match_assign_array(expr))
768*efe51d0cSJohn Levon 		return;
769*efe51d0cSJohn Levon 	match_assign_size(expr);
770*efe51d0cSJohn Levon }
771*efe51d0cSJohn Levon 
772*efe51d0cSJohn Levon static void match_copy(const char *fn, struct expression *expr, void *unused)
773*efe51d0cSJohn Levon {
774*efe51d0cSJohn Levon 	struct expression *src, *size;
775*efe51d0cSJohn Levon 	int src_param, size_param;
776*efe51d0cSJohn Levon 
777*efe51d0cSJohn Levon 	src = get_argument_from_call_expr(expr->args, 1);
778*efe51d0cSJohn Levon 	size = get_argument_from_call_expr(expr->args, 2);
779*efe51d0cSJohn Levon 	src = strip_expr(src);
780*efe51d0cSJohn Levon 	size = strip_expr(size);
781*efe51d0cSJohn Levon 	if (!src || !size)
782*efe51d0cSJohn Levon 		return;
783*efe51d0cSJohn Levon 	if (src->type != EXPR_SYMBOL || size->type != EXPR_SYMBOL)
784*efe51d0cSJohn Levon 		return;
785*efe51d0cSJohn Levon 
786*efe51d0cSJohn Levon 	src_param = get_param_num_from_sym(src->symbol);
787*efe51d0cSJohn Levon 	size_param = get_param_num_from_sym(size->symbol);
788*efe51d0cSJohn Levon 	if (src_param < 0 || size_param < 0)
789*efe51d0cSJohn Levon 		return;
790*efe51d0cSJohn Levon 
791*efe51d0cSJohn Levon 	sql_insert_cache(call_implies, "'%s', '%s', 0, %d, %d, %d, '==$%d', '%d'",
792*efe51d0cSJohn Levon 			 get_base_file(), get_function(), fn_static(),
793*efe51d0cSJohn Levon 			 BYTE_COUNT, src_param, size_param, BYTE_COUNT);
794*efe51d0cSJohn Levon }
795*efe51d0cSJohn Levon 
7961f5207b7SJohn Levon void register_buf_comparison(int id)
7971f5207b7SJohn Levon {
798*efe51d0cSJohn Levon 	int i;
799*efe51d0cSJohn Levon 
8001f5207b7SJohn Levon 	size_id = id;
8011f5207b7SJohn Levon 
802*efe51d0cSJohn Levon 	set_dynamic_states(size_id);
803*efe51d0cSJohn Levon 
8041f5207b7SJohn Levon 	add_unmatched_state_hook(size_id, &unmatched_state);
8051f5207b7SJohn Levon 
8061f5207b7SJohn Levon 	add_allocation_function("malloc", &match_alloc, 0);
8071f5207b7SJohn Levon 	add_allocation_function("memdup", &match_alloc, 1);
8081f5207b7SJohn Levon 	add_allocation_function("realloc", &match_alloc, 1);
8091f5207b7SJohn Levon 	if (option_project == PROJ_KERNEL) {
8101f5207b7SJohn Levon 		add_allocation_function("kmalloc", &match_alloc, 0);
8111f5207b7SJohn Levon 		add_allocation_function("kzalloc", &match_alloc, 0);
8121f5207b7SJohn Levon 		add_allocation_function("vmalloc", &match_alloc, 0);
8131f5207b7SJohn Levon 		add_allocation_function("__vmalloc", &match_alloc, 0);
8141f5207b7SJohn Levon 		add_allocation_function("sock_kmalloc", &match_alloc, 1);
8151f5207b7SJohn Levon 		add_allocation_function("kmemdup", &match_alloc, 1);
8161f5207b7SJohn Levon 		add_allocation_function("kmemdup_user", &match_alloc, 1);
8171f5207b7SJohn Levon 		add_allocation_function("dma_alloc_attrs", &match_alloc, 1);
8181f5207b7SJohn Levon 		add_allocation_function("pci_alloc_consistent", &match_alloc, 1);
8191f5207b7SJohn Levon 		add_allocation_function("pci_alloc_coherent", &match_alloc, 1);
8201f5207b7SJohn Levon 		add_allocation_function("devm_kmalloc", &match_alloc, 1);
8211f5207b7SJohn Levon 		add_allocation_function("devm_kzalloc", &match_alloc, 1);
8221f5207b7SJohn Levon 		add_allocation_function("kcalloc", &match_calloc, 0);
8231f5207b7SJohn Levon 		add_allocation_function("devm_kcalloc", &match_calloc, 1);
8241f5207b7SJohn Levon 		add_allocation_function("kmalloc_array", &match_calloc, 0);
8251f5207b7SJohn Levon 		add_allocation_function("krealloc", &match_alloc, 1);
826*efe51d0cSJohn Levon 
827*efe51d0cSJohn Levon 		add_function_hook("copy_from_user", &match_copy, NULL);
828*efe51d0cSJohn Levon 		add_function_hook("__copy_from_user", &match_copy, NULL);
8291f5207b7SJohn Levon 	}
8301f5207b7SJohn Levon 
8311f5207b7SJohn Levon 	add_hook(&array_check, OP_HOOK);
8321f5207b7SJohn Levon 	add_hook(&array_check_data_info, OP_HOOK);
833*efe51d0cSJohn Levon 	add_hook(&set_used, OP_HOOK);
8341f5207b7SJohn Levon 
8351f5207b7SJohn Levon 	add_hook(&match_call, FUNCTION_CALL_HOOK);
8361f5207b7SJohn Levon 	add_hook(&munge_start_states, AFTER_DEF_HOOK);
837*efe51d0cSJohn Levon 
838*efe51d0cSJohn Levon 	add_hook(&match_assign, ASSIGNMENT_HOOK);
839*efe51d0cSJohn Levon 
840*efe51d0cSJohn Levon 	for (i = BYTE_COUNT; i <= USED_COUNT; i++) {
841*efe51d0cSJohn Levon 		select_call_implies_hook(i, &set_implied);
842*efe51d0cSJohn Levon 		select_caller_info_hook(set_param_compare, i);
843*efe51d0cSJohn Levon 		select_return_implies_hook(i, &set_implied);
844*efe51d0cSJohn Levon 	}
8451f5207b7SJohn Levon }
8461f5207b7SJohn Levon 
8471f5207b7SJohn Levon void register_buf_comparison_links(int id)
8481f5207b7SJohn Levon {
8491f5207b7SJohn Levon 	link_id = id;
850*efe51d0cSJohn Levon 	set_dynamic_states(link_id);
8511f5207b7SJohn Levon 	add_merge_hook(link_id, &merge_links);
8521f5207b7SJohn Levon 	add_modification_hook(link_id, &match_link_modify);
8531f5207b7SJohn Levon }
854