11f5207b7SJohn Levon /*
21f5207b7SJohn Levon  * Copyright (C) 2010 Dan Carpenter.
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 <stdlib.h>
191f5207b7SJohn Levon #include <errno.h>
201f5207b7SJohn Levon #include "parse.h"
211f5207b7SJohn Levon #include "smatch.h"
221f5207b7SJohn Levon #include "smatch_slist.h"
231f5207b7SJohn Levon #include "smatch_extra.h"
241f5207b7SJohn Levon #include "smatch_function_hashtable.h"
251f5207b7SJohn Levon 
26c85f09ccSJohn Levon #define UNKNOWN_SIZE -1
271f5207b7SJohn Levon 
281f5207b7SJohn Levon static int my_size_id;
291f5207b7SJohn Levon 
301f5207b7SJohn Levon static DEFINE_HASHTABLE_INSERT(insert_func, char, int);
311f5207b7SJohn Levon static DEFINE_HASHTABLE_SEARCH(search_func, char, int);
321f5207b7SJohn Levon static struct hashtable *allocation_funcs;
331f5207b7SJohn Levon 
get_fn_name(struct expression * expr)341f5207b7SJohn Levon static char *get_fn_name(struct expression *expr)
351f5207b7SJohn Levon {
361f5207b7SJohn Levon 	if (expr->type != EXPR_CALL)
371f5207b7SJohn Levon 		return NULL;
381f5207b7SJohn Levon 	if (expr->fn->type != EXPR_SYMBOL)
391f5207b7SJohn Levon 		return NULL;
401f5207b7SJohn Levon 	return expr_to_var(expr->fn);
411f5207b7SJohn Levon }
421f5207b7SJohn Levon 
is_allocation_function(struct expression * expr)431f5207b7SJohn Levon static int is_allocation_function(struct expression *expr)
441f5207b7SJohn Levon {
451f5207b7SJohn Levon 	char *func;
461f5207b7SJohn Levon 	int ret = 0;
471f5207b7SJohn Levon 
481f5207b7SJohn Levon 	func = get_fn_name(expr);
491f5207b7SJohn Levon 	if (!func)
501f5207b7SJohn Levon 		return 0;
511f5207b7SJohn Levon 	if (search_func(allocation_funcs, func))
521f5207b7SJohn Levon 		ret = 1;
531f5207b7SJohn Levon 	free_string(func);
541f5207b7SJohn Levon 	return ret;
551f5207b7SJohn Levon }
561f5207b7SJohn Levon 
add_allocation_function(const char * func,void * call_back,int param)571f5207b7SJohn Levon static void add_allocation_function(const char *func, void *call_back, int param)
581f5207b7SJohn Levon {
591f5207b7SJohn Levon 	insert_func(allocation_funcs, (char *)func, (int *)1);
601f5207b7SJohn Levon 	add_function_assign_hook(func, call_back, INT_PTR(param));
611f5207b7SJohn Levon }
621f5207b7SJohn Levon 
estate_to_size(struct smatch_state * state)631f5207b7SJohn Levon static int estate_to_size(struct smatch_state *state)
641f5207b7SJohn Levon {
651f5207b7SJohn Levon 	sval_t sval;
661f5207b7SJohn Levon 
671f5207b7SJohn Levon 	if (!state || !estate_rl(state))
681f5207b7SJohn Levon 		return 0;
691f5207b7SJohn Levon 	sval = estate_max(state);
701f5207b7SJohn Levon 	return sval.value;
711f5207b7SJohn Levon }
721f5207b7SJohn Levon 
size_to_estate(int size)731f5207b7SJohn Levon static struct smatch_state *size_to_estate(int size)
741f5207b7SJohn Levon {
751f5207b7SJohn Levon 	sval_t sval;
761f5207b7SJohn Levon 
771f5207b7SJohn Levon 	sval.type = &int_ctype;
781f5207b7SJohn Levon 	sval.value = size;
791f5207b7SJohn Levon 
801f5207b7SJohn Levon 	return alloc_estate_sval(sval);
811f5207b7SJohn Levon }
821f5207b7SJohn Levon 
size_to_rl(int size)831f5207b7SJohn Levon static struct range_list *size_to_rl(int size)
841f5207b7SJohn Levon {
851f5207b7SJohn Levon 	sval_t sval;
861f5207b7SJohn Levon 
871f5207b7SJohn Levon 	sval.type = &int_ctype;
881f5207b7SJohn Levon 	sval.value = size;
891f5207b7SJohn Levon 
901f5207b7SJohn Levon 	return alloc_rl(sval, sval);
911f5207b7SJohn Levon }
921f5207b7SJohn Levon 
unmatched_size_state(struct sm_state * sm)931f5207b7SJohn Levon static struct smatch_state *unmatched_size_state(struct sm_state *sm)
941f5207b7SJohn Levon {
951f5207b7SJohn Levon 	return size_to_estate(UNKNOWN_SIZE);
961f5207b7SJohn Levon }
971f5207b7SJohn Levon 
set_size_undefined(struct sm_state * sm,struct expression * mod_expr)981f5207b7SJohn Levon static void set_size_undefined(struct sm_state *sm, struct expression *mod_expr)
991f5207b7SJohn Levon {
1001f5207b7SJohn Levon 	set_state(sm->owner, sm->name, sm->sym, size_to_estate(UNKNOWN_SIZE));
1011f5207b7SJohn Levon }
1021f5207b7SJohn Levon 
merge_size_func(struct smatch_state * s1,struct smatch_state * s2)1031f5207b7SJohn Levon static struct smatch_state *merge_size_func(struct smatch_state *s1, struct smatch_state *s2)
1041f5207b7SJohn Levon {
1051f5207b7SJohn Levon 	return merge_estates(s1, s2);
1061f5207b7SJohn Levon }
1071f5207b7SJohn Levon 
set_param_buf_size(const char * name,struct symbol * sym,char * key,char * value)1081f5207b7SJohn Levon void set_param_buf_size(const char *name, struct symbol *sym, char *key, char *value)
1091f5207b7SJohn Levon {
1101f5207b7SJohn Levon 	struct range_list *rl = NULL;
1111f5207b7SJohn Levon 	struct smatch_state *state;
1121f5207b7SJohn Levon 	char fullname[256];
1131f5207b7SJohn Levon 
1141f5207b7SJohn Levon 	if (strncmp(key, "$", 1) != 0)
1151f5207b7SJohn Levon 		return;
1161f5207b7SJohn Levon 
1171f5207b7SJohn Levon 	snprintf(fullname, 256, "%s%s", name, key + 1);
1181f5207b7SJohn Levon 
1191f5207b7SJohn Levon 	str_to_rl(&int_ctype, value, &rl);
1201f5207b7SJohn Levon 	if (!rl || is_whole_rl(rl))
1211f5207b7SJohn Levon 		return;
1221f5207b7SJohn Levon 	state = alloc_estate_rl(rl);
1231f5207b7SJohn Levon 	set_state(my_size_id, fullname, sym, state);
1241f5207b7SJohn Levon }
1251f5207b7SJohn Levon 
bytes_per_element(struct expression * expr)1261f5207b7SJohn Levon static int bytes_per_element(struct expression *expr)
1271f5207b7SJohn Levon {
1281f5207b7SJohn Levon 	struct symbol *type;
1291f5207b7SJohn Levon 
1301f5207b7SJohn Levon 	if (!expr)
1311f5207b7SJohn Levon 		return 0;
1321f5207b7SJohn Levon 	if (expr->type == EXPR_STRING)
1331f5207b7SJohn Levon 		return 1;
1341f5207b7SJohn Levon 	if (expr->type == EXPR_PREOP && expr->op == '&') {
1351f5207b7SJohn Levon 		type = get_type(expr->unop);
1361f5207b7SJohn Levon 		if (type && type->type == SYM_ARRAY)
1371f5207b7SJohn Levon 			expr = expr->unop;
1381f5207b7SJohn Levon 	}
1391f5207b7SJohn Levon 	type = get_type(expr);
1401f5207b7SJohn Levon 	if (!type)
1411f5207b7SJohn Levon 		return 0;
1421f5207b7SJohn Levon 
1431f5207b7SJohn Levon 	if (type->type != SYM_PTR && type->type != SYM_ARRAY)
1441f5207b7SJohn Levon 		return 0;
1451f5207b7SJohn Levon 
1461f5207b7SJohn Levon 	type = get_base_type(type);
1471f5207b7SJohn Levon 	return type_bytes(type);
1481f5207b7SJohn Levon }
1491f5207b7SJohn Levon 
bytes_to_elements(struct expression * expr,int bytes)1501f5207b7SJohn Levon static int bytes_to_elements(struct expression *expr, int bytes)
1511f5207b7SJohn Levon {
1521f5207b7SJohn Levon 	int bpe;
1531f5207b7SJohn Levon 
1541f5207b7SJohn Levon 	bpe = bytes_per_element(expr);
1551f5207b7SJohn Levon 	if (bpe == 0)
1561f5207b7SJohn Levon 		return 0;
1571f5207b7SJohn Levon 	return bytes / bpe;
1581f5207b7SJohn Levon }
1591f5207b7SJohn Levon 
elements_to_bytes(struct expression * expr,int elements)1601f5207b7SJohn Levon static int elements_to_bytes(struct expression *expr, int elements)
1611f5207b7SJohn Levon {
1621f5207b7SJohn Levon 	int bpe;
1631f5207b7SJohn Levon 
1641f5207b7SJohn Levon 	bpe = bytes_per_element(expr);
1651f5207b7SJohn Levon 	return elements * bpe;
1661f5207b7SJohn Levon }
1671f5207b7SJohn Levon 
get_initializer_size(struct expression * expr)1681f5207b7SJohn Levon static int get_initializer_size(struct expression *expr)
1691f5207b7SJohn Levon {
1701f5207b7SJohn Levon 	switch (expr->type) {
1711f5207b7SJohn Levon 	case EXPR_STRING:
1721f5207b7SJohn Levon 		return expr->string->length;
1731f5207b7SJohn Levon 	case EXPR_INITIALIZER: {
1741f5207b7SJohn Levon 		struct expression *tmp;
1751f5207b7SJohn Levon 		int i = 0;
1761f5207b7SJohn Levon 
1771f5207b7SJohn Levon 		FOR_EACH_PTR(expr->expr_list, tmp) {
1781f5207b7SJohn Levon 			if (tmp->type == EXPR_INDEX) {
1791f5207b7SJohn Levon 				if (tmp->idx_to >= i)
1801f5207b7SJohn Levon 					i = tmp->idx_to;
1811f5207b7SJohn Levon 				else
1821f5207b7SJohn Levon 					continue;
1831f5207b7SJohn Levon 			}
1841f5207b7SJohn Levon 
1851f5207b7SJohn Levon 			i++;
1861f5207b7SJohn Levon 		} END_FOR_EACH_PTR(tmp);
1871f5207b7SJohn Levon 		return i;
1881f5207b7SJohn Levon 	}
1891f5207b7SJohn Levon 	case EXPR_SYMBOL:
1901f5207b7SJohn Levon 		return get_array_size(expr);
1911f5207b7SJohn Levon 	}
1921f5207b7SJohn Levon 	return 0;
1931f5207b7SJohn Levon }
1941f5207b7SJohn Levon 
1951f5207b7SJohn Levon static struct range_list *db_size_rl;
db_size_callback(void * unused,int argc,char ** argv,char ** azColName)1961f5207b7SJohn Levon static int db_size_callback(void *unused, int argc, char **argv, char **azColName)
1971f5207b7SJohn Levon {
1981f5207b7SJohn Levon 	struct range_list *tmp = NULL;
1991f5207b7SJohn Levon 
2001f5207b7SJohn Levon 	if (!db_size_rl) {
2011f5207b7SJohn Levon 		str_to_rl(&int_ctype, argv[0], &db_size_rl);
2021f5207b7SJohn Levon 	} else {
2031f5207b7SJohn Levon 		str_to_rl(&int_ctype, argv[0], &tmp);
2041f5207b7SJohn Levon 		db_size_rl = rl_union(db_size_rl, tmp);
2051f5207b7SJohn Levon 	}
2061f5207b7SJohn Levon 	return 0;
2071f5207b7SJohn Levon }
2081f5207b7SJohn Levon 
size_from_db_type(struct expression * expr)2091f5207b7SJohn Levon static struct range_list *size_from_db_type(struct expression *expr)
2101f5207b7SJohn Levon {
2111f5207b7SJohn Levon 	int this_file_only = 0;
2121f5207b7SJohn Levon 	char *name;
2131f5207b7SJohn Levon 
2141f5207b7SJohn Levon 	name = get_member_name(expr);
2151f5207b7SJohn Levon 	if (!name && is_static(expr)) {
2161f5207b7SJohn Levon 		name = expr_to_var(expr);
2171f5207b7SJohn Levon 		this_file_only = 1;
2181f5207b7SJohn Levon 	}
2191f5207b7SJohn Levon 	if (!name)
2201f5207b7SJohn Levon 		return NULL;
2211f5207b7SJohn Levon 
2221f5207b7SJohn Levon 	if (this_file_only) {
2231f5207b7SJohn Levon 		db_size_rl = NULL;
2241f5207b7SJohn Levon 		run_sql(db_size_callback, NULL,
2251f5207b7SJohn Levon 			"select size from function_type_size where type = '%s' and file = '%s';",
2261f5207b7SJohn Levon 			name, get_filename());
2271f5207b7SJohn Levon 		if (db_size_rl)
2281f5207b7SJohn Levon 			return db_size_rl;
2291f5207b7SJohn Levon 		return NULL;
2301f5207b7SJohn Levon 	}
2311f5207b7SJohn Levon 
2321f5207b7SJohn Levon 	db_size_rl = NULL;
2331f5207b7SJohn Levon 	run_sql(db_size_callback, NULL,
2341f5207b7SJohn Levon 		"select size from type_size where type = '%s';",
2351f5207b7SJohn Levon 		name);
2361f5207b7SJohn Levon 	return db_size_rl;
2371f5207b7SJohn Levon }
2381f5207b7SJohn Levon 
size_from_db_symbol(struct expression * expr)2391f5207b7SJohn Levon static struct range_list *size_from_db_symbol(struct expression *expr)
2401f5207b7SJohn Levon {
2411f5207b7SJohn Levon 	struct symbol *sym;
2421f5207b7SJohn Levon 
2431f5207b7SJohn Levon 	if (expr->type != EXPR_SYMBOL)
2441f5207b7SJohn Levon 		return NULL;
2451f5207b7SJohn Levon 	sym = expr->symbol;
2461f5207b7SJohn Levon 	if (!sym || !sym->ident ||
2471f5207b7SJohn Levon 	    !(sym->ctype.modifiers & MOD_TOPLEVEL) ||
2481f5207b7SJohn Levon 	    sym->ctype.modifiers & MOD_STATIC)
2491f5207b7SJohn Levon 		return NULL;
2501f5207b7SJohn Levon 
2511f5207b7SJohn Levon 	db_size_rl = NULL;
2521f5207b7SJohn Levon 	run_sql(db_size_callback, NULL,
2531f5207b7SJohn Levon 		"select value from data_info where file = 'extern' and data = '%s' and type = %d;",
2541f5207b7SJohn Levon 		sym->ident->name, BUF_SIZE);
2551f5207b7SJohn Levon 	return db_size_rl;
2561f5207b7SJohn Levon }
2571f5207b7SJohn Levon 
size_from_db(struct expression * expr)2581f5207b7SJohn Levon static struct range_list *size_from_db(struct expression *expr)
2591f5207b7SJohn Levon {
2601f5207b7SJohn Levon 	struct range_list *rl;
2611f5207b7SJohn Levon 
2621f5207b7SJohn Levon 	rl = size_from_db_symbol(expr);
2631f5207b7SJohn Levon 	if (rl)
2641f5207b7SJohn Levon 		return rl;
2651f5207b7SJohn Levon 	return size_from_db_type(expr);
2661f5207b7SJohn Levon }
2671f5207b7SJohn Levon 
db_returns_buf_size(struct expression * expr,int param,char * unused,char * math)2681f5207b7SJohn Levon static void db_returns_buf_size(struct expression *expr, int param, char *unused, char *math)
2691f5207b7SJohn Levon {
2701f5207b7SJohn Levon 	struct expression *call;
2711f5207b7SJohn Levon 	struct range_list *rl;
272*6523a3aaSJohn Levon 	sval_t sval;
2731f5207b7SJohn Levon 
2741f5207b7SJohn Levon 	if (expr->type != EXPR_ASSIGNMENT)
2751f5207b7SJohn Levon 		return;
2761f5207b7SJohn Levon 	call = strip_expr(expr->right);
2771f5207b7SJohn Levon 
278c85f09ccSJohn Levon 	call_results_to_rl(call, &int_ctype, math, &rl);
2791f5207b7SJohn Levon 	rl = cast_rl(&int_ctype, rl);
280*6523a3aaSJohn Levon 	if (rl_to_sval(rl, &sval) && sval.value == 0)
281*6523a3aaSJohn Levon 		return;
2821f5207b7SJohn Levon 	set_state_expr(my_size_id, expr->left, alloc_estate_rl(rl));
2831f5207b7SJohn Levon }
2841f5207b7SJohn Levon 
get_real_array_size_from_type(struct symbol * type)2851f5207b7SJohn Levon static int get_real_array_size_from_type(struct symbol *type)
2861f5207b7SJohn Levon {
2871f5207b7SJohn Levon 	sval_t sval;
2881f5207b7SJohn Levon 
2891f5207b7SJohn Levon 	if (!type)
2901f5207b7SJohn Levon 		return 0;
2911f5207b7SJohn Levon 	if (!type || type->type != SYM_ARRAY)
2921f5207b7SJohn Levon 		return 0;
2931f5207b7SJohn Levon 
2941f5207b7SJohn Levon 	if (!get_implied_value(type->array_size, &sval))
2951f5207b7SJohn Levon 		return 0;
2961f5207b7SJohn Levon 
2971f5207b7SJohn Levon 	return sval.value;
2981f5207b7SJohn Levon }
2991f5207b7SJohn Levon 
get_real_array_size(struct expression * expr)3001f5207b7SJohn Levon int get_real_array_size(struct expression *expr)
3011f5207b7SJohn Levon {
3021f5207b7SJohn Levon 	if (!expr)
3031f5207b7SJohn Levon 		return 0;
3041f5207b7SJohn Levon 	if (expr->type == EXPR_PREOP && expr->op == '&')
3051f5207b7SJohn Levon 		expr = expr->unop;
3061f5207b7SJohn Levon 	if (expr->type == EXPR_BINOP) /* array elements foo[5] */
3071f5207b7SJohn Levon 		return 0;
3081f5207b7SJohn Levon 	return get_real_array_size_from_type(get_type(expr));
3091f5207b7SJohn Levon }
3101f5207b7SJohn Levon 
get_size_from_initializer(struct expression * expr)3111f5207b7SJohn Levon static int get_size_from_initializer(struct expression *expr)
3121f5207b7SJohn Levon {
3131f5207b7SJohn Levon 	if (expr->type != EXPR_SYMBOL || !expr->symbol || !expr->symbol->initializer)
3141f5207b7SJohn Levon 		return 0;
3151f5207b7SJohn Levon 	if (expr->symbol->initializer == expr) /* int a = a; */
3161f5207b7SJohn Levon 		return 0;
3171f5207b7SJohn Levon 	return get_initializer_size(expr->symbol->initializer);
3181f5207b7SJohn Levon }
3191f5207b7SJohn Levon 
get_stored_size_bytes(struct expression * expr)3201f5207b7SJohn Levon static struct range_list *get_stored_size_bytes(struct expression *expr)
3211f5207b7SJohn Levon {
3221f5207b7SJohn Levon 	struct smatch_state *state;
3231f5207b7SJohn Levon 
3241f5207b7SJohn Levon 	state = get_state_expr(my_size_id, expr);
3251f5207b7SJohn Levon 	if (!state)
3261f5207b7SJohn Levon 		return NULL;
3271f5207b7SJohn Levon 	return estate_rl(state);
3281f5207b7SJohn Levon }
3291f5207b7SJohn Levon 
get_bytes_from_address(struct expression * expr)3301f5207b7SJohn Levon static int get_bytes_from_address(struct expression *expr)
3311f5207b7SJohn Levon {
3321f5207b7SJohn Levon 	struct symbol *type;
3331f5207b7SJohn Levon 	int ret;
3341f5207b7SJohn Levon 
3351f5207b7SJohn Levon 	if (expr->type != EXPR_PREOP || expr->op != '&')
3361f5207b7SJohn Levon 		return 0;
3371f5207b7SJohn Levon 	type = get_type(expr);
3381f5207b7SJohn Levon 	if (!type)
3391f5207b7SJohn Levon 		return 0;
3401f5207b7SJohn Levon 
3411f5207b7SJohn Levon 	if (type->type == SYM_PTR)
3421f5207b7SJohn Levon 		type = get_base_type(type);
3431f5207b7SJohn Levon 
3441f5207b7SJohn Levon 	ret = type_bytes(type);
3451f5207b7SJohn Levon 	if (ret == 1)
3461f5207b7SJohn Levon 		return 0;  /* ignore char pointers */
3471f5207b7SJohn Levon 
3481f5207b7SJohn Levon 	return ret;
3491f5207b7SJohn Levon }
3501f5207b7SJohn Levon 
remove_addr_fluff(struct expression * expr)3511f5207b7SJohn Levon static struct expression *remove_addr_fluff(struct expression *expr)
3521f5207b7SJohn Levon {
3531f5207b7SJohn Levon 	struct expression *tmp;
3541f5207b7SJohn Levon 	sval_t sval;
3551f5207b7SJohn Levon 
3561f5207b7SJohn Levon 	expr = strip_expr(expr);
3571f5207b7SJohn Levon 
3581f5207b7SJohn Levon 	/* remove '&' and '*' operations that cancel */
3591f5207b7SJohn Levon 	while (expr && expr->type == EXPR_PREOP && expr->op == '&') {
3601f5207b7SJohn Levon 		tmp = strip_expr(expr->unop);
3611f5207b7SJohn Levon 		if (tmp->type != EXPR_PREOP)
3621f5207b7SJohn Levon 			break;
3631f5207b7SJohn Levon 		if (tmp->op != '*')
3641f5207b7SJohn Levon 			break;
3651f5207b7SJohn Levon 		expr = strip_expr(tmp->unop);
3661f5207b7SJohn Levon 	}
3671f5207b7SJohn Levon 
3681f5207b7SJohn Levon 	if (!expr)
3691f5207b7SJohn Levon 		return NULL;
3701f5207b7SJohn Levon 
3711f5207b7SJohn Levon 	/* "foo + 0" is just "foo" */
3721f5207b7SJohn Levon 	if (expr->type == EXPR_BINOP && expr->op == '+' &&
3731f5207b7SJohn Levon 	    get_value(expr->right, &sval) && sval.value == 0)
3741f5207b7SJohn Levon 		return expr->left;
3751f5207b7SJohn Levon 
3761f5207b7SJohn Levon 	return expr;
3771f5207b7SJohn Levon }
3781f5207b7SJohn Levon 
is_last_member_of_struct(struct symbol * sym,struct ident * member)3791f5207b7SJohn Levon static int is_last_member_of_struct(struct symbol *sym, struct ident *member)
3801f5207b7SJohn Levon {
3811f5207b7SJohn Levon 	struct symbol *tmp;
3821f5207b7SJohn Levon 	int i;
3831f5207b7SJohn Levon 
3841f5207b7SJohn Levon 	i = 0;
3851f5207b7SJohn Levon 	FOR_EACH_PTR_REVERSE(sym->symbol_list, tmp) {
3861f5207b7SJohn Levon 		if (i++ || !tmp->ident)
3871f5207b7SJohn Levon 			return 0;
3881f5207b7SJohn Levon 		if (tmp->ident == member)
3891f5207b7SJohn Levon 			return 1;
3901f5207b7SJohn Levon 		return 0;
3911f5207b7SJohn Levon 	} END_FOR_EACH_PTR_REVERSE(tmp);
3921f5207b7SJohn Levon 
3931f5207b7SJohn Levon 	return 0;
3941f5207b7SJohn Levon }
3951f5207b7SJohn Levon 
last_member_is_resizable(struct symbol * sym)3961f5207b7SJohn Levon int last_member_is_resizable(struct symbol *sym)
3971f5207b7SJohn Levon {
3981f5207b7SJohn Levon 	struct symbol *last_member;
3991f5207b7SJohn Levon 	struct symbol *type;
4001f5207b7SJohn Levon 	sval_t sval;
4011f5207b7SJohn Levon 
4021f5207b7SJohn Levon 	if (!sym || sym->type != SYM_STRUCT)
4031f5207b7SJohn Levon 		return 0;
4041f5207b7SJohn Levon 
4051f5207b7SJohn Levon 	last_member = last_ptr_list((struct ptr_list *)sym->symbol_list);
4061f5207b7SJohn Levon 	if (!last_member || !last_member->ident)
4071f5207b7SJohn Levon 		return 0;
4081f5207b7SJohn Levon 
4091f5207b7SJohn Levon 	type = get_real_base_type(last_member);
4101f5207b7SJohn Levon 	if (type->type == SYM_STRUCT)
4111f5207b7SJohn Levon 		return last_member_is_resizable(type);
4121f5207b7SJohn Levon 	if (type->type != SYM_ARRAY)
4131f5207b7SJohn Levon 		return 0;
4141f5207b7SJohn Levon 
4151f5207b7SJohn Levon 	if (!get_implied_value(type->array_size, &sval))
4161f5207b7SJohn Levon 		return 0;
4171f5207b7SJohn Levon 
4181f5207b7SJohn Levon 	if (sval.value != 0 && sval.value != 1)
4191f5207b7SJohn Levon 		return 0;
4201f5207b7SJohn Levon 
4211f5207b7SJohn Levon 	return 1;
4221f5207b7SJohn Levon }
4231f5207b7SJohn Levon 
get_stored_size_end_struct_bytes(struct expression * expr)4241f5207b7SJohn Levon static int get_stored_size_end_struct_bytes(struct expression *expr)
4251f5207b7SJohn Levon {
4261f5207b7SJohn Levon 	struct symbol *sym;
4271f5207b7SJohn Levon 	struct symbol *base_sym;
4281f5207b7SJohn Levon 	struct smatch_state *state;
4291f5207b7SJohn Levon 
4301f5207b7SJohn Levon 	if (expr->type == EXPR_BINOP) /* array elements foo[5] */
4311f5207b7SJohn Levon 		return 0;
4321f5207b7SJohn Levon 
4331f5207b7SJohn Levon 	if (expr->type == EXPR_PREOP && expr->op == '&')
4341f5207b7SJohn Levon 		expr = strip_parens(expr->unop);
4351f5207b7SJohn Levon 
4361f5207b7SJohn Levon 	sym = expr_to_sym(expr);
4371f5207b7SJohn Levon 	if (!sym || !sym->ident)
4381f5207b7SJohn Levon 		return 0;
4391f5207b7SJohn Levon 	if (!type_bytes(sym))
4401f5207b7SJohn Levon 		return 0;
4411f5207b7SJohn Levon 	if (sym->type != SYM_NODE)
4421f5207b7SJohn Levon 		return 0;
4431f5207b7SJohn Levon 
4441f5207b7SJohn Levon 	base_sym = get_real_base_type(sym);
4451f5207b7SJohn Levon 	if (!base_sym || base_sym->type != SYM_PTR)
4461f5207b7SJohn Levon 		return 0;
4471f5207b7SJohn Levon 	base_sym = get_real_base_type(base_sym);
4481f5207b7SJohn Levon 	if (!base_sym || base_sym->type != SYM_STRUCT)
4491f5207b7SJohn Levon 		return 0;
4501f5207b7SJohn Levon 
4511f5207b7SJohn Levon 	if (!is_last_member_of_struct(base_sym, expr->member))
4521f5207b7SJohn Levon 		return 0;
4531f5207b7SJohn Levon 	if (!last_member_is_resizable(base_sym))
4541f5207b7SJohn Levon 		return 0;
4551f5207b7SJohn Levon 
4561f5207b7SJohn Levon 	state = get_state(my_size_id, sym->ident->name, sym);
457*6523a3aaSJohn Levon 	if (!estate_to_size(state) || estate_to_size(state) == -1)
4581f5207b7SJohn Levon 		return 0;
4591f5207b7SJohn Levon 
4601f5207b7SJohn Levon 	return estate_to_size(state) - type_bytes(base_sym) + type_bytes(get_type(expr));
4611f5207b7SJohn Levon }
4621f5207b7SJohn Levon 
alloc_int_rl(int value)4631f5207b7SJohn Levon static struct range_list *alloc_int_rl(int value)
4641f5207b7SJohn Levon {
4651f5207b7SJohn Levon 	sval_t sval = {
4661f5207b7SJohn Levon 		.type = &int_ctype,
4671f5207b7SJohn Levon 		{.value = value},
4681f5207b7SJohn Levon 	};
4691f5207b7SJohn Levon 
4701f5207b7SJohn Levon 	return alloc_rl(sval, sval);
4711f5207b7SJohn Levon }
4721f5207b7SJohn Levon 
get_array_size_bytes_rl(struct expression * expr)4731f5207b7SJohn Levon struct range_list *get_array_size_bytes_rl(struct expression *expr)
4741f5207b7SJohn Levon {
4751f5207b7SJohn Levon 	struct range_list *ret = NULL;
476c85f09ccSJohn Levon 	sval_t sval;
4771f5207b7SJohn Levon 	int size;
4781f5207b7SJohn Levon 
4791f5207b7SJohn Levon 	expr = remove_addr_fluff(expr);
4801f5207b7SJohn Levon 	if (!expr)
4811f5207b7SJohn Levon 		return NULL;
4821f5207b7SJohn Levon 
4831f5207b7SJohn Levon 	/* "BAR" */
4841f5207b7SJohn Levon 	if (expr->type == EXPR_STRING)
4851f5207b7SJohn Levon 		return alloc_int_rl(expr->string->length);
4861f5207b7SJohn Levon 
4871f5207b7SJohn Levon 	if (expr->type == EXPR_BINOP && expr->op == '+') {
4881f5207b7SJohn Levon 		sval_t offset;
4891f5207b7SJohn Levon 		struct symbol *type;
4901f5207b7SJohn Levon 		int bytes;
4911f5207b7SJohn Levon 
4921f5207b7SJohn Levon 		if (!get_implied_value(expr->right, &offset))
4931f5207b7SJohn Levon 			return NULL;
4941f5207b7SJohn Levon 		type = get_type(expr->left);
4951f5207b7SJohn Levon 		if (!type)
4961f5207b7SJohn Levon 			return NULL;
4971f5207b7SJohn Levon 		if (type->type != SYM_ARRAY && type->type != SYM_PTR)
4981f5207b7SJohn Levon 			return NULL;
4991f5207b7SJohn Levon 		type = get_real_base_type(type);
5001f5207b7SJohn Levon 		bytes = type_bytes(type);
5011f5207b7SJohn Levon 		if (bytes == 0)
5021f5207b7SJohn Levon 			return NULL;
5031f5207b7SJohn Levon 		offset.value *= bytes;
5041f5207b7SJohn Levon 		size = get_array_size_bytes(expr->left);
5051f5207b7SJohn Levon 		if (size <= 0)
5061f5207b7SJohn Levon 			return NULL;
5071f5207b7SJohn Levon 		return alloc_int_rl(size - offset.value);
5081f5207b7SJohn Levon 	}
5091f5207b7SJohn Levon 
510*6523a3aaSJohn Levon 	/* buf = malloc(1024); */
511*6523a3aaSJohn Levon 	ret = get_stored_size_bytes(expr);
512*6523a3aaSJohn Levon 	if (ret)
513*6523a3aaSJohn Levon 		return ret;
514*6523a3aaSJohn Levon 
515efe51d0cSJohn Levon 	size = get_stored_size_end_struct_bytes(expr);
516efe51d0cSJohn Levon 	if (size)
517efe51d0cSJohn Levon 		return alloc_int_rl(size);
518efe51d0cSJohn Levon 
5191f5207b7SJohn Levon 	/* buf[4] */
5201f5207b7SJohn Levon 	size = get_real_array_size(expr);
5211f5207b7SJohn Levon 	if (size)
5221f5207b7SJohn Levon 		return alloc_int_rl(elements_to_bytes(expr, size));
5231f5207b7SJohn Levon 
5241f5207b7SJohn Levon 	/* char *foo = "BAR" */
5251f5207b7SJohn Levon 	size = get_size_from_initializer(expr);
5261f5207b7SJohn Levon 	if (size)
5271f5207b7SJohn Levon 		return alloc_int_rl(elements_to_bytes(expr, size));
5281f5207b7SJohn Levon 
5291f5207b7SJohn Levon 	size = get_bytes_from_address(expr);
5301f5207b7SJohn Levon 	if (size)
5311f5207b7SJohn Levon 		return alloc_int_rl(size);
5321f5207b7SJohn Levon 
5331f5207b7SJohn Levon 	ret = size_from_db(expr);
534c85f09ccSJohn Levon 	if (rl_to_sval(ret, &sval) && sval.value == -1)
535c85f09ccSJohn Levon 		return NULL;
5361f5207b7SJohn Levon 	if (ret)
5371f5207b7SJohn Levon 		return ret;
5381f5207b7SJohn Levon 
5391f5207b7SJohn Levon 	return NULL;
5401f5207b7SJohn Levon }
5411f5207b7SJohn Levon 
get_array_size_bytes(struct expression * expr)5421f5207b7SJohn Levon int get_array_size_bytes(struct expression *expr)
5431f5207b7SJohn Levon {
5441f5207b7SJohn Levon 	struct range_list *rl;
5451f5207b7SJohn Levon 	sval_t sval;
5461f5207b7SJohn Levon 
5471f5207b7SJohn Levon 	rl = get_array_size_bytes_rl(expr);
5481f5207b7SJohn Levon 	if (!rl_to_sval(rl, &sval))
5491f5207b7SJohn Levon 		return 0;
5501f5207b7SJohn Levon 	if (sval.uvalue >= INT_MAX)
5511f5207b7SJohn Levon 		return 0;
5521f5207b7SJohn Levon 	return sval.value;
5531f5207b7SJohn Levon }
5541f5207b7SJohn Levon 
get_array_size_bytes_max(struct expression * expr)5551f5207b7SJohn Levon int get_array_size_bytes_max(struct expression *expr)
5561f5207b7SJohn Levon {
5571f5207b7SJohn Levon 	struct range_list *rl;
5581f5207b7SJohn Levon 	sval_t bytes;
5591f5207b7SJohn Levon 
5601f5207b7SJohn Levon 	rl = get_array_size_bytes_rl(expr);
5611f5207b7SJohn Levon 	if (!rl)
5621f5207b7SJohn Levon 		return 0;
5631f5207b7SJohn Levon 	bytes = rl_min(rl);
5641f5207b7SJohn Levon 	if (bytes.value < 0)
5651f5207b7SJohn Levon 		return 0;
5661f5207b7SJohn Levon 	bytes = rl_max(rl);
5671f5207b7SJohn Levon 	if (bytes.uvalue >= INT_MAX)
5681f5207b7SJohn Levon 		return 0;
5691f5207b7SJohn Levon 	return bytes.value;
5701f5207b7SJohn Levon }
5711f5207b7SJohn Levon 
get_array_size_bytes_min(struct expression * expr)5721f5207b7SJohn Levon int get_array_size_bytes_min(struct expression *expr)
5731f5207b7SJohn Levon {
5741f5207b7SJohn Levon 	struct range_list *rl;
5751f5207b7SJohn Levon 	struct data_range *range;
5761f5207b7SJohn Levon 
5771f5207b7SJohn Levon 	rl = get_array_size_bytes_rl(expr);
5781f5207b7SJohn Levon 	if (!rl)
5791f5207b7SJohn Levon 		return 0;
5801f5207b7SJohn Levon 
5811f5207b7SJohn Levon 	FOR_EACH_PTR(rl, range) {
5821f5207b7SJohn Levon 		if (range->min.value <= 0)
5831f5207b7SJohn Levon 			return 0;
5841f5207b7SJohn Levon 		if (range->max.value <= 0)
5851f5207b7SJohn Levon 			return 0;
5861f5207b7SJohn Levon 		if (range->min.uvalue >= INT_MAX)
5871f5207b7SJohn Levon 			return 0;
5881f5207b7SJohn Levon 		return range->min.value;
5891f5207b7SJohn Levon 	} END_FOR_EACH_PTR(range);
5901f5207b7SJohn Levon 
5911f5207b7SJohn Levon 	return 0;
5921f5207b7SJohn Levon }
5931f5207b7SJohn Levon 
get_array_size(struct expression * expr)5941f5207b7SJohn Levon int get_array_size(struct expression *expr)
5951f5207b7SJohn Levon {
5961f5207b7SJohn Levon 	if (!expr)
5971f5207b7SJohn Levon 		return 0;
5981f5207b7SJohn Levon 	return bytes_to_elements(expr, get_array_size_bytes_max(expr));
5991f5207b7SJohn Levon }
6001f5207b7SJohn Levon 
strip_ampersands(struct expression * expr)6011f5207b7SJohn Levon static struct expression *strip_ampersands(struct expression *expr)
6021f5207b7SJohn Levon {
6031f5207b7SJohn Levon 	struct symbol *type;
6041f5207b7SJohn Levon 
6051f5207b7SJohn Levon 	if (expr->type != EXPR_PREOP)
6061f5207b7SJohn Levon 		return expr;
6071f5207b7SJohn Levon 	if (expr->op != '&')
6081f5207b7SJohn Levon 		return expr;
6091f5207b7SJohn Levon 	type = get_type(expr->unop);
6101f5207b7SJohn Levon 	if (!type || type->type != SYM_ARRAY)
6111f5207b7SJohn Levon 		return expr;
6121f5207b7SJohn Levon 	return expr->unop;
6131f5207b7SJohn Levon }
6141f5207b7SJohn Levon 
info_record_alloction(struct expression * buffer,struct range_list * rl)6151f5207b7SJohn Levon static void info_record_alloction(struct expression *buffer, struct range_list *rl)
6161f5207b7SJohn Levon {
6171f5207b7SJohn Levon 	char *name;
6181f5207b7SJohn Levon 
6191f5207b7SJohn Levon 	if (!option_info)
6201f5207b7SJohn Levon 		return;
6211f5207b7SJohn Levon 
6221f5207b7SJohn Levon 	name = get_member_name(buffer);
6231f5207b7SJohn Levon 	if (!name && is_static(buffer))
6241f5207b7SJohn Levon 		name = expr_to_var(buffer);
6251f5207b7SJohn Levon 	if (!name)
6261f5207b7SJohn Levon 		return;
6271f5207b7SJohn Levon 	if (rl && !is_whole_rl(rl))
6281f5207b7SJohn Levon 		sql_insert_function_type_size(name, show_rl(rl));
6291f5207b7SJohn Levon 	else
6301f5207b7SJohn Levon 		sql_insert_function_type_size(name, "(-1)");
6311f5207b7SJohn Levon 
6321f5207b7SJohn Levon 	free_string(name);
6331f5207b7SJohn Levon }
6341f5207b7SJohn Levon 
store_alloc(struct expression * expr,struct range_list * rl)6351f5207b7SJohn Levon static void store_alloc(struct expression *expr, struct range_list *rl)
6361f5207b7SJohn Levon {
6371f5207b7SJohn Levon 	struct symbol *type;
6381f5207b7SJohn Levon 
6391f5207b7SJohn Levon 	rl = clone_rl(rl); // FIXME!!!
640c85f09ccSJohn Levon 	if (!rl)
641c85f09ccSJohn Levon 		rl = size_to_rl(UNKNOWN_SIZE);
642*6523a3aaSJohn Levon 
643*6523a3aaSJohn Levon 	if (rl_min(rl).value != UNKNOWN_SIZE ||
644*6523a3aaSJohn Levon 	    rl_max(rl).value != UNKNOWN_SIZE ||
645*6523a3aaSJohn Levon 	    get_state_expr(my_size_id, expr))
646*6523a3aaSJohn Levon 		set_state_expr(my_size_id, expr, alloc_estate_rl(rl));
6471f5207b7SJohn Levon 
6481f5207b7SJohn Levon 	type = get_type(expr);
6491f5207b7SJohn Levon 	if (!type)
6501f5207b7SJohn Levon 		return;
6511f5207b7SJohn Levon 	if (type->type != SYM_PTR)
6521f5207b7SJohn Levon 		return;
6531f5207b7SJohn Levon 	type = get_real_base_type(type);
6541f5207b7SJohn Levon 	if (!type)
6551f5207b7SJohn Levon 		return;
6561f5207b7SJohn Levon 	if (type == &void_ctype)
6571f5207b7SJohn Levon 		return;
6581f5207b7SJohn Levon 	if (type->type != SYM_BASETYPE && type->type != SYM_PTR)
6591f5207b7SJohn Levon 		return;
6601f5207b7SJohn Levon 
6611f5207b7SJohn Levon 	info_record_alloction(expr, rl);
6621f5207b7SJohn Levon }
6631f5207b7SJohn Levon 
is_array_base(struct expression * expr)664*6523a3aaSJohn Levon static bool is_array_base(struct expression *expr)
665*6523a3aaSJohn Levon {
666*6523a3aaSJohn Levon 	struct symbol *type;
667*6523a3aaSJohn Levon 
668*6523a3aaSJohn Levon 	type = get_type(expr);
669*6523a3aaSJohn Levon 	if (type && type->type == SYM_ARRAY)
670*6523a3aaSJohn Levon 		return true;
671*6523a3aaSJohn Levon 	return false;
672*6523a3aaSJohn Levon }
673*6523a3aaSJohn Levon 
match_array_assignment(struct expression * expr)6741f5207b7SJohn Levon static void match_array_assignment(struct expression *expr)
6751f5207b7SJohn Levon {
6761f5207b7SJohn Levon 	struct expression *left;
6771f5207b7SJohn Levon 	struct expression *right;
6781f5207b7SJohn Levon 	char *left_member, *right_member;
6791f5207b7SJohn Levon 	struct range_list *rl;
6801f5207b7SJohn Levon 	sval_t sval;
6811f5207b7SJohn Levon 
6821f5207b7SJohn Levon 	if (expr->op != '=')
6831f5207b7SJohn Levon 		return;
684*6523a3aaSJohn Levon 
6851f5207b7SJohn Levon 	left = strip_expr(expr->left);
6861f5207b7SJohn Levon 	right = strip_expr(expr->right);
6871f5207b7SJohn Levon 	right = strip_ampersands(right);
6881f5207b7SJohn Levon 
6891f5207b7SJohn Levon 	if (!is_pointer(left))
6901f5207b7SJohn Levon 		return;
691*6523a3aaSJohn Levon 	/* char buf[24] = "str"; */
692*6523a3aaSJohn Levon 	if (is_array_base(left))
693*6523a3aaSJohn Levon 		return;
6941f5207b7SJohn Levon 	if (is_allocation_function(right))
6951f5207b7SJohn Levon 		return;
6961f5207b7SJohn Levon 
6971f5207b7SJohn Levon 	left_member = get_member_name(left);
6981f5207b7SJohn Levon 	right_member = get_member_name(right);
6991f5207b7SJohn Levon 	if (left_member && right_member && strcmp(left_member, right_member) == 0) {
7001f5207b7SJohn Levon 		free_string(left_member);
7011f5207b7SJohn Levon 		free_string(right_member);
7021f5207b7SJohn Levon 		return;
7031f5207b7SJohn Levon 	}
7041f5207b7SJohn Levon 	free_string(left_member);
7051f5207b7SJohn Levon 	free_string(right_member);
7061f5207b7SJohn Levon 
7071f5207b7SJohn Levon 	if (get_implied_value(right, &sval) && sval.value == 0) {
7081f5207b7SJohn Levon 		rl = alloc_int_rl(0);
7091f5207b7SJohn Levon 		goto store;
7101f5207b7SJohn Levon 	}
7111f5207b7SJohn Levon 
7121f5207b7SJohn Levon 	rl = get_array_size_bytes_rl(right);
7131f5207b7SJohn Levon 	if (!rl && __in_fake_assign)
7141f5207b7SJohn Levon 		return;
7151f5207b7SJohn Levon 
7161f5207b7SJohn Levon store:
7171f5207b7SJohn Levon 	store_alloc(left, rl);
7181f5207b7SJohn Levon }
7191f5207b7SJohn Levon 
match_alloc(const char * fn,struct expression * expr,void * _size_arg)7201f5207b7SJohn Levon static void match_alloc(const char *fn, struct expression *expr, void *_size_arg)
7211f5207b7SJohn Levon {
7221f5207b7SJohn Levon 	int size_arg = PTR_INT(_size_arg);
7231f5207b7SJohn Levon 	struct expression *right;
7241f5207b7SJohn Levon 	struct expression *arg;
7251f5207b7SJohn Levon 	struct range_list *rl;
7261f5207b7SJohn Levon 
7271f5207b7SJohn Levon 	right = strip_expr(expr->right);
7281f5207b7SJohn Levon 	arg = get_argument_from_call_expr(right->args, size_arg);
7291f5207b7SJohn Levon 	get_absolute_rl(arg, &rl);
7301f5207b7SJohn Levon 	rl = cast_rl(&int_ctype, rl);
7311f5207b7SJohn Levon 	store_alloc(expr->left, rl);
7321f5207b7SJohn Levon }
7331f5207b7SJohn Levon 
match_calloc(const char * fn,struct expression * expr,void * _param)734*6523a3aaSJohn Levon static void match_calloc(const char *fn, struct expression *expr, void *_param)
7351f5207b7SJohn Levon {
7361f5207b7SJohn Levon 	struct expression *right;
737efe51d0cSJohn Levon 	struct expression *size, *nr, *mult;
738efe51d0cSJohn Levon 	struct range_list *rl;
739*6523a3aaSJohn Levon 	int param = PTR_INT(_param);
7401f5207b7SJohn Levon 
7411f5207b7SJohn Levon 	right = strip_expr(expr->right);
742*6523a3aaSJohn Levon 	nr = get_argument_from_call_expr(right->args, param);
743*6523a3aaSJohn Levon 	size = get_argument_from_call_expr(right->args, param + 1);
744efe51d0cSJohn Levon 	mult = binop_expression(nr, '*', size);
745efe51d0cSJohn Levon 	if (get_implied_rl(mult, &rl))
746efe51d0cSJohn Levon 		store_alloc(expr->left, rl);
7471f5207b7SJohn Levon 	else
748c85f09ccSJohn Levon 		store_alloc(expr->left, size_to_rl(UNKNOWN_SIZE));
7491f5207b7SJohn Levon }
7501f5207b7SJohn Levon 
match_page(const char * fn,struct expression * expr,void * _unused)7511f5207b7SJohn Levon static void match_page(const char *fn, struct expression *expr, void *_unused)
7521f5207b7SJohn Levon {
7531f5207b7SJohn Levon 	sval_t page_size = {
7541f5207b7SJohn Levon 		.type = &int_ctype,
7551f5207b7SJohn Levon 		{.value = 4096},
7561f5207b7SJohn Levon 	};
7571f5207b7SJohn Levon 
7581f5207b7SJohn Levon 	store_alloc(expr->left, alloc_rl(page_size, page_size));
7591f5207b7SJohn Levon }
7601f5207b7SJohn Levon 
match_strndup(const char * fn,struct expression * expr,void * unused)7611f5207b7SJohn Levon static void match_strndup(const char *fn, struct expression *expr, void *unused)
7621f5207b7SJohn Levon {
7631f5207b7SJohn Levon 	struct expression *fn_expr;
7641f5207b7SJohn Levon 	struct expression *size_expr;
7651f5207b7SJohn Levon 	sval_t size;
7661f5207b7SJohn Levon 
7671f5207b7SJohn Levon 	fn_expr = strip_expr(expr->right);
7681f5207b7SJohn Levon 	size_expr = get_argument_from_call_expr(fn_expr->args, 1);
7691f5207b7SJohn Levon 	if (get_implied_max(size_expr, &size)) {
7701f5207b7SJohn Levon 		size.value++;
7711f5207b7SJohn Levon 		store_alloc(expr->left, size_to_rl(size.value));
7721f5207b7SJohn Levon 	} else {
773c85f09ccSJohn Levon 		store_alloc(expr->left, size_to_rl(UNKNOWN_SIZE));
7741f5207b7SJohn Levon 	}
7751f5207b7SJohn Levon 
7761f5207b7SJohn Levon }
7771f5207b7SJohn Levon 
match_alloc_pages(const char * fn,struct expression * expr,void * _order_arg)7781f5207b7SJohn Levon static void match_alloc_pages(const char *fn, struct expression *expr, void *_order_arg)
7791f5207b7SJohn Levon {
7801f5207b7SJohn Levon 	int order_arg = PTR_INT(_order_arg);
7811f5207b7SJohn Levon 	struct expression *right;
7821f5207b7SJohn Levon 	struct expression *arg;
7831f5207b7SJohn Levon 	sval_t sval;
7841f5207b7SJohn Levon 
7851f5207b7SJohn Levon 	right = strip_expr(expr->right);
7861f5207b7SJohn Levon 	arg = get_argument_from_call_expr(right->args, order_arg);
7871f5207b7SJohn Levon 	if (!get_implied_value(arg, &sval))
7881f5207b7SJohn Levon 		return;
7891f5207b7SJohn Levon 	if (sval.value < 0 || sval.value > 10)
7901f5207b7SJohn Levon 		return;
7911f5207b7SJohn Levon 
7921f5207b7SJohn Levon 	sval.type = &int_ctype;
7931f5207b7SJohn Levon 	sval.value = 1 << sval.value;
7941f5207b7SJohn Levon 	sval.value *= 4096;
7951f5207b7SJohn Levon 
7961f5207b7SJohn Levon 	store_alloc(expr->left, alloc_rl(sval, sval));
7971f5207b7SJohn Levon }
7981f5207b7SJohn Levon 
is_type_bytes(struct range_list * rl,struct expression * arg)7991f5207b7SJohn Levon static int is_type_bytes(struct range_list *rl, struct expression *arg)
8001f5207b7SJohn Levon {
8011f5207b7SJohn Levon 	struct symbol *type;
8021f5207b7SJohn Levon 	sval_t sval;
8031f5207b7SJohn Levon 
8041f5207b7SJohn Levon 	if (!rl_to_sval(rl, &sval))
8051f5207b7SJohn Levon 		return 0;
8061f5207b7SJohn Levon 
8071f5207b7SJohn Levon 	type = get_type(arg);
8081f5207b7SJohn Levon 	if (!type)
8091f5207b7SJohn Levon 		return 0;
8101f5207b7SJohn Levon 	if (type->type != SYM_PTR)
8111f5207b7SJohn Levon 		return 0;
8121f5207b7SJohn Levon 	type = get_real_base_type(type);
8131f5207b7SJohn Levon 	if (type->type != SYM_STRUCT &&
8141f5207b7SJohn Levon 	    type->type != SYM_UNION)
8151f5207b7SJohn Levon 		return 0;
8161f5207b7SJohn Levon 	if (sval.value != type_bytes(type))
8171f5207b7SJohn Levon 		return 0;
8181f5207b7SJohn Levon 	return 1;
8191f5207b7SJohn Levon }
8201f5207b7SJohn Levon 
match_call(struct expression * expr)8211f5207b7SJohn Levon static void match_call(struct expression *expr)
8221f5207b7SJohn Levon {
8231f5207b7SJohn Levon 	struct expression *arg;
8241f5207b7SJohn Levon 	struct symbol *type;
8251f5207b7SJohn Levon 	struct range_list *rl;
8261f5207b7SJohn Levon 	int i;
8271f5207b7SJohn Levon 
8281f5207b7SJohn Levon 	i = -1;
8291f5207b7SJohn Levon 	FOR_EACH_PTR(expr->args, arg) {
8301f5207b7SJohn Levon 		i++;
8311f5207b7SJohn Levon 		type = get_type(arg);
8321f5207b7SJohn Levon 		if (!type || (type->type != SYM_PTR && type->type != SYM_ARRAY))
8331f5207b7SJohn Levon 			continue;
8341f5207b7SJohn Levon 		rl = get_array_size_bytes_rl(arg);
8351f5207b7SJohn Levon 		if (!rl)
8361f5207b7SJohn Levon 			continue;
837*6523a3aaSJohn Levon 		if (rl_min(rl).value == UNKNOWN_SIZE &&
838*6523a3aaSJohn Levon 		    rl_max(rl).value == UNKNOWN_SIZE)
839*6523a3aaSJohn Levon 			continue;
8401f5207b7SJohn Levon 		if (is_whole_rl(rl))
8411f5207b7SJohn Levon 			continue;
8421f5207b7SJohn Levon 		if (is_type_bytes(rl, arg))
8431f5207b7SJohn Levon 			continue;
8441f5207b7SJohn Levon 		sql_insert_caller_info(expr, BUF_SIZE, i, "$", show_rl(rl));
8451f5207b7SJohn Levon 	} END_FOR_EACH_PTR(arg);
8461f5207b7SJohn Levon }
8471f5207b7SJohn Levon 
struct_member_callback(struct expression * call,int param,char * printed_name,struct sm_state * sm)8481f5207b7SJohn Levon static void struct_member_callback(struct expression *call, int param, char *printed_name, struct sm_state *sm)
8491f5207b7SJohn Levon {
850c85f09ccSJohn Levon 	sval_t sval;
851c85f09ccSJohn Levon 
852c85f09ccSJohn Levon 	if (!estate_rl(sm->state) ||
853c85f09ccSJohn Levon 	    (estate_get_single_value(sm->state, &sval) &&
854c85f09ccSJohn Levon 	     (sval.value == -1 || sval.value == 0)))
8551f5207b7SJohn Levon 		return;
856c85f09ccSJohn Levon 
8571f5207b7SJohn Levon 	sql_insert_caller_info(call, BUF_SIZE, param, printed_name, sm->state->name);
8581f5207b7SJohn Levon }
8591f5207b7SJohn Levon 
8601f5207b7SJohn Levon /*
8611f5207b7SJohn Levon  * This is slightly (very) weird because half of this stuff is handled in
8621f5207b7SJohn Levon  * smatch_parse_call_math.c which is poorly named.  But anyway, add some buf
8631f5207b7SJohn Levon  * sizes here.
8641f5207b7SJohn Levon  *
8651f5207b7SJohn Levon  */
print_returned_allocations(int return_id,char * return_ranges,struct expression * expr)8661f5207b7SJohn Levon static void print_returned_allocations(int return_id, char *return_ranges, struct expression *expr)
8671f5207b7SJohn Levon {
868c85f09ccSJohn Levon 	const char *param_math;
869c85f09ccSJohn Levon 	struct range_list *rl;
870c85f09ccSJohn Levon 	char buf[64];
871c85f09ccSJohn Levon 	sval_t sval;
872c85f09ccSJohn Levon 
873c85f09ccSJohn Levon 	rl = get_array_size_bytes_rl(expr);
874c85f09ccSJohn Levon 	param_math = get_allocation_math(expr);
875c85f09ccSJohn Levon 	if (!rl && !param_math)
876c85f09ccSJohn Levon 		return;
8771f5207b7SJohn Levon 
878c85f09ccSJohn Levon 	if (!param_math &&
879c85f09ccSJohn Levon 	    rl_to_sval(rl, &sval) &&
880c85f09ccSJohn Levon 	    (sval.value == -1 || sval.value == 0))
8811f5207b7SJohn Levon 		return;
8821f5207b7SJohn Levon 
883c85f09ccSJohn Levon 	if (param_math)
884c85f09ccSJohn Levon 		snprintf(buf, sizeof(buf), "%s[%s]", show_rl(rl), param_math);
885c85f09ccSJohn Levon 	else
886c85f09ccSJohn Levon 		snprintf(buf, sizeof(buf), "%s", show_rl(rl));
887c85f09ccSJohn Levon 
888c85f09ccSJohn Levon 	// FIXME: don't store if you can guess the size from the type
889c85f09ccSJohn Levon 	// FIXME: return if we allocate a parameter $0->bar
8901f5207b7SJohn Levon 	sql_insert_return_states(return_id, return_ranges, BUF_SIZE, -1, "", buf);
8911f5207b7SJohn Levon }
8921f5207b7SJohn Levon 
record_global_size(struct symbol * sym)8931f5207b7SJohn Levon static void record_global_size(struct symbol *sym)
8941f5207b7SJohn Levon {
8951f5207b7SJohn Levon 	int bytes;
8961f5207b7SJohn Levon 	char buf[16];
8971f5207b7SJohn Levon 
8981f5207b7SJohn Levon 	if (!sym->ident)
8991f5207b7SJohn Levon 		return;
9001f5207b7SJohn Levon 
9011f5207b7SJohn Levon 	if (!(sym->ctype.modifiers & MOD_TOPLEVEL) ||
9021f5207b7SJohn Levon 	    sym->ctype.modifiers & MOD_STATIC)
9031f5207b7SJohn Levon 		return;
9041f5207b7SJohn Levon 
9051f5207b7SJohn Levon 	bytes = get_array_size_bytes(symbol_expression(sym));
9061f5207b7SJohn Levon 	if (bytes <= 1)
9071f5207b7SJohn Levon 		return;
9081f5207b7SJohn Levon 
9091f5207b7SJohn Levon 	snprintf(buf, sizeof(buf), "%d", bytes);
9101f5207b7SJohn Levon 	sql_insert_data_info_var_sym(sym->ident->name, sym, BUF_SIZE, buf);
9111f5207b7SJohn Levon }
9121f5207b7SJohn Levon 
register_buf_size(int id)9131f5207b7SJohn Levon void register_buf_size(int id)
9141f5207b7SJohn Levon {
9151f5207b7SJohn Levon 	my_size_id = id;
9161f5207b7SJohn Levon 
917efe51d0cSJohn Levon 	set_dynamic_states(my_size_id);
918efe51d0cSJohn Levon 
9191f5207b7SJohn Levon 	add_unmatched_state_hook(my_size_id, &unmatched_size_state);
920c85f09ccSJohn Levon 	add_merge_hook(my_size_id, &merge_estates);
9211f5207b7SJohn Levon 
9221f5207b7SJohn Levon 	select_caller_info_hook(set_param_buf_size, BUF_SIZE);
9231f5207b7SJohn Levon 	select_return_states_hook(BUF_SIZE, &db_returns_buf_size);
9241f5207b7SJohn Levon 	add_split_return_callback(print_returned_allocations);
9251f5207b7SJohn Levon 
9261f5207b7SJohn Levon 	allocation_funcs = create_function_hashtable(100);
9271f5207b7SJohn Levon 	add_allocation_function("malloc", &match_alloc, 0);
9281f5207b7SJohn Levon 	add_allocation_function("calloc", &match_calloc, 0);
9291f5207b7SJohn Levon 	add_allocation_function("memdup", &match_alloc, 1);
9301f5207b7SJohn Levon 	add_allocation_function("realloc", &match_alloc, 1);
9311f5207b7SJohn Levon 	if (option_project == PROJ_KERNEL) {
9321f5207b7SJohn Levon 		add_allocation_function("kmalloc", &match_alloc, 0);
9331f5207b7SJohn Levon 		add_allocation_function("kmalloc_node", &match_alloc, 0);
9341f5207b7SJohn Levon 		add_allocation_function("kzalloc", &match_alloc, 0);
9351f5207b7SJohn Levon 		add_allocation_function("kzalloc_node", &match_alloc, 0);
9361f5207b7SJohn Levon 		add_allocation_function("vmalloc", &match_alloc, 0);
937*6523a3aaSJohn Levon 		add_allocation_function("vzalloc", &match_alloc, 0);
9381f5207b7SJohn Levon 		add_allocation_function("__vmalloc", &match_alloc, 0);
9395a0e240fSJohn Levon 		add_allocation_function("kvmalloc", &match_alloc, 0);
9401f5207b7SJohn Levon 		add_allocation_function("kcalloc", &match_calloc, 0);
9411f5207b7SJohn Levon 		add_allocation_function("kmalloc_array", &match_calloc, 0);
942*6523a3aaSJohn Levon 		add_allocation_function("devm_kmalloc_array", &match_calloc, 1);
9431f5207b7SJohn Levon 		add_allocation_function("sock_kmalloc", &match_alloc, 1);
9441f5207b7SJohn Levon 		add_allocation_function("kmemdup", &match_alloc, 1);
9451f5207b7SJohn Levon 		add_allocation_function("kmemdup_user", &match_alloc, 1);
9461f5207b7SJohn Levon 		add_allocation_function("dma_alloc_attrs", &match_alloc, 1);
9471f5207b7SJohn Levon 		add_allocation_function("pci_alloc_consistent", &match_alloc, 1);
9481f5207b7SJohn Levon 		add_allocation_function("pci_alloc_coherent", &match_alloc, 1);
9491f5207b7SJohn Levon 		add_allocation_function("devm_kmalloc", &match_alloc, 1);
9501f5207b7SJohn Levon 		add_allocation_function("devm_kzalloc", &match_alloc, 1);
9511f5207b7SJohn Levon 		add_allocation_function("krealloc", &match_alloc, 1);
9521f5207b7SJohn Levon 		add_allocation_function("__alloc_bootmem", &match_alloc, 0);
9531f5207b7SJohn Levon 		add_allocation_function("alloc_bootmem", &match_alloc, 0);
9541f5207b7SJohn Levon 		add_allocation_function("kmap", &match_page, 0);
955c85f09ccSJohn Levon 		add_allocation_function("kmap_atomic", &match_page, 0);
9561f5207b7SJohn Levon 		add_allocation_function("get_zeroed_page", &match_page, 0);
957efe51d0cSJohn Levon 		add_allocation_function("alloc_page", &match_page, 0);
9581f5207b7SJohn Levon 		add_allocation_function("alloc_pages", &match_alloc_pages, 1);
9591f5207b7SJohn Levon 		add_allocation_function("alloc_pages_current", &match_alloc_pages, 1);
9601f5207b7SJohn Levon 		add_allocation_function("__get_free_pages", &match_alloc_pages, 1);
961c85f09ccSJohn Levon 		add_allocation_function("dma_alloc_contiguous", &match_alloc, 1);
962c85f09ccSJohn Levon 		add_allocation_function("dma_alloc_coherent", &match_alloc, 1);
9631f5207b7SJohn Levon 	}
9641f5207b7SJohn Levon 
9651f5207b7SJohn Levon 	add_allocation_function("strndup", match_strndup, 0);
9661f5207b7SJohn Levon 	if (option_project == PROJ_KERNEL)
9671f5207b7SJohn Levon 		add_allocation_function("kstrndup", match_strndup, 0);
9681f5207b7SJohn Levon 
9691f5207b7SJohn Levon 	add_modification_hook(my_size_id, &set_size_undefined);
9701f5207b7SJohn Levon 
9711f5207b7SJohn Levon 	add_merge_hook(my_size_id, &merge_size_func);
9721f5207b7SJohn Levon 
9731f5207b7SJohn Levon 	if (option_info)
9741f5207b7SJohn Levon 		add_hook(record_global_size, BASE_HOOK);
9751f5207b7SJohn Levon }
9761f5207b7SJohn Levon 
register_buf_size_late(int id)9771f5207b7SJohn Levon void register_buf_size_late(int id)
9781f5207b7SJohn Levon {
9791f5207b7SJohn Levon 	/* has to happen after match_alloc() */
9801f5207b7SJohn Levon 	add_hook(&match_array_assignment, ASSIGNMENT_HOOK);
9811f5207b7SJohn Levon 
9821f5207b7SJohn Levon 	add_hook(&match_call, FUNCTION_CALL_HOOK);
9831f5207b7SJohn Levon 	add_member_info_callback(my_size_id, struct_member_callback);
9841f5207b7SJohn Levon }
985