xref: /illumos-gate/usr/src/tools/smatch/src/smatch_extra.c (revision efe51d0cc2398b9ac179568b63a44e4bf295b8e2)
11f5207b7SJohn Levon /*
21f5207b7SJohn Levon  * Copyright (C) 2008 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 /*
191f5207b7SJohn Levon  * smatch_extra.c is supposed to track the value of every variable.
201f5207b7SJohn Levon  *
211f5207b7SJohn Levon  */
221f5207b7SJohn Levon 
231f5207b7SJohn Levon #define _GNU_SOURCE
241f5207b7SJohn Levon #include <string.h>
251f5207b7SJohn Levon 
261f5207b7SJohn Levon #include <stdlib.h>
271f5207b7SJohn Levon #include <errno.h>
281f5207b7SJohn Levon #ifndef __USE_ISOC99
291f5207b7SJohn Levon #define __USE_ISOC99
301f5207b7SJohn Levon #endif
311f5207b7SJohn Levon #include <limits.h>
321f5207b7SJohn Levon #include "parse.h"
331f5207b7SJohn Levon #include "smatch.h"
341f5207b7SJohn Levon #include "smatch_slist.h"
351f5207b7SJohn Levon #include "smatch_extra.h"
361f5207b7SJohn Levon 
371f5207b7SJohn Levon static int my_id;
381f5207b7SJohn Levon static int link_id;
39*efe51d0cSJohn Levon extern int check_assigned_expr_id;
401f5207b7SJohn Levon 
411f5207b7SJohn Levon static void match_link_modify(struct sm_state *sm, struct expression *mod_expr);
421f5207b7SJohn Levon 
431f5207b7SJohn Levon struct string_list *__ignored_macros = NULL;
44*efe51d0cSJohn Levon int in_warn_on_macro(void)
451f5207b7SJohn Levon {
461f5207b7SJohn Levon 	struct statement *stmt;
471f5207b7SJohn Levon 	char *tmp;
481f5207b7SJohn Levon 	char *macro;
491f5207b7SJohn Levon 
501f5207b7SJohn Levon 	stmt = get_current_statement();
511f5207b7SJohn Levon 	if (!stmt)
521f5207b7SJohn Levon 		return 0;
531f5207b7SJohn Levon 	macro = get_macro_name(stmt->pos);
541f5207b7SJohn Levon 	if (!macro)
551f5207b7SJohn Levon 		return 0;
561f5207b7SJohn Levon 
571f5207b7SJohn Levon 	FOR_EACH_PTR(__ignored_macros, tmp) {
581f5207b7SJohn Levon 		if (!strcmp(tmp, macro))
591f5207b7SJohn Levon 			return 1;
601f5207b7SJohn Levon 	} END_FOR_EACH_PTR(tmp);
611f5207b7SJohn Levon 	return 0;
621f5207b7SJohn Levon }
631f5207b7SJohn Levon 
641f5207b7SJohn Levon typedef void (mod_hook)(const char *name, struct symbol *sym, struct expression *expr, struct smatch_state *state);
651f5207b7SJohn Levon DECLARE_PTR_LIST(void_fn_list, mod_hook *);
661f5207b7SJohn Levon static struct void_fn_list *extra_mod_hooks;
671f5207b7SJohn Levon static struct void_fn_list *extra_nomod_hooks;
681f5207b7SJohn Levon 
691f5207b7SJohn Levon void add_extra_mod_hook(mod_hook *fn)
701f5207b7SJohn Levon {
711f5207b7SJohn Levon 	mod_hook **p = malloc(sizeof(mod_hook *));
721f5207b7SJohn Levon 	*p = fn;
731f5207b7SJohn Levon 	add_ptr_list(&extra_mod_hooks, p);
741f5207b7SJohn Levon }
751f5207b7SJohn Levon 
761f5207b7SJohn Levon void add_extra_nomod_hook(mod_hook *fn)
771f5207b7SJohn Levon {
781f5207b7SJohn Levon 	mod_hook **p = malloc(sizeof(mod_hook *));
791f5207b7SJohn Levon 	*p = fn;
801f5207b7SJohn Levon 	add_ptr_list(&extra_nomod_hooks, p);
811f5207b7SJohn Levon }
821f5207b7SJohn Levon 
831f5207b7SJohn Levon void call_extra_hooks(struct void_fn_list *hooks, const char *name, struct symbol *sym, struct expression *expr, struct smatch_state *state)
841f5207b7SJohn Levon {
851f5207b7SJohn Levon 	mod_hook **fn;
861f5207b7SJohn Levon 
871f5207b7SJohn Levon 	FOR_EACH_PTR(hooks, fn) {
881f5207b7SJohn Levon 		(*fn)(name, sym, expr, state);
891f5207b7SJohn Levon 	} END_FOR_EACH_PTR(fn);
901f5207b7SJohn Levon }
911f5207b7SJohn Levon 
921f5207b7SJohn Levon void call_extra_mod_hooks(const char *name, struct symbol *sym, struct expression *expr, struct smatch_state *state)
931f5207b7SJohn Levon {
941f5207b7SJohn Levon 	call_extra_hooks(extra_mod_hooks, name, sym, expr, state);
951f5207b7SJohn Levon }
961f5207b7SJohn Levon 
971f5207b7SJohn Levon void call_extra_nomod_hooks(const char *name, struct symbol *sym, struct expression *expr, struct smatch_state *state)
981f5207b7SJohn Levon {
991f5207b7SJohn Levon 	call_extra_hooks(extra_nomod_hooks, name, sym, expr, state);
1001f5207b7SJohn Levon }
1011f5207b7SJohn Levon 
1021f5207b7SJohn Levon static bool in_param_set;
1031f5207b7SJohn Levon void set_extra_mod_helper(const char *name, struct symbol *sym, struct expression *expr, struct smatch_state *state)
1041f5207b7SJohn Levon {
1051f5207b7SJohn Levon 	remove_from_equiv(name, sym);
1061f5207b7SJohn Levon 	call_extra_mod_hooks(name, sym, expr, state);
1071f5207b7SJohn Levon 	if ((__in_fake_assign || in_param_set) &&
1081f5207b7SJohn Levon 	    estate_is_unknown(state) && !get_state(SMATCH_EXTRA, name, sym))
1091f5207b7SJohn Levon 		return;
1101f5207b7SJohn Levon 	set_state(SMATCH_EXTRA, name, sym, state);
1111f5207b7SJohn Levon }
1121f5207b7SJohn Levon 
1131f5207b7SJohn Levon static void set_extra_nomod_helper(const char *name, struct symbol *sym, struct expression *expr, struct smatch_state *state)
1141f5207b7SJohn Levon {
1151f5207b7SJohn Levon 	call_extra_nomod_hooks(name, sym, expr, state);
1161f5207b7SJohn Levon 	set_state(SMATCH_EXTRA, name, sym, state);
1171f5207b7SJohn Levon }
1181f5207b7SJohn Levon 
1191f5207b7SJohn Levon static char *get_pointed_at(const char *name, struct symbol *sym, struct symbol **new_sym)
1201f5207b7SJohn Levon {
1211f5207b7SJohn Levon 	struct expression *assigned;
1221f5207b7SJohn Levon 
1231f5207b7SJohn Levon 	if (name[0] != '*')
1241f5207b7SJohn Levon 		return NULL;
1251f5207b7SJohn Levon 	if (strcmp(name + 1, sym->ident->name) != 0)
1261f5207b7SJohn Levon 		return NULL;
1271f5207b7SJohn Levon 
1281f5207b7SJohn Levon 	assigned = get_assigned_expr_name_sym(sym->ident->name, sym);
1291f5207b7SJohn Levon 	if (!assigned)
1301f5207b7SJohn Levon 		return NULL;
1311f5207b7SJohn Levon 	assigned = strip_parens(assigned);
1321f5207b7SJohn Levon 	if (assigned->type != EXPR_PREOP || assigned->op != '&')
1331f5207b7SJohn Levon 		return NULL;
1341f5207b7SJohn Levon 
1351f5207b7SJohn Levon 	return expr_to_var_sym(assigned->unop, new_sym);
1361f5207b7SJohn Levon }
1371f5207b7SJohn Levon 
138*efe51d0cSJohn Levon char *get_other_name_sym_from_chunk(const char *name, const char *chunk, int len, struct symbol *sym, struct symbol **new_sym)
1391f5207b7SJohn Levon {
1401f5207b7SJohn Levon 	struct expression *assigned;
1411f5207b7SJohn Levon 	char *orig_name = NULL;
1421f5207b7SJohn Levon 	char buf[256];
143*efe51d0cSJohn Levon 	char *ret;
1441f5207b7SJohn Levon 
145*efe51d0cSJohn Levon 	assigned = get_assigned_expr_name_sym(chunk, sym);
1461f5207b7SJohn Levon 	if (!assigned)
1471f5207b7SJohn Levon 		return NULL;
1481f5207b7SJohn Levon 	if (assigned->type == EXPR_CALL)
1491f5207b7SJohn Levon 		return map_call_to_other_name_sym(name, sym, new_sym);
150*efe51d0cSJohn Levon 	if (assigned->type == EXPR_PREOP && assigned->op == '&') {
1511f5207b7SJohn Levon 
1521f5207b7SJohn Levon 		orig_name = expr_to_var_sym(assigned, new_sym);
1531f5207b7SJohn Levon 		if (!orig_name || !*new_sym)
1541f5207b7SJohn Levon 			goto free;
1551f5207b7SJohn Levon 
156*efe51d0cSJohn Levon 		snprintf(buf, sizeof(buf), "%s.%s", orig_name + 1, name + len);
1571f5207b7SJohn Levon 		ret = alloc_string(buf);
1581f5207b7SJohn Levon 		free_string(orig_name);
1591f5207b7SJohn Levon 		return ret;
1601f5207b7SJohn Levon 	}
1611f5207b7SJohn Levon 
1621f5207b7SJohn Levon 	orig_name = expr_to_var_sym(assigned, new_sym);
1631f5207b7SJohn Levon 	if (!orig_name || !*new_sym)
1641f5207b7SJohn Levon 		goto free;
1651f5207b7SJohn Levon 
166*efe51d0cSJohn Levon 	snprintf(buf, sizeof(buf), "%s->%s", orig_name, name + len);
1671f5207b7SJohn Levon 	ret = alloc_string(buf);
1681f5207b7SJohn Levon 	free_string(orig_name);
1691f5207b7SJohn Levon 	return ret;
1701f5207b7SJohn Levon free:
1711f5207b7SJohn Levon 	free_string(orig_name);
1721f5207b7SJohn Levon 	return NULL;
1731f5207b7SJohn Levon }
1741f5207b7SJohn Levon 
175*efe51d0cSJohn Levon static char *get_long_name_sym(const char *name, struct symbol *sym, struct symbol **new_sym)
176*efe51d0cSJohn Levon {
177*efe51d0cSJohn Levon 	struct expression *tmp;
178*efe51d0cSJohn Levon 	struct sm_state *sm;
179*efe51d0cSJohn Levon 	char buf[256];
180*efe51d0cSJohn Levon 
181*efe51d0cSJohn Levon 	/*
182*efe51d0cSJohn Levon 	 * Just prepend the name with a different name/sym and return that.
183*efe51d0cSJohn Levon 	 * For example, if we set "foo->bar = bar;" then we clamp "bar->baz",
184*efe51d0cSJohn Levon 	 * that also clamps "foo->bar->baz".
185*efe51d0cSJohn Levon 	 *
186*efe51d0cSJohn Levon 	 */
187*efe51d0cSJohn Levon 
188*efe51d0cSJohn Levon 	FOR_EACH_MY_SM(check_assigned_expr_id, __get_cur_stree(), sm) {
189*efe51d0cSJohn Levon 		tmp = sm->state->data;
190*efe51d0cSJohn Levon 		if (!tmp || tmp->type != EXPR_SYMBOL)
191*efe51d0cSJohn Levon 			continue;
192*efe51d0cSJohn Levon 		if (tmp->symbol == sym)
193*efe51d0cSJohn Levon 			goto found;
194*efe51d0cSJohn Levon 	} END_FOR_EACH_SM(sm);
195*efe51d0cSJohn Levon 
196*efe51d0cSJohn Levon 	return NULL;
197*efe51d0cSJohn Levon 
198*efe51d0cSJohn Levon found:
199*efe51d0cSJohn Levon 	snprintf(buf, sizeof(buf), "%s%s", sm->name, name + tmp->symbol->ident->len);
200*efe51d0cSJohn Levon 	*new_sym = sm->sym;
201*efe51d0cSJohn Levon 	return alloc_string(buf);
202*efe51d0cSJohn Levon }
203*efe51d0cSJohn Levon 
204*efe51d0cSJohn Levon char *get_other_name_sym_helper(const char *name, struct symbol *sym, struct symbol **new_sym, bool use_stack)
205*efe51d0cSJohn Levon {
206*efe51d0cSJohn Levon 	char buf[256];
207*efe51d0cSJohn Levon 	char *ret;
208*efe51d0cSJohn Levon 	int len;
209*efe51d0cSJohn Levon 
210*efe51d0cSJohn Levon 	*new_sym = NULL;
211*efe51d0cSJohn Levon 
212*efe51d0cSJohn Levon 	if (!sym || !sym->ident)
213*efe51d0cSJohn Levon 		return NULL;
214*efe51d0cSJohn Levon 
215*efe51d0cSJohn Levon 	ret = get_pointed_at(name, sym, new_sym);
216*efe51d0cSJohn Levon 	if (ret)
217*efe51d0cSJohn Levon 		return ret;
218*efe51d0cSJohn Levon 
219*efe51d0cSJohn Levon 	ret = map_long_to_short_name_sym(name, sym, new_sym, use_stack);
220*efe51d0cSJohn Levon 	if (ret)
221*efe51d0cSJohn Levon 		return ret;
222*efe51d0cSJohn Levon 
223*efe51d0cSJohn Levon 	len = snprintf(buf, sizeof(buf), "%s", name);
224*efe51d0cSJohn Levon 	if (len >= sizeof(buf) - 2)
225*efe51d0cSJohn Levon 		return NULL;
226*efe51d0cSJohn Levon 
227*efe51d0cSJohn Levon 	while (len >= 1) {
228*efe51d0cSJohn Levon 		if (buf[len] == '>' && buf[len - 1] == '-') {
229*efe51d0cSJohn Levon 			len--;
230*efe51d0cSJohn Levon 			buf[len] = '\0';
231*efe51d0cSJohn Levon 			ret = get_other_name_sym_from_chunk(name, buf, len + 2, sym, new_sym);
232*efe51d0cSJohn Levon 			if (ret)
233*efe51d0cSJohn Levon 				return ret;
234*efe51d0cSJohn Levon 		}
235*efe51d0cSJohn Levon 		len--;
236*efe51d0cSJohn Levon 	}
237*efe51d0cSJohn Levon 
238*efe51d0cSJohn Levon 	ret = get_long_name_sym(name, sym, new_sym);
239*efe51d0cSJohn Levon 	if (ret)
240*efe51d0cSJohn Levon 		return ret;
241*efe51d0cSJohn Levon 
242*efe51d0cSJohn Levon 	return NULL;
243*efe51d0cSJohn Levon }
244*efe51d0cSJohn Levon 
245*efe51d0cSJohn Levon char *get_other_name_sym(const char *name, struct symbol *sym, struct symbol **new_sym)
246*efe51d0cSJohn Levon {
247*efe51d0cSJohn Levon 	return get_other_name_sym_helper(name, sym, new_sym, true);
248*efe51d0cSJohn Levon }
249*efe51d0cSJohn Levon 
250*efe51d0cSJohn Levon char *get_other_name_sym_nostack(const char *name, struct symbol *sym, struct symbol **new_sym)
251*efe51d0cSJohn Levon {
252*efe51d0cSJohn Levon 	return get_other_name_sym_helper(name, sym, new_sym, false);
253*efe51d0cSJohn Levon }
254*efe51d0cSJohn Levon 
2551f5207b7SJohn Levon void set_extra_mod(const char *name, struct symbol *sym, struct expression *expr, struct smatch_state *state)
2561f5207b7SJohn Levon {
2571f5207b7SJohn Levon 	char *new_name;
2581f5207b7SJohn Levon 	struct symbol *new_sym;
2591f5207b7SJohn Levon 
2601f5207b7SJohn Levon 	set_extra_mod_helper(name, sym, expr, state);
2611f5207b7SJohn Levon 	new_name = get_other_name_sym(name, sym, &new_sym);
2621f5207b7SJohn Levon 	if (new_name && new_sym)
2631f5207b7SJohn Levon 		set_extra_mod_helper(new_name, new_sym, expr, state);
2641f5207b7SJohn Levon 	free_string(new_name);
2651f5207b7SJohn Levon }
2661f5207b7SJohn Levon 
2671f5207b7SJohn Levon static struct expression *chunk_get_array_base(struct expression *expr)
2681f5207b7SJohn Levon {
2691f5207b7SJohn Levon 	/*
2701f5207b7SJohn Levon 	 * The problem with is_array() is that it only returns true for things
2711f5207b7SJohn Levon 	 * like foo[1] but not for foo[1].bar.
2721f5207b7SJohn Levon 	 *
2731f5207b7SJohn Levon 	 */
2741f5207b7SJohn Levon 	expr = strip_expr(expr);
2751f5207b7SJohn Levon 	while (expr && expr->type == EXPR_DEREF)
2761f5207b7SJohn Levon 		expr = strip_expr(expr->deref);
2771f5207b7SJohn Levon 	return get_array_base(expr);
2781f5207b7SJohn Levon }
2791f5207b7SJohn Levon 
2801f5207b7SJohn Levon static int chunk_has_array(struct expression *expr)
2811f5207b7SJohn Levon {
2821f5207b7SJohn Levon 	return !!chunk_get_array_base(expr);
2831f5207b7SJohn Levon }
2841f5207b7SJohn Levon 
2851f5207b7SJohn Levon static void clear_array_states(struct expression *array)
2861f5207b7SJohn Levon {
2871f5207b7SJohn Levon 	struct sm_state *sm;
2881f5207b7SJohn Levon 
2891f5207b7SJohn Levon 	sm = get_sm_state_expr(link_id, array);
2901f5207b7SJohn Levon 	if (sm)
2911f5207b7SJohn Levon 		match_link_modify(sm, NULL);
2921f5207b7SJohn Levon }
2931f5207b7SJohn Levon 
2941f5207b7SJohn Levon static void set_extra_array_mod(struct expression *expr, struct smatch_state *state)
2951f5207b7SJohn Levon {
2961f5207b7SJohn Levon 	struct expression *array;
2971f5207b7SJohn Levon 	struct var_sym_list *vsl;
2981f5207b7SJohn Levon 	struct var_sym *vs;
2991f5207b7SJohn Levon 	char *name;
3001f5207b7SJohn Levon 	struct symbol *sym;
3011f5207b7SJohn Levon 
3021f5207b7SJohn Levon 	array = chunk_get_array_base(expr);
3031f5207b7SJohn Levon 
3041f5207b7SJohn Levon 	name = expr_to_chunk_sym_vsl(expr, &sym, &vsl);
3051f5207b7SJohn Levon 	if (!name || !vsl) {
3061f5207b7SJohn Levon 		clear_array_states(array);
3071f5207b7SJohn Levon 		goto free;
3081f5207b7SJohn Levon 	}
3091f5207b7SJohn Levon 
3101f5207b7SJohn Levon 	FOR_EACH_PTR(vsl, vs) {
3111f5207b7SJohn Levon 		store_link(link_id, vs->var, vs->sym, name, sym);
3121f5207b7SJohn Levon 	} END_FOR_EACH_PTR(vs);
3131f5207b7SJohn Levon 
3141f5207b7SJohn Levon 	call_extra_mod_hooks(name, sym, expr, state);
3151f5207b7SJohn Levon 	set_state(SMATCH_EXTRA, name, sym, state);
3161f5207b7SJohn Levon free:
3171f5207b7SJohn Levon 	free_string(name);
3181f5207b7SJohn Levon }
3191f5207b7SJohn Levon 
3201f5207b7SJohn Levon void set_extra_expr_mod(struct expression *expr, struct smatch_state *state)
3211f5207b7SJohn Levon {
3221f5207b7SJohn Levon 	struct symbol *sym;
3231f5207b7SJohn Levon 	char *name;
3241f5207b7SJohn Levon 
3251f5207b7SJohn Levon 	if (chunk_has_array(expr)) {
3261f5207b7SJohn Levon 		set_extra_array_mod(expr, state);
3271f5207b7SJohn Levon 		return;
3281f5207b7SJohn Levon 	}
3291f5207b7SJohn Levon 
3301f5207b7SJohn Levon 	expr = strip_expr(expr);
3311f5207b7SJohn Levon 	name = expr_to_var_sym(expr, &sym);
3321f5207b7SJohn Levon 	if (!name || !sym)
3331f5207b7SJohn Levon 		goto free;
3341f5207b7SJohn Levon 	set_extra_mod(name, sym, expr, state);
3351f5207b7SJohn Levon free:
3361f5207b7SJohn Levon 	free_string(name);
3371f5207b7SJohn Levon }
3381f5207b7SJohn Levon 
3391f5207b7SJohn Levon void set_extra_nomod(const char *name, struct symbol *sym, struct expression *expr, struct smatch_state *state)
3401f5207b7SJohn Levon {
3411f5207b7SJohn Levon 	char *new_name;
3421f5207b7SJohn Levon 	struct symbol *new_sym;
3431f5207b7SJohn Levon 	struct relation *rel;
3441f5207b7SJohn Levon 	struct smatch_state *orig_state;
3451f5207b7SJohn Levon 
3461f5207b7SJohn Levon 	orig_state = get_state(SMATCH_EXTRA, name, sym);
3471f5207b7SJohn Levon 
3481f5207b7SJohn Levon 	/* don't save unknown states if leaving it blank is the same */
3491f5207b7SJohn Levon 	if (!orig_state && estate_is_unknown(state))
3501f5207b7SJohn Levon 		return;
3511f5207b7SJohn Levon 
3521f5207b7SJohn Levon 	new_name = get_other_name_sym(name, sym, &new_sym);
3531f5207b7SJohn Levon 	if (new_name && new_sym)
3541f5207b7SJohn Levon 		set_extra_nomod_helper(new_name, new_sym, expr, state);
3551f5207b7SJohn Levon 	free_string(new_name);
3561f5207b7SJohn Levon 
3571f5207b7SJohn Levon 	if (!estate_related(orig_state)) {
3581f5207b7SJohn Levon 		set_extra_nomod_helper(name, sym, expr, state);
3591f5207b7SJohn Levon 		return;
3601f5207b7SJohn Levon 	}
3611f5207b7SJohn Levon 
3621f5207b7SJohn Levon 	set_related(state, estate_related(orig_state));
3631f5207b7SJohn Levon 	FOR_EACH_PTR(estate_related(orig_state), rel) {
3641f5207b7SJohn Levon 		struct smatch_state *estate;
3651f5207b7SJohn Levon 
3661f5207b7SJohn Levon 		estate = get_state(SMATCH_EXTRA, rel->name, rel->sym);
3671f5207b7SJohn Levon 		if (!estate)
3681f5207b7SJohn Levon 			continue;
3691f5207b7SJohn Levon 		set_extra_nomod_helper(rel->name, rel->sym, expr, clone_estate_cast(estate_type(estate), state));
3701f5207b7SJohn Levon 	} END_FOR_EACH_PTR(rel);
3711f5207b7SJohn Levon }
3721f5207b7SJohn Levon 
3731f5207b7SJohn Levon void set_extra_nomod_vsl(const char *name, struct symbol *sym, struct var_sym_list *vsl, struct expression *expr, struct smatch_state *state)
3741f5207b7SJohn Levon {
3751f5207b7SJohn Levon 	struct var_sym *vs;
3761f5207b7SJohn Levon 
3771f5207b7SJohn Levon 	FOR_EACH_PTR(vsl, vs) {
3781f5207b7SJohn Levon 		store_link(link_id, vs->var, vs->sym, name, sym);
3791f5207b7SJohn Levon 	} END_FOR_EACH_PTR(vs);
3801f5207b7SJohn Levon 
3811f5207b7SJohn Levon 	set_extra_nomod(name, sym, expr, state);
3821f5207b7SJohn Levon }
3831f5207b7SJohn Levon 
3841f5207b7SJohn Levon /*
3851f5207b7SJohn Levon  * This is for return_implies_state() hooks which modify a SMATCH_EXTRA state
3861f5207b7SJohn Levon  */
3871f5207b7SJohn Levon void set_extra_expr_nomod(struct expression *expr, struct smatch_state *state)
3881f5207b7SJohn Levon {
3891f5207b7SJohn Levon 	struct var_sym_list *vsl;
3901f5207b7SJohn Levon 	struct var_sym *vs;
3911f5207b7SJohn Levon 	char *name;
3921f5207b7SJohn Levon 	struct symbol *sym;
3931f5207b7SJohn Levon 
3941f5207b7SJohn Levon 	name = expr_to_chunk_sym_vsl(expr, &sym, &vsl);
3951f5207b7SJohn Levon 	if (!name || !vsl)
3961f5207b7SJohn Levon 		goto free;
3971f5207b7SJohn Levon 	FOR_EACH_PTR(vsl, vs) {
3981f5207b7SJohn Levon 		store_link(link_id, vs->var, vs->sym, name, sym);
3991f5207b7SJohn Levon 	} END_FOR_EACH_PTR(vs);
4001f5207b7SJohn Levon 
4011f5207b7SJohn Levon 	set_extra_nomod(name, sym, expr, state);
4021f5207b7SJohn Levon free:
4031f5207b7SJohn Levon 	free_string(name);
4041f5207b7SJohn Levon }
4051f5207b7SJohn Levon 
4061f5207b7SJohn Levon static void set_extra_true_false(const char *name, struct symbol *sym,
4071f5207b7SJohn Levon 			struct smatch_state *true_state,
4081f5207b7SJohn Levon 			struct smatch_state *false_state)
4091f5207b7SJohn Levon {
4101f5207b7SJohn Levon 	char *new_name;
4111f5207b7SJohn Levon 	struct symbol *new_sym;
4121f5207b7SJohn Levon 	struct relation *rel;
4131f5207b7SJohn Levon 	struct smatch_state *orig_state;
4141f5207b7SJohn Levon 
4151f5207b7SJohn Levon 	if (!true_state && !false_state)
4161f5207b7SJohn Levon 		return;
4171f5207b7SJohn Levon 
4181f5207b7SJohn Levon 	if (in_warn_on_macro())
4191f5207b7SJohn Levon 		return;
4201f5207b7SJohn Levon 
4211f5207b7SJohn Levon 	new_name = get_other_name_sym(name, sym, &new_sym);
4221f5207b7SJohn Levon 	if (new_name && new_sym)
4231f5207b7SJohn Levon 		set_true_false_states(SMATCH_EXTRA, new_name, new_sym, true_state, false_state);
4241f5207b7SJohn Levon 	free_string(new_name);
4251f5207b7SJohn Levon 
4261f5207b7SJohn Levon 	orig_state = get_state(SMATCH_EXTRA, name, sym);
4271f5207b7SJohn Levon 
4281f5207b7SJohn Levon 	if (!estate_related(orig_state)) {
4291f5207b7SJohn Levon 		set_true_false_states(SMATCH_EXTRA, name, sym, true_state, false_state);
4301f5207b7SJohn Levon 		return;
4311f5207b7SJohn Levon 	}
4321f5207b7SJohn Levon 
4331f5207b7SJohn Levon 	if (true_state)
4341f5207b7SJohn Levon 		set_related(true_state, estate_related(orig_state));
4351f5207b7SJohn Levon 	if (false_state)
4361f5207b7SJohn Levon 		set_related(false_state, estate_related(orig_state));
4371f5207b7SJohn Levon 
4381f5207b7SJohn Levon 	FOR_EACH_PTR(estate_related(orig_state), rel) {
4391f5207b7SJohn Levon 		set_true_false_states(SMATCH_EXTRA, rel->name, rel->sym,
4401f5207b7SJohn Levon 				true_state, false_state);
4411f5207b7SJohn Levon 	} END_FOR_EACH_PTR(rel);
4421f5207b7SJohn Levon }
4431f5207b7SJohn Levon 
4441f5207b7SJohn Levon static void set_extra_chunk_true_false(struct expression *expr,
4451f5207b7SJohn Levon 				       struct smatch_state *true_state,
4461f5207b7SJohn Levon 				       struct smatch_state *false_state)
4471f5207b7SJohn Levon {
4481f5207b7SJohn Levon 	struct var_sym_list *vsl;
4491f5207b7SJohn Levon 	struct var_sym *vs;
4501f5207b7SJohn Levon 	struct symbol *type;
4511f5207b7SJohn Levon 	char *name;
4521f5207b7SJohn Levon 	struct symbol *sym;
4531f5207b7SJohn Levon 
4541f5207b7SJohn Levon 	if (in_warn_on_macro())
4551f5207b7SJohn Levon 		return;
4561f5207b7SJohn Levon 
4571f5207b7SJohn Levon 	type = get_type(expr);
4581f5207b7SJohn Levon 	if (!type)
4591f5207b7SJohn Levon 		return;
4601f5207b7SJohn Levon 
4611f5207b7SJohn Levon 	name = expr_to_chunk_sym_vsl(expr, &sym, &vsl);
4621f5207b7SJohn Levon 	if (!name || !vsl)
4631f5207b7SJohn Levon 		goto free;
4641f5207b7SJohn Levon 	FOR_EACH_PTR(vsl, vs) {
4651f5207b7SJohn Levon 		store_link(link_id, vs->var, vs->sym, name, sym);
4661f5207b7SJohn Levon 	} END_FOR_EACH_PTR(vs);
4671f5207b7SJohn Levon 
4681f5207b7SJohn Levon 	set_true_false_states(SMATCH_EXTRA, name, sym,
4691f5207b7SJohn Levon 			      clone_estate(true_state),
4701f5207b7SJohn Levon 			      clone_estate(false_state));
4711f5207b7SJohn Levon free:
4721f5207b7SJohn Levon 	free_string(name);
4731f5207b7SJohn Levon }
4741f5207b7SJohn Levon 
4751f5207b7SJohn Levon static void set_extra_expr_true_false(struct expression *expr,
4761f5207b7SJohn Levon 		struct smatch_state *true_state,
4771f5207b7SJohn Levon 		struct smatch_state *false_state)
4781f5207b7SJohn Levon {
4791f5207b7SJohn Levon 	char *name;
4801f5207b7SJohn Levon 	struct symbol *sym;
4811f5207b7SJohn Levon 	sval_t sval;
4821f5207b7SJohn Levon 
4831f5207b7SJohn Levon 	if (!true_state && !false_state)
4841f5207b7SJohn Levon 		return;
4851f5207b7SJohn Levon 
4861f5207b7SJohn Levon 	if (get_value(expr, &sval))
4871f5207b7SJohn Levon 		return;
4881f5207b7SJohn Levon 
4891f5207b7SJohn Levon 	expr = strip_expr(expr);
4901f5207b7SJohn Levon 	name = expr_to_var_sym(expr, &sym);
4911f5207b7SJohn Levon 	if (!name || !sym) {
4921f5207b7SJohn Levon 		free_string(name);
4931f5207b7SJohn Levon 		set_extra_chunk_true_false(expr, true_state, false_state);
4941f5207b7SJohn Levon 		return;
4951f5207b7SJohn Levon 	}
4961f5207b7SJohn Levon 	set_extra_true_false(name, sym, true_state, false_state);
4971f5207b7SJohn Levon 	free_string(name);
4981f5207b7SJohn Levon }
4991f5207b7SJohn Levon 
5001f5207b7SJohn Levon static int get_countdown_info(struct expression *condition, struct expression **unop, int *op, sval_t *right)
5011f5207b7SJohn Levon {
5021f5207b7SJohn Levon 	struct expression *unop_expr;
5031f5207b7SJohn Levon 	int comparison;
5041f5207b7SJohn Levon 	sval_t limit;
5051f5207b7SJohn Levon 
5061f5207b7SJohn Levon 	right->type = &int_ctype;
5071f5207b7SJohn Levon 	right->value = 0;
5081f5207b7SJohn Levon 
5091f5207b7SJohn Levon 	condition = strip_expr(condition);
5101f5207b7SJohn Levon 
5111f5207b7SJohn Levon 	if (condition->type == EXPR_COMPARE) {
5121f5207b7SJohn Levon 		comparison = remove_unsigned_from_comparison(condition->op);
5131f5207b7SJohn Levon 
5141f5207b7SJohn Levon 		if (comparison != SPECIAL_GTE && comparison != '>')
5151f5207b7SJohn Levon 			return 0;
5161f5207b7SJohn Levon 		if (!get_value(condition->right, &limit))
5171f5207b7SJohn Levon 			return 0;
5181f5207b7SJohn Levon 
5191f5207b7SJohn Levon 		unop_expr = condition->left;
5201f5207b7SJohn Levon 		if (unop_expr->type != EXPR_PREOP && unop_expr->type != EXPR_POSTOP)
5211f5207b7SJohn Levon 			return 0;
5221f5207b7SJohn Levon 		if (unop_expr->op != SPECIAL_DECREMENT)
5231f5207b7SJohn Levon 			return 0;
5241f5207b7SJohn Levon 
5251f5207b7SJohn Levon 		*unop = unop_expr;
5261f5207b7SJohn Levon 		*op = comparison;
5271f5207b7SJohn Levon 		*right = limit;
5281f5207b7SJohn Levon 
5291f5207b7SJohn Levon 		return 1;
5301f5207b7SJohn Levon 	}
5311f5207b7SJohn Levon 
5321f5207b7SJohn Levon 	if (condition->type != EXPR_PREOP && condition->type != EXPR_POSTOP)
5331f5207b7SJohn Levon 		return 0;
5341f5207b7SJohn Levon 	if (condition->op != SPECIAL_DECREMENT)
5351f5207b7SJohn Levon 		return 0;
5361f5207b7SJohn Levon 
5371f5207b7SJohn Levon 	*unop = condition;
5381f5207b7SJohn Levon 	*op = '>';
5391f5207b7SJohn Levon 
5401f5207b7SJohn Levon 	return 1;
5411f5207b7SJohn Levon }
5421f5207b7SJohn Levon 
5431f5207b7SJohn Levon static struct sm_state *handle_canonical_while_count_down(struct statement *loop)
5441f5207b7SJohn Levon {
5451f5207b7SJohn Levon 	struct expression *iter_var;
5461f5207b7SJohn Levon 	struct expression *condition, *unop;
547*efe51d0cSJohn Levon 	struct symbol *type;
5481f5207b7SJohn Levon 	struct sm_state *sm;
5491f5207b7SJohn Levon 	struct smatch_state *estate;
5501f5207b7SJohn Levon 	int op;
5511f5207b7SJohn Levon 	sval_t start, right;
5521f5207b7SJohn Levon 
5531f5207b7SJohn Levon 	right.type = &int_ctype;
5541f5207b7SJohn Levon 	right.value = 0;
5551f5207b7SJohn Levon 
5561f5207b7SJohn Levon 	condition = strip_expr(loop->iterator_pre_condition);
5571f5207b7SJohn Levon 	if (!condition)
5581f5207b7SJohn Levon 		return NULL;
5591f5207b7SJohn Levon 
5601f5207b7SJohn Levon 	if (!get_countdown_info(condition, &unop, &op, &right))
5611f5207b7SJohn Levon 		return NULL;
5621f5207b7SJohn Levon 
5631f5207b7SJohn Levon 	iter_var = unop->unop;
5641f5207b7SJohn Levon 
5651f5207b7SJohn Levon 	sm = get_sm_state_expr(SMATCH_EXTRA, iter_var);
5661f5207b7SJohn Levon 	if (!sm)
5671f5207b7SJohn Levon 		return NULL;
5681f5207b7SJohn Levon 	if (sval_cmp(estate_min(sm->state), right) < 0)
5691f5207b7SJohn Levon 		return NULL;
5701f5207b7SJohn Levon 	start = estate_max(sm->state);
571*efe51d0cSJohn Levon 
572*efe51d0cSJohn Levon 	type = get_type(iter_var);
573*efe51d0cSJohn Levon 	right = sval_cast(type, right);
574*efe51d0cSJohn Levon 	start = sval_cast(type, start);
575*efe51d0cSJohn Levon 
5761f5207b7SJohn Levon 	if  (sval_cmp(start, right) <= 0)
5771f5207b7SJohn Levon 		return NULL;
5781f5207b7SJohn Levon 	if (!sval_is_max(start))
5791f5207b7SJohn Levon 		start.value--;
5801f5207b7SJohn Levon 
5811f5207b7SJohn Levon 	if (op == SPECIAL_GTE)
5821f5207b7SJohn Levon 		right.value--;
5831f5207b7SJohn Levon 
5841f5207b7SJohn Levon 	if (unop->type == EXPR_PREOP) {
5851f5207b7SJohn Levon 		right.value++;
5861f5207b7SJohn Levon 		estate = alloc_estate_range(right, start);
5871f5207b7SJohn Levon 		if (estate_has_hard_max(sm->state))
5881f5207b7SJohn Levon 			estate_set_hard_max(estate);
5891f5207b7SJohn Levon 		estate_copy_fuzzy_max(estate, sm->state);
5901f5207b7SJohn Levon 		set_extra_expr_mod(iter_var, estate);
5911f5207b7SJohn Levon 	}
5921f5207b7SJohn Levon 	if (unop->type == EXPR_POSTOP) {
5931f5207b7SJohn Levon 		estate = alloc_estate_range(right, start);
5941f5207b7SJohn Levon 		if (estate_has_hard_max(sm->state))
5951f5207b7SJohn Levon 			estate_set_hard_max(estate);
5961f5207b7SJohn Levon 		estate_copy_fuzzy_max(estate, sm->state);
5971f5207b7SJohn Levon 		set_extra_expr_mod(iter_var, estate);
5981f5207b7SJohn Levon 	}
5991f5207b7SJohn Levon 	return get_sm_state_expr(SMATCH_EXTRA, iter_var);
6001f5207b7SJohn Levon }
6011f5207b7SJohn Levon 
6021f5207b7SJohn Levon static struct sm_state *handle_canonical_for_inc(struct expression *iter_expr,
6031f5207b7SJohn Levon 						struct expression *condition)
6041f5207b7SJohn Levon {
6051f5207b7SJohn Levon 	struct expression *iter_var;
6061f5207b7SJohn Levon 	struct sm_state *sm;
6071f5207b7SJohn Levon 	struct smatch_state *estate;
6081f5207b7SJohn Levon 	sval_t start, end, max;
609*efe51d0cSJohn Levon 	struct symbol *type;
6101f5207b7SJohn Levon 
6111f5207b7SJohn Levon 	iter_var = iter_expr->unop;
6121f5207b7SJohn Levon 	sm = get_sm_state_expr(SMATCH_EXTRA, iter_var);
6131f5207b7SJohn Levon 	if (!sm)
6141f5207b7SJohn Levon 		return NULL;
6151f5207b7SJohn Levon 	if (!estate_get_single_value(sm->state, &start))
6161f5207b7SJohn Levon 		return NULL;
617*efe51d0cSJohn Levon 	if (!get_implied_value(condition->right, &end))
618*efe51d0cSJohn Levon 		return NULL;
6191f5207b7SJohn Levon 
6201f5207b7SJohn Levon 	if (get_sm_state_expr(SMATCH_EXTRA, condition->left) != sm)
6211f5207b7SJohn Levon 		return NULL;
6221f5207b7SJohn Levon 
6231f5207b7SJohn Levon 	switch (condition->op) {
6241f5207b7SJohn Levon 	case SPECIAL_UNSIGNED_LT:
6251f5207b7SJohn Levon 	case SPECIAL_NOTEQUAL:
6261f5207b7SJohn Levon 	case '<':
6271f5207b7SJohn Levon 		if (!sval_is_min(end))
6281f5207b7SJohn Levon 			end.value--;
6291f5207b7SJohn Levon 		break;
6301f5207b7SJohn Levon 	case SPECIAL_UNSIGNED_LTE:
6311f5207b7SJohn Levon 	case SPECIAL_LTE:
6321f5207b7SJohn Levon 		break;
6331f5207b7SJohn Levon 	default:
6341f5207b7SJohn Levon 		return NULL;
6351f5207b7SJohn Levon 	}
6361f5207b7SJohn Levon 	if (sval_cmp(end, start) < 0)
6371f5207b7SJohn Levon 		return NULL;
638*efe51d0cSJohn Levon 	type = get_type(iter_var);
639*efe51d0cSJohn Levon 	start = sval_cast(type, start);
640*efe51d0cSJohn Levon 	end = sval_cast(type, end);
6411f5207b7SJohn Levon 	estate = alloc_estate_range(start, end);
6421f5207b7SJohn Levon 	if (get_hard_max(condition->right, &max)) {
643*efe51d0cSJohn Levon 		if (!get_macro_name(condition->pos))
644*efe51d0cSJohn Levon 			estate_set_hard_max(estate);
6451f5207b7SJohn Levon 		if (condition->op == '<' ||
6461f5207b7SJohn Levon 		    condition->op == SPECIAL_UNSIGNED_LT ||
6471f5207b7SJohn Levon 		    condition->op == SPECIAL_NOTEQUAL)
6481f5207b7SJohn Levon 			max.value--;
649*efe51d0cSJohn Levon 		max = sval_cast(type, max);
6501f5207b7SJohn Levon 		estate_set_fuzzy_max(estate, max);
6511f5207b7SJohn Levon 	}
6521f5207b7SJohn Levon 	set_extra_expr_mod(iter_var, estate);
6531f5207b7SJohn Levon 	return get_sm_state_expr(SMATCH_EXTRA, iter_var);
6541f5207b7SJohn Levon }
6551f5207b7SJohn Levon 
6561f5207b7SJohn Levon static struct sm_state *handle_canonical_for_dec(struct expression *iter_expr,
6571f5207b7SJohn Levon 						struct expression *condition)
6581f5207b7SJohn Levon {
6591f5207b7SJohn Levon 	struct expression *iter_var;
6601f5207b7SJohn Levon 	struct sm_state *sm;
6611f5207b7SJohn Levon 	struct smatch_state *estate;
6621f5207b7SJohn Levon 	sval_t start, end;
6631f5207b7SJohn Levon 
6641f5207b7SJohn Levon 	iter_var = iter_expr->unop;
6651f5207b7SJohn Levon 	sm = get_sm_state_expr(SMATCH_EXTRA, iter_var);
6661f5207b7SJohn Levon 	if (!sm)
6671f5207b7SJohn Levon 		return NULL;
6681f5207b7SJohn Levon 	if (!estate_get_single_value(sm->state, &start))
6691f5207b7SJohn Levon 		return NULL;
6701f5207b7SJohn Levon 	if (!get_implied_min(condition->right, &end))
6711f5207b7SJohn Levon 		end = sval_type_min(get_type(iter_var));
672*efe51d0cSJohn Levon 	end = sval_cast(estate_type(sm->state), end);
6731f5207b7SJohn Levon 	if (get_sm_state_expr(SMATCH_EXTRA, condition->left) != sm)
6741f5207b7SJohn Levon 		return NULL;
6751f5207b7SJohn Levon 
6761f5207b7SJohn Levon 	switch (condition->op) {
6771f5207b7SJohn Levon 	case SPECIAL_NOTEQUAL:
6781f5207b7SJohn Levon 	case '>':
679*efe51d0cSJohn Levon 		if (!sval_is_max(end))
6801f5207b7SJohn Levon 			end.value++;
6811f5207b7SJohn Levon 		break;
6821f5207b7SJohn Levon 	case SPECIAL_GTE:
6831f5207b7SJohn Levon 		break;
6841f5207b7SJohn Levon 	default:
6851f5207b7SJohn Levon 		return NULL;
6861f5207b7SJohn Levon 	}
6871f5207b7SJohn Levon 	if (sval_cmp(end, start) > 0)
6881f5207b7SJohn Levon 		return NULL;
6891f5207b7SJohn Levon 	estate = alloc_estate_range(end, start);
6901f5207b7SJohn Levon 	estate_set_hard_max(estate);
6911f5207b7SJohn Levon 	estate_set_fuzzy_max(estate, estate_get_fuzzy_max(estate));
6921f5207b7SJohn Levon 	set_extra_expr_mod(iter_var, estate);
6931f5207b7SJohn Levon 	return get_sm_state_expr(SMATCH_EXTRA, iter_var);
6941f5207b7SJohn Levon }
6951f5207b7SJohn Levon 
6961f5207b7SJohn Levon static struct sm_state *handle_canonical_for_loops(struct statement *loop)
6971f5207b7SJohn Levon {
6981f5207b7SJohn Levon 	struct expression *iter_expr;
6991f5207b7SJohn Levon 	struct expression *condition;
7001f5207b7SJohn Levon 
7011f5207b7SJohn Levon 	if (!loop->iterator_post_statement)
7021f5207b7SJohn Levon 		return NULL;
7031f5207b7SJohn Levon 	if (loop->iterator_post_statement->type != STMT_EXPRESSION)
7041f5207b7SJohn Levon 		return NULL;
7051f5207b7SJohn Levon 	iter_expr = loop->iterator_post_statement->expression;
7061f5207b7SJohn Levon 	if (!loop->iterator_pre_condition)
7071f5207b7SJohn Levon 		return NULL;
7081f5207b7SJohn Levon 	if (loop->iterator_pre_condition->type != EXPR_COMPARE)
7091f5207b7SJohn Levon 		return NULL;
7101f5207b7SJohn Levon 	condition = loop->iterator_pre_condition;
7111f5207b7SJohn Levon 
7121f5207b7SJohn Levon 	if (iter_expr->op == SPECIAL_INCREMENT)
7131f5207b7SJohn Levon 		return handle_canonical_for_inc(iter_expr, condition);
7141f5207b7SJohn Levon 	if (iter_expr->op == SPECIAL_DECREMENT)
7151f5207b7SJohn Levon 		return handle_canonical_for_dec(iter_expr, condition);
7161f5207b7SJohn Levon 	return NULL;
7171f5207b7SJohn Levon }
7181f5207b7SJohn Levon 
7191f5207b7SJohn Levon struct sm_state *__extra_handle_canonical_loops(struct statement *loop, struct stree **stree)
7201f5207b7SJohn Levon {
7211f5207b7SJohn Levon 	struct sm_state *ret;
7221f5207b7SJohn Levon 
7231f5207b7SJohn Levon 	/*
7241f5207b7SJohn Levon 	 * Canonical loops are a hack.  The proper way to handle this is to
7251f5207b7SJohn Levon 	 * use two passes, but unfortunately, doing two passes makes parsing
7261f5207b7SJohn Levon 	 * code twice as slow.
7271f5207b7SJohn Levon 	 *
7281f5207b7SJohn Levon 	 * What we do is we set the inside state here, which overwrites whatever
7291f5207b7SJohn Levon 	 * __extra_match_condition() does.  Then we set the outside state in
7301f5207b7SJohn Levon 	 * __extra_pre_loop_hook_after().
7311f5207b7SJohn Levon 	 *
7321f5207b7SJohn Levon 	 */
7331f5207b7SJohn Levon 	__push_fake_cur_stree();
7341f5207b7SJohn Levon 	if (!loop->iterator_post_statement)
7351f5207b7SJohn Levon 		ret = handle_canonical_while_count_down(loop);
7361f5207b7SJohn Levon 	else
7371f5207b7SJohn Levon 		ret = handle_canonical_for_loops(loop);
7381f5207b7SJohn Levon 	*stree = __pop_fake_cur_stree();
7391f5207b7SJohn Levon 	return ret;
7401f5207b7SJohn Levon }
7411f5207b7SJohn Levon 
7421f5207b7SJohn Levon int __iterator_unchanged(struct sm_state *sm)
7431f5207b7SJohn Levon {
7441f5207b7SJohn Levon 	if (!sm)
7451f5207b7SJohn Levon 		return 0;
7461f5207b7SJohn Levon 	if (get_sm_state(my_id, sm->name, sm->sym) == sm)
7471f5207b7SJohn Levon 		return 1;
7481f5207b7SJohn Levon 	return 0;
7491f5207b7SJohn Levon }
7501f5207b7SJohn Levon 
7511f5207b7SJohn Levon static void while_count_down_after(struct sm_state *sm, struct expression *condition)
7521f5207b7SJohn Levon {
7531f5207b7SJohn Levon 	struct expression *unop;
7541f5207b7SJohn Levon 	int op;
7551f5207b7SJohn Levon 	sval_t limit, after_value;
7561f5207b7SJohn Levon 
7571f5207b7SJohn Levon 	if (!get_countdown_info(condition, &unop, &op, &limit))
7581f5207b7SJohn Levon 		return;
7591f5207b7SJohn Levon 	after_value = estate_min(sm->state);
7601f5207b7SJohn Levon 	after_value.value--;
7611f5207b7SJohn Levon 	set_extra_mod(sm->name, sm->sym, condition->unop, alloc_estate_sval(after_value));
7621f5207b7SJohn Levon }
7631f5207b7SJohn Levon 
7641f5207b7SJohn Levon void __extra_pre_loop_hook_after(struct sm_state *sm,
7651f5207b7SJohn Levon 				struct statement *iterator,
7661f5207b7SJohn Levon 				struct expression *condition)
7671f5207b7SJohn Levon {
7681f5207b7SJohn Levon 	struct expression *iter_expr;
7691f5207b7SJohn Levon 	sval_t limit;
7701f5207b7SJohn Levon 	struct smatch_state *state;
7711f5207b7SJohn Levon 
7721f5207b7SJohn Levon 	if (!iterator) {
7731f5207b7SJohn Levon 		while_count_down_after(sm, condition);
7741f5207b7SJohn Levon 		return;
7751f5207b7SJohn Levon 	}
7761f5207b7SJohn Levon 
7771f5207b7SJohn Levon 	iter_expr = iterator->expression;
7781f5207b7SJohn Levon 
7791f5207b7SJohn Levon 	if (condition->type != EXPR_COMPARE)
7801f5207b7SJohn Levon 		return;
7811f5207b7SJohn Levon 	if (iter_expr->op == SPECIAL_INCREMENT) {
7821f5207b7SJohn Levon 		limit = sval_binop(estate_max(sm->state), '+',
7831f5207b7SJohn Levon 				   sval_type_val(estate_type(sm->state), 1));
7841f5207b7SJohn Levon 	} else {
7851f5207b7SJohn Levon 		limit = sval_binop(estate_min(sm->state), '-',
7861f5207b7SJohn Levon 				   sval_type_val(estate_type(sm->state), 1));
7871f5207b7SJohn Levon 	}
788*efe51d0cSJohn Levon 	limit = sval_cast(estate_type(sm->state), limit);
7891f5207b7SJohn Levon 	if (!estate_has_hard_max(sm->state) && !__has_breaks()) {
7901f5207b7SJohn Levon 		if (iter_expr->op == SPECIAL_INCREMENT)
7911f5207b7SJohn Levon 			state = alloc_estate_range(estate_min(sm->state), limit);
7921f5207b7SJohn Levon 		else
7931f5207b7SJohn Levon 			state = alloc_estate_range(limit, estate_max(sm->state));
7941f5207b7SJohn Levon 	} else {
7951f5207b7SJohn Levon 		state = alloc_estate_sval(limit);
7961f5207b7SJohn Levon 	}
7971f5207b7SJohn Levon 	if (!estate_has_hard_max(sm->state)) {
7981f5207b7SJohn Levon 		estate_clear_hard_max(state);
7991f5207b7SJohn Levon 	}
8001f5207b7SJohn Levon 	if (estate_has_fuzzy_max(sm->state)) {
8011f5207b7SJohn Levon 		sval_t hmax = estate_get_fuzzy_max(sm->state);
8021f5207b7SJohn Levon 		sval_t max = estate_max(sm->state);
8031f5207b7SJohn Levon 
8041f5207b7SJohn Levon 		if (sval_cmp(hmax, max) != 0)
8051f5207b7SJohn Levon 			estate_clear_fuzzy_max(state);
8061f5207b7SJohn Levon 	} else if (!estate_has_fuzzy_max(sm->state)) {
8071f5207b7SJohn Levon 		estate_clear_fuzzy_max(state);
8081f5207b7SJohn Levon 	}
8091f5207b7SJohn Levon 
8101f5207b7SJohn Levon 	set_extra_mod(sm->name, sm->sym, iter_expr, state);
8111f5207b7SJohn Levon }
8121f5207b7SJohn Levon 
813*efe51d0cSJohn Levon static bool get_global_rl(const char *name, struct symbol *sym, struct range_list **rl)
814*efe51d0cSJohn Levon {
815*efe51d0cSJohn Levon 	struct expression *expr;
816*efe51d0cSJohn Levon 
817*efe51d0cSJohn Levon 	if (!sym || !(sym->ctype.modifiers & MOD_TOPLEVEL) || !sym->ident)
818*efe51d0cSJohn Levon 		return false;
819*efe51d0cSJohn Levon 	if (strcmp(sym->ident->name, name) != 0)
820*efe51d0cSJohn Levon 		return false;
821*efe51d0cSJohn Levon 
822*efe51d0cSJohn Levon 	expr = symbol_expression(sym);
823*efe51d0cSJohn Levon 	return get_implied_rl(expr, rl);
824*efe51d0cSJohn Levon }
825*efe51d0cSJohn Levon 
8261f5207b7SJohn Levon static struct stree *unmatched_stree;
8271f5207b7SJohn Levon static struct smatch_state *unmatched_state(struct sm_state *sm)
8281f5207b7SJohn Levon {
8291f5207b7SJohn Levon 	struct smatch_state *state;
830*efe51d0cSJohn Levon 	struct range_list *rl;
8311f5207b7SJohn Levon 
8321f5207b7SJohn Levon 	if (unmatched_stree) {
8331f5207b7SJohn Levon 		state = get_state_stree(unmatched_stree, SMATCH_EXTRA, sm->name, sm->sym);
8341f5207b7SJohn Levon 		if (state)
8351f5207b7SJohn Levon 			return state;
8361f5207b7SJohn Levon 	}
8371f5207b7SJohn Levon 	if (parent_is_gone_var_sym(sm->name, sm->sym))
8381f5207b7SJohn Levon 		return alloc_estate_empty();
839*efe51d0cSJohn Levon 	if (get_global_rl(sm->name, sm->sym, &rl))
840*efe51d0cSJohn Levon 		return alloc_estate_rl(rl);
8411f5207b7SJohn Levon 	return alloc_estate_whole(estate_type(sm->state));
8421f5207b7SJohn Levon }
8431f5207b7SJohn Levon 
8441f5207b7SJohn Levon static void clear_the_pointed_at(struct expression *expr)
8451f5207b7SJohn Levon {
8461f5207b7SJohn Levon 	struct stree *stree;
8471f5207b7SJohn Levon 	char *name;
8481f5207b7SJohn Levon 	struct symbol *sym;
8491f5207b7SJohn Levon 	struct sm_state *tmp;
8501f5207b7SJohn Levon 
8511f5207b7SJohn Levon 	name = expr_to_var_sym(expr, &sym);
8521f5207b7SJohn Levon 	if (!name || !sym)
8531f5207b7SJohn Levon 		goto free;
8541f5207b7SJohn Levon 
8551f5207b7SJohn Levon 	stree = __get_cur_stree();
8561f5207b7SJohn Levon 	FOR_EACH_MY_SM(SMATCH_EXTRA, stree, tmp) {
8571f5207b7SJohn Levon 		if (tmp->name[0] != '*')
8581f5207b7SJohn Levon 			continue;
8591f5207b7SJohn Levon 		if (tmp->sym != sym)
8601f5207b7SJohn Levon 			continue;
8611f5207b7SJohn Levon 		if (strcmp(tmp->name + 1, name) != 0)
8621f5207b7SJohn Levon 			continue;
8631f5207b7SJohn Levon 		set_extra_mod(tmp->name, tmp->sym, expr, alloc_estate_whole(estate_type(tmp->state)));
8641f5207b7SJohn Levon 	} END_FOR_EACH_SM(tmp);
8651f5207b7SJohn Levon 
8661f5207b7SJohn Levon free:
8671f5207b7SJohn Levon 	free_string(name);
8681f5207b7SJohn Levon }
8691f5207b7SJohn Levon 
8701f5207b7SJohn Levon static int is_const_param(struct expression *expr, int param)
8711f5207b7SJohn Levon {
8721f5207b7SJohn Levon 	struct symbol *type;
8731f5207b7SJohn Levon 
8741f5207b7SJohn Levon 	type = get_arg_type(expr, param);
8751f5207b7SJohn Levon 	if (!type)
8761f5207b7SJohn Levon 		return 0;
8771f5207b7SJohn Levon 	if (type->ctype.modifiers & MOD_CONST)
8781f5207b7SJohn Levon 		return 1;
8791f5207b7SJohn Levon 	return 0;
8801f5207b7SJohn Levon }
8811f5207b7SJohn Levon 
8821f5207b7SJohn Levon static void match_function_call(struct expression *expr)
8831f5207b7SJohn Levon {
8841f5207b7SJohn Levon 	struct expression *arg;
8851f5207b7SJohn Levon 	struct expression *tmp;
8861f5207b7SJohn Levon 	int param = -1;
8871f5207b7SJohn Levon 
8881f5207b7SJohn Levon 	/* if we have the db this is handled in smatch_function_hooks.c */
8891f5207b7SJohn Levon 	if (!option_no_db)
8901f5207b7SJohn Levon 		return;
8911f5207b7SJohn Levon 	if (inlinable(expr->fn))
8921f5207b7SJohn Levon 		return;
8931f5207b7SJohn Levon 
8941f5207b7SJohn Levon 	FOR_EACH_PTR(expr->args, arg) {
8951f5207b7SJohn Levon 		param++;
8961f5207b7SJohn Levon 		if (is_const_param(expr->fn, param))
8971f5207b7SJohn Levon 			continue;
8981f5207b7SJohn Levon 		tmp = strip_expr(arg);
8991f5207b7SJohn Levon 		if (tmp->type == EXPR_PREOP && tmp->op == '&')
9001f5207b7SJohn Levon 			set_extra_expr_mod(tmp->unop, alloc_estate_whole(get_type(tmp->unop)));
9011f5207b7SJohn Levon 		else
9021f5207b7SJohn Levon 			clear_the_pointed_at(tmp);
9031f5207b7SJohn Levon 	} END_FOR_EACH_PTR(arg);
9041f5207b7SJohn Levon }
9051f5207b7SJohn Levon 
906*efe51d0cSJohn Levon int values_fit_type(struct expression *left, struct expression *right)
9071f5207b7SJohn Levon {
9081f5207b7SJohn Levon 	struct range_list *rl;
9091f5207b7SJohn Levon 	struct symbol *type;
9101f5207b7SJohn Levon 
9111f5207b7SJohn Levon 	type = get_type(left);
9121f5207b7SJohn Levon 	if (!type)
9131f5207b7SJohn Levon 		return 0;
9141f5207b7SJohn Levon 	get_absolute_rl(right, &rl);
915*efe51d0cSJohn Levon 	if (type == rl_type(rl))
916*efe51d0cSJohn Levon 		return 1;
9171f5207b7SJohn Levon 	if (type_unsigned(type) && sval_is_negative(rl_min(rl)))
9181f5207b7SJohn Levon 		return 0;
9191f5207b7SJohn Levon 	if (sval_cmp(sval_type_min(type), rl_min(rl)) > 0)
9201f5207b7SJohn Levon 		return 0;
9211f5207b7SJohn Levon 	if (sval_cmp(sval_type_max(type), rl_max(rl)) < 0)
9221f5207b7SJohn Levon 		return 0;
9231f5207b7SJohn Levon 	return 1;
9241f5207b7SJohn Levon }
9251f5207b7SJohn Levon 
9261f5207b7SJohn Levon static void save_chunk_info(struct expression *left, struct expression *right)
9271f5207b7SJohn Levon {
9281f5207b7SJohn Levon 	struct var_sym_list *vsl;
9291f5207b7SJohn Levon 	struct var_sym *vs;
9301f5207b7SJohn Levon 	struct expression *add_expr;
9311f5207b7SJohn Levon 	struct symbol *type;
9321f5207b7SJohn Levon 	sval_t sval;
9331f5207b7SJohn Levon 	char *name;
9341f5207b7SJohn Levon 	struct symbol *sym;
9351f5207b7SJohn Levon 
9361f5207b7SJohn Levon 	if (right->type != EXPR_BINOP || right->op != '-')
9371f5207b7SJohn Levon 		return;
9381f5207b7SJohn Levon 	if (!get_value(right->left, &sval))
9391f5207b7SJohn Levon 		return;
9401f5207b7SJohn Levon 	if (!expr_to_sym(right->right))
9411f5207b7SJohn Levon 		return;
9421f5207b7SJohn Levon 
9431f5207b7SJohn Levon 	add_expr = binop_expression(left, '+', right->right);
9441f5207b7SJohn Levon 	type = get_type(add_expr);
9451f5207b7SJohn Levon 	if (!type)
9461f5207b7SJohn Levon 		return;
9471f5207b7SJohn Levon 	name = expr_to_chunk_sym_vsl(add_expr, &sym, &vsl);
9481f5207b7SJohn Levon 	if (!name || !vsl)
9491f5207b7SJohn Levon 		goto free;
9501f5207b7SJohn Levon 	FOR_EACH_PTR(vsl, vs) {
9511f5207b7SJohn Levon 		store_link(link_id, vs->var, vs->sym, name, sym);
9521f5207b7SJohn Levon 	} END_FOR_EACH_PTR(vs);
9531f5207b7SJohn Levon 
9541f5207b7SJohn Levon 	set_state(SMATCH_EXTRA, name, sym, alloc_estate_sval(sval_cast(type, sval)));
9551f5207b7SJohn Levon free:
9561f5207b7SJohn Levon 	free_string(name);
9571f5207b7SJohn Levon }
9581f5207b7SJohn Levon 
9591f5207b7SJohn Levon static void do_array_assign(struct expression *left, int op, struct expression *right)
9601f5207b7SJohn Levon {
9611f5207b7SJohn Levon 	struct range_list *rl;
9621f5207b7SJohn Levon 
9631f5207b7SJohn Levon 	if (op == '=') {
9641f5207b7SJohn Levon 		get_absolute_rl(right, &rl);
9651f5207b7SJohn Levon 		rl = cast_rl(get_type(left), rl);
9661f5207b7SJohn Levon 	} else {
9671f5207b7SJohn Levon 		rl = alloc_whole_rl(get_type(left));
9681f5207b7SJohn Levon 	}
9691f5207b7SJohn Levon 
9701f5207b7SJohn Levon 	set_extra_array_mod(left, alloc_estate_rl(rl));
9711f5207b7SJohn Levon }
9721f5207b7SJohn Levon 
9731f5207b7SJohn Levon static void match_vanilla_assign(struct expression *left, struct expression *right)
9741f5207b7SJohn Levon {
9751f5207b7SJohn Levon 	struct range_list *orig_rl = NULL;
9761f5207b7SJohn Levon 	struct range_list *rl = NULL;
9771f5207b7SJohn Levon 	struct symbol *right_sym;
9781f5207b7SJohn Levon 	struct symbol *left_type;
9791f5207b7SJohn Levon 	struct symbol *right_type;
9801f5207b7SJohn Levon 	char *right_name = NULL;
9811f5207b7SJohn Levon 	struct symbol *sym;
9821f5207b7SJohn Levon 	char *name;
9831f5207b7SJohn Levon 	sval_t sval, max;
9841f5207b7SJohn Levon 	struct smatch_state *state;
9851f5207b7SJohn Levon 	int comparison;
9861f5207b7SJohn Levon 
9871f5207b7SJohn Levon 	if (is_struct(left))
9881f5207b7SJohn Levon 		return;
9891f5207b7SJohn Levon 
9901f5207b7SJohn Levon 	save_chunk_info(left, right);
9911f5207b7SJohn Levon 
9921f5207b7SJohn Levon 	name = expr_to_var_sym(left, &sym);
9931f5207b7SJohn Levon 	if (!name) {
9941f5207b7SJohn Levon 		if (chunk_has_array(left))
9951f5207b7SJohn Levon 			do_array_assign(left, '=', right);
9961f5207b7SJohn Levon 		return;
9971f5207b7SJohn Levon 	}
9981f5207b7SJohn Levon 
9991f5207b7SJohn Levon 	left_type = get_type(left);
10001f5207b7SJohn Levon 	right_type = get_type(right);
10011f5207b7SJohn Levon 
10021f5207b7SJohn Levon 	right_name = expr_to_var_sym(right, &right_sym);
10031f5207b7SJohn Levon 
10041f5207b7SJohn Levon 	if (!__in_fake_assign &&
10051f5207b7SJohn Levon 	    !(right->type == EXPR_PREOP && right->op == '&') &&
10061f5207b7SJohn Levon 	    right_name && right_sym &&
10071f5207b7SJohn Levon 	    values_fit_type(left, strip_expr(right)) &&
10081f5207b7SJohn Levon 	    !has_symbol(right, sym)) {
10091f5207b7SJohn Levon 		set_equiv(left, right);
10101f5207b7SJohn Levon 		goto free;
10111f5207b7SJohn Levon 	}
10121f5207b7SJohn Levon 
10131f5207b7SJohn Levon 	if (is_pointer(right) && get_address_rl(right, &rl)) {
10141f5207b7SJohn Levon 		state = alloc_estate_rl(rl);
10151f5207b7SJohn Levon 		goto done;
10161f5207b7SJohn Levon 	}
10171f5207b7SJohn Levon 
10181f5207b7SJohn Levon 	if (get_implied_value(right, &sval)) {
10191f5207b7SJohn Levon 		state = alloc_estate_sval(sval_cast(left_type, sval));
10201f5207b7SJohn Levon 		goto done;
10211f5207b7SJohn Levon 	}
10221f5207b7SJohn Levon 
10231f5207b7SJohn Levon 	if (__in_fake_assign) {
10241f5207b7SJohn Levon 		struct smatch_state *right_state;
10251f5207b7SJohn Levon 		sval_t sval;
10261f5207b7SJohn Levon 
10271f5207b7SJohn Levon 		if (get_value(right, &sval)) {
10281f5207b7SJohn Levon 			sval = sval_cast(left_type, sval);
10291f5207b7SJohn Levon 			state = alloc_estate_sval(sval);
10301f5207b7SJohn Levon 			goto done;
10311f5207b7SJohn Levon 		}
10321f5207b7SJohn Levon 
10331f5207b7SJohn Levon 		right_state = get_state(SMATCH_EXTRA, right_name, right_sym);
10341f5207b7SJohn Levon 		if (right_state) {
10351f5207b7SJohn Levon 			/* simple assignment */
10361f5207b7SJohn Levon 			state = clone_estate(right_state);
10371f5207b7SJohn Levon 			goto done;
10381f5207b7SJohn Levon 		}
10391f5207b7SJohn Levon 
10401f5207b7SJohn Levon 		state = alloc_estate_rl(alloc_whole_rl(left_type));
10411f5207b7SJohn Levon 		goto done;
10421f5207b7SJohn Levon 	}
10431f5207b7SJohn Levon 
1044*efe51d0cSJohn Levon 	comparison = get_comparison_no_extra(left, right);
10451f5207b7SJohn Levon 	if (comparison) {
10461f5207b7SJohn Levon 		comparison = flip_comparison(comparison);
10471f5207b7SJohn Levon 		get_implied_rl(left, &orig_rl);
10481f5207b7SJohn Levon 	}
10491f5207b7SJohn Levon 
10501f5207b7SJohn Levon 	if (get_implied_rl(right, &rl)) {
10511f5207b7SJohn Levon 		rl = cast_rl(left_type, rl);
10521f5207b7SJohn Levon 		if (orig_rl)
10531f5207b7SJohn Levon 			filter_by_comparison(&rl, comparison, orig_rl);
10541f5207b7SJohn Levon 		state = alloc_estate_rl(rl);
10551f5207b7SJohn Levon 		if (get_hard_max(right, &max)) {
10561f5207b7SJohn Levon 			estate_set_hard_max(state);
10571f5207b7SJohn Levon 			estate_set_fuzzy_max(state, max);
10581f5207b7SJohn Levon 		}
10591f5207b7SJohn Levon 	} else {
10601f5207b7SJohn Levon 		rl = alloc_whole_rl(right_type);
10611f5207b7SJohn Levon 		rl = cast_rl(left_type, rl);
10621f5207b7SJohn Levon 		if (orig_rl)
10631f5207b7SJohn Levon 			filter_by_comparison(&rl, comparison, orig_rl);
10641f5207b7SJohn Levon 		state = alloc_estate_rl(rl);
10651f5207b7SJohn Levon 	}
10661f5207b7SJohn Levon 
10671f5207b7SJohn Levon done:
10681f5207b7SJohn Levon 	set_extra_mod(name, sym, left, state);
10691f5207b7SJohn Levon free:
10701f5207b7SJohn Levon 	free_string(right_name);
10711f5207b7SJohn Levon }
10721f5207b7SJohn Levon 
10731f5207b7SJohn Levon static void match_assign(struct expression *expr)
10741f5207b7SJohn Levon {
10751f5207b7SJohn Levon 	struct range_list *rl = NULL;
10761f5207b7SJohn Levon 	struct expression *left;
10771f5207b7SJohn Levon 	struct expression *right;
10781f5207b7SJohn Levon 	struct expression *binop_expr;
10791f5207b7SJohn Levon 	struct symbol *left_type;
10801f5207b7SJohn Levon 	struct symbol *sym;
10811f5207b7SJohn Levon 	char *name;
10821f5207b7SJohn Levon 
10831f5207b7SJohn Levon 	left = strip_expr(expr->left);
10841f5207b7SJohn Levon 
10851f5207b7SJohn Levon 	right = strip_parens(expr->right);
10861f5207b7SJohn Levon 	if (right->type == EXPR_CALL && sym_name_is("__builtin_expect", right->fn))
10871f5207b7SJohn Levon 		right = get_argument_from_call_expr(right->args, 0);
10881f5207b7SJohn Levon 	while (right->type == EXPR_ASSIGNMENT && right->op == '=')
10891f5207b7SJohn Levon 		right = strip_parens(right->left);
10901f5207b7SJohn Levon 
10911f5207b7SJohn Levon 	if (expr->op == '=' && is_condition(expr->right))
10921f5207b7SJohn Levon 		return; /* handled in smatch_condition.c */
10931f5207b7SJohn Levon 	if (expr->op == '=' && right->type == EXPR_CALL)
10941f5207b7SJohn Levon 		return; /* handled in smatch_function_hooks.c */
10951f5207b7SJohn Levon 	if (expr->op == '=') {
10961f5207b7SJohn Levon 		match_vanilla_assign(left, right);
10971f5207b7SJohn Levon 		return;
10981f5207b7SJohn Levon 	}
10991f5207b7SJohn Levon 
11001f5207b7SJohn Levon 	name = expr_to_var_sym(left, &sym);
11011f5207b7SJohn Levon 	if (!name)
11021f5207b7SJohn Levon 		return;
11031f5207b7SJohn Levon 
11041f5207b7SJohn Levon 	left_type = get_type(left);
11051f5207b7SJohn Levon 
11061f5207b7SJohn Levon 	switch (expr->op) {
11071f5207b7SJohn Levon 	case SPECIAL_ADD_ASSIGN:
11081f5207b7SJohn Levon 	case SPECIAL_SUB_ASSIGN:
11091f5207b7SJohn Levon 	case SPECIAL_AND_ASSIGN:
11101f5207b7SJohn Levon 	case SPECIAL_MOD_ASSIGN:
11111f5207b7SJohn Levon 	case SPECIAL_SHL_ASSIGN:
11121f5207b7SJohn Levon 	case SPECIAL_SHR_ASSIGN:
11131f5207b7SJohn Levon 	case SPECIAL_OR_ASSIGN:
11141f5207b7SJohn Levon 	case SPECIAL_XOR_ASSIGN:
11151f5207b7SJohn Levon 	case SPECIAL_MUL_ASSIGN:
11161f5207b7SJohn Levon 	case SPECIAL_DIV_ASSIGN:
11171f5207b7SJohn Levon 		binop_expr = binop_expression(expr->left,
11181f5207b7SJohn Levon 					      op_remove_assign(expr->op),
11191f5207b7SJohn Levon 					      expr->right);
1120*efe51d0cSJohn Levon 		get_absolute_rl(binop_expr, &rl);
1121*efe51d0cSJohn Levon 		rl = cast_rl(left_type, rl);
1122*efe51d0cSJohn Levon 		if (inside_loop()) {
1123*efe51d0cSJohn Levon 			if (expr->op == SPECIAL_ADD_ASSIGN)
1124*efe51d0cSJohn Levon 				add_range(&rl, rl_max(rl), sval_type_max(rl_type(rl)));
1125*efe51d0cSJohn Levon 
1126*efe51d0cSJohn Levon 			if (expr->op == SPECIAL_SUB_ASSIGN &&
1127*efe51d0cSJohn Levon 			    !sval_is_negative(rl_min(rl))) {
1128*efe51d0cSJohn Levon 				sval_t zero = { .type = rl_type(rl) };
1129*efe51d0cSJohn Levon 
1130*efe51d0cSJohn Levon 				add_range(&rl, rl_min(rl), zero);
1131*efe51d0cSJohn Levon 			}
11321f5207b7SJohn Levon 		}
1133*efe51d0cSJohn Levon 		set_extra_mod(name, sym, left, alloc_estate_rl(rl));
1134*efe51d0cSJohn Levon 		goto free;
11351f5207b7SJohn Levon 	}
1136*efe51d0cSJohn Levon 	set_extra_mod(name, sym, left, alloc_estate_whole(left_type));
11371f5207b7SJohn Levon free:
11381f5207b7SJohn Levon 	free_string(name);
11391f5207b7SJohn Levon }
11401f5207b7SJohn Levon 
11411f5207b7SJohn Levon static struct smatch_state *increment_state(struct smatch_state *state)
11421f5207b7SJohn Levon {
11431f5207b7SJohn Levon 	sval_t min = estate_min(state);
11441f5207b7SJohn Levon 	sval_t max = estate_max(state);
11451f5207b7SJohn Levon 
11461f5207b7SJohn Levon 	if (!estate_rl(state))
11471f5207b7SJohn Levon 		return NULL;
11481f5207b7SJohn Levon 
11491f5207b7SJohn Levon 	if (inside_loop())
11501f5207b7SJohn Levon 		max = sval_type_max(max.type);
11511f5207b7SJohn Levon 
11521f5207b7SJohn Levon 	if (!sval_is_min(min) && !sval_is_max(min))
11531f5207b7SJohn Levon 		min.value++;
11541f5207b7SJohn Levon 	if (!sval_is_min(max) && !sval_is_max(max))
11551f5207b7SJohn Levon 		max.value++;
11561f5207b7SJohn Levon 	return alloc_estate_range(min, max);
11571f5207b7SJohn Levon }
11581f5207b7SJohn Levon 
11591f5207b7SJohn Levon static struct smatch_state *decrement_state(struct smatch_state *state)
11601f5207b7SJohn Levon {
11611f5207b7SJohn Levon 	sval_t min = estate_min(state);
11621f5207b7SJohn Levon 	sval_t max = estate_max(state);
11631f5207b7SJohn Levon 
11641f5207b7SJohn Levon 	if (!estate_rl(state))
11651f5207b7SJohn Levon 		return NULL;
11661f5207b7SJohn Levon 
11671f5207b7SJohn Levon 	if (inside_loop())
11681f5207b7SJohn Levon 		min = sval_type_min(min.type);
11691f5207b7SJohn Levon 
11701f5207b7SJohn Levon 	if (!sval_is_min(min) && !sval_is_max(min))
11711f5207b7SJohn Levon 		min.value--;
11721f5207b7SJohn Levon 	if (!sval_is_min(max) && !sval_is_max(max))
11731f5207b7SJohn Levon 		max.value--;
11741f5207b7SJohn Levon 	return alloc_estate_range(min, max);
11751f5207b7SJohn Levon }
11761f5207b7SJohn Levon 
11771f5207b7SJohn Levon static void clear_pointed_at_state(struct expression *expr)
11781f5207b7SJohn Levon {
11791f5207b7SJohn Levon 	struct symbol *type;
11801f5207b7SJohn Levon 
11811f5207b7SJohn Levon 	/*
11821f5207b7SJohn Levon          * ALERT: This is sort of a mess.  If it's is a struct assigment like
11831f5207b7SJohn Levon 	 * "foo = bar;", then that's handled by smatch_struct_assignment.c.
11841f5207b7SJohn Levon 	 * the same thing for p++ where "p" is a struct.  Most modifications
11851f5207b7SJohn Levon 	 * are handled by the assignment hook or the db.  Smatch_extra.c doesn't
11861f5207b7SJohn Levon 	 * use smatch_modification.c because we have to get the ordering right
11871f5207b7SJohn Levon 	 * or something.  So if you have p++ where p is a pointer to a standard
11881f5207b7SJohn Levon 	 * c type then we handle that here.  What a mess.
11891f5207b7SJohn Levon 	 */
11901f5207b7SJohn Levon 	expr = strip_expr(expr);
11911f5207b7SJohn Levon 	type = get_type(expr);
11921f5207b7SJohn Levon 	if (!type || type->type != SYM_PTR)
11931f5207b7SJohn Levon 		return;
11941f5207b7SJohn Levon 	type = get_real_base_type(type);
11951f5207b7SJohn Levon 	if (!type || type->type != SYM_BASETYPE)
11961f5207b7SJohn Levon 		return;
11971f5207b7SJohn Levon 	set_extra_expr_nomod(deref_expression(expr), alloc_estate_whole(type));
11981f5207b7SJohn Levon }
11991f5207b7SJohn Levon 
12001f5207b7SJohn Levon static void unop_expr(struct expression *expr)
12011f5207b7SJohn Levon {
12021f5207b7SJohn Levon 	struct smatch_state *state;
12031f5207b7SJohn Levon 
12041f5207b7SJohn Levon 	if (expr->smatch_flags & Handled)
12051f5207b7SJohn Levon 		return;
12061f5207b7SJohn Levon 
12071f5207b7SJohn Levon 	switch (expr->op) {
12081f5207b7SJohn Levon 	case SPECIAL_INCREMENT:
12091f5207b7SJohn Levon 		state = get_state_expr(SMATCH_EXTRA, expr->unop);
12101f5207b7SJohn Levon 		state = increment_state(state);
12111f5207b7SJohn Levon 		if (!state)
12121f5207b7SJohn Levon 			state = alloc_estate_whole(get_type(expr));
12131f5207b7SJohn Levon 		set_extra_expr_mod(expr->unop, state);
12141f5207b7SJohn Levon 		clear_pointed_at_state(expr->unop);
12151f5207b7SJohn Levon 		break;
12161f5207b7SJohn Levon 	case SPECIAL_DECREMENT:
12171f5207b7SJohn Levon 		state = get_state_expr(SMATCH_EXTRA, expr->unop);
12181f5207b7SJohn Levon 		state = decrement_state(state);
12191f5207b7SJohn Levon 		if (!state)
12201f5207b7SJohn Levon 			state = alloc_estate_whole(get_type(expr));
12211f5207b7SJohn Levon 		set_extra_expr_mod(expr->unop, state);
12221f5207b7SJohn Levon 		clear_pointed_at_state(expr->unop);
12231f5207b7SJohn Levon 		break;
12241f5207b7SJohn Levon 	default:
12251f5207b7SJohn Levon 		return;
12261f5207b7SJohn Levon 	}
12271f5207b7SJohn Levon }
12281f5207b7SJohn Levon 
12291f5207b7SJohn Levon static void asm_expr(struct statement *stmt)
12301f5207b7SJohn Levon {
12311f5207b7SJohn Levon 
12321f5207b7SJohn Levon 	struct expression *expr;
12331f5207b7SJohn Levon 	struct symbol *type;
12341f5207b7SJohn Levon 	int state = 0;
12351f5207b7SJohn Levon 
12361f5207b7SJohn Levon 	FOR_EACH_PTR(stmt->asm_outputs, expr) {
12371f5207b7SJohn Levon 		switch (state) {
12381f5207b7SJohn Levon 		case 0: /* identifier */
12391f5207b7SJohn Levon 		case 1: /* constraint */
12401f5207b7SJohn Levon 			state++;
12411f5207b7SJohn Levon 			continue;
12421f5207b7SJohn Levon 		case 2: /* expression */
12431f5207b7SJohn Levon 			state = 0;
12441f5207b7SJohn Levon 			type = get_type(strip_expr(expr));
12451f5207b7SJohn Levon 			set_extra_expr_mod(expr, alloc_estate_whole(type));
12461f5207b7SJohn Levon 			continue;
12471f5207b7SJohn Levon 		}
12481f5207b7SJohn Levon 	} END_FOR_EACH_PTR(expr);
12491f5207b7SJohn Levon }
12501f5207b7SJohn Levon 
12511f5207b7SJohn Levon static void check_dereference(struct expression *expr)
12521f5207b7SJohn Levon {
12531f5207b7SJohn Levon 	struct smatch_state *state;
12541f5207b7SJohn Levon 
12551f5207b7SJohn Levon 	if (__in_fake_assign)
12561f5207b7SJohn Levon 		return;
12571f5207b7SJohn Levon 	if (outside_of_function())
12581f5207b7SJohn Levon 		return;
12591f5207b7SJohn Levon 	state = get_extra_state(expr);
12601f5207b7SJohn Levon 	if (state) {
12611f5207b7SJohn Levon 		struct range_list *rl;
12621f5207b7SJohn Levon 
12631f5207b7SJohn Levon 		rl = rl_intersection(estate_rl(state), valid_ptr_rl);
12641f5207b7SJohn Levon 		if (rl_equiv(rl, estate_rl(state)))
12651f5207b7SJohn Levon 			return;
12661f5207b7SJohn Levon 		set_extra_expr_nomod(expr, alloc_estate_rl(rl));
12671f5207b7SJohn Levon 	} else {
1268*efe51d0cSJohn Levon 		struct range_list *rl;
1269*efe51d0cSJohn Levon 
1270*efe51d0cSJohn Levon 		if (get_mtag_rl(expr, &rl))
1271*efe51d0cSJohn Levon 			rl = rl_intersection(rl, valid_ptr_rl);
1272*efe51d0cSJohn Levon 		else
1273*efe51d0cSJohn Levon 			rl = clone_rl(valid_ptr_rl);
1274*efe51d0cSJohn Levon 
1275*efe51d0cSJohn Levon 		set_extra_expr_nomod(expr, alloc_estate_rl(rl));
12761f5207b7SJohn Levon 	}
12771f5207b7SJohn Levon }
12781f5207b7SJohn Levon 
12791f5207b7SJohn Levon static void match_dereferences(struct expression *expr)
12801f5207b7SJohn Levon {
12811f5207b7SJohn Levon 	if (expr->type != EXPR_PREOP)
12821f5207b7SJohn Levon 		return;
12831f5207b7SJohn Levon 	/* it's saying that foo[1] = bar dereferences foo[1] */
12841f5207b7SJohn Levon 	if (is_array(expr))
12851f5207b7SJohn Levon 		return;
12861f5207b7SJohn Levon 	check_dereference(expr->unop);
12871f5207b7SJohn Levon }
12881f5207b7SJohn Levon 
12891f5207b7SJohn Levon static void match_pointer_as_array(struct expression *expr)
12901f5207b7SJohn Levon {
12911f5207b7SJohn Levon 	if (!is_array(expr))
12921f5207b7SJohn Levon 		return;
12931f5207b7SJohn Levon 	check_dereference(get_array_base(expr));
12941f5207b7SJohn Levon }
12951f5207b7SJohn Levon 
12961f5207b7SJohn Levon static void find_dereferences(struct expression *expr)
12971f5207b7SJohn Levon {
12981f5207b7SJohn Levon 	while (expr->type == EXPR_PREOP) {
12991f5207b7SJohn Levon 		if (expr->op == '*')
13001f5207b7SJohn Levon 			check_dereference(expr->unop);
13011f5207b7SJohn Levon 		expr = strip_expr(expr->unop);
13021f5207b7SJohn Levon 	}
13031f5207b7SJohn Levon }
13041f5207b7SJohn Levon 
13051f5207b7SJohn Levon static void set_param_dereferenced(struct expression *call, struct expression *arg, char *key, char *unused)
13061f5207b7SJohn Levon {
13071f5207b7SJohn Levon 	struct symbol *sym;
13081f5207b7SJohn Levon 	char *name;
13091f5207b7SJohn Levon 
13101f5207b7SJohn Levon 	name = get_variable_from_key(arg, key, &sym);
13111f5207b7SJohn Levon 	if (name && sym) {
13121f5207b7SJohn Levon 		struct smatch_state *orig, *new;
13131f5207b7SJohn Levon 		struct range_list *rl;
13141f5207b7SJohn Levon 
13151f5207b7SJohn Levon 		orig = get_state(SMATCH_EXTRA, name, sym);
13161f5207b7SJohn Levon 		if (orig) {
13171f5207b7SJohn Levon 			rl = rl_intersection(estate_rl(orig),
13181f5207b7SJohn Levon 					     alloc_rl(valid_ptr_min_sval,
13191f5207b7SJohn Levon 						      valid_ptr_max_sval));
13201f5207b7SJohn Levon 			new = alloc_estate_rl(rl);
13211f5207b7SJohn Levon 		} else {
13221f5207b7SJohn Levon 			new = alloc_estate_range(valid_ptr_min_sval, valid_ptr_max_sval);
13231f5207b7SJohn Levon 		}
13241f5207b7SJohn Levon 
13251f5207b7SJohn Levon 		set_extra_nomod(name, sym, NULL, new);
13261f5207b7SJohn Levon 	}
13271f5207b7SJohn Levon 	free_string(name);
13281f5207b7SJohn Levon 
13291f5207b7SJohn Levon 	find_dereferences(arg);
13301f5207b7SJohn Levon }
13311f5207b7SJohn Levon 
13321f5207b7SJohn Levon static sval_t add_one(sval_t sval)
13331f5207b7SJohn Levon {
13341f5207b7SJohn Levon 	sval.value++;
13351f5207b7SJohn Levon 	return sval;
13361f5207b7SJohn Levon }
13371f5207b7SJohn Levon 
13381f5207b7SJohn Levon static int handle_postop_inc(struct expression *left, int op, struct expression *right)
13391f5207b7SJohn Levon {
13401f5207b7SJohn Levon 	struct statement *stmt;
13411f5207b7SJohn Levon 	struct expression *cond;
13421f5207b7SJohn Levon 	struct smatch_state *true_state, *false_state;
1343*efe51d0cSJohn Levon 	struct symbol *type;
13441f5207b7SJohn Levon 	sval_t start;
13451f5207b7SJohn Levon 	sval_t limit;
13461f5207b7SJohn Levon 
13471f5207b7SJohn Levon 	/*
13481f5207b7SJohn Levon 	 * If we're decrementing here then that's a canonical while count down
13491f5207b7SJohn Levon 	 * so it's handled already.  We're only handling loops like:
13501f5207b7SJohn Levon 	 * i = 0;
13511f5207b7SJohn Levon 	 * do { ... } while (i++ < 3);
13521f5207b7SJohn Levon 	 */
13531f5207b7SJohn Levon 
13541f5207b7SJohn Levon 	if (left->type != EXPR_POSTOP || left->op != SPECIAL_INCREMENT)
13551f5207b7SJohn Levon 		return 0;
13561f5207b7SJohn Levon 
13571f5207b7SJohn Levon 	stmt = __cur_stmt->parent;
13581f5207b7SJohn Levon 	if (!stmt)
13591f5207b7SJohn Levon 		return 0;
13601f5207b7SJohn Levon 	if (stmt->type == STMT_COMPOUND)
13611f5207b7SJohn Levon 		stmt = stmt->parent;
13621f5207b7SJohn Levon 	if (!stmt || stmt->type != STMT_ITERATOR || !stmt->iterator_post_condition)
13631f5207b7SJohn Levon 		return 0;
13641f5207b7SJohn Levon 
13651f5207b7SJohn Levon 	cond = strip_expr(stmt->iterator_post_condition);
13661f5207b7SJohn Levon 	if (cond->type != EXPR_COMPARE || cond->op != op)
13671f5207b7SJohn Levon 		return 0;
13681f5207b7SJohn Levon 	if (left != strip_expr(cond->left) || right != strip_expr(cond->right))
13691f5207b7SJohn Levon 		return 0;
13701f5207b7SJohn Levon 
13711f5207b7SJohn Levon 	if (!get_implied_value(left->unop, &start))
13721f5207b7SJohn Levon 		return 0;
13731f5207b7SJohn Levon 	if (!get_implied_value(right, &limit))
13741f5207b7SJohn Levon 		return 0;
1375*efe51d0cSJohn Levon 	type = get_type(left->unop);
1376*efe51d0cSJohn Levon 	limit = sval_cast(type, limit);
13771f5207b7SJohn Levon 	if (sval_cmp(start, limit) > 0)
13781f5207b7SJohn Levon 		return 0;
13791f5207b7SJohn Levon 
13801f5207b7SJohn Levon 	switch (op) {
13811f5207b7SJohn Levon 	case '<':
13821f5207b7SJohn Levon 	case SPECIAL_UNSIGNED_LT:
13831f5207b7SJohn Levon 		break;
13841f5207b7SJohn Levon 	case SPECIAL_LTE:
13851f5207b7SJohn Levon 	case SPECIAL_UNSIGNED_LTE:
13861f5207b7SJohn Levon 		limit = add_one(limit);
13871f5207b7SJohn Levon 	default:
13881f5207b7SJohn Levon 		return 0;
13891f5207b7SJohn Levon 
13901f5207b7SJohn Levon 	}
13911f5207b7SJohn Levon 
13921f5207b7SJohn Levon 	true_state = alloc_estate_range(add_one(start), limit);
13931f5207b7SJohn Levon 	false_state = alloc_estate_range(add_one(limit), add_one(limit));
13941f5207b7SJohn Levon 
13951f5207b7SJohn Levon 	/* Currently we just discard the false state but when two passes is
13961f5207b7SJohn Levon 	 * implimented correctly then it will use it.
13971f5207b7SJohn Levon 	 */
13981f5207b7SJohn Levon 
13991f5207b7SJohn Levon 	set_extra_expr_true_false(left->unop, true_state, false_state);
14001f5207b7SJohn Levon 
14011f5207b7SJohn Levon 	return 1;
14021f5207b7SJohn Levon }
14031f5207b7SJohn Levon 
14041f5207b7SJohn Levon bool is_impossible_variable(struct expression *expr)
14051f5207b7SJohn Levon {
14061f5207b7SJohn Levon 	struct smatch_state *state;
14071f5207b7SJohn Levon 
14081f5207b7SJohn Levon 	state = get_extra_state(expr);
14091f5207b7SJohn Levon 	if (state && !estate_rl(state))
14101f5207b7SJohn Levon 		return true;
14111f5207b7SJohn Levon 	return false;
14121f5207b7SJohn Levon }
14131f5207b7SJohn Levon 
1414*efe51d0cSJohn Levon static bool in_macro(struct expression *left, struct expression *right)
1415*efe51d0cSJohn Levon {
1416*efe51d0cSJohn Levon 	if (!left || !right)
1417*efe51d0cSJohn Levon 		return 0;
1418*efe51d0cSJohn Levon 	if (left->pos.line != right->pos.line || left->pos.pos != right->pos.pos)
1419*efe51d0cSJohn Levon 		return 0;
1420*efe51d0cSJohn Levon 	if (get_macro_name(left->pos))
1421*efe51d0cSJohn Levon 		return 1;
1422*efe51d0cSJohn Levon 	return 0;
1423*efe51d0cSJohn Levon }
1424*efe51d0cSJohn Levon 
14251f5207b7SJohn Levon static void handle_comparison(struct symbol *type, struct expression *left, int op, struct expression *right)
14261f5207b7SJohn Levon {
14271f5207b7SJohn Levon 	struct range_list *left_orig;
14281f5207b7SJohn Levon 	struct range_list *left_true;
14291f5207b7SJohn Levon 	struct range_list *left_false;
14301f5207b7SJohn Levon 	struct range_list *right_orig;
14311f5207b7SJohn Levon 	struct range_list *right_true;
14321f5207b7SJohn Levon 	struct range_list *right_false;
14331f5207b7SJohn Levon 	struct smatch_state *left_true_state;
14341f5207b7SJohn Levon 	struct smatch_state *left_false_state;
14351f5207b7SJohn Levon 	struct smatch_state *right_true_state;
14361f5207b7SJohn Levon 	struct smatch_state *right_false_state;
14371f5207b7SJohn Levon 	sval_t dummy, hard_max;
14381f5207b7SJohn Levon 	int left_postop = 0;
14391f5207b7SJohn Levon 	int right_postop = 0;
14401f5207b7SJohn Levon 
14411f5207b7SJohn Levon 	if (left->op == SPECIAL_INCREMENT || left->op == SPECIAL_DECREMENT) {
14421f5207b7SJohn Levon 		if (left->type == EXPR_POSTOP) {
14431f5207b7SJohn Levon 			left->smatch_flags |= Handled;
14441f5207b7SJohn Levon 			left_postop = left->op;
14451f5207b7SJohn Levon 			if (handle_postop_inc(left, op, right))
14461f5207b7SJohn Levon 				return;
14471f5207b7SJohn Levon 		}
14481f5207b7SJohn Levon 		left = strip_parens(left->unop);
14491f5207b7SJohn Levon 	}
14501f5207b7SJohn Levon 	while (left->type == EXPR_ASSIGNMENT)
14511f5207b7SJohn Levon 		left = strip_parens(left->left);
14521f5207b7SJohn Levon 
14531f5207b7SJohn Levon 	if (right->op == SPECIAL_INCREMENT || right->op == SPECIAL_DECREMENT) {
14541f5207b7SJohn Levon 		if (right->type == EXPR_POSTOP) {
14551f5207b7SJohn Levon 			right->smatch_flags |= Handled;
14561f5207b7SJohn Levon 			right_postop = right->op;
14571f5207b7SJohn Levon 		}
14581f5207b7SJohn Levon 		right = strip_parens(right->unop);
14591f5207b7SJohn Levon 	}
14601f5207b7SJohn Levon 
14611f5207b7SJohn Levon 	if (is_impossible_variable(left) || is_impossible_variable(right))
14621f5207b7SJohn Levon 		return;
14631f5207b7SJohn Levon 
14641f5207b7SJohn Levon 	get_real_absolute_rl(left, &left_orig);
14651f5207b7SJohn Levon 	left_orig = cast_rl(type, left_orig);
14661f5207b7SJohn Levon 
14671f5207b7SJohn Levon 	get_real_absolute_rl(right, &right_orig);
14681f5207b7SJohn Levon 	right_orig = cast_rl(type, right_orig);
14691f5207b7SJohn Levon 
14701f5207b7SJohn Levon 	split_comparison_rl(left_orig, op, right_orig, &left_true, &left_false, &right_true, &right_false);
14711f5207b7SJohn Levon 
14721f5207b7SJohn Levon 	left_true = rl_truncate_cast(get_type(strip_expr(left)), left_true);
14731f5207b7SJohn Levon 	left_false = rl_truncate_cast(get_type(strip_expr(left)), left_false);
14741f5207b7SJohn Levon 	right_true = rl_truncate_cast(get_type(strip_expr(right)), right_true);
14751f5207b7SJohn Levon 	right_false = rl_truncate_cast(get_type(strip_expr(right)), right_false);
14761f5207b7SJohn Levon 
14771f5207b7SJohn Levon 	if (!left_true || !left_false) {
14781f5207b7SJohn Levon 		struct range_list *tmp_true, *tmp_false;
14791f5207b7SJohn Levon 
14801f5207b7SJohn Levon 		split_comparison_rl(alloc_whole_rl(type), op, right_orig, &tmp_true, &tmp_false, NULL, NULL);
14811f5207b7SJohn Levon 		tmp_true = rl_truncate_cast(get_type(strip_expr(left)), tmp_true);
14821f5207b7SJohn Levon 		tmp_false = rl_truncate_cast(get_type(strip_expr(left)), tmp_false);
14831f5207b7SJohn Levon 		if (tmp_true && tmp_false)
14841f5207b7SJohn Levon 			__save_imaginary_state(left, tmp_true, tmp_false);
14851f5207b7SJohn Levon 	}
14861f5207b7SJohn Levon 
14871f5207b7SJohn Levon 	if (!right_true || !right_false) {
14881f5207b7SJohn Levon 		struct range_list *tmp_true, *tmp_false;
14891f5207b7SJohn Levon 
14901f5207b7SJohn Levon 		split_comparison_rl(alloc_whole_rl(type), op, right_orig, NULL, NULL, &tmp_true, &tmp_false);
14911f5207b7SJohn Levon 		tmp_true = rl_truncate_cast(get_type(strip_expr(right)), tmp_true);
14921f5207b7SJohn Levon 		tmp_false = rl_truncate_cast(get_type(strip_expr(right)), tmp_false);
14931f5207b7SJohn Levon 		if (tmp_true && tmp_false)
14941f5207b7SJohn Levon 			__save_imaginary_state(right, tmp_true, tmp_false);
14951f5207b7SJohn Levon 	}
14961f5207b7SJohn Levon 
14971f5207b7SJohn Levon 	left_true_state = alloc_estate_rl(left_true);
14981f5207b7SJohn Levon 	left_false_state = alloc_estate_rl(left_false);
14991f5207b7SJohn Levon 	right_true_state = alloc_estate_rl(right_true);
15001f5207b7SJohn Levon 	right_false_state = alloc_estate_rl(right_false);
15011f5207b7SJohn Levon 
15021f5207b7SJohn Levon 	switch (op) {
15031f5207b7SJohn Levon 	case '<':
15041f5207b7SJohn Levon 	case SPECIAL_UNSIGNED_LT:
15051f5207b7SJohn Levon 	case SPECIAL_UNSIGNED_LTE:
15061f5207b7SJohn Levon 	case SPECIAL_LTE:
1507*efe51d0cSJohn Levon 		if (get_implied_value(right, &dummy) && !in_macro(left, right))
15081f5207b7SJohn Levon 			estate_set_hard_max(left_true_state);
1509*efe51d0cSJohn Levon 		if (get_implied_value(left, &dummy) && !in_macro(left, right))
15101f5207b7SJohn Levon 			estate_set_hard_max(right_false_state);
15111f5207b7SJohn Levon 		break;
15121f5207b7SJohn Levon 	case '>':
15131f5207b7SJohn Levon 	case SPECIAL_UNSIGNED_GT:
15141f5207b7SJohn Levon 	case SPECIAL_UNSIGNED_GTE:
15151f5207b7SJohn Levon 	case SPECIAL_GTE:
1516*efe51d0cSJohn Levon 		if (get_implied_value(left, &dummy) && !in_macro(left, right))
15171f5207b7SJohn Levon 			estate_set_hard_max(right_true_state);
1518*efe51d0cSJohn Levon 		if (get_implied_value(right, &dummy) && !in_macro(left, right))
15191f5207b7SJohn Levon 			estate_set_hard_max(left_false_state);
15201f5207b7SJohn Levon 		break;
15211f5207b7SJohn Levon 	}
15221f5207b7SJohn Levon 
15231f5207b7SJohn Levon 	switch (op) {
15241f5207b7SJohn Levon 	case '<':
15251f5207b7SJohn Levon 	case SPECIAL_UNSIGNED_LT:
15261f5207b7SJohn Levon 	case SPECIAL_UNSIGNED_LTE:
15271f5207b7SJohn Levon 	case SPECIAL_LTE:
15281f5207b7SJohn Levon 		if (get_hard_max(right, &hard_max)) {
15291f5207b7SJohn Levon 			if (op == '<' || op == SPECIAL_UNSIGNED_LT)
15301f5207b7SJohn Levon 				hard_max.value--;
15311f5207b7SJohn Levon 			estate_set_fuzzy_max(left_true_state, hard_max);
15321f5207b7SJohn Levon 		}
15331f5207b7SJohn Levon 		if (get_implied_value(right, &hard_max)) {
15341f5207b7SJohn Levon 			if (op == SPECIAL_UNSIGNED_LTE ||
15351f5207b7SJohn Levon 			    op == SPECIAL_LTE)
15361f5207b7SJohn Levon 				hard_max.value++;
15371f5207b7SJohn Levon 			estate_set_fuzzy_max(left_false_state, hard_max);
15381f5207b7SJohn Levon 		}
15391f5207b7SJohn Levon 		if (get_hard_max(left, &hard_max)) {
15401f5207b7SJohn Levon 			if (op == SPECIAL_UNSIGNED_LTE ||
15411f5207b7SJohn Levon 			    op == SPECIAL_LTE)
15421f5207b7SJohn Levon 				hard_max.value--;
15431f5207b7SJohn Levon 			estate_set_fuzzy_max(right_false_state, hard_max);
15441f5207b7SJohn Levon 		}
15451f5207b7SJohn Levon 		if (get_implied_value(left, &hard_max)) {
15461f5207b7SJohn Levon 			if (op == '<' || op == SPECIAL_UNSIGNED_LT)
15471f5207b7SJohn Levon 				hard_max.value++;
15481f5207b7SJohn Levon 			estate_set_fuzzy_max(right_true_state, hard_max);
15491f5207b7SJohn Levon 		}
15501f5207b7SJohn Levon 		break;
15511f5207b7SJohn Levon 	case '>':
15521f5207b7SJohn Levon 	case SPECIAL_UNSIGNED_GT:
15531f5207b7SJohn Levon 	case SPECIAL_UNSIGNED_GTE:
15541f5207b7SJohn Levon 	case SPECIAL_GTE:
15551f5207b7SJohn Levon 		if (get_hard_max(left, &hard_max)) {
15561f5207b7SJohn Levon 			if (op == '>' || op == SPECIAL_UNSIGNED_GT)
15571f5207b7SJohn Levon 				hard_max.value--;
15581f5207b7SJohn Levon 			estate_set_fuzzy_max(right_true_state, hard_max);
15591f5207b7SJohn Levon 		}
15601f5207b7SJohn Levon 		if (get_implied_value(left, &hard_max)) {
15611f5207b7SJohn Levon 			if (op == SPECIAL_UNSIGNED_GTE ||
15621f5207b7SJohn Levon 			    op == SPECIAL_GTE)
15631f5207b7SJohn Levon 				hard_max.value++;
15641f5207b7SJohn Levon 			estate_set_fuzzy_max(right_false_state, hard_max);
15651f5207b7SJohn Levon 		}
15661f5207b7SJohn Levon 		if (get_hard_max(right, &hard_max)) {
15671f5207b7SJohn Levon 			if (op == SPECIAL_UNSIGNED_LTE ||
15681f5207b7SJohn Levon 			    op == SPECIAL_LTE)
15691f5207b7SJohn Levon 				hard_max.value--;
15701f5207b7SJohn Levon 			estate_set_fuzzy_max(left_false_state, hard_max);
15711f5207b7SJohn Levon 		}
15721f5207b7SJohn Levon 		if (get_implied_value(right, &hard_max)) {
15731f5207b7SJohn Levon 			if (op == '>' ||
15741f5207b7SJohn Levon 			    op == SPECIAL_UNSIGNED_GT)
15751f5207b7SJohn Levon 				hard_max.value++;
15761f5207b7SJohn Levon 			estate_set_fuzzy_max(left_true_state, hard_max);
15771f5207b7SJohn Levon 		}
15781f5207b7SJohn Levon 		break;
15791f5207b7SJohn Levon 	case SPECIAL_EQUAL:
15801f5207b7SJohn Levon 		if (get_hard_max(left, &hard_max))
15811f5207b7SJohn Levon 			estate_set_fuzzy_max(right_true_state, hard_max);
15821f5207b7SJohn Levon 		if (get_hard_max(right, &hard_max))
15831f5207b7SJohn Levon 			estate_set_fuzzy_max(left_true_state, hard_max);
15841f5207b7SJohn Levon 		break;
15851f5207b7SJohn Levon 	}
15861f5207b7SJohn Levon 
15871f5207b7SJohn Levon 	if (get_hard_max(left, &hard_max)) {
15881f5207b7SJohn Levon 		estate_set_hard_max(left_true_state);
15891f5207b7SJohn Levon 		estate_set_hard_max(left_false_state);
15901f5207b7SJohn Levon 	}
15911f5207b7SJohn Levon 	if (get_hard_max(right, &hard_max)) {
15921f5207b7SJohn Levon 		estate_set_hard_max(right_true_state);
15931f5207b7SJohn Levon 		estate_set_hard_max(right_false_state);
15941f5207b7SJohn Levon 	}
15951f5207b7SJohn Levon 
15961f5207b7SJohn Levon 	if (left_postop == SPECIAL_INCREMENT) {
15971f5207b7SJohn Levon 		left_true_state = increment_state(left_true_state);
15981f5207b7SJohn Levon 		left_false_state = increment_state(left_false_state);
15991f5207b7SJohn Levon 	}
16001f5207b7SJohn Levon 	if (left_postop == SPECIAL_DECREMENT) {
16011f5207b7SJohn Levon 		left_true_state = decrement_state(left_true_state);
16021f5207b7SJohn Levon 		left_false_state = decrement_state(left_false_state);
16031f5207b7SJohn Levon 	}
16041f5207b7SJohn Levon 	if (right_postop == SPECIAL_INCREMENT) {
16051f5207b7SJohn Levon 		right_true_state = increment_state(right_true_state);
16061f5207b7SJohn Levon 		right_false_state = increment_state(right_false_state);
16071f5207b7SJohn Levon 	}
16081f5207b7SJohn Levon 	if (right_postop == SPECIAL_DECREMENT) {
16091f5207b7SJohn Levon 		right_true_state = decrement_state(right_true_state);
16101f5207b7SJohn Levon 		right_false_state = decrement_state(right_false_state);
16111f5207b7SJohn Levon 	}
16121f5207b7SJohn Levon 
16131f5207b7SJohn Levon 	if (estate_rl(left_true_state) && estates_equiv(left_true_state, left_false_state)) {
16141f5207b7SJohn Levon 		left_true_state = NULL;
16151f5207b7SJohn Levon 		left_false_state = NULL;
16161f5207b7SJohn Levon 	}
16171f5207b7SJohn Levon 
16181f5207b7SJohn Levon 	if (estate_rl(right_true_state) && estates_equiv(right_true_state, right_false_state)) {
16191f5207b7SJohn Levon 		right_true_state = NULL;
16201f5207b7SJohn Levon 		right_false_state = NULL;
16211f5207b7SJohn Levon 	}
16221f5207b7SJohn Levon 
16231f5207b7SJohn Levon 	/* Don't introduce new states for known true/false conditions */
16241f5207b7SJohn Levon 	if (rl_equiv(left_orig, estate_rl(left_true_state)))
16251f5207b7SJohn Levon 		left_true_state = NULL;
16261f5207b7SJohn Levon 	if (rl_equiv(left_orig, estate_rl(left_false_state)))
16271f5207b7SJohn Levon 		left_false_state = NULL;
16281f5207b7SJohn Levon 	if (rl_equiv(right_orig, estate_rl(right_true_state)))
16291f5207b7SJohn Levon 		right_true_state = NULL;
16301f5207b7SJohn Levon 	if (rl_equiv(right_orig, estate_rl(right_false_state)))
16311f5207b7SJohn Levon 		right_false_state = NULL;
16321f5207b7SJohn Levon 
16331f5207b7SJohn Levon 	set_extra_expr_true_false(left, left_true_state, left_false_state);
16341f5207b7SJohn Levon 	set_extra_expr_true_false(right, right_true_state, right_false_state);
16351f5207b7SJohn Levon }
16361f5207b7SJohn Levon 
16371f5207b7SJohn Levon static int is_simple_math(struct expression *expr)
16381f5207b7SJohn Levon {
16391f5207b7SJohn Levon 	if (!expr)
16401f5207b7SJohn Levon 		return 0;
16411f5207b7SJohn Levon 	if (expr->type != EXPR_BINOP)
16421f5207b7SJohn Levon 		return 0;
16431f5207b7SJohn Levon 	switch (expr->op) {
16441f5207b7SJohn Levon 	case '+':
16451f5207b7SJohn Levon 	case '-':
16461f5207b7SJohn Levon 	case '*':
16471f5207b7SJohn Levon 		return 1;
16481f5207b7SJohn Levon 	}
16491f5207b7SJohn Levon 	return 0;
16501f5207b7SJohn Levon }
16511f5207b7SJohn Levon 
1652*efe51d0cSJohn Levon static int flip_op(int op)
1653*efe51d0cSJohn Levon {
1654*efe51d0cSJohn Levon 	/* We only care about simple math */
1655*efe51d0cSJohn Levon 	switch (op) {
1656*efe51d0cSJohn Levon 	case '+':
1657*efe51d0cSJohn Levon 		return '-';
1658*efe51d0cSJohn Levon 	case '-':
1659*efe51d0cSJohn Levon 		return '+';
1660*efe51d0cSJohn Levon 	case '*':
1661*efe51d0cSJohn Levon 		return '/';
1662*efe51d0cSJohn Levon 	}
1663*efe51d0cSJohn Levon 	return 0;
1664*efe51d0cSJohn Levon }
1665*efe51d0cSJohn Levon 
1666*efe51d0cSJohn Levon static void move_known_to_rl(struct expression **expr_p, struct range_list **rl_p)
1667*efe51d0cSJohn Levon {
1668*efe51d0cSJohn Levon 	struct expression *expr = *expr_p;
1669*efe51d0cSJohn Levon 	struct range_list *rl = *rl_p;
1670*efe51d0cSJohn Levon 	sval_t sval;
1671*efe51d0cSJohn Levon 
1672*efe51d0cSJohn Levon 	if (!is_simple_math(expr))
1673*efe51d0cSJohn Levon 		return;
1674*efe51d0cSJohn Levon 
1675*efe51d0cSJohn Levon 	if (get_implied_value(expr->right, &sval)) {
1676*efe51d0cSJohn Levon 		*expr_p = expr->left;
1677*efe51d0cSJohn Levon 		*rl_p = rl_binop(rl, flip_op(expr->op), alloc_rl(sval, sval));
1678*efe51d0cSJohn Levon 		move_known_to_rl(expr_p, rl_p);
1679*efe51d0cSJohn Levon 		return;
1680*efe51d0cSJohn Levon 	}
1681*efe51d0cSJohn Levon 	if (expr->op == '-')
1682*efe51d0cSJohn Levon 		return;
1683*efe51d0cSJohn Levon 	if (get_implied_value(expr->left, &sval)) {
1684*efe51d0cSJohn Levon 		*expr_p = expr->right;
1685*efe51d0cSJohn Levon 		*rl_p = rl_binop(rl, flip_op(expr->op), alloc_rl(sval, sval));
1686*efe51d0cSJohn Levon 		move_known_to_rl(expr_p, rl_p);
1687*efe51d0cSJohn Levon 		return;
1688*efe51d0cSJohn Levon 	}
1689*efe51d0cSJohn Levon }
1690*efe51d0cSJohn Levon 
16911f5207b7SJohn Levon static void move_known_values(struct expression **left_p, struct expression **right_p)
16921f5207b7SJohn Levon {
16931f5207b7SJohn Levon 	struct expression *left = *left_p;
16941f5207b7SJohn Levon 	struct expression *right = *right_p;
16951f5207b7SJohn Levon 	sval_t sval, dummy;
16961f5207b7SJohn Levon 
16971f5207b7SJohn Levon 	if (get_implied_value(left, &sval)) {
16981f5207b7SJohn Levon 		if (!is_simple_math(right))
16991f5207b7SJohn Levon 			return;
17001f5207b7SJohn Levon 		if (get_implied_value(right, &dummy))
17011f5207b7SJohn Levon 			return;
17021f5207b7SJohn Levon 		if (right->op == '*') {
17031f5207b7SJohn Levon 			sval_t divisor;
17041f5207b7SJohn Levon 
17051f5207b7SJohn Levon 			if (!get_value(right->right, &divisor))
17061f5207b7SJohn Levon 				return;
17071f5207b7SJohn Levon 			if (divisor.value == 0)
17081f5207b7SJohn Levon 				return;
17091f5207b7SJohn Levon 			*left_p = binop_expression(left, invert_op(right->op), right->right);
17101f5207b7SJohn Levon 			*right_p = right->left;
17111f5207b7SJohn Levon 			return;
17121f5207b7SJohn Levon 		}
17131f5207b7SJohn Levon 		if (right->op == '+' && get_value(right->left, &sval)) {
17141f5207b7SJohn Levon 			*left_p = binop_expression(left, invert_op(right->op), right->left);
17151f5207b7SJohn Levon 			*right_p = right->right;
17161f5207b7SJohn Levon 			return;
17171f5207b7SJohn Levon 		}
17181f5207b7SJohn Levon 		if (get_value(right->right, &sval)) {
17191f5207b7SJohn Levon 			*left_p = binop_expression(left, invert_op(right->op), right->right);
17201f5207b7SJohn Levon 			*right_p = right->left;
17211f5207b7SJohn Levon 			return;
17221f5207b7SJohn Levon 		}
17231f5207b7SJohn Levon 		return;
17241f5207b7SJohn Levon 	}
17251f5207b7SJohn Levon 	if (get_implied_value(right, &sval)) {
17261f5207b7SJohn Levon 		if (!is_simple_math(left))
17271f5207b7SJohn Levon 			return;
17281f5207b7SJohn Levon 		if (get_implied_value(left, &dummy))
17291f5207b7SJohn Levon 			return;
17301f5207b7SJohn Levon 		if (left->op == '*') {
17311f5207b7SJohn Levon 			sval_t divisor;
17321f5207b7SJohn Levon 
17331f5207b7SJohn Levon 			if (!get_value(left->right, &divisor))
17341f5207b7SJohn Levon 				return;
17351f5207b7SJohn Levon 			if (divisor.value == 0)
17361f5207b7SJohn Levon 				return;
17371f5207b7SJohn Levon 			*right_p = binop_expression(right, invert_op(left->op), left->right);
17381f5207b7SJohn Levon 			*left_p = left->left;
17391f5207b7SJohn Levon 			return;
17401f5207b7SJohn Levon 		}
17411f5207b7SJohn Levon 		if (left->op == '+' && get_value(left->left, &sval)) {
17421f5207b7SJohn Levon 			*right_p = binop_expression(right, invert_op(left->op), left->left);
17431f5207b7SJohn Levon 			*left_p = left->right;
17441f5207b7SJohn Levon 			return;
17451f5207b7SJohn Levon 		}
17461f5207b7SJohn Levon 
17471f5207b7SJohn Levon 		if (get_value(left->right, &sval)) {
17481f5207b7SJohn Levon 			*right_p = binop_expression(right, invert_op(left->op), left->right);
17491f5207b7SJohn Levon 			*left_p = left->left;
17501f5207b7SJohn Levon 			return;
17511f5207b7SJohn Levon 		}
17521f5207b7SJohn Levon 		return;
17531f5207b7SJohn Levon 	}
17541f5207b7SJohn Levon }
17551f5207b7SJohn Levon 
17561f5207b7SJohn Levon /*
17571f5207b7SJohn Levon  * The reason for do_simple_algebra() is to solve things like:
17581f5207b7SJohn Levon  * if (foo > 66 || foo + bar > 64) {
17591f5207b7SJohn Levon  * "foo" is not really a known variable so it won't be handled by
17601f5207b7SJohn Levon  * move_known_variables() but it's a super common idiom.
17611f5207b7SJohn Levon  *
17621f5207b7SJohn Levon  */
17631f5207b7SJohn Levon static int do_simple_algebra(struct expression **left_p, struct expression **right_p)
17641f5207b7SJohn Levon {
17651f5207b7SJohn Levon 	struct expression *left = *left_p;
17661f5207b7SJohn Levon 	struct expression *right = *right_p;
17671f5207b7SJohn Levon 	struct range_list *rl;
17681f5207b7SJohn Levon 	sval_t tmp;
17691f5207b7SJohn Levon 
17701f5207b7SJohn Levon 	if (left->type != EXPR_BINOP || left->op != '+')
17711f5207b7SJohn Levon 		return 0;
17721f5207b7SJohn Levon 	if (can_integer_overflow(get_type(left), left))
17731f5207b7SJohn Levon 		return 0;
17741f5207b7SJohn Levon 	if (!get_implied_value(right, &tmp))
17751f5207b7SJohn Levon 		return 0;
17761f5207b7SJohn Levon 
17771f5207b7SJohn Levon 	if (!get_implied_value(left->left, &tmp) &&
17781f5207b7SJohn Levon 	    get_implied_rl(left->left, &rl) &&
17791f5207b7SJohn Levon 	    !is_whole_rl(rl)) {
17801f5207b7SJohn Levon 		*right_p = binop_expression(right, '-', left->left);
17811f5207b7SJohn Levon 		*left_p = left->right;
17821f5207b7SJohn Levon 		return 1;
17831f5207b7SJohn Levon 	}
17841f5207b7SJohn Levon 	if (!get_implied_value(left->right, &tmp) &&
17851f5207b7SJohn Levon 	    get_implied_rl(left->right, &rl) &&
17861f5207b7SJohn Levon 	    !is_whole_rl(rl)) {
17871f5207b7SJohn Levon 		*right_p = binop_expression(right, '-', left->right);
17881f5207b7SJohn Levon 		*left_p = left->left;
17891f5207b7SJohn Levon 		return 1;
17901f5207b7SJohn Levon 	}
17911f5207b7SJohn Levon 
17921f5207b7SJohn Levon 	return 0;
17931f5207b7SJohn Levon }
17941f5207b7SJohn Levon 
17951f5207b7SJohn Levon static int match_func_comparison(struct expression *expr)
17961f5207b7SJohn Levon {
17971f5207b7SJohn Levon 	struct expression *left = strip_expr(expr->left);
17981f5207b7SJohn Levon 	struct expression *right = strip_expr(expr->right);
17991f5207b7SJohn Levon 
1800*efe51d0cSJohn Levon 	if (left->type == EXPR_CALL || right->type == EXPR_CALL) {
18011f5207b7SJohn Levon 		function_comparison(left, expr->op, right);
18021f5207b7SJohn Levon 		return 1;
18031f5207b7SJohn Levon 	}
18041f5207b7SJohn Levon 
18051f5207b7SJohn Levon 	return 0;
18061f5207b7SJohn Levon }
18071f5207b7SJohn Levon 
18081f5207b7SJohn Levon /* Handle conditions like "if (foo + bar < foo) {" */
18091f5207b7SJohn Levon static int handle_integer_overflow_test(struct expression *expr)
18101f5207b7SJohn Levon {
18111f5207b7SJohn Levon 	struct expression *left, *right;
18121f5207b7SJohn Levon 	struct symbol *type;
18131f5207b7SJohn Levon 	sval_t left_min, right_min, min, max;
18141f5207b7SJohn Levon 
18151f5207b7SJohn Levon 	if (expr->op != '<' && expr->op != SPECIAL_UNSIGNED_LT)
18161f5207b7SJohn Levon 		return 0;
18171f5207b7SJohn Levon 
18181f5207b7SJohn Levon 	left = strip_parens(expr->left);
18191f5207b7SJohn Levon 	right = strip_parens(expr->right);
18201f5207b7SJohn Levon 
18211f5207b7SJohn Levon 	if (left->op != '+')
18221f5207b7SJohn Levon 		return 0;
18231f5207b7SJohn Levon 
18241f5207b7SJohn Levon 	type = get_type(expr);
18251f5207b7SJohn Levon 	if (!type)
18261f5207b7SJohn Levon 		return 0;
18271f5207b7SJohn Levon 	if (type_positive_bits(type) == 32) {
18281f5207b7SJohn Levon 		max.type = &uint_ctype;
18291f5207b7SJohn Levon 		max.uvalue = (unsigned int)-1;
18301f5207b7SJohn Levon 	} else if (type_positive_bits(type) == 64) {
18311f5207b7SJohn Levon 		max.type = &ulong_ctype;
18321f5207b7SJohn Levon 		max.value = (unsigned long long)-1;
18331f5207b7SJohn Levon 	} else {
18341f5207b7SJohn Levon 		return 0;
18351f5207b7SJohn Levon 	}
18361f5207b7SJohn Levon 
18371f5207b7SJohn Levon 	if (!expr_equiv(left->left, right) && !expr_equiv(left->right, right))
18381f5207b7SJohn Levon 		return 0;
18391f5207b7SJohn Levon 
18401f5207b7SJohn Levon 	get_absolute_min(left->left, &left_min);
18411f5207b7SJohn Levon 	get_absolute_min(left->right, &right_min);
18421f5207b7SJohn Levon 	min = sval_binop(left_min, '+', right_min);
18431f5207b7SJohn Levon 
1844*efe51d0cSJohn Levon 	type = get_type(left);
1845*efe51d0cSJohn Levon 	min = sval_cast(type, min);
1846*efe51d0cSJohn Levon 	max = sval_cast(type, max);
1847*efe51d0cSJohn Levon 
18481f5207b7SJohn Levon 	set_extra_chunk_true_false(left, NULL, alloc_estate_range(min, max));
18491f5207b7SJohn Levon 	return 1;
18501f5207b7SJohn Levon }
18511f5207b7SJohn Levon 
18521f5207b7SJohn Levon static void match_comparison(struct expression *expr)
18531f5207b7SJohn Levon {
18541f5207b7SJohn Levon 	struct expression *left_orig = strip_parens(expr->left);
18551f5207b7SJohn Levon 	struct expression *right_orig = strip_parens(expr->right);
18561f5207b7SJohn Levon 	struct expression *left, *right, *tmp;
18571f5207b7SJohn Levon 	struct expression *prev;
18581f5207b7SJohn Levon 	struct symbol *type;
18591f5207b7SJohn Levon 	int redo, count;
18601f5207b7SJohn Levon 
18611f5207b7SJohn Levon 	if (match_func_comparison(expr))
18621f5207b7SJohn Levon 		return;
18631f5207b7SJohn Levon 
18641f5207b7SJohn Levon 	type = get_type(expr);
18651f5207b7SJohn Levon 	if (!type)
18661f5207b7SJohn Levon 		type = &llong_ctype;
18671f5207b7SJohn Levon 
18681f5207b7SJohn Levon 	if (handle_integer_overflow_test(expr))
18691f5207b7SJohn Levon 		return;
18701f5207b7SJohn Levon 
18711f5207b7SJohn Levon 	left = left_orig;
18721f5207b7SJohn Levon 	right = right_orig;
18731f5207b7SJohn Levon 	move_known_values(&left, &right);
18741f5207b7SJohn Levon 	handle_comparison(type, left, expr->op, right);
18751f5207b7SJohn Levon 
18761f5207b7SJohn Levon 	left = left_orig;
18771f5207b7SJohn Levon 	right = right_orig;
18781f5207b7SJohn Levon 	if (do_simple_algebra(&left, &right))
18791f5207b7SJohn Levon 		handle_comparison(type, left, expr->op, right);
18801f5207b7SJohn Levon 
18811f5207b7SJohn Levon 	prev = get_assigned_expr(left_orig);
18821f5207b7SJohn Levon 	if (is_simple_math(prev) && has_variable(prev, left_orig) == 0) {
18831f5207b7SJohn Levon 		left = prev;
18841f5207b7SJohn Levon 		right = right_orig;
18851f5207b7SJohn Levon 		move_known_values(&left, &right);
18861f5207b7SJohn Levon 		handle_comparison(type, left, expr->op, right);
18871f5207b7SJohn Levon 	}
18881f5207b7SJohn Levon 
18891f5207b7SJohn Levon 	prev = get_assigned_expr(right_orig);
18901f5207b7SJohn Levon 	if (is_simple_math(prev) && has_variable(prev, right_orig) == 0) {
18911f5207b7SJohn Levon 		left = left_orig;
18921f5207b7SJohn Levon 		right = prev;
18931f5207b7SJohn Levon 		move_known_values(&left, &right);
18941f5207b7SJohn Levon 		handle_comparison(type, left, expr->op, right);
18951f5207b7SJohn Levon 	}
18961f5207b7SJohn Levon 
18971f5207b7SJohn Levon 	redo = 0;
18981f5207b7SJohn Levon 	left = left_orig;
18991f5207b7SJohn Levon 	right = right_orig;
19001f5207b7SJohn Levon 	if (get_last_expr_from_expression_stmt(left_orig)) {
19011f5207b7SJohn Levon 		left = get_last_expr_from_expression_stmt(left_orig);
19021f5207b7SJohn Levon 		redo = 1;
19031f5207b7SJohn Levon 	}
19041f5207b7SJohn Levon 	if (get_last_expr_from_expression_stmt(right_orig)) {
19051f5207b7SJohn Levon 		right = get_last_expr_from_expression_stmt(right_orig);
19061f5207b7SJohn Levon 		redo = 1;
19071f5207b7SJohn Levon 	}
19081f5207b7SJohn Levon 
19091f5207b7SJohn Levon 	if (!redo)
19101f5207b7SJohn Levon 		return;
19111f5207b7SJohn Levon 
19121f5207b7SJohn Levon 	count = 0;
19131f5207b7SJohn Levon 	while ((tmp = get_assigned_expr(left))) {
19141f5207b7SJohn Levon 		if (count++ > 3)
19151f5207b7SJohn Levon 			break;
19161f5207b7SJohn Levon 		left = strip_expr(tmp);
19171f5207b7SJohn Levon 	}
19181f5207b7SJohn Levon 	count = 0;
19191f5207b7SJohn Levon 	while ((tmp = get_assigned_expr(right))) {
19201f5207b7SJohn Levon 		if (count++ > 3)
19211f5207b7SJohn Levon 			break;
19221f5207b7SJohn Levon 		right = strip_expr(tmp);
19231f5207b7SJohn Levon 	}
19241f5207b7SJohn Levon 
19251f5207b7SJohn Levon 	handle_comparison(type, left, expr->op, right);
19261f5207b7SJohn Levon }
19271f5207b7SJohn Levon 
19281f5207b7SJohn Levon static sval_t get_high_mask(sval_t known)
19291f5207b7SJohn Levon {
19301f5207b7SJohn Levon 	sval_t ret;
19311f5207b7SJohn Levon 	int i;
19321f5207b7SJohn Levon 
19331f5207b7SJohn Levon 	ret = known;
19341f5207b7SJohn Levon 	ret.value = 0;
19351f5207b7SJohn Levon 
19361f5207b7SJohn Levon 	for (i = type_bits(known.type) - 1; i >= 0; i--) {
19371f5207b7SJohn Levon 		if (known.uvalue & (1ULL << i))
19381f5207b7SJohn Levon 			ret.uvalue |= (1ULL << i);
19391f5207b7SJohn Levon 		else
19401f5207b7SJohn Levon 			return ret;
19411f5207b7SJohn Levon 
19421f5207b7SJohn Levon 	}
19431f5207b7SJohn Levon 	return ret;
19441f5207b7SJohn Levon }
19451f5207b7SJohn Levon 
1946*efe51d0cSJohn Levon static bool handle_bit_test(struct expression *expr)
1947*efe51d0cSJohn Levon {
1948*efe51d0cSJohn Levon 	struct range_list *orig_rl, *rl;
1949*efe51d0cSJohn Levon 	struct expression *shift, *mask, *var;
1950*efe51d0cSJohn Levon 	struct bit_info *bit_info;
1951*efe51d0cSJohn Levon 	sval_t sval;
1952*efe51d0cSJohn Levon 	sval_t high = { .type = &int_ctype };
1953*efe51d0cSJohn Levon 	sval_t low = { .type = &int_ctype };
1954*efe51d0cSJohn Levon 
1955*efe51d0cSJohn Levon 	shift = strip_expr(expr->right);
1956*efe51d0cSJohn Levon 	mask = strip_expr(expr->left);
1957*efe51d0cSJohn Levon 	if (shift->type != EXPR_BINOP || shift->op != SPECIAL_LEFTSHIFT) {
1958*efe51d0cSJohn Levon 		shift = strip_expr(expr->left);
1959*efe51d0cSJohn Levon 		mask = strip_expr(expr->right);
1960*efe51d0cSJohn Levon 		if (shift->type != EXPR_BINOP || shift->op != SPECIAL_LEFTSHIFT)
1961*efe51d0cSJohn Levon 			return false;
1962*efe51d0cSJohn Levon 	}
1963*efe51d0cSJohn Levon 	if (!get_implied_value(shift->left, &sval) || sval.value != 1)
1964*efe51d0cSJohn Levon 		return false;
1965*efe51d0cSJohn Levon 	var = strip_expr(shift->right);
1966*efe51d0cSJohn Levon 
1967*efe51d0cSJohn Levon 	bit_info = get_bit_info(mask);
1968*efe51d0cSJohn Levon 	if (!bit_info)
1969*efe51d0cSJohn Levon 		return false;
1970*efe51d0cSJohn Levon 	if (!bit_info->possible)
1971*efe51d0cSJohn Levon 		return false;
1972*efe51d0cSJohn Levon 
1973*efe51d0cSJohn Levon 	get_absolute_rl(var, &orig_rl);
1974*efe51d0cSJohn Levon 	if (sval_is_negative(rl_min(orig_rl)) ||
1975*efe51d0cSJohn Levon 	    rl_max(orig_rl).uvalue > type_bits(get_type(shift->left)))
1976*efe51d0cSJohn Levon 		return false;
1977*efe51d0cSJohn Levon 
1978*efe51d0cSJohn Levon 	low.value = ffsll(bit_info->possible);
1979*efe51d0cSJohn Levon 	high.value = sm_fls64(bit_info->possible);
1980*efe51d0cSJohn Levon 	rl = alloc_rl(low, high);
1981*efe51d0cSJohn Levon 	rl = cast_rl(get_type(var), rl);
1982*efe51d0cSJohn Levon 	rl = rl_intersection(orig_rl, rl);
1983*efe51d0cSJohn Levon 	if (!rl)
1984*efe51d0cSJohn Levon 		return false;
1985*efe51d0cSJohn Levon 
1986*efe51d0cSJohn Levon 	set_extra_expr_true_false(shift->right, alloc_estate_rl(rl), NULL);
1987*efe51d0cSJohn Levon 
1988*efe51d0cSJohn Levon 	return true;
1989*efe51d0cSJohn Levon }
1990*efe51d0cSJohn Levon 
19911f5207b7SJohn Levon static void handle_AND_op(struct expression *var, sval_t known)
19921f5207b7SJohn Levon {
19931f5207b7SJohn Levon 	struct range_list *orig_rl;
19941f5207b7SJohn Levon 	struct range_list *true_rl = NULL;
19951f5207b7SJohn Levon 	struct range_list *false_rl = NULL;
19961f5207b7SJohn Levon 	int bit;
19971f5207b7SJohn Levon 	sval_t low_mask = known;
19981f5207b7SJohn Levon 	sval_t high_mask;
19991f5207b7SJohn Levon 	sval_t max;
20001f5207b7SJohn Levon 
20011f5207b7SJohn Levon 	get_absolute_rl(var, &orig_rl);
20021f5207b7SJohn Levon 
20031f5207b7SJohn Levon 	if (known.value > 0) {
20041f5207b7SJohn Levon 		bit = ffsll(known.value) - 1;
20051f5207b7SJohn Levon 		low_mask.uvalue = (1ULL << bit) - 1;
20061f5207b7SJohn Levon 		true_rl = remove_range(orig_rl, sval_type_val(known.type, 0), low_mask);
20071f5207b7SJohn Levon 	}
20081f5207b7SJohn Levon 	high_mask = get_high_mask(known);
20091f5207b7SJohn Levon 	if (high_mask.value) {
20101f5207b7SJohn Levon 		bit = ffsll(high_mask.value) - 1;
20111f5207b7SJohn Levon 		low_mask.uvalue = (1ULL << bit) - 1;
20121f5207b7SJohn Levon 
20131f5207b7SJohn Levon 		false_rl = orig_rl;
20141f5207b7SJohn Levon 		if (sval_is_negative(rl_min(orig_rl)))
20151f5207b7SJohn Levon 			false_rl = remove_range(false_rl, sval_type_min(known.type), sval_type_val(known.type, -1));
20161f5207b7SJohn Levon 		false_rl = remove_range(false_rl, low_mask, sval_type_max(known.type));
20171f5207b7SJohn Levon 		if (type_signed(high_mask.type) && type_unsigned(rl_type(false_rl))) {
20181f5207b7SJohn Levon 			false_rl = remove_range(false_rl,
20191f5207b7SJohn Levon 						sval_type_val(rl_type(false_rl), sval_type_max(known.type).uvalue),
20201f5207b7SJohn Levon 					sval_type_val(rl_type(false_rl), -1));
20211f5207b7SJohn Levon 		}
20221f5207b7SJohn Levon 	} else if (known.value == 1 &&
20231f5207b7SJohn Levon 		   get_hard_max(var, &max) &&
20241f5207b7SJohn Levon 		   sval_cmp(max, rl_max(orig_rl)) == 0 &&
20251f5207b7SJohn Levon 		   max.value & 1) {
20261f5207b7SJohn Levon 		false_rl = remove_range(orig_rl, max, max);
20271f5207b7SJohn Levon 	}
20281f5207b7SJohn Levon 	set_extra_expr_true_false(var,
20291f5207b7SJohn Levon 				  true_rl ? alloc_estate_rl(true_rl) : NULL,
20301f5207b7SJohn Levon 				  false_rl ? alloc_estate_rl(false_rl) : NULL);
20311f5207b7SJohn Levon }
20321f5207b7SJohn Levon 
20331f5207b7SJohn Levon static void handle_AND_condition(struct expression *expr)
20341f5207b7SJohn Levon {
20351f5207b7SJohn Levon 	sval_t known;
20361f5207b7SJohn Levon 
2037*efe51d0cSJohn Levon 	if (handle_bit_test(expr))
2038*efe51d0cSJohn Levon 		return;
2039*efe51d0cSJohn Levon 
20401f5207b7SJohn Levon 	if (get_implied_value(expr->left, &known))
20411f5207b7SJohn Levon 		handle_AND_op(expr->right, known);
20421f5207b7SJohn Levon 	else if (get_implied_value(expr->right, &known))
20431f5207b7SJohn Levon 		handle_AND_op(expr->left, known);
20441f5207b7SJohn Levon }
20451f5207b7SJohn Levon 
20461f5207b7SJohn Levon static void handle_MOD_condition(struct expression *expr)
20471f5207b7SJohn Levon {
20481f5207b7SJohn Levon 	struct range_list *orig_rl;
20491f5207b7SJohn Levon 	struct range_list *true_rl;
20501f5207b7SJohn Levon 	struct range_list *false_rl = NULL;
20511f5207b7SJohn Levon 	sval_t right;
2052*efe51d0cSJohn Levon 	sval_t zero = { 0, };
20531f5207b7SJohn Levon 
20541f5207b7SJohn Levon 	if (!get_implied_value(expr->right, &right) || right.value == 0)
20551f5207b7SJohn Levon 		return;
20561f5207b7SJohn Levon 	get_absolute_rl(expr->left, &orig_rl);
20571f5207b7SJohn Levon 
20581f5207b7SJohn Levon 	zero.value = 0;
20591f5207b7SJohn Levon 	zero.type = rl_type(orig_rl);
20601f5207b7SJohn Levon 
20611f5207b7SJohn Levon 	/* We're basically dorking around the min and max here */
20621f5207b7SJohn Levon 	true_rl = remove_range(orig_rl, zero, zero);
20631f5207b7SJohn Levon 	if (!sval_is_max(rl_max(true_rl)) &&
20641f5207b7SJohn Levon 	    !(rl_max(true_rl).value % right.value))
20651f5207b7SJohn Levon 		true_rl = remove_range(true_rl, rl_max(true_rl), rl_max(true_rl));
20661f5207b7SJohn Levon 
20671f5207b7SJohn Levon 	if (rl_equiv(true_rl, orig_rl))
20681f5207b7SJohn Levon 		true_rl = NULL;
20691f5207b7SJohn Levon 
20701f5207b7SJohn Levon 	if (sval_is_positive(rl_min(orig_rl)) &&
20711f5207b7SJohn Levon 	    (rl_max(orig_rl).value - rl_min(orig_rl).value) / right.value < 5) {
20721f5207b7SJohn Levon 		sval_t add;
20731f5207b7SJohn Levon 		int i;
20741f5207b7SJohn Levon 
20751f5207b7SJohn Levon 		add = rl_min(orig_rl);
20761f5207b7SJohn Levon 		add.value += right.value - (add.value % right.value);
20771f5207b7SJohn Levon 		add.value -= right.value;
20781f5207b7SJohn Levon 
20791f5207b7SJohn Levon 		for (i = 0; i < 5; i++) {
20801f5207b7SJohn Levon 			add.value += right.value;
20811f5207b7SJohn Levon 			if (add.value > rl_max(orig_rl).value)
20821f5207b7SJohn Levon 				break;
20831f5207b7SJohn Levon 			add_range(&false_rl, add, add);
20841f5207b7SJohn Levon 		}
20851f5207b7SJohn Levon 	} else {
20861f5207b7SJohn Levon 		if (rl_min(orig_rl).uvalue != 0 &&
20871f5207b7SJohn Levon 		    rl_min(orig_rl).uvalue < right.uvalue) {
20881f5207b7SJohn Levon 			sval_t chop = right;
20891f5207b7SJohn Levon 			chop.value--;
20901f5207b7SJohn Levon 			false_rl = remove_range(orig_rl, zero, chop);
20911f5207b7SJohn Levon 		}
20921f5207b7SJohn Levon 
20931f5207b7SJohn Levon 		if (!sval_is_max(rl_max(orig_rl)) &&
20941f5207b7SJohn Levon 		    (rl_max(orig_rl).value % right.value)) {
20951f5207b7SJohn Levon 			sval_t chop = rl_max(orig_rl);
20961f5207b7SJohn Levon 			chop.value -= chop.value % right.value;
20971f5207b7SJohn Levon 			chop.value++;
20981f5207b7SJohn Levon 			if (!false_rl)
20991f5207b7SJohn Levon 				false_rl = clone_rl(orig_rl);
21001f5207b7SJohn Levon 			false_rl = remove_range(false_rl, chop, rl_max(orig_rl));
21011f5207b7SJohn Levon 		}
21021f5207b7SJohn Levon 	}
21031f5207b7SJohn Levon 
21041f5207b7SJohn Levon 	set_extra_expr_true_false(expr->left,
21051f5207b7SJohn Levon 				  true_rl ? alloc_estate_rl(true_rl) : NULL,
21061f5207b7SJohn Levon 				  false_rl ? alloc_estate_rl(false_rl) : NULL);
21071f5207b7SJohn Levon }
21081f5207b7SJohn Levon 
21091f5207b7SJohn Levon /* this is actually hooked from smatch_implied.c...  it's hacky, yes */
21101f5207b7SJohn Levon void __extra_match_condition(struct expression *expr)
21111f5207b7SJohn Levon {
21121f5207b7SJohn Levon 	expr = strip_expr(expr);
21131f5207b7SJohn Levon 	switch (expr->type) {
21141f5207b7SJohn Levon 	case EXPR_CALL:
21151f5207b7SJohn Levon 		function_comparison(expr, SPECIAL_NOTEQUAL, zero_expr());
21161f5207b7SJohn Levon 		return;
21171f5207b7SJohn Levon 	case EXPR_PREOP:
21181f5207b7SJohn Levon 	case EXPR_SYMBOL:
2119*efe51d0cSJohn Levon 	case EXPR_DEREF:
2120*efe51d0cSJohn Levon 		handle_comparison(get_type(expr), expr, SPECIAL_NOTEQUAL, zero_expr());
21211f5207b7SJohn Levon 		return;
21221f5207b7SJohn Levon 	case EXPR_COMPARE:
21231f5207b7SJohn Levon 		match_comparison(expr);
21241f5207b7SJohn Levon 		return;
21251f5207b7SJohn Levon 	case EXPR_ASSIGNMENT:
21261f5207b7SJohn Levon 		__extra_match_condition(expr->left);
21271f5207b7SJohn Levon 		return;
21281f5207b7SJohn Levon 	case EXPR_BINOP:
21291f5207b7SJohn Levon 		if (expr->op == '&')
21301f5207b7SJohn Levon 			handle_AND_condition(expr);
21311f5207b7SJohn Levon 		if (expr->op == '%')
21321f5207b7SJohn Levon 			handle_MOD_condition(expr);
21331f5207b7SJohn Levon 		return;
21341f5207b7SJohn Levon 	}
21351f5207b7SJohn Levon }
21361f5207b7SJohn Levon 
21371f5207b7SJohn Levon static void assume_indexes_are_valid(struct expression *expr)
21381f5207b7SJohn Levon {
21391f5207b7SJohn Levon 	struct expression *array_expr;
21401f5207b7SJohn Levon 	int array_size;
21411f5207b7SJohn Levon 	struct expression *offset;
21421f5207b7SJohn Levon 	struct symbol *offset_type;
21431f5207b7SJohn Levon 	struct range_list *rl_before;
21441f5207b7SJohn Levon 	struct range_list *rl_after;
21451f5207b7SJohn Levon 	struct range_list *filter = NULL;
21461f5207b7SJohn Levon 	sval_t size;
21471f5207b7SJohn Levon 
21481f5207b7SJohn Levon 	expr = strip_expr(expr);
21491f5207b7SJohn Levon 	if (!is_array(expr))
21501f5207b7SJohn Levon 		return;
21511f5207b7SJohn Levon 
21521f5207b7SJohn Levon 	offset = get_array_offset(expr);
21531f5207b7SJohn Levon 	offset_type = get_type(offset);
21541f5207b7SJohn Levon 	if (offset_type && type_signed(offset_type)) {
21551f5207b7SJohn Levon 		filter = alloc_rl(sval_type_min(offset_type),
21561f5207b7SJohn Levon 				  sval_type_val(offset_type, -1));
21571f5207b7SJohn Levon 	}
21581f5207b7SJohn Levon 
21591f5207b7SJohn Levon 	array_expr = get_array_base(expr);
21601f5207b7SJohn Levon 	array_size = get_real_array_size(array_expr);
21611f5207b7SJohn Levon 	if (array_size > 1) {
21621f5207b7SJohn Levon 		size = sval_type_val(offset_type, array_size);
21631f5207b7SJohn Levon 		add_range(&filter, size, sval_type_max(offset_type));
21641f5207b7SJohn Levon 	}
21651f5207b7SJohn Levon 
21661f5207b7SJohn Levon 	if (!filter)
21671f5207b7SJohn Levon 		return;
21681f5207b7SJohn Levon 	get_absolute_rl(offset, &rl_before);
21691f5207b7SJohn Levon 	rl_after = rl_filter(rl_before, filter);
21701f5207b7SJohn Levon 	if (rl_equiv(rl_before, rl_after))
21711f5207b7SJohn Levon 		return;
21721f5207b7SJohn Levon 	set_extra_expr_nomod(offset, alloc_estate_rl(rl_after));
21731f5207b7SJohn Levon }
21741f5207b7SJohn Levon 
21751f5207b7SJohn Levon /* returns 1 if it is not possible for expr to be value, otherwise returns 0 */
21761f5207b7SJohn Levon int implied_not_equal(struct expression *expr, long long val)
21771f5207b7SJohn Levon {
21781f5207b7SJohn Levon 	return !possibly_false(expr, SPECIAL_NOTEQUAL, value_expr(val));
21791f5207b7SJohn Levon }
21801f5207b7SJohn Levon 
21811f5207b7SJohn Levon int implied_not_equal_name_sym(char *name, struct symbol *sym, long long val)
21821f5207b7SJohn Levon {
21831f5207b7SJohn Levon 	struct smatch_state *estate;
21841f5207b7SJohn Levon 
21851f5207b7SJohn Levon 	estate = get_state(SMATCH_EXTRA, name, sym);
21861f5207b7SJohn Levon 	if (!estate)
21871f5207b7SJohn Levon 		return 0;
21881f5207b7SJohn Levon 	if (!rl_has_sval(estate_rl(estate), sval_type_val(estate_type(estate), 0)))
21891f5207b7SJohn Levon 		return 1;
21901f5207b7SJohn Levon 	return 0;
21911f5207b7SJohn Levon }
21921f5207b7SJohn Levon 
21931f5207b7SJohn Levon int parent_is_null_var_sym(const char *name, struct symbol *sym)
21941f5207b7SJohn Levon {
21951f5207b7SJohn Levon 	char buf[256];
21961f5207b7SJohn Levon 	char *start;
21971f5207b7SJohn Levon 	char *end;
21981f5207b7SJohn Levon 	struct smatch_state *state;
21991f5207b7SJohn Levon 
22001f5207b7SJohn Levon 	strncpy(buf, name, sizeof(buf) - 1);
22011f5207b7SJohn Levon 	buf[sizeof(buf) - 1] = '\0';
22021f5207b7SJohn Levon 
22031f5207b7SJohn Levon 	start = &buf[0];
22041f5207b7SJohn Levon 	while (*start == '*') {
22051f5207b7SJohn Levon 		start++;
22061f5207b7SJohn Levon 		state = get_state(SMATCH_EXTRA, start, sym);
22071f5207b7SJohn Levon 		if (!state)
22081f5207b7SJohn Levon 			continue;
22091f5207b7SJohn Levon 		if (!estate_rl(state))
22101f5207b7SJohn Levon 			return 1;
22111f5207b7SJohn Levon 		if (estate_min(state).value == 0 &&
22121f5207b7SJohn Levon 		    estate_max(state).value == 0)
22131f5207b7SJohn Levon 			return 1;
22141f5207b7SJohn Levon 	}
22151f5207b7SJohn Levon 
22161f5207b7SJohn Levon 	start = &buf[0];
22171f5207b7SJohn Levon 	while (*start == '&')
22181f5207b7SJohn Levon 		start++;
22191f5207b7SJohn Levon 
22201f5207b7SJohn Levon 	while ((end = strrchr(start, '-'))) {
22211f5207b7SJohn Levon 		*end = '\0';
22221f5207b7SJohn Levon 		state = __get_state(SMATCH_EXTRA, start, sym);
22231f5207b7SJohn Levon 		if (!state)
22241f5207b7SJohn Levon 			continue;
22251f5207b7SJohn Levon 		if (estate_min(state).value == 0 &&
22261f5207b7SJohn Levon 		    estate_max(state).value == 0)
22271f5207b7SJohn Levon 			return 1;
22281f5207b7SJohn Levon 	}
22291f5207b7SJohn Levon 	return 0;
22301f5207b7SJohn Levon }
22311f5207b7SJohn Levon 
22321f5207b7SJohn Levon int parent_is_null(struct expression *expr)
22331f5207b7SJohn Levon {
22341f5207b7SJohn Levon 	struct symbol *sym;
22351f5207b7SJohn Levon 	char *var;
22361f5207b7SJohn Levon 	int ret = 0;
22371f5207b7SJohn Levon 
22381f5207b7SJohn Levon 	expr = strip_expr(expr);
22391f5207b7SJohn Levon 	var = expr_to_var_sym(expr, &sym);
22401f5207b7SJohn Levon 	if (!var || !sym)
22411f5207b7SJohn Levon 		goto free;
22421f5207b7SJohn Levon 	ret = parent_is_null_var_sym(var, sym);
22431f5207b7SJohn Levon free:
22441f5207b7SJohn Levon 	free_string(var);
22451f5207b7SJohn Levon 	return ret;
22461f5207b7SJohn Levon }
22471f5207b7SJohn Levon 
22481f5207b7SJohn Levon static int param_used_callback(void *found, int argc, char **argv, char **azColName)
22491f5207b7SJohn Levon {
22501f5207b7SJohn Levon 	*(int *)found = 1;
22511f5207b7SJohn Levon 	return 0;
22521f5207b7SJohn Levon }
22531f5207b7SJohn Levon 
2254*efe51d0cSJohn Levon static int is_kzalloc_info(struct sm_state *sm)
22551f5207b7SJohn Levon {
22561f5207b7SJohn Levon 	sval_t sval;
2257*efe51d0cSJohn Levon 
2258*efe51d0cSJohn Levon 	/*
2259*efe51d0cSJohn Levon 	 * kzalloc() information is treated as special because so there is just
2260*efe51d0cSJohn Levon 	 * a lot of stuff initialized to zero and it makes building the database
2261*efe51d0cSJohn Levon 	 * take hours and hours.
2262*efe51d0cSJohn Levon 	 *
2263*efe51d0cSJohn Levon 	 * In theory, we should just remove this line and not pass any unused
2264*efe51d0cSJohn Levon 	 * information, but I'm not sure enough that this code works so I want
2265*efe51d0cSJohn Levon 	 * to hold off on that for now.
2266*efe51d0cSJohn Levon 	 */
2267*efe51d0cSJohn Levon 	if (!estate_get_single_value(sm->state, &sval))
2268*efe51d0cSJohn Levon 		return 0;
2269*efe51d0cSJohn Levon 	if (sval.value != 0)
2270*efe51d0cSJohn Levon 		return 0;
2271*efe51d0cSJohn Levon 	return 1;
2272*efe51d0cSJohn Levon }
2273*efe51d0cSJohn Levon 
2274*efe51d0cSJohn Levon static int is_really_long(struct sm_state *sm)
2275*efe51d0cSJohn Levon {
2276*efe51d0cSJohn Levon 	const char *p;
2277*efe51d0cSJohn Levon 	int cnt = 0;
2278*efe51d0cSJohn Levon 
2279*efe51d0cSJohn Levon 	p = sm->name;
2280*efe51d0cSJohn Levon 	while ((p = strstr(p, "->"))) {
2281*efe51d0cSJohn Levon 		p += 2;
2282*efe51d0cSJohn Levon 		cnt++;
2283*efe51d0cSJohn Levon 	}
2284*efe51d0cSJohn Levon 
2285*efe51d0cSJohn Levon 	if (cnt < 3 ||
2286*efe51d0cSJohn Levon 	    strlen(sm->name) < 40)
2287*efe51d0cSJohn Levon 		return 0;
2288*efe51d0cSJohn Levon 	return 1;
2289*efe51d0cSJohn Levon }
2290*efe51d0cSJohn Levon 
2291*efe51d0cSJohn Levon static int filter_unused_param_value_info(struct expression *call, int param, char *printed_name, struct sm_state *sm)
2292*efe51d0cSJohn Levon {
22931f5207b7SJohn Levon 	int found = 0;
22941f5207b7SJohn Levon 
22951f5207b7SJohn Levon 	/* for function pointers assume everything is used */
22961f5207b7SJohn Levon 	if (call->fn->type != EXPR_SYMBOL)
22971f5207b7SJohn Levon 		return 0;
22981f5207b7SJohn Levon 
22991f5207b7SJohn Levon 	/*
23001f5207b7SJohn Levon 	 * This is to handle __builtin_mul_overflow().  In an ideal world we
23011f5207b7SJohn Levon 	 * would only need this for invalid code.
23021f5207b7SJohn Levon 	 *
23031f5207b7SJohn Levon 	 */
23041f5207b7SJohn Levon 	if (!call->fn->symbol)
23051f5207b7SJohn Levon 		return 0;
23061f5207b7SJohn Levon 
2307*efe51d0cSJohn Levon 	if (!is_kzalloc_info(sm) && !is_really_long(sm))
23081f5207b7SJohn Levon 		return 0;
23091f5207b7SJohn Levon 
23101f5207b7SJohn Levon 	run_sql(&param_used_callback, &found,
23111f5207b7SJohn Levon 		"select * from return_implies where %s and type = %d and parameter = %d and key = '%s';",
23121f5207b7SJohn Levon 		get_static_filter(call->fn->symbol), PARAM_USED, param, printed_name);
23131f5207b7SJohn Levon 	if (found)
23141f5207b7SJohn Levon 		return 0;
23151f5207b7SJohn Levon 
23161f5207b7SJohn Levon 	/* If the database is not built yet, then assume everything is used */
23171f5207b7SJohn Levon 	run_sql(&param_used_callback, &found,
23181f5207b7SJohn Levon 		"select * from return_implies where %s and type = %d;",
23191f5207b7SJohn Levon 		get_static_filter(call->fn->symbol), PARAM_USED);
23201f5207b7SJohn Levon 	if (!found)
23211f5207b7SJohn Levon 		return 0;
23221f5207b7SJohn Levon 
23231f5207b7SJohn Levon 	return 1;
23241f5207b7SJohn Levon }
23251f5207b7SJohn Levon 
23261f5207b7SJohn Levon struct range_list *intersect_with_real_abs_var_sym(const char *name, struct symbol *sym, struct range_list *start)
23271f5207b7SJohn Levon {
23281f5207b7SJohn Levon 	struct smatch_state *state;
23291f5207b7SJohn Levon 
23301f5207b7SJohn Levon 	/*
23311f5207b7SJohn Levon 	 * Here is the difference between implied value and real absolute, say
23321f5207b7SJohn Levon 	 * you have:
23331f5207b7SJohn Levon 	 *
23341f5207b7SJohn Levon 	 *	int a = (u8)x;
23351f5207b7SJohn Levon 	 *
23361f5207b7SJohn Levon 	 * Then you know that a is 0-255.  That's real absolute.  But you don't
23371f5207b7SJohn Levon 	 * know for sure that it actually goes up to 255.  So it's not implied.
23381f5207b7SJohn Levon 	 * Implied indicates a degree of certainty.
23391f5207b7SJohn Levon 	 *
23401f5207b7SJohn Levon 	 * But then say you cap "a" at 8.  That means you know it goes up to
23411f5207b7SJohn Levon 	 * 8.  So now the implied value is s32min-8.  But you can combine it
23421f5207b7SJohn Levon 	 * with the real absolute to say that actually it's 0-8.
23431f5207b7SJohn Levon 	 *
23441f5207b7SJohn Levon 	 * We are combining it here.  But now that I think about it, this is
23451f5207b7SJohn Levon 	 * probably not the ideal place to combine it because it should proably
23461f5207b7SJohn Levon 	 * be done earlier.  Oh well, this is an improvement on what was there
23471f5207b7SJohn Levon 	 * before so I'm going to commit this code.
23481f5207b7SJohn Levon 	 *
23491f5207b7SJohn Levon 	 */
23501f5207b7SJohn Levon 
23511f5207b7SJohn Levon 	state = get_real_absolute_state_var_sym(name, sym);
23521f5207b7SJohn Levon 	if (!state || !estate_rl(state))
23531f5207b7SJohn Levon 		return start;
23541f5207b7SJohn Levon 
23551f5207b7SJohn Levon 	return rl_intersection(estate_rl(state), start);
23561f5207b7SJohn Levon }
23571f5207b7SJohn Levon 
23581f5207b7SJohn Levon struct range_list *intersect_with_real_abs_expr(struct expression *expr, struct range_list *start)
23591f5207b7SJohn Levon {
23601f5207b7SJohn Levon 	struct smatch_state *state;
23611f5207b7SJohn Levon 	struct range_list *abs_rl;
23621f5207b7SJohn Levon 
23631f5207b7SJohn Levon 	state = get_real_absolute_state(expr);
23641f5207b7SJohn Levon 	if (!state || !estate_rl(state))
23651f5207b7SJohn Levon 		return start;
23661f5207b7SJohn Levon 
23671f5207b7SJohn Levon 	abs_rl = cast_rl(rl_type(start), estate_rl(state));
23681f5207b7SJohn Levon 	return rl_intersection(abs_rl, start);
23691f5207b7SJohn Levon }
23701f5207b7SJohn Levon 
23711f5207b7SJohn Levon static void struct_member_callback(struct expression *call, int param, char *printed_name, struct sm_state *sm)
23721f5207b7SJohn Levon {
23731f5207b7SJohn Levon 	struct range_list *rl;
2374*efe51d0cSJohn Levon 	sval_t dummy;
23751f5207b7SJohn Levon 
23761f5207b7SJohn Levon 	if (estate_is_whole(sm->state))
23771f5207b7SJohn Levon 		return;
2378*efe51d0cSJohn Levon 	if (filter_unused_param_value_info(call, param, printed_name, sm))
23791f5207b7SJohn Levon 		return;
23801f5207b7SJohn Levon 	rl = estate_rl(sm->state);
23811f5207b7SJohn Levon 	rl = intersect_with_real_abs_var_sym(sm->name, sm->sym, rl);
23821f5207b7SJohn Levon 	sql_insert_caller_info(call, PARAM_VALUE, param, printed_name, show_rl(rl));
2383*efe51d0cSJohn Levon 	if (!estate_get_single_value(sm->state, &dummy)) {
2384*efe51d0cSJohn Levon 		if (estate_has_hard_max(sm->state))
2385*efe51d0cSJohn Levon 			sql_insert_caller_info(call, HARD_MAX, param, printed_name,
2386*efe51d0cSJohn Levon 					       sval_to_str(estate_max(sm->state)));
2387*efe51d0cSJohn Levon 		if (estate_has_fuzzy_max(sm->state))
2388*efe51d0cSJohn Levon 			sql_insert_caller_info(call, FUZZY_MAX, param, printed_name,
2389*efe51d0cSJohn Levon 					       sval_to_str(estate_get_fuzzy_max(sm->state)));
2390*efe51d0cSJohn Levon 	}
23911f5207b7SJohn Levon }
23921f5207b7SJohn Levon 
23931f5207b7SJohn Levon static void returned_struct_members(int return_id, char *return_ranges, struct expression *expr)
23941f5207b7SJohn Levon {
23951f5207b7SJohn Levon 	struct symbol *returned_sym;
2396*efe51d0cSJohn Levon 	char *returned_name;
23971f5207b7SJohn Levon 	struct sm_state *sm;
23981f5207b7SJohn Levon 	char *compare_str;
2399*efe51d0cSJohn Levon 	char name_buf[256];
2400*efe51d0cSJohn Levon 	char val_buf[256];
2401*efe51d0cSJohn Levon 	int len;
24021f5207b7SJohn Levon 
2403*efe51d0cSJohn Levon 	// FIXME handle *$
2404*efe51d0cSJohn Levon 
2405*efe51d0cSJohn Levon 	if (!is_pointer(expr))
24061f5207b7SJohn Levon 		return;
24071f5207b7SJohn Levon 
2408*efe51d0cSJohn Levon 	returned_name = expr_to_var_sym(expr, &returned_sym);
2409*efe51d0cSJohn Levon 	if (!returned_name || !returned_sym)
2410*efe51d0cSJohn Levon 		goto free;
2411*efe51d0cSJohn Levon 	len = strlen(returned_name);
2412*efe51d0cSJohn Levon 
24131f5207b7SJohn Levon 	FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
24141f5207b7SJohn Levon 		if (!estate_rl(sm->state))
24151f5207b7SJohn Levon 			continue;
24161f5207b7SJohn Levon 		if (returned_sym != sm->sym)
24171f5207b7SJohn Levon 			continue;
2418*efe51d0cSJohn Levon 		if (strncmp(returned_name, sm->name, len) != 0)
24191f5207b7SJohn Levon 			continue;
2420*efe51d0cSJohn Levon 		if (sm->name[len] != '-')
24211f5207b7SJohn Levon 			continue;
2422*efe51d0cSJohn Levon 
2423*efe51d0cSJohn Levon 		snprintf(name_buf, sizeof(name_buf), "$%s", sm->name + len);
2424*efe51d0cSJohn Levon 
24251f5207b7SJohn Levon 		compare_str = name_sym_to_param_comparison(sm->name, sm->sym);
24261f5207b7SJohn Levon 		if (!compare_str && estate_is_whole(sm->state))
24271f5207b7SJohn Levon 			continue;
2428*efe51d0cSJohn Levon 		snprintf(val_buf, sizeof(val_buf), "%s%s", sm->state->name, compare_str ?: "");
24291f5207b7SJohn Levon 
24301f5207b7SJohn Levon 		sql_insert_return_states(return_id, return_ranges, PARAM_VALUE,
2431*efe51d0cSJohn Levon 					 -1, name_buf, val_buf);
24321f5207b7SJohn Levon 	} END_FOR_EACH_SM(sm);
2433*efe51d0cSJohn Levon 
2434*efe51d0cSJohn Levon free:
2435*efe51d0cSJohn Levon 	free_string(returned_name);
24361f5207b7SJohn Levon }
24371f5207b7SJohn Levon 
24381f5207b7SJohn Levon static void db_limited_before(void)
24391f5207b7SJohn Levon {
24401f5207b7SJohn Levon 	unmatched_stree = clone_stree(__get_cur_stree());
24411f5207b7SJohn Levon }
24421f5207b7SJohn Levon 
24431f5207b7SJohn Levon static void db_limited_after(void)
24441f5207b7SJohn Levon {
24451f5207b7SJohn Levon 	free_stree(&unmatched_stree);
24461f5207b7SJohn Levon }
24471f5207b7SJohn Levon 
24481f5207b7SJohn Levon static int basically_the_same(struct range_list *orig, struct range_list *new)
24491f5207b7SJohn Levon {
24501f5207b7SJohn Levon 	if (rl_equiv(orig, new))
24511f5207b7SJohn Levon 		return 1;
24521f5207b7SJohn Levon 
24531f5207b7SJohn Levon 	/*
24541f5207b7SJohn Levon 	 * The whole range is essentially the same as 0,4096-27777777777 so
24551f5207b7SJohn Levon 	 * don't overwrite the implications just to store that.
24561f5207b7SJohn Levon 	 *
24571f5207b7SJohn Levon 	 */
24581f5207b7SJohn Levon 	if (rl_type(orig)->type == SYM_PTR &&
24591f5207b7SJohn Levon 	    is_whole_rl(orig) &&
24601f5207b7SJohn Levon 	    rl_min(new).value == 0 &&
24611f5207b7SJohn Levon 	    rl_max(new).value == valid_ptr_max)
24621f5207b7SJohn Levon 		return 1;
24631f5207b7SJohn Levon 	return 0;
24641f5207b7SJohn Levon }
24651f5207b7SJohn Levon 
24661f5207b7SJohn Levon static void db_param_limit_binops(struct expression *arg, char *key, struct range_list *rl)
24671f5207b7SJohn Levon {
24681f5207b7SJohn Levon 	struct range_list *left_rl;
24691f5207b7SJohn Levon 	sval_t zero = {	.type = rl_type(rl), };
24701f5207b7SJohn Levon 	sval_t sval;
24711f5207b7SJohn Levon 
24721f5207b7SJohn Levon 	if (arg->op != '*')
24731f5207b7SJohn Levon 		return;
24741f5207b7SJohn Levon 	if (!get_implied_value(arg->right, &sval))
24751f5207b7SJohn Levon 		return;
24761f5207b7SJohn Levon 	if (can_integer_overflow(get_type(arg), arg))
24771f5207b7SJohn Levon 		return;
24781f5207b7SJohn Levon 
24791f5207b7SJohn Levon 	left_rl = rl_binop(rl, '/', alloc_rl(sval, sval));
24801f5207b7SJohn Levon 	if (!rl_has_sval(rl, zero))
24811f5207b7SJohn Levon 		left_rl = remove_range(left_rl, zero, zero);
24821f5207b7SJohn Levon 
24831f5207b7SJohn Levon 	set_extra_expr_nomod(arg->left, alloc_estate_rl(left_rl));
24841f5207b7SJohn Levon }
24851f5207b7SJohn Levon 
24861f5207b7SJohn Levon static void db_param_limit_filter(struct expression *expr, int param, char *key, char *value, enum info_type op)
24871f5207b7SJohn Levon {
24881f5207b7SJohn Levon 	struct expression *arg;
24891f5207b7SJohn Levon 	char *name;
24901f5207b7SJohn Levon 	struct symbol *sym;
24911f5207b7SJohn Levon 	struct var_sym_list *vsl = NULL;
24921f5207b7SJohn Levon 	struct sm_state *sm;
24931f5207b7SJohn Levon 	struct symbol *compare_type, *var_type;
24941f5207b7SJohn Levon 	struct range_list *rl;
24951f5207b7SJohn Levon 	struct range_list *limit;
24961f5207b7SJohn Levon 	struct range_list *new;
2497*efe51d0cSJohn Levon 	char *other_name;
2498*efe51d0cSJohn Levon 	struct symbol *other_sym;
24991f5207b7SJohn Levon 
25001f5207b7SJohn Levon 	while (expr->type == EXPR_ASSIGNMENT)
25011f5207b7SJohn Levon 		expr = strip_expr(expr->right);
25021f5207b7SJohn Levon 	if (expr->type != EXPR_CALL)
25031f5207b7SJohn Levon 		return;
25041f5207b7SJohn Levon 
25051f5207b7SJohn Levon 	arg = get_argument_from_call_expr(expr->args, param);
25061f5207b7SJohn Levon 	if (!arg)
25071f5207b7SJohn Levon 		return;
25081f5207b7SJohn Levon 
2509*efe51d0cSJohn Levon 	if (strcmp(key, "$") == 0)
2510*efe51d0cSJohn Levon 		compare_type = get_arg_type(expr->fn, param);
2511*efe51d0cSJohn Levon 	else
2512*efe51d0cSJohn Levon 		compare_type = get_member_type_from_key(arg, key);
2513*efe51d0cSJohn Levon 
2514*efe51d0cSJohn Levon 	call_results_to_rl(expr, compare_type, value, &limit);
2515*efe51d0cSJohn Levon 	if (strcmp(key, "$") == 0)
2516*efe51d0cSJohn Levon 		move_known_to_rl(&arg, &limit);
25171f5207b7SJohn Levon 	name = get_chunk_from_key(arg, key, &sym, &vsl);
25181f5207b7SJohn Levon 	if (!name)
25191f5207b7SJohn Levon 		return;
25201f5207b7SJohn Levon 	if (op != PARAM_LIMIT && !sym)
25211f5207b7SJohn Levon 		goto free;
25221f5207b7SJohn Levon 
25231f5207b7SJohn Levon 	sm = get_sm_state(SMATCH_EXTRA, name, sym);
25241f5207b7SJohn Levon 	if (sm)
25251f5207b7SJohn Levon 		rl = estate_rl(sm->state);
25261f5207b7SJohn Levon 	else
25271f5207b7SJohn Levon 		rl = alloc_whole_rl(compare_type);
25281f5207b7SJohn Levon 
25291f5207b7SJohn Levon 	if (op == PARAM_LIMIT && !rl_fits_in_type(rl, compare_type))
25301f5207b7SJohn Levon 		goto free;
25311f5207b7SJohn Levon 
25321f5207b7SJohn Levon 	new = rl_intersection(rl, limit);
25331f5207b7SJohn Levon 
25341f5207b7SJohn Levon 	var_type = get_member_type_from_key(arg, key);
25351f5207b7SJohn Levon 	new = cast_rl(var_type, new);
25361f5207b7SJohn Levon 
25371f5207b7SJohn Levon 	/* We want to preserve the implications here */
2538*efe51d0cSJohn Levon 	if (sm && basically_the_same(rl, new))
25391f5207b7SJohn Levon 		goto free;
2540*efe51d0cSJohn Levon 	other_name = get_other_name_sym(name, sym, &other_sym);
25411f5207b7SJohn Levon 
25421f5207b7SJohn Levon 	if (op == PARAM_LIMIT)
25431f5207b7SJohn Levon 		set_extra_nomod_vsl(name, sym, vsl, NULL, alloc_estate_rl(new));
25441f5207b7SJohn Levon 	else
25451f5207b7SJohn Levon 		set_extra_mod(name, sym, NULL, alloc_estate_rl(new));
25461f5207b7SJohn Levon 
2547*efe51d0cSJohn Levon 	if (other_name && other_sym) {
2548*efe51d0cSJohn Levon 		if (op == PARAM_LIMIT)
2549*efe51d0cSJohn Levon 			set_extra_nomod_vsl(other_name, other_sym, vsl, NULL, alloc_estate_rl(new));
2550*efe51d0cSJohn Levon 		else
2551*efe51d0cSJohn Levon 			set_extra_mod(other_name, other_sym, NULL, alloc_estate_rl(new));
2552*efe51d0cSJohn Levon 	}
2553*efe51d0cSJohn Levon 
25541f5207b7SJohn Levon 	if (op == PARAM_LIMIT && arg->type == EXPR_BINOP)
25551f5207b7SJohn Levon 		db_param_limit_binops(arg, key, new);
25561f5207b7SJohn Levon free:
25571f5207b7SJohn Levon 	free_string(name);
25581f5207b7SJohn Levon }
25591f5207b7SJohn Levon 
25601f5207b7SJohn Levon static void db_param_limit(struct expression *expr, int param, char *key, char *value)
25611f5207b7SJohn Levon {
25621f5207b7SJohn Levon 	db_param_limit_filter(expr, param, key, value, PARAM_LIMIT);
25631f5207b7SJohn Levon }
25641f5207b7SJohn Levon 
25651f5207b7SJohn Levon static void db_param_filter(struct expression *expr, int param, char *key, char *value)
25661f5207b7SJohn Levon {
25671f5207b7SJohn Levon 	db_param_limit_filter(expr, param, key, value, PARAM_FILTER);
25681f5207b7SJohn Levon }
25691f5207b7SJohn Levon 
25701f5207b7SJohn Levon static void db_param_add_set(struct expression *expr, int param, char *key, char *value, enum info_type op)
25711f5207b7SJohn Levon {
25721f5207b7SJohn Levon 	struct expression *arg;
2573*efe51d0cSJohn Levon 	char *name;
2574*efe51d0cSJohn Levon 	char *other_name = NULL;
2575*efe51d0cSJohn Levon 	struct symbol *sym, *other_sym;
25761f5207b7SJohn Levon 	struct symbol *param_type, *arg_type;
25771f5207b7SJohn Levon 	struct smatch_state *state;
25781f5207b7SJohn Levon 	struct range_list *new = NULL;
25791f5207b7SJohn Levon 	struct range_list *added = NULL;
25801f5207b7SJohn Levon 
25811f5207b7SJohn Levon 	while (expr->type == EXPR_ASSIGNMENT)
25821f5207b7SJohn Levon 		expr = strip_expr(expr->right);
25831f5207b7SJohn Levon 	if (expr->type != EXPR_CALL)
25841f5207b7SJohn Levon 		return;
25851f5207b7SJohn Levon 
25861f5207b7SJohn Levon 	arg = get_argument_from_call_expr(expr->args, param);
25871f5207b7SJohn Levon 	if (!arg)
25881f5207b7SJohn Levon 		return;
25891f5207b7SJohn Levon 
25901f5207b7SJohn Levon 	arg_type = get_arg_type_from_key(expr->fn, param, arg, key);
25911f5207b7SJohn Levon 	param_type = get_member_type_from_key(arg, key);
25921f5207b7SJohn Levon 	name = get_variable_from_key(arg, key, &sym);
25931f5207b7SJohn Levon 	if (!name || !sym)
25941f5207b7SJohn Levon 		goto free;
25951f5207b7SJohn Levon 
25961f5207b7SJohn Levon 	state = get_state(SMATCH_EXTRA, name, sym);
25971f5207b7SJohn Levon 	if (state)
25981f5207b7SJohn Levon 		new = estate_rl(state);
25991f5207b7SJohn Levon 
26001f5207b7SJohn Levon 	call_results_to_rl(expr, arg_type, value, &added);
26011f5207b7SJohn Levon 	added = cast_rl(param_type, added);
26021f5207b7SJohn Levon 	if (op == PARAM_SET)
26031f5207b7SJohn Levon 		new = added;
26041f5207b7SJohn Levon 	else
26051f5207b7SJohn Levon 		new = rl_union(new, added);
26061f5207b7SJohn Levon 
2607*efe51d0cSJohn Levon 	other_name = get_other_name_sym_nostack(name, sym, &other_sym);
26081f5207b7SJohn Levon 	set_extra_mod(name, sym, NULL, alloc_estate_rl(new));
2609*efe51d0cSJohn Levon 	if (other_name && other_sym)
2610*efe51d0cSJohn Levon 		set_extra_mod(other_name, other_sym, NULL, alloc_estate_rl(new));
26111f5207b7SJohn Levon free:
2612*efe51d0cSJohn Levon 	free_string(other_name);
26131f5207b7SJohn Levon 	free_string(name);
26141f5207b7SJohn Levon }
26151f5207b7SJohn Levon 
26161f5207b7SJohn Levon static void db_param_add(struct expression *expr, int param, char *key, char *value)
26171f5207b7SJohn Levon {
26181f5207b7SJohn Levon 	in_param_set = true;
26191f5207b7SJohn Levon 	db_param_add_set(expr, param, key, value, PARAM_ADD);
26201f5207b7SJohn Levon 	in_param_set = false;
26211f5207b7SJohn Levon }
26221f5207b7SJohn Levon 
26231f5207b7SJohn Levon static void db_param_set(struct expression *expr, int param, char *key, char *value)
26241f5207b7SJohn Levon {
26251f5207b7SJohn Levon 	in_param_set = true;
26261f5207b7SJohn Levon 	db_param_add_set(expr, param, key, value, PARAM_SET);
26271f5207b7SJohn Levon 	in_param_set = false;
26281f5207b7SJohn Levon }
26291f5207b7SJohn Levon 
2630*efe51d0cSJohn Levon static void match_lost_param(struct expression *call, int param)
2631*efe51d0cSJohn Levon {
2632*efe51d0cSJohn Levon 	struct expression *arg;
2633*efe51d0cSJohn Levon 
2634*efe51d0cSJohn Levon 	if (is_const_param(call->fn, param))
2635*efe51d0cSJohn Levon 		return;
2636*efe51d0cSJohn Levon 
2637*efe51d0cSJohn Levon 	arg = get_argument_from_call_expr(call->args, param);
2638*efe51d0cSJohn Levon 	if (!arg)
2639*efe51d0cSJohn Levon 		return;
2640*efe51d0cSJohn Levon 
2641*efe51d0cSJohn Levon 	arg = strip_expr(arg);
2642*efe51d0cSJohn Levon 	if (arg->type == EXPR_PREOP && arg->op == '&')
2643*efe51d0cSJohn Levon 		set_extra_expr_mod(arg->unop, alloc_estate_whole(get_type(arg->unop)));
2644*efe51d0cSJohn Levon 	else
2645*efe51d0cSJohn Levon 		; /* if pointer then set struct members, maybe?*/
2646*efe51d0cSJohn Levon }
2647*efe51d0cSJohn Levon 
26481f5207b7SJohn Levon static void db_param_value(struct expression *expr, int param, char *key, char *value)
26491f5207b7SJohn Levon {
26501f5207b7SJohn Levon 	struct expression *call;
26511f5207b7SJohn Levon 	char *name;
26521f5207b7SJohn Levon 	struct symbol *sym;
26531f5207b7SJohn Levon 	struct symbol *type;
26541f5207b7SJohn Levon 	struct range_list *rl = NULL;
26551f5207b7SJohn Levon 
26561f5207b7SJohn Levon 	if (param != -1)
26571f5207b7SJohn Levon 		return;
26581f5207b7SJohn Levon 
26591f5207b7SJohn Levon 	call = expr;
26601f5207b7SJohn Levon 	while (call->type == EXPR_ASSIGNMENT)
26611f5207b7SJohn Levon 		call = strip_expr(call->right);
26621f5207b7SJohn Levon 	if (call->type != EXPR_CALL)
26631f5207b7SJohn Levon 		return;
26641f5207b7SJohn Levon 
26651f5207b7SJohn Levon 	type = get_member_type_from_key(expr->left, key);
26661f5207b7SJohn Levon 	name = get_variable_from_key(expr->left, key, &sym);
26671f5207b7SJohn Levon 	if (!name || !sym)
26681f5207b7SJohn Levon 		goto free;
26691f5207b7SJohn Levon 
26701f5207b7SJohn Levon 	call_results_to_rl(call, type, value, &rl);
26711f5207b7SJohn Levon 
26721f5207b7SJohn Levon 	set_extra_mod(name, sym, NULL, alloc_estate_rl(rl));
26731f5207b7SJohn Levon free:
26741f5207b7SJohn Levon 	free_string(name);
26751f5207b7SJohn Levon }
26761f5207b7SJohn Levon 
26771f5207b7SJohn Levon static void match_call_info(struct expression *expr)
26781f5207b7SJohn Levon {
26791f5207b7SJohn Levon 	struct smatch_state *state;
26801f5207b7SJohn Levon 	struct range_list *rl = NULL;
26811f5207b7SJohn Levon 	struct expression *arg;
26821f5207b7SJohn Levon 	struct symbol *type;
2683*efe51d0cSJohn Levon 	sval_t dummy;
26841f5207b7SJohn Levon 	int i = 0;
26851f5207b7SJohn Levon 
26861f5207b7SJohn Levon 	FOR_EACH_PTR(expr->args, arg) {
26871f5207b7SJohn Levon 		type = get_arg_type(expr->fn, i);
26881f5207b7SJohn Levon 
26891f5207b7SJohn Levon 		get_absolute_rl(arg, &rl);
26901f5207b7SJohn Levon 		rl = cast_rl(type, rl);
26911f5207b7SJohn Levon 
26921f5207b7SJohn Levon 		if (!is_whole_rl(rl)) {
26931f5207b7SJohn Levon 			rl = intersect_with_real_abs_expr(arg, rl);
26941f5207b7SJohn Levon 			sql_insert_caller_info(expr, PARAM_VALUE, i, "$", show_rl(rl));
26951f5207b7SJohn Levon 		}
26961f5207b7SJohn Levon 		state = get_state_expr(SMATCH_EXTRA, arg);
2697*efe51d0cSJohn Levon 		if (!estate_get_single_value(state, &dummy) && estate_has_hard_max(state)) {
2698*efe51d0cSJohn Levon 			sql_insert_caller_info(expr, HARD_MAX, i, "$",
2699*efe51d0cSJohn Levon 					       sval_to_str(estate_max(state)));
2700*efe51d0cSJohn Levon 		}
27011f5207b7SJohn Levon 		if (estate_has_fuzzy_max(state)) {
27021f5207b7SJohn Levon 			sql_insert_caller_info(expr, FUZZY_MAX, i, "$",
27031f5207b7SJohn Levon 					       sval_to_str(estate_get_fuzzy_max(state)));
27041f5207b7SJohn Levon 		}
27051f5207b7SJohn Levon 		i++;
27061f5207b7SJohn Levon 	} END_FOR_EACH_PTR(arg);
27071f5207b7SJohn Levon }
27081f5207b7SJohn Levon 
27091f5207b7SJohn Levon static void set_param_value(const char *name, struct symbol *sym, char *key, char *value)
27101f5207b7SJohn Levon {
2711*efe51d0cSJohn Levon 	struct expression *expr;
27121f5207b7SJohn Levon 	struct range_list *rl = NULL;
27131f5207b7SJohn Levon 	struct smatch_state *state;
27141f5207b7SJohn Levon 	struct symbol *type;
27151f5207b7SJohn Levon 	char fullname[256];
2716*efe51d0cSJohn Levon 	char *key_orig = key;
2717*efe51d0cSJohn Levon 	bool add_star = false;
27181f5207b7SJohn Levon 	sval_t dummy;
27191f5207b7SJohn Levon 
2720*efe51d0cSJohn Levon 	if (key[0] == '*') {
2721*efe51d0cSJohn Levon 		add_star = true;
2722*efe51d0cSJohn Levon 		key++;
2723*efe51d0cSJohn Levon 	}
2724*efe51d0cSJohn Levon 
2725*efe51d0cSJohn Levon 	snprintf(fullname, 256, "%s%s%s", add_star ? "*" : "", name, key + 1);
27261f5207b7SJohn Levon 
2727*efe51d0cSJohn Levon 	expr = symbol_expression(sym);
2728*efe51d0cSJohn Levon 	type = get_member_type_from_key(expr, key_orig);
27291f5207b7SJohn Levon 	str_to_rl(type, value, &rl);
27301f5207b7SJohn Levon 	state = alloc_estate_rl(rl);
27311f5207b7SJohn Levon 	if (estate_get_single_value(state, &dummy))
27321f5207b7SJohn Levon 		estate_set_hard_max(state);
27331f5207b7SJohn Levon 	set_state(SMATCH_EXTRA, fullname, sym, state);
27341f5207b7SJohn Levon }
27351f5207b7SJohn Levon 
2736*efe51d0cSJohn Levon static void set_param_fuzzy_max(const char *name, struct symbol *sym, char *key, char *value)
27371f5207b7SJohn Levon {
27381f5207b7SJohn Levon 	struct range_list *rl = NULL;
27391f5207b7SJohn Levon 	struct smatch_state *state;
27401f5207b7SJohn Levon 	struct symbol *type;
27411f5207b7SJohn Levon 	char fullname[256];
27421f5207b7SJohn Levon 	sval_t max;
27431f5207b7SJohn Levon 
27441f5207b7SJohn Levon 	if (strcmp(key, "*$") == 0)
27451f5207b7SJohn Levon 		snprintf(fullname, sizeof(fullname), "*%s", name);
27461f5207b7SJohn Levon 	else if (strncmp(key, "$", 1) == 0)
27471f5207b7SJohn Levon 		snprintf(fullname, 256, "%s%s", name, key + 1);
27481f5207b7SJohn Levon 	else
27491f5207b7SJohn Levon 		return;
27501f5207b7SJohn Levon 
27511f5207b7SJohn Levon 	state = get_state(SMATCH_EXTRA, fullname, sym);
27521f5207b7SJohn Levon 	if (!state)
27531f5207b7SJohn Levon 		return;
2754*efe51d0cSJohn Levon 	type = estate_type(state);
27551f5207b7SJohn Levon 	str_to_rl(type, value, &rl);
27561f5207b7SJohn Levon 	if (!rl_to_sval(rl, &max))
27571f5207b7SJohn Levon 		return;
27581f5207b7SJohn Levon 	estate_set_fuzzy_max(state, max);
27591f5207b7SJohn Levon }
27601f5207b7SJohn Levon 
2761*efe51d0cSJohn Levon static void set_param_hard_max(const char *name, struct symbol *sym, char *key, char *value)
2762*efe51d0cSJohn Levon {
2763*efe51d0cSJohn Levon 	struct smatch_state *state;
2764*efe51d0cSJohn Levon 	char fullname[256];
2765*efe51d0cSJohn Levon 
2766*efe51d0cSJohn Levon 	if (strcmp(key, "*$") == 0)
2767*efe51d0cSJohn Levon 		snprintf(fullname, sizeof(fullname), "*%s", name);
2768*efe51d0cSJohn Levon 	else if (strncmp(key, "$", 1) == 0)
2769*efe51d0cSJohn Levon 		snprintf(fullname, 256, "%s%s", name, key + 1);
2770*efe51d0cSJohn Levon 	else
2771*efe51d0cSJohn Levon 		return;
2772*efe51d0cSJohn Levon 
2773*efe51d0cSJohn Levon 	state = get_state(SMATCH_EXTRA, fullname, sym);
2774*efe51d0cSJohn Levon 	if (!state)
2775*efe51d0cSJohn Levon 		return;
2776*efe51d0cSJohn Levon 	estate_set_hard_max(state);
2777*efe51d0cSJohn Levon }
2778*efe51d0cSJohn Levon 
27791f5207b7SJohn Levon struct sm_state *get_extra_sm_state(struct expression *expr)
27801f5207b7SJohn Levon {
27811f5207b7SJohn Levon 	char *name;
27821f5207b7SJohn Levon 	struct symbol *sym;
27831f5207b7SJohn Levon 	struct sm_state *ret = NULL;
27841f5207b7SJohn Levon 
27851f5207b7SJohn Levon 	name = expr_to_known_chunk_sym(expr, &sym);
27861f5207b7SJohn Levon 	if (!name)
27871f5207b7SJohn Levon 		goto free;
27881f5207b7SJohn Levon 
27891f5207b7SJohn Levon 	ret = get_sm_state(SMATCH_EXTRA, name, sym);
27901f5207b7SJohn Levon free:
27911f5207b7SJohn Levon 	free_string(name);
27921f5207b7SJohn Levon 	return ret;
27931f5207b7SJohn Levon }
27941f5207b7SJohn Levon 
27951f5207b7SJohn Levon struct smatch_state *get_extra_state(struct expression *expr)
27961f5207b7SJohn Levon {
27971f5207b7SJohn Levon 	struct sm_state *sm;
27981f5207b7SJohn Levon 
27991f5207b7SJohn Levon 	sm = get_extra_sm_state(expr);
28001f5207b7SJohn Levon 	if (!sm)
28011f5207b7SJohn Levon 		return NULL;
28021f5207b7SJohn Levon 	return sm->state;
28031f5207b7SJohn Levon }
28041f5207b7SJohn Levon 
28051f5207b7SJohn Levon void register_smatch_extra(int id)
28061f5207b7SJohn Levon {
28071f5207b7SJohn Levon 	my_id = id;
28081f5207b7SJohn Levon 
2809*efe51d0cSJohn Levon 	set_dynamic_states(my_id);
28101f5207b7SJohn Levon 	add_merge_hook(my_id, &merge_estates);
28111f5207b7SJohn Levon 	add_unmatched_state_hook(my_id, &unmatched_state);
28121f5207b7SJohn Levon 	select_caller_info_hook(set_param_value, PARAM_VALUE);
2813*efe51d0cSJohn Levon 	select_caller_info_hook(set_param_fuzzy_max, FUZZY_MAX);
2814*efe51d0cSJohn Levon 	select_caller_info_hook(set_param_hard_max, HARD_MAX);
28151f5207b7SJohn Levon 	select_return_states_before(&db_limited_before);
28161f5207b7SJohn Levon 	select_return_states_hook(PARAM_LIMIT, &db_param_limit);
28171f5207b7SJohn Levon 	select_return_states_hook(PARAM_FILTER, &db_param_filter);
28181f5207b7SJohn Levon 	select_return_states_hook(PARAM_ADD, &db_param_add);
28191f5207b7SJohn Levon 	select_return_states_hook(PARAM_SET, &db_param_set);
2820*efe51d0cSJohn Levon 	add_lost_param_hook(&match_lost_param);
28211f5207b7SJohn Levon 	select_return_states_hook(PARAM_VALUE, &db_param_value);
28221f5207b7SJohn Levon 	select_return_states_after(&db_limited_after);
28231f5207b7SJohn Levon }
28241f5207b7SJohn Levon 
28251f5207b7SJohn Levon static void match_link_modify(struct sm_state *sm, struct expression *mod_expr)
28261f5207b7SJohn Levon {
28271f5207b7SJohn Levon 	struct var_sym_list *links;
28281f5207b7SJohn Levon 	struct var_sym *tmp;
28291f5207b7SJohn Levon 	struct smatch_state *state;
28301f5207b7SJohn Levon 
28311f5207b7SJohn Levon 	links = sm->state->data;
28321f5207b7SJohn Levon 
28331f5207b7SJohn Levon 	FOR_EACH_PTR(links, tmp) {
28341f5207b7SJohn Levon 		if (sm->sym == tmp->sym &&
28351f5207b7SJohn Levon 		    strcmp(sm->name, tmp->var) == 0)
28361f5207b7SJohn Levon 			continue;
28371f5207b7SJohn Levon 		state = get_state(SMATCH_EXTRA, tmp->var, tmp->sym);
28381f5207b7SJohn Levon 		if (!state)
28391f5207b7SJohn Levon 			continue;
28401f5207b7SJohn Levon 		set_state(SMATCH_EXTRA, tmp->var, tmp->sym, alloc_estate_whole(estate_type(state)));
28411f5207b7SJohn Levon 	} END_FOR_EACH_PTR(tmp);
28421f5207b7SJohn Levon 	set_state(link_id, sm->name, sm->sym, &undefined);
28431f5207b7SJohn Levon }
28441f5207b7SJohn Levon 
28451f5207b7SJohn Levon void register_smatch_extra_links(int id)
28461f5207b7SJohn Levon {
28471f5207b7SJohn Levon 	link_id = id;
2848*efe51d0cSJohn Levon 	set_dynamic_states(link_id);
28491f5207b7SJohn Levon }
28501f5207b7SJohn Levon 
28511f5207b7SJohn Levon void register_smatch_extra_late(int id)
28521f5207b7SJohn Levon {
28531f5207b7SJohn Levon 	add_merge_hook(link_id, &merge_link_states);
28541f5207b7SJohn Levon 	add_modification_hook(link_id, &match_link_modify);
28551f5207b7SJohn Levon 	add_hook(&match_dereferences, DEREF_HOOK);
28561f5207b7SJohn Levon 	add_hook(&match_pointer_as_array, OP_HOOK);
28571f5207b7SJohn Levon 	select_return_implies_hook(DEREFERENCE, &set_param_dereferenced);
28581f5207b7SJohn Levon 	add_hook(&match_function_call, FUNCTION_CALL_HOOK);
28591f5207b7SJohn Levon 	add_hook(&match_assign, ASSIGNMENT_HOOK);
28601f5207b7SJohn Levon 	add_hook(&match_assign, GLOBAL_ASSIGNMENT_HOOK);
28611f5207b7SJohn Levon 	add_hook(&unop_expr, OP_HOOK);
28621f5207b7SJohn Levon 	add_hook(&asm_expr, ASM_HOOK);
28631f5207b7SJohn Levon 
28641f5207b7SJohn Levon 	add_hook(&match_call_info, FUNCTION_CALL_HOOK);
28651f5207b7SJohn Levon 	add_member_info_callback(my_id, struct_member_callback);
28661f5207b7SJohn Levon 	add_split_return_callback(&returned_struct_members);
28671f5207b7SJohn Levon 
28681f5207b7SJohn Levon //	add_hook(&assume_indexes_are_valid, OP_HOOK);
28691f5207b7SJohn Levon }
2870