11f5207b7SJohn Levon /*
21f5207b7SJohn Levon  * Copyright (C) 2017 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 #include "smatch.h"
191f5207b7SJohn Levon #include "smatch_extra.h"
201f5207b7SJohn Levon 
211f5207b7SJohn Levon static int my_id;
221f5207b7SJohn Levon 
231f5207b7SJohn Levon struct allocator {
241f5207b7SJohn Levon 	const char *func;
251f5207b7SJohn Levon 	int param;
261f5207b7SJohn Levon 	int param2;
271f5207b7SJohn Levon };
281f5207b7SJohn Levon 
291f5207b7SJohn Levon static struct allocator generic_allocator_table[] = {
301f5207b7SJohn Levon 	{"malloc", 0},
311f5207b7SJohn Levon 	{"memdup", 1},
321f5207b7SJohn Levon 	{"realloc", 1},
331f5207b7SJohn Levon };
341f5207b7SJohn Levon 
351f5207b7SJohn Levon static struct allocator kernel_allocator_table[] = {
361f5207b7SJohn Levon 	{"kmalloc", 0},
371f5207b7SJohn Levon 	{"kzalloc", 0},
381f5207b7SJohn Levon 	{"vmalloc", 0},
391f5207b7SJohn Levon 	{"__vmalloc", 0},
401f5207b7SJohn Levon 	{"vzalloc", 0},
411f5207b7SJohn Levon 	{"sock_kmalloc", 1},
421f5207b7SJohn Levon 	{"kmemdup", 1},
431f5207b7SJohn Levon 	{"kmemdup_user", 1},
441f5207b7SJohn Levon 	{"dma_alloc_attrs", 1},
451f5207b7SJohn Levon 	{"pci_alloc_consistent", 1},
461f5207b7SJohn Levon 	{"pci_alloc_coherent", 1},
471f5207b7SJohn Levon 	{"devm_kmalloc", 1},
481f5207b7SJohn Levon 	{"devm_kzalloc", 1},
491f5207b7SJohn Levon 	{"krealloc", 1},
501f5207b7SJohn Levon };
511f5207b7SJohn Levon 
521f5207b7SJohn Levon static struct allocator calloc_table[] = {
531f5207b7SJohn Levon 	{"calloc", 0, 1},
541f5207b7SJohn Levon 	{"kcalloc", 0, 1},
551f5207b7SJohn Levon 	{"kmalloc_array", 0, 1},
561f5207b7SJohn Levon 	{"devm_kcalloc", 1, 2},
571f5207b7SJohn Levon };
581f5207b7SJohn Levon 
bytes_per_element(struct expression * expr)591f5207b7SJohn Levon static int bytes_per_element(struct expression *expr)
601f5207b7SJohn Levon {
611f5207b7SJohn Levon 	struct symbol *type;
621f5207b7SJohn Levon 
631f5207b7SJohn Levon 	type = get_type(expr);
641f5207b7SJohn Levon 	if (!type)
651f5207b7SJohn Levon 		return 0;
661f5207b7SJohn Levon 
671f5207b7SJohn Levon 	if (type->type != SYM_PTR && type->type != SYM_ARRAY)
681f5207b7SJohn Levon 		return 0;
691f5207b7SJohn Levon 
701f5207b7SJohn Levon 	type = get_base_type(type);
711f5207b7SJohn Levon 	return type_bytes(type);
721f5207b7SJohn Levon }
731f5207b7SJohn Levon 
save_constraint_required(struct expression * pointer,int op,struct expression * constraint)741f5207b7SJohn Levon static void save_constraint_required(struct expression *pointer, int op, struct expression *constraint)
751f5207b7SJohn Levon {
761f5207b7SJohn Levon 	char *data, *limit;
771f5207b7SJohn Levon 
781f5207b7SJohn Levon 	data = get_constraint_str(pointer);
791f5207b7SJohn Levon 	if (!data)
801f5207b7SJohn Levon 		return;
811f5207b7SJohn Levon 
821f5207b7SJohn Levon 	limit = get_constraint_str(constraint);
831f5207b7SJohn Levon 	if (!limit) {
841f5207b7SJohn Levon 		// FIXME deal with <= also
851f5207b7SJohn Levon 		if (op == '<')
861f5207b7SJohn Levon 			set_state_expr(my_id, constraint, alloc_state_expr(pointer));
871f5207b7SJohn Levon 		goto free_data;
881f5207b7SJohn Levon 	}
891f5207b7SJohn Levon 
901f5207b7SJohn Levon 	sql_save_constraint_required(data, op, limit);
911f5207b7SJohn Levon 
921f5207b7SJohn Levon 	free_string(limit);
931f5207b7SJohn Levon free_data:
941f5207b7SJohn Levon 	free_string(data);
951f5207b7SJohn Levon }
961f5207b7SJohn Levon 
handle_zero_size_arrays(struct expression * pointer,struct expression * size)971f5207b7SJohn Levon static int handle_zero_size_arrays(struct expression *pointer, struct expression *size)
981f5207b7SJohn Levon {
991f5207b7SJohn Levon 	struct expression *left, *right;
1001f5207b7SJohn Levon 	struct symbol *type, *array, *array_type;
1011f5207b7SJohn Levon 	sval_t struct_size;
1021f5207b7SJohn Levon 	char *limit;
1031f5207b7SJohn Levon 	char data[128];
1041f5207b7SJohn Levon 
1051f5207b7SJohn Levon 	if (size->type != EXPR_BINOP || size->op != '+')
1061f5207b7SJohn Levon 		return 0;
1071f5207b7SJohn Levon 
1081f5207b7SJohn Levon 	type = get_type(pointer);
1091f5207b7SJohn Levon 	if (!type || type->type != SYM_PTR)
1101f5207b7SJohn Levon 		return 0;
1111f5207b7SJohn Levon 	type = get_real_base_type(type);
1121f5207b7SJohn Levon 	if (!type || !type->ident || type->type != SYM_STRUCT)
1131f5207b7SJohn Levon 		return 0;
1141f5207b7SJohn Levon 	if (!last_member_is_resizable(type))
1151f5207b7SJohn Levon 		return 0;
1161f5207b7SJohn Levon 	array = last_ptr_list((struct ptr_list *)type->symbol_list);
1171f5207b7SJohn Levon 	if (!array || !array->ident)
1181f5207b7SJohn Levon 		return 0;
1191f5207b7SJohn Levon 	array_type = get_real_base_type(array);
1201f5207b7SJohn Levon 	if (!array_type || array_type->type != SYM_ARRAY)
1211f5207b7SJohn Levon 		return 0;
1221f5207b7SJohn Levon 	array_type = get_real_base_type(array_type);
1231f5207b7SJohn Levon 
1241f5207b7SJohn Levon 	left = strip_expr(size->left);
1251f5207b7SJohn Levon 	right = strip_expr(size->right);
1261f5207b7SJohn Levon 
1271f5207b7SJohn Levon 	if (!get_implied_value(left, &struct_size))
1281f5207b7SJohn Levon 		return 0;
1291f5207b7SJohn Levon 	if (struct_size.value != type_bytes(type))
1301f5207b7SJohn Levon 		return 0;
1311f5207b7SJohn Levon 
1321f5207b7SJohn Levon 	if (right->type == EXPR_BINOP && right->op == '*') {
1331f5207b7SJohn Levon 		struct expression *mult_left, *mult_right;
1341f5207b7SJohn Levon 		sval_t sval;
1351f5207b7SJohn Levon 
1361f5207b7SJohn Levon 		mult_left = strip_expr(right->left);
1371f5207b7SJohn Levon 		mult_right = strip_expr(right->right);
1381f5207b7SJohn Levon 
1391f5207b7SJohn Levon 		if (get_implied_value(mult_left, &sval) &&
1401f5207b7SJohn Levon 		    sval.value == type_bytes(array_type))
1411f5207b7SJohn Levon 			size = mult_right;
1421f5207b7SJohn Levon 		else if (get_implied_value(mult_right, &sval) &&
1431f5207b7SJohn Levon 		    sval.value == type_bytes(array_type))
1441f5207b7SJohn Levon 			size = mult_left;
1451f5207b7SJohn Levon 		else
1461f5207b7SJohn Levon 			return 0;
1471f5207b7SJohn Levon 	}
1481f5207b7SJohn Levon 
1491f5207b7SJohn Levon 	snprintf(data, sizeof(data), "(struct %s)->%s", type->ident->name, array->ident->name);
1501f5207b7SJohn Levon 	limit = get_constraint_str(size);
1511f5207b7SJohn Levon 	if (!limit) {
1521f5207b7SJohn Levon 		set_state_expr(my_id, size, alloc_state_expr(
1531f5207b7SJohn Levon 			       member_expression(deref_expression(pointer), '*', array->ident)));
1541f5207b7SJohn Levon 		return 1;
1551f5207b7SJohn Levon 	}
1561f5207b7SJohn Levon 
1571f5207b7SJohn Levon 	sql_save_constraint_required(data, '<', limit);
1581f5207b7SJohn Levon 
1591f5207b7SJohn Levon 	free_string(limit);
1601f5207b7SJohn Levon 	return 1;
1611f5207b7SJohn Levon }
1621f5207b7SJohn Levon 
match_alloc_helper(struct expression * pointer,struct expression * size,int recurse)1631f5207b7SJohn Levon static void match_alloc_helper(struct expression *pointer, struct expression *size, int recurse)
1641f5207b7SJohn Levon {
1651f5207b7SJohn Levon 	struct expression *size_orig, *tmp;
1661f5207b7SJohn Levon 	sval_t sval;
1671f5207b7SJohn Levon 	int cnt = 0;
1681f5207b7SJohn Levon 
1691f5207b7SJohn Levon 	pointer = strip_expr(pointer);
1701f5207b7SJohn Levon 	size = strip_expr(size);
1711f5207b7SJohn Levon 	if (!size || !pointer)
1721f5207b7SJohn Levon 		return;
1731f5207b7SJohn Levon 
1741f5207b7SJohn Levon 	size_orig = size;
1751f5207b7SJohn Levon 	if (recurse) {
1761f5207b7SJohn Levon 		while ((tmp = get_assigned_expr(size))) {
1771f5207b7SJohn Levon 			size = strip_expr(tmp);
1781f5207b7SJohn Levon 			if (cnt++ > 5)
1791f5207b7SJohn Levon 				break;
1801f5207b7SJohn Levon 		}
1811f5207b7SJohn Levon 		if (size != size_orig) {
1821f5207b7SJohn Levon 			match_alloc_helper(pointer, size, 0);
1831f5207b7SJohn Levon 			size = size_orig;
1841f5207b7SJohn Levon 		}
1851f5207b7SJohn Levon 	}
1861f5207b7SJohn Levon 
1871f5207b7SJohn Levon 	if (handle_zero_size_arrays(pointer, size))
1881f5207b7SJohn Levon 		return;
1891f5207b7SJohn Levon 
1901f5207b7SJohn Levon 	if (size->type == EXPR_BINOP && size->op == '*') {
1911f5207b7SJohn Levon 		struct expression *mult_left, *mult_right;
1921f5207b7SJohn Levon 
1931f5207b7SJohn Levon 		mult_left = strip_expr(size->left);
1941f5207b7SJohn Levon 		mult_right = strip_expr(size->right);
1951f5207b7SJohn Levon 
1961f5207b7SJohn Levon 		if (get_implied_value(mult_left, &sval) &&
1971f5207b7SJohn Levon 		    sval.value == bytes_per_element(pointer))
1981f5207b7SJohn Levon 			size = mult_right;
1991f5207b7SJohn Levon 		else if (get_implied_value(mult_right, &sval) &&
2001f5207b7SJohn Levon 		    sval.value == bytes_per_element(pointer))
2011f5207b7SJohn Levon 			size = mult_left;
2021f5207b7SJohn Levon 		else
2031f5207b7SJohn Levon 			return;
2041f5207b7SJohn Levon 	}
2051f5207b7SJohn Levon 
2061f5207b7SJohn Levon 	if (size->type == EXPR_BINOP && size->op == '+' &&
2071f5207b7SJohn Levon 	    get_implied_value(size->right, &sval) &&
2081f5207b7SJohn Levon 	    sval.value == 1)
2091f5207b7SJohn Levon 		save_constraint_required(pointer, SPECIAL_LTE, size->left);
2101f5207b7SJohn Levon 	else
2111f5207b7SJohn Levon 		save_constraint_required(pointer, '<', size);
2121f5207b7SJohn Levon }
2131f5207b7SJohn Levon 
match_alloc(const char * fn,struct expression * expr,void * _size_arg)2141f5207b7SJohn Levon static void match_alloc(const char *fn, struct expression *expr, void *_size_arg)
2151f5207b7SJohn Levon {
2161f5207b7SJohn Levon 	int size_arg = PTR_INT(_size_arg);
2171f5207b7SJohn Levon 	struct expression *call, *arg;
2181f5207b7SJohn Levon 
2191f5207b7SJohn Levon 	call = strip_expr(expr->right);
2201f5207b7SJohn Levon 	arg = get_argument_from_call_expr(call->args, size_arg);
2211f5207b7SJohn Levon 
2221f5207b7SJohn Levon 	match_alloc_helper(expr->left, arg, 1);
2231f5207b7SJohn Levon }
2241f5207b7SJohn Levon 
match_calloc(const char * fn,struct expression * expr,void * _start_arg)2251f5207b7SJohn Levon static void match_calloc(const char *fn, struct expression *expr, void *_start_arg)
2261f5207b7SJohn Levon {
2271f5207b7SJohn Levon 	struct expression *pointer, *call, *size;
2281f5207b7SJohn Levon 	struct expression *count = NULL;
2291f5207b7SJohn Levon 	int start_arg = PTR_INT(_start_arg);
2301f5207b7SJohn Levon 	sval_t sval;
2311f5207b7SJohn Levon 
2321f5207b7SJohn Levon 	pointer = strip_expr(expr->left);
2331f5207b7SJohn Levon 	call = strip_expr(expr->right);
2341f5207b7SJohn Levon 
2351f5207b7SJohn Levon 	size = get_argument_from_call_expr(call->args, start_arg);
2361f5207b7SJohn Levon 	if (get_implied_value(size, &sval) &&
2371f5207b7SJohn Levon 	    sval.value == bytes_per_element(pointer))
2381f5207b7SJohn Levon 		count = get_argument_from_call_expr(call->args, start_arg + 1);
2391f5207b7SJohn Levon 	else {
2401f5207b7SJohn Levon 		size = get_argument_from_call_expr(call->args, start_arg + 1);
2411f5207b7SJohn Levon 		if (get_implied_value(size, &sval) &&
2421f5207b7SJohn Levon 		    sval.value == bytes_per_element(pointer))
2431f5207b7SJohn Levon 			count = get_argument_from_call_expr(call->args, start_arg);
2441f5207b7SJohn Levon 	}
2451f5207b7SJohn Levon 
2461f5207b7SJohn Levon 	if (!count)
2471f5207b7SJohn Levon 		return;
2481f5207b7SJohn Levon 
2491f5207b7SJohn Levon 	save_constraint_required(pointer, '<', count);
2501f5207b7SJohn Levon }
2511f5207b7SJohn Levon 
add_allocation_function(const char * func,void * call_back,int param)2521f5207b7SJohn Levon static void add_allocation_function(const char *func, void *call_back, int param)
2531f5207b7SJohn Levon {
2541f5207b7SJohn Levon 	add_function_assign_hook(func, call_back, INT_PTR(param));
2551f5207b7SJohn Levon }
2561f5207b7SJohn Levon 
match_assign_size(struct expression * expr)2571f5207b7SJohn Levon static void match_assign_size(struct expression *expr)
2581f5207b7SJohn Levon {
2591f5207b7SJohn Levon 	struct smatch_state *state;
2601f5207b7SJohn Levon 	char *data, *limit;
2611f5207b7SJohn Levon 
2621f5207b7SJohn Levon 	state = get_state_expr(my_id, expr->right);
2631f5207b7SJohn Levon 	if (!state || !state->data)
2641f5207b7SJohn Levon 		return;
2651f5207b7SJohn Levon 
2661f5207b7SJohn Levon 	data = get_constraint_str(state->data);
2671f5207b7SJohn Levon 	if (!data)
2681f5207b7SJohn Levon 		return;
2691f5207b7SJohn Levon 
2701f5207b7SJohn Levon 	limit = get_constraint_str(expr->left);
2711f5207b7SJohn Levon 	if (!limit)
2721f5207b7SJohn Levon 		goto free_data;
2731f5207b7SJohn Levon 
2741f5207b7SJohn Levon 	sql_save_constraint_required(data, '<', limit);
2751f5207b7SJohn Levon 
2761f5207b7SJohn Levon 	free_string(limit);
2771f5207b7SJohn Levon free_data:
2781f5207b7SJohn Levon 	free_string(data);
2791f5207b7SJohn Levon }
2801f5207b7SJohn Levon 
match_assign_has_buf_comparison(struct expression * expr)2811f5207b7SJohn Levon static void match_assign_has_buf_comparison(struct expression *expr)
2821f5207b7SJohn Levon {
2831f5207b7SJohn Levon 	struct expression *size;
284*efe51d0cSJohn Levon 	int limit_type;
2851f5207b7SJohn Levon 
2861f5207b7SJohn Levon 	if (expr->op != '=')
2871f5207b7SJohn Levon 		return;
2881f5207b7SJohn Levon 	if (expr->right->type == EXPR_CALL)
2891f5207b7SJohn Levon 		return;
290*efe51d0cSJohn Levon 	size = get_size_variable(expr->right, &limit_type);
2911f5207b7SJohn Levon 	if (!size)
2921f5207b7SJohn Levon 		return;
293*efe51d0cSJohn Levon 	if (limit_type != ELEM_COUNT)
294*efe51d0cSJohn Levon 		return;
2951f5207b7SJohn Levon 	match_alloc_helper(expr->left, size, 1);
2961f5207b7SJohn Levon }
2971f5207b7SJohn Levon 
match_assign_data(struct expression * expr)2981f5207b7SJohn Levon static void match_assign_data(struct expression *expr)
2991f5207b7SJohn Levon {
3001f5207b7SJohn Levon 	struct expression *right, *arg, *tmp;
3011f5207b7SJohn Levon 	int i;
3021f5207b7SJohn Levon 	int size_arg;
3031f5207b7SJohn Levon 	int size_arg2 = -1;
3041f5207b7SJohn Levon 
3051f5207b7SJohn Levon 	if (expr->op != '=')
3061f5207b7SJohn Levon 		return;
3071f5207b7SJohn Levon 
3081f5207b7SJohn Levon 	/* Direct calls are handled else where (for now at least) */
3091f5207b7SJohn Levon 	tmp = get_assigned_expr(expr->right);
3101f5207b7SJohn Levon 	if (!tmp)
3111f5207b7SJohn Levon 		return;
3121f5207b7SJohn Levon 
3131f5207b7SJohn Levon 	right = strip_expr(tmp);
3141f5207b7SJohn Levon 	if (right->type != EXPR_CALL)
3151f5207b7SJohn Levon 		return;
3161f5207b7SJohn Levon 
3171f5207b7SJohn Levon 	if (right->fn->type != EXPR_SYMBOL ||
3181f5207b7SJohn Levon 	    !right->fn->symbol ||
3191f5207b7SJohn Levon 	    !right->fn->symbol->ident)
3201f5207b7SJohn Levon 		return;
3211f5207b7SJohn Levon 
3221f5207b7SJohn Levon 	for (i = 0; i < ARRAY_SIZE(generic_allocator_table); i++) {
3231f5207b7SJohn Levon 		if (strcmp(right->fn->symbol->ident->name,
3241f5207b7SJohn Levon 			   generic_allocator_table[i].func) == 0) {
3251f5207b7SJohn Levon 			size_arg = generic_allocator_table[i].param;
3261f5207b7SJohn Levon 			goto found;
3271f5207b7SJohn Levon 		}
3281f5207b7SJohn Levon 	}
3291f5207b7SJohn Levon 
3301f5207b7SJohn Levon 	if (option_project != PROJ_KERNEL)
3311f5207b7SJohn Levon 		return;
3321f5207b7SJohn Levon 
3331f5207b7SJohn Levon 	for (i = 0; i < ARRAY_SIZE(kernel_allocator_table); i++) {
3341f5207b7SJohn Levon 		if (strcmp(right->fn->symbol->ident->name,
3351f5207b7SJohn Levon 			   kernel_allocator_table[i].func) == 0) {
3361f5207b7SJohn Levon 			size_arg = kernel_allocator_table[i].param;
3371f5207b7SJohn Levon 			goto found;
3381f5207b7SJohn Levon 		}
3391f5207b7SJohn Levon 	}
3401f5207b7SJohn Levon 
3411f5207b7SJohn Levon 	for (i = 0; i < ARRAY_SIZE(calloc_table); i++) {
3421f5207b7SJohn Levon 		if (strcmp(right->fn->symbol->ident->name,
3431f5207b7SJohn Levon 			   calloc_table[i].func) == 0) {
3441f5207b7SJohn Levon 			size_arg = calloc_table[i].param;
3451f5207b7SJohn Levon 			size_arg2 = calloc_table[i].param2;
3461f5207b7SJohn Levon 			goto found;
3471f5207b7SJohn Levon 		}
3481f5207b7SJohn Levon 	}
3491f5207b7SJohn Levon 
3501f5207b7SJohn Levon 	return;
3511f5207b7SJohn Levon 
3521f5207b7SJohn Levon found:
3531f5207b7SJohn Levon 	arg = get_argument_from_call_expr(right->args, size_arg);
3541f5207b7SJohn Levon 	match_alloc_helper(expr->left, arg, 1);
3551f5207b7SJohn Levon 	if (size_arg2 == -1)
3561f5207b7SJohn Levon 		return;
3571f5207b7SJohn Levon 	arg = get_argument_from_call_expr(right->args, size_arg2);
3581f5207b7SJohn Levon 	match_alloc_helper(expr->left, arg, 1);
3591f5207b7SJohn Levon }
3601f5207b7SJohn Levon 
match_assign_ARRAY_SIZE(struct expression * expr)3611f5207b7SJohn Levon static void match_assign_ARRAY_SIZE(struct expression *expr)
3621f5207b7SJohn Levon {
3631f5207b7SJohn Levon 	struct expression *array;
3641f5207b7SJohn Levon 	char *data, *limit;
3651f5207b7SJohn Levon 	const char *macro;
3661f5207b7SJohn Levon 
3671f5207b7SJohn Levon 	macro = get_macro_name(expr->right->pos);
3681f5207b7SJohn Levon 	if (!macro || strcmp(macro, "ARRAY_SIZE") != 0)
3691f5207b7SJohn Levon 		return;
3701f5207b7SJohn Levon 	array = strip_expr(expr->right);
3711f5207b7SJohn Levon 	if (array->type != EXPR_BINOP || array->op != '+')
3721f5207b7SJohn Levon 		return;
3731f5207b7SJohn Levon 	array = strip_expr(array->left);
3741f5207b7SJohn Levon 	if (array->type != EXPR_BINOP || array->op != '/')
3751f5207b7SJohn Levon 		return;
3761f5207b7SJohn Levon 	array = strip_expr(array->left);
3771f5207b7SJohn Levon 	if (array->type != EXPR_SIZEOF)
3781f5207b7SJohn Levon 		return;
3791f5207b7SJohn Levon 	array = strip_expr(array->cast_expression);
3801f5207b7SJohn Levon 	if (array->type != EXPR_PREOP || array->op != '*')
3811f5207b7SJohn Levon 		return;
3821f5207b7SJohn Levon 	array = strip_expr(array->unop);
3831f5207b7SJohn Levon 
3841f5207b7SJohn Levon 	data = get_constraint_str(array);
3851f5207b7SJohn Levon 	limit = get_constraint_str(expr->left);
3861f5207b7SJohn Levon 	if (!data || !limit)
3871f5207b7SJohn Levon 		goto free;
3881f5207b7SJohn Levon 
3891f5207b7SJohn Levon 	sql_save_constraint_required(data, '<', limit);
3901f5207b7SJohn Levon 
3911f5207b7SJohn Levon free:
3921f5207b7SJohn Levon 	free_string(data);
3931f5207b7SJohn Levon 	free_string(limit);
3941f5207b7SJohn Levon }
3951f5207b7SJohn Levon 
match_assign_buf_comparison(struct expression * expr)3961f5207b7SJohn Levon static void match_assign_buf_comparison(struct expression *expr)
3971f5207b7SJohn Levon {
3981f5207b7SJohn Levon 	struct expression *pointer;
3991f5207b7SJohn Levon 
4001f5207b7SJohn Levon 	if (expr->op != '=')
4011f5207b7SJohn Levon 		return;
4021f5207b7SJohn Levon 	pointer = get_array_variable(expr->right);
4031f5207b7SJohn Levon 	if (!pointer)
4041f5207b7SJohn Levon 		return;
4051f5207b7SJohn Levon 
4061f5207b7SJohn Levon 	match_alloc_helper(pointer, expr->right, 1);
4071f5207b7SJohn Levon }
4081f5207b7SJohn Levon 
constraint_found(void * _found,int argc,char ** argv,char ** azColName)4091f5207b7SJohn Levon static int constraint_found(void *_found, int argc, char **argv, char **azColName)
4101f5207b7SJohn Levon {
4111f5207b7SJohn Levon 	int *found = _found;
4121f5207b7SJohn Levon 
4131f5207b7SJohn Levon 	*found = 1;
4141f5207b7SJohn Levon 	return 0;
4151f5207b7SJohn Levon }
4161f5207b7SJohn Levon 
has_constraint(struct expression * expr,const char * constraint)4171f5207b7SJohn Levon static int has_constraint(struct expression *expr, const char *constraint)
4181f5207b7SJohn Levon {
4191f5207b7SJohn Levon 	int found = 0;
4201f5207b7SJohn Levon 
4211f5207b7SJohn Levon 	if (get_state_expr(my_id, expr))
4221f5207b7SJohn Levon 		return 1;
4231f5207b7SJohn Levon 
4241f5207b7SJohn Levon 	run_sql(constraint_found, &found,
4251f5207b7SJohn Levon 		"select data from constraints_required where bound = '%q' limit 1",
4261f5207b7SJohn Levon 		escape_newlines(constraint));
4271f5207b7SJohn Levon 
4281f5207b7SJohn Levon 	return found;
4291f5207b7SJohn Levon }
4301f5207b7SJohn Levon 
match_assign_constraint(struct expression * expr)4311f5207b7SJohn Levon static void match_assign_constraint(struct expression *expr)
4321f5207b7SJohn Levon {
4331f5207b7SJohn Levon 	struct symbol *type;
4341f5207b7SJohn Levon 	char *left, *right;
4351f5207b7SJohn Levon 
4361f5207b7SJohn Levon 	if (expr->op != '=')
4371f5207b7SJohn Levon 		return;
4381f5207b7SJohn Levon 
4391f5207b7SJohn Levon 	type = get_type(expr->left);
4401f5207b7SJohn Levon 	if (!type || type->type != SYM_BASETYPE)
4411f5207b7SJohn Levon 		return;
4421f5207b7SJohn Levon 
4431f5207b7SJohn Levon 	left = get_constraint_str(expr->left);
4441f5207b7SJohn Levon 	if (!left)
4451f5207b7SJohn Levon 		return;
4461f5207b7SJohn Levon 	right = get_constraint_str(expr->right);
4471f5207b7SJohn Levon 	if (!right)
4481f5207b7SJohn Levon 		goto free;
4491f5207b7SJohn Levon 	if (!has_constraint(expr->right, right))
4501f5207b7SJohn Levon 		return;
4511f5207b7SJohn Levon 	sql_copy_constraint_required(left, right);
4521f5207b7SJohn Levon free:
4531f5207b7SJohn Levon 	free_string(right);
4541f5207b7SJohn Levon 	free_string(left);
4551f5207b7SJohn Levon }
4561f5207b7SJohn Levon 
register_constraints_required(int id)4571f5207b7SJohn Levon void register_constraints_required(int id)
4581f5207b7SJohn Levon {
4591f5207b7SJohn Levon 	my_id = id;
4601f5207b7SJohn Levon 
461*efe51d0cSJohn Levon 	set_dynamic_states(my_id);
4621f5207b7SJohn Levon 	add_hook(&match_assign_size, ASSIGNMENT_HOOK);
4631f5207b7SJohn Levon 	add_hook(&match_assign_data, ASSIGNMENT_HOOK);
4641f5207b7SJohn Levon 	add_hook(&match_assign_has_buf_comparison, ASSIGNMENT_HOOK);
4651f5207b7SJohn Levon 
4661f5207b7SJohn Levon 	add_hook(&match_assign_ARRAY_SIZE, ASSIGNMENT_HOOK);
4671f5207b7SJohn Levon 	add_hook(&match_assign_ARRAY_SIZE, GLOBAL_ASSIGNMENT_HOOK);
4681f5207b7SJohn Levon 	add_hook(&match_assign_buf_comparison, ASSIGNMENT_HOOK);
4691f5207b7SJohn Levon 	add_hook(&match_assign_constraint, ASSIGNMENT_HOOK);
4701f5207b7SJohn Levon 
4711f5207b7SJohn Levon 	add_allocation_function("malloc", &match_alloc, 0);
4721f5207b7SJohn Levon 	add_allocation_function("memdup", &match_alloc, 1);
4731f5207b7SJohn Levon 	add_allocation_function("realloc", &match_alloc, 1);
4741f5207b7SJohn Levon 	add_allocation_function("realloc", &match_calloc, 0);
4751f5207b7SJohn Levon 	if (option_project == PROJ_KERNEL) {
4761f5207b7SJohn Levon 		add_allocation_function("kmalloc", &match_alloc, 0);
4771f5207b7SJohn Levon 		add_allocation_function("kzalloc", &match_alloc, 0);
4781f5207b7SJohn Levon 		add_allocation_function("vmalloc", &match_alloc, 0);
4791f5207b7SJohn Levon 		add_allocation_function("__vmalloc", &match_alloc, 0);
4801f5207b7SJohn Levon 		add_allocation_function("vzalloc", &match_alloc, 0);
4811f5207b7SJohn Levon 		add_allocation_function("sock_kmalloc", &match_alloc, 1);
4821f5207b7SJohn Levon 		add_allocation_function("kmemdup", &match_alloc, 1);
4831f5207b7SJohn Levon 		add_allocation_function("kmemdup_user", &match_alloc, 1);
4841f5207b7SJohn Levon 		add_allocation_function("dma_alloc_attrs", &match_alloc, 1);
4851f5207b7SJohn Levon 		add_allocation_function("pci_alloc_consistent", &match_alloc, 1);
4861f5207b7SJohn Levon 		add_allocation_function("pci_alloc_coherent", &match_alloc, 1);
4871f5207b7SJohn Levon 		add_allocation_function("devm_kmalloc", &match_alloc, 1);
4881f5207b7SJohn Levon 		add_allocation_function("devm_kzalloc", &match_alloc, 1);
4891f5207b7SJohn Levon 		add_allocation_function("kcalloc", &match_calloc, 0);
4901f5207b7SJohn Levon 		add_allocation_function("kmalloc_array", &match_calloc, 0);
4911f5207b7SJohn Levon 		add_allocation_function("devm_kcalloc", &match_calloc, 1);
4921f5207b7SJohn Levon 		add_allocation_function("krealloc", &match_alloc, 1);
4931f5207b7SJohn Levon 	}
4941f5207b7SJohn Levon }
495