11f5207bJohn Levon/*
21f5207bJohn Levon * Copyright (C) 2008 Dan Carpenter.
31f5207bJohn Levon *
41f5207bJohn Levon * This program is free software; you can redistribute it and/or
51f5207bJohn Levon * modify it under the terms of the GNU General Public License
61f5207bJohn Levon * as published by the Free Software Foundation; either version 2
71f5207bJohn Levon * of the License, or (at your option) any later version.
81f5207bJohn Levon *
91f5207bJohn Levon * This program is distributed in the hope that it will be useful,
101f5207bJohn Levon * but WITHOUT ANY WARRANTY; without even the implied warranty of
111f5207bJohn Levon * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
121f5207bJohn Levon * GNU General Public License for more details.
131f5207bJohn Levon *
141f5207bJohn Levon * You should have received a copy of the GNU General Public License
151f5207bJohn Levon * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
161f5207bJohn Levon */
171f5207bJohn Levon
181f5207bJohn Levon/*
191f5207bJohn Levon * smatch_extra.c is supposed to track the value of every variable.
201f5207bJohn Levon *
211f5207bJohn Levon */
221f5207bJohn Levon
231f5207bJohn Levon#define _GNU_SOURCE
241f5207bJohn Levon#include <string.h>
251f5207bJohn Levon
261f5207bJohn Levon#include <stdlib.h>
271f5207bJohn Levon#include <errno.h>
281f5207bJohn Levon#ifndef __USE_ISOC99
291f5207bJohn Levon#define __USE_ISOC99
301f5207bJohn Levon#endif
311f5207bJohn Levon#include <limits.h>
321f5207bJohn Levon#include "parse.h"
331f5207bJohn Levon#include "smatch.h"
341f5207bJohn Levon#include "smatch_slist.h"
351f5207bJohn Levon#include "smatch_extra.h"
361f5207bJohn Levon
371f5207bJohn Levonstatic int my_id;
381f5207bJohn Levonstatic int link_id;
39efe51d0John Levonextern int check_assigned_expr_id;
401f5207bJohn Levon
411f5207bJohn Levonstatic void match_link_modify(struct sm_state *sm, struct expression *mod_expr);
421f5207bJohn Levon
431f5207bJohn Levonstruct string_list *__ignored_macros = NULL;
44efe51d0John Levonint in_warn_on_macro(void)
451f5207bJohn Levon{
461f5207bJohn Levon	struct statement *stmt;
471f5207bJohn Levon	char *tmp;
481f5207bJohn Levon	char *macro;
491f5207bJohn Levon
501f5207bJohn Levon	stmt = get_current_statement();
511f5207bJohn Levon	if (!stmt)
521f5207bJohn Levon		return 0;
531f5207bJohn Levon	macro = get_macro_name(stmt->pos);
541f5207bJohn Levon	if (!macro)
551f5207bJohn Levon		return 0;
561f5207bJohn Levon
571f5207bJohn Levon	FOR_EACH_PTR(__ignored_macros, tmp) {
581f5207bJohn Levon		if (!strcmp(tmp, macro))
591f5207bJohn Levon			return 1;
601f5207bJohn Levon	} END_FOR_EACH_PTR(tmp);
611f5207bJohn Levon	return 0;
621f5207bJohn Levon}
631f5207bJohn Levon
641f5207bJohn Levontypedef void (mod_hook)(const char *name, struct symbol *sym, struct expression *expr, struct smatch_state *state);
651f5207bJohn LevonDECLARE_PTR_LIST(void_fn_list, mod_hook *);
661f5207bJohn Levonstatic struct void_fn_list *extra_mod_hooks;
671f5207bJohn Levonstatic struct void_fn_list *extra_nomod_hooks;
681f5207bJohn Levon
691f5207bJohn Levonvoid add_extra_mod_hook(mod_hook *fn)
701f5207bJohn Levon{
711f5207bJohn Levon	mod_hook **p = malloc(sizeof(mod_hook *));
721f5207bJohn Levon	*p = fn;
731f5207bJohn Levon	add_ptr_list(&extra_mod_hooks, p);
741f5207bJohn Levon}
751f5207bJohn Levon
761f5207bJohn Levonvoid add_extra_nomod_hook(mod_hook *fn)
771f5207bJohn Levon{
781f5207bJohn Levon	mod_hook **p = malloc(sizeof(mod_hook *));
791f5207bJohn Levon	*p = fn;
801f5207bJohn Levon	add_ptr_list(&extra_nomod_hooks, p);
811f5207bJohn Levon}
821f5207bJohn Levon
831f5207bJohn Levonvoid call_extra_hooks(struct void_fn_list *hooks, const char *name, struct symbol *sym, struct expression *expr, struct smatch_state *state)
841f5207bJohn Levon{
851f5207bJohn Levon	mod_hook **fn;
861f5207bJohn Levon
871f5207bJohn Levon	FOR_EACH_PTR(hooks, fn) {
881f5207bJohn Levon		(*fn)(name, sym, expr, state);
891f5207bJohn Levon	} END_FOR_EACH_PTR(fn);
901f5207bJohn Levon}
911f5207bJohn Levon
921f5207bJohn Levonvoid call_extra_mod_hooks(const char *name, struct symbol *sym, struct expression *expr, struct smatch_state *state)
931f5207bJohn Levon{
941f5207bJohn Levon	call_extra_hooks(extra_mod_hooks, name, sym, expr, state);
951f5207bJohn Levon}
961f5207bJohn Levon
971f5207bJohn Levonvoid call_extra_nomod_hooks(const char *name, struct symbol *sym, struct expression *expr, struct smatch_state *state)
981f5207bJohn Levon{
991f5207bJohn Levon	call_extra_hooks(extra_nomod_hooks, name, sym, expr, state);
1001f5207bJohn Levon}
1011f5207bJohn Levon
102c85f09cJohn Levonstatic void set_union_info(const char *name, struct symbol *sym, struct expression *expr, struct smatch_state *state)
103c85f09cJohn Levon{
104c85f09cJohn Levon	struct symbol *type, *tmp, *inner_type, *inner, *new_type;
105c85f09cJohn Levon	struct expression *deref, *member_expr;
106c85f09cJohn Levon	struct smatch_state *new;
107c85f09cJohn Levon	int offset, inner_offset;
108c85f09cJohn Levon	static bool in_recurse;
109c85f09cJohn Levon	char *member_name;
110c85f09cJohn Levon
111c85f09cJohn Levon	if (__in_fake_assign)
112c85f09cJohn Levon		return;
113c85f09cJohn Levon
114c85f09cJohn Levon	if (in_recurse)
115c85f09cJohn Levon		return;
116c85f09cJohn Levon	in_recurse = true;
117c85f09cJohn Levon
118c85f09cJohn Levon	if (!expr || expr->type != EXPR_DEREF || !expr->member)
119c85f09cJohn Levon		goto done;
120c85f09cJohn Levon	offset = get_member_offset_from_deref(expr);
121c85f09cJohn Levon	if (offset < 0)
122c85f09cJohn Levon		goto done;
123c85f09cJohn Levon
124c85f09cJohn Levon	deref = strip_expr(expr->deref);
125c85f09cJohn Levon	type = get_type(deref);
126c85f09cJohn Levon	if (type_is_ptr(type))
127c85f09cJohn Levon		type = get_real_base_type(type);
128c85f09cJohn Levon	if (!type || type->type != SYM_STRUCT)
129c85f09cJohn Levon		goto done;
130c85f09cJohn Levon
131c85f09cJohn Levon	FOR_EACH_PTR(type->symbol_list, tmp) {
132c85f09cJohn Levon		inner_type = get_real_base_type(tmp);
133c85f09cJohn Levon		if (!inner_type || inner_type->type != SYM_UNION)
134c85f09cJohn Levon			continue;
135c85f09cJohn Levon
136c85f09cJohn Levon		inner = first_ptr_list((struct ptr_list *)inner_type->symbol_list);
137c85f09cJohn Levon		if (!inner || !inner->ident)
138c85f09cJohn Levon			continue;
139c85f09cJohn Levon
140c85f09cJohn Levon		inner_offset = get_member_offset(type, inner->ident->name);
141c85f09cJohn Levon		if (inner_offset < offset)
142c85f09cJohn Levon			continue;
143c85f09cJohn Levon		if (inner_offset > offset)
144c85f09cJohn Levon			goto done;
145c85f09cJohn Levon
146c85f09cJohn Levon		FOR_EACH_PTR(inner_type->symbol_list, inner) {
147c85f09cJohn Levon			struct symbol *tmp_type;
148c85f09cJohn Levon
149c85f09cJohn Levon			if (!inner->ident || inner->ident == expr->member)
150c85f09cJohn Levon				continue;
151c85f09cJohn Levon			tmp_type = get_real_base_type(inner);
152c85f09cJohn Levon			if (tmp_type && tmp_type->type == SYM_STRUCT)
153c85f09cJohn Levon				continue;
154c85f09cJohn Levon			member_expr = deref;
155c85f09cJohn Levon			if (tmp->ident)
156c85f09cJohn Levon				member_expr = member_expression(member_expr, '.', tmp->ident);
157c85f09cJohn Levon			member_expr = member_expression(member_expr, expr->op, inner->ident);
158c85f09cJohn Levon			member_name = expr_to_var(member_expr);
159c85f09cJohn Levon			if (!member_name)
160c85f09cJohn Levon				continue;
161c85f09cJohn Levon			new_type = get_real_base_type(inner);
162c85f09cJohn Levon			new = alloc_estate_rl(cast_rl(new_type, estate_rl(state)));
163c85f09cJohn Levon			set_extra_mod_helper(member_name, sym, member_expr, new);
164c85f09cJohn Levon			free_string(member_name);
165c85f09cJohn Levon		} END_FOR_EACH_PTR(inner);
166c85f09cJohn Levon	} END_FOR_EACH_PTR(tmp);
167c85f09cJohn Levon
168c85f09cJohn Levondone:
169c85f09cJohn Levon	in_recurse = false;
170c85f09cJohn Levon}
171c85f09cJohn Levon
1721f5207bJohn Levonstatic bool in_param_set;
1731f5207bJohn Levonvoid set_extra_mod_helper(const char *name, struct symbol *sym, struct expression *expr, struct smatch_state *state)
1741f5207bJohn Levon{
175c85f09cJohn Levon	if (!expr)
176c85f09cJohn Levon		expr = gen_expression_from_name_sym(name, sym);
1771f5207bJohn Levon	remove_from_equiv(name, sym);
178c85f09cJohn Levon	set_union_info(name, sym, expr, state);
1791f5207bJohn Levon	call_extra_mod_hooks(name, sym, expr, state);
180c85f09cJohn Levon	update_mtag_data(expr, state);
181c85f09cJohn Levon	if (in_param_set &&
1821f5207bJohn Levon	    estate_is_unknown(state) && !get_state(SMATCH_EXTRA, name, sym))
1831f5207bJohn Levon		return;
1841f5207bJohn Levon	set_state(SMATCH_EXTRA, name, sym, state);
1851f5207bJohn Levon}
1861f5207bJohn Levon
1871f5207bJohn Levonstatic void set_extra_nomod_helper(const char *name, struct symbol *sym, struct expression *expr, struct smatch_state *state)
1881f5207bJohn Levon{
1891f5207bJohn Levon	call_extra_nomod_hooks(name, sym, expr, state);
1901f5207bJohn Levon	set_state(SMATCH_EXTRA, name, sym, state);
1911f5207bJohn Levon}
1921f5207bJohn Levon
1931f5207bJohn Levonstatic char *get_pointed_at(const char *name, struct symbol *sym, struct symbol **new_sym)
1941f5207bJohn Levon{
1951f5207bJohn Levon	struct expression *assigned;
1961f5207bJohn Levon
1975a0e240John Levon	/*
1985a0e240John Levon	 * Imagine we have an assignment: "foo = &addr;" then the other name
1995a0e240John Levon	 * of "*foo" is addr.
2005a0e240John Levon	 */
2015a0e240John Levon
2021f5207bJohn Levon	if (name[0] != '*')
2031f5207bJohn Levon		return NULL;
2041f5207bJohn Levon	if (strcmp(name + 1, sym->ident->name) != 0)
2051f5207bJohn Levon		return NULL;
2061f5207bJohn Levon
2071f5207bJohn Levon	assigned = get_assigned_expr_name_sym(sym->ident->name, sym);
2081f5207bJohn Levon	if (!assigned)
2091f5207bJohn Levon		return NULL;
2101f5207bJohn Levon	assigned = strip_parens(assigned);
2111f5207bJohn Levon	if (assigned->type != EXPR_PREOP || assigned->op != '&')
2121f5207bJohn Levon		return NULL;
2131f5207bJohn Levon
2141f5207bJohn Levon	return expr_to_var_sym(assigned->unop, new_sym);
2151f5207bJohn Levon}
2161f5207bJohn Levon
217efe51d0John Levonchar *get_other_name_sym_from_chunk(const char *name, const char *chunk, int len, struct symbol *sym, struct symbol **new_sym)
2181f5207bJohn Levon{
2191f5207bJohn Levon	struct expression *assigned;
2201f5207bJohn Levon	char *orig_name = NULL;
2211f5207bJohn Levon	char buf[256];
222efe51d0John Levon	char *ret;
2231f5207bJohn Levon
224efe51d0John Levon	assigned = get_assigned_expr_name_sym(chunk, sym);
2251f5207bJohn Levon	if (!assigned)
2261f5207bJohn Levon		return NULL;
2271f5207bJohn Levon	if (assigned->type == EXPR_CALL)
2281f5207bJohn Levon		return map_call_to_other_name_sym(name, sym, new_sym);
229efe51d0John Levon	if (assigned->type == EXPR_PREOP && assigned->op == '&') {
2301f5207bJohn Levon
2311f5207bJohn Levon		orig_name = expr_to_var_sym(assigned, new_sym);
2321f5207bJohn Levon		if (!orig_name || !*new_sym)
2331f5207bJohn Levon			goto free;
2341f5207bJohn Levon
235efe51d0John Levon		snprintf(buf, sizeof(buf), "%s.%s", orig_name + 1, name + len);
2361f5207bJohn Levon		ret = alloc_string(buf);
2371f5207bJohn Levon		free_string(orig_name);
2381f5207bJohn Levon		return ret;
2391f5207bJohn Levon	}
2401f5207bJohn Levon
2411f5207bJohn Levon	orig_name = expr_to_var_sym(assigned, new_sym);
2421f5207bJohn Levon	if (!orig_name || !*new_sym)
2431f5207bJohn Levon		goto free;
2441f5207bJohn Levon
245efe51d0John Levon	snprintf(buf, sizeof(buf), "%s->%s", orig_name, name + len);
2461f5207bJohn Levon	ret = alloc_string(buf);
2471f5207bJohn Levon	free_string(orig_name);
2481f5207bJohn Levon	return ret;
2491f5207bJohn Levonfree:
2501f5207bJohn Levon	free_string(orig_name);
2511f5207bJohn Levon	return NULL;
2521f5207bJohn Levon}
2531f5207bJohn Levon
254c85f09cJohn Levonstatic char *get_long_name_sym(const char *name, struct symbol *sym, struct symbol **new_sym, bool use_stack)
255efe51d0John Levon{
256efe51d0John Levon	struct expression *tmp;
257efe51d0John Levon	struct sm_state *sm;
258efe51d0John Levon	char buf[256];
259efe51d0John Levon
260efe51d0John Levon	/*
261efe51d0John Levon	 * Just prepend the name with a different name/sym and return that.
2625a0e240John Levon	 * For example, if we set "foo->bar = bar;" then the other name
2635a0e240John Levon	 * for "bar->baz" is "foo->bar->baz".  Or if we have "foo = bar;" then
2645a0e240John Levon	 * the other name for "bar" is "foo".  A third option is if we have
2655a0e240John Levon	 * "foo = bar;" then another name for "*bar" is "*foo".
266efe51d0John Levon	 */
267efe51d0John Levon
268efe51d0John Levon	FOR_EACH_MY_SM(check_assigned_expr_id, __get_cur_stree(), sm) {
269efe51d0John Levon		tmp = sm->state->data;
270efe51d0John Levon		if (!tmp || tmp->type != EXPR_SYMBOL)
271efe51d0John Levon			continue;
272efe51d0John Levon		if (tmp->symbol == sym)
273efe51d0John Levon			goto found;
274efe51d0John Levon	} END_FOR_EACH_SM(sm);
275efe51d0John Levon
276efe51d0John Levon	return NULL;
277efe51d0John Levon
278efe51d0John Levonfound:
279c85f09cJohn Levon	if (!use_stack && name[tmp->symbol->ident->len] != '-')
280c85f09cJohn Levon		return NULL;
2815a0e240John Levon
2825a0e240John Levon	if (name[0] == '*' && strcmp(name + 1, tmp->symbol_name->name) == 0)
2835a0e240John Levon		snprintf(buf, sizeof(buf), "*%s", sm->name);
2845a0e240John Levon	else if (name[tmp->symbol->ident->len] == '-' ||
2855a0e240John Levon		 name[tmp->symbol->ident->len] == '.')
2865a0e240John Levon		snprintf(buf, sizeof(buf), "%s%s", sm->name, name + tmp->symbol->ident->len);
2875a0e240John Levon	else if (strcmp(name, tmp->symbol_name->name) == 0)
2885a0e240John Levon		snprintf(buf, sizeof(buf), "%s", sm->name);
2895a0e240John Levon	else
2905a0e240John Levon		return NULL;
2915a0e240John Levon
292efe51d0John Levon	*new_sym = sm->sym;
293efe51d0John Levon	return alloc_string(buf);
294efe51d0John Levon}
295efe51d0John Levon
296efe51d0John Levonchar *get_other_name_sym_helper(const char *name, struct symbol *sym, struct symbol **new_sym, bool use_stack)
297efe51d0John Levon{
298efe51d0John Levon	char buf[256];
299efe51d0John Levon	char *ret;
300efe51d0John Levon	int len;
301efe51d0John Levon
302efe51d0John Levon	*new_sym = NULL;
303efe51d0John Levon
304efe51d0John Levon	if (!sym || !sym->ident)
305efe51d0John Levon		return NULL;
306efe51d0John Levon
307efe51d0John Levon	ret = get_pointed_at(name, sym, new_sym);
308efe51d0John Levon	if (ret)
309efe51d0John Levon		return ret;
310efe51d0John Levon
311efe51d0John Levon	ret = map_long_to_short_name_sym(name, sym, new_sym, use_stack);
312efe51d0John Levon	if (ret)
313efe51d0John Levon		return ret;
314efe51d0John Levon
315efe51d0John Levon	len = snprintf(buf, sizeof(buf), "%s", name);
316efe51d0John Levon	if (len >= sizeof(buf) - 2)
317efe51d0John Levon		return NULL;
318efe51d0John Levon
319c85f09cJohn Levon	while (use_stack && len >= 1) {
320efe51d0John Levon		if (buf[len] == '>' && buf[len - 1] == '-') {
321efe51d0John Levon			len--;
322efe51d0John Levon			buf[len] = '\0';
323efe51d0John Levon			ret = get_other_name_sym_from_chunk(name, buf, len + 2, sym, new_sym);
324efe51d0John Levon			if (ret)
325efe51d0John Levon				return ret;
326efe51d0John Levon		}
327efe51d0John Levon		len--;
328efe51d0John Levon	}
329efe51d0John Levon
330c85f09cJohn Levon	ret = get_long_name_sym(name, sym, new_sym, use_stack);
331efe51d0John Levon	if (ret)
332efe51d0John Levon		return ret;
333efe51d0John Levon
334efe51d0John Levon	return NULL;
335efe51d0John Levon}
336efe51d0John Levon
337efe51d0John Levonchar *get_other_name_sym(const char *name, struct symbol *sym, struct symbol **new_sym)
338efe51d0John Levon{
339efe51d0John Levon	return get_other_name_sym_helper(name, sym, new_sym, true);
340efe51d0John Levon}
341efe51d0John Levon
342efe51d0John Levonchar *get_other_name_sym_nostack(const char *name, struct symbol *sym, struct symbol **new_sym)
343efe51d0John Levon{
344efe51d0John Levon	return get_other_name_sym_helper(name, sym, new_sym, false);
345efe51d0John Levon}
346efe51d0John Levon
3471f5207bJohn Levonvoid set_extra_mod(const char *name, struct symbol *sym, struct expression *expr, struct smatch_state *state)
3481f5207bJohn Levon{
3491f5207bJohn Levon	char *new_name;
3501f5207bJohn Levon	struct symbol *new_sym;
3511f5207bJohn Levon
3521f5207bJohn Levon	set_extra_mod_helper(name, sym, expr, state);
353c85f09cJohn Levon	new_name = get_other_name_sym_nostack(name, sym, &new_sym);
3541f5207bJohn Levon	if (new_name && new_sym)
355c85f09cJohn Levon		set_extra_mod_helper(new_name, new_sym, NULL, state);
3561f5207bJohn Levon	free_string(new_name);
3571f5207bJohn Levon}
3581f5207bJohn Levon
3591f5207bJohn Levonstatic struct expression *chunk_get_array_base(struct expression *expr)
3601f5207bJohn Levon{
3611f5207bJohn Levon	/*
3621f5207bJohn Levon	 * The problem with is_array() is that it only returns true for things
3631f5207bJohn Levon	 * like foo[1] but not for foo[1].bar.
3641f5207bJohn Levon	 *
3651f5207bJohn Levon	 */
3661f5207bJohn Levon	expr = strip_expr(expr);
3671f5207bJohn Levon	while (expr && expr->type == EXPR_DEREF)
3681f5207bJohn Levon		expr = strip_expr(expr->deref);
3691f5207bJohn Levon	return get_array_base(expr);
3701f5207bJohn Levon}
3711f5207bJohn Levon
3721f5207bJohn Levonstatic int chunk_has_array(struct expression *expr)
3731f5207bJohn Levon{
3741f5207bJohn Levon	return !!chunk_get_array_base(expr);
3751f5207bJohn Levon}
3761f5207bJohn Levon
3771f5207bJohn Levonstatic void clear_array_states(struct expression *array)
3781f5207bJohn Levon{
3791f5207bJohn Levon	struct sm_state *sm;
3801f5207bJohn Levon
3811f5207bJohn Levon	sm = get_sm_state_expr(link_id, array);
3821f5207bJohn Levon	if (sm)
3831f5207bJohn Levon		match_link_modify(sm, NULL);
3841f5207bJohn Levon}
3851f5207bJohn Levon
3861f5207bJohn Levonstatic void set_extra_array_mod(struct expression *expr, struct smatch_state *state)
3871f5207bJohn Levon{
3881f5207bJohn Levon	struct expression *array;
3891f5207bJohn Levon	struct var_sym_list *vsl;
3901f5207bJohn Levon	struct var_sym *vs;
3911f5207bJohn Levon	char *name;
3921f5207bJohn Levon	struct symbol *sym;
3931f5207bJohn Levon
3941f5207bJohn Levon	array = chunk_get_array_base(expr);
3951f5207bJohn Levon
3961f5207bJohn Levon	name = expr_to_chunk_sym_vsl(expr, &sym, &vsl);
3971f5207bJohn Levon	if (!name || !vsl) {
3981f5207bJohn Levon		clear_array_states(array);
3991f5207bJohn Levon		goto free;
4001f5207bJohn Levon	}
4011f5207bJohn Levon
4021f5207bJohn Levon	FOR_EACH_PTR(vsl, vs) {
4031f5207bJohn Levon		store_link(link_id, vs->var, vs->sym, name, sym);
4041f5207bJohn Levon	} END_FOR_EACH_PTR(vs);
4051f5207bJohn Levon
4061f5207bJohn Levon	call_extra_mod_hooks(name, sym, expr, state);
4071f5207bJohn Levon	set_state(SMATCH_EXTRA, name, sym, state);
4081f5207bJohn Levonfree:
4091f5207bJohn Levon	free_string(name);
4101f5207bJohn Levon}
4111f5207bJohn Levon
4121f5207bJohn Levonvoid set_extra_expr_mod(struct expression *expr, struct smatch_state *state)
4131f5207bJohn Levon{
4141f5207bJohn Levon	struct symbol *sym;
4151f5207bJohn Levon	char *name;
4161f5207bJohn Levon
4171f5207bJohn Levon	if (chunk_has_array(expr)) {
4181f5207bJohn Levon		set_extra_array_mod(expr, state);
4191f5207bJohn Levon		return;
4201f5207bJohn Levon	}
4211f5207bJohn Levon
4221f5207bJohn Levon	expr = strip_expr(expr);
4231f5207bJohn Levon	name = expr_to_var_sym(expr, &sym);
4241f5207bJohn Levon	if (!name || !sym)
4251f5207bJohn Levon		goto free;
4261f5207bJohn Levon	set_extra_mod(name, sym, expr, state);
4271f5207bJohn Levonfree:
4281f5207bJohn Levon	free_string(name);
4291f5207bJohn Levon}
4301f5207bJohn Levon
4311f5207bJohn Levonvoid set_extra_nomod(const char *name, struct symbol *sym, struct expression *expr, struct smatch_state *state)
4321f5207bJohn Levon{
4331f5207bJohn Levon	char *new_name;
4341f5207bJohn Levon	struct symbol *new_sym;
4351f5207bJohn Levon	struct relation *rel;
4361f5207bJohn Levon	struct smatch_state *orig_state;
4371f5207bJohn Levon
4381f5207bJohn Levon	orig_state = get_state(SMATCH_EXTRA, name, sym);
4391f5207bJohn Levon
4401f5207bJohn Levon	/* don't save unknown states if leaving it blank is the same */
4411f5207bJohn Levon	if (!orig_state && estate_is_unknown(state))
4421f5207bJohn Levon		return;
4431f5207bJohn Levon
4441f5207bJohn Levon	new_name = get_other_name_sym(name, sym, &new_sym);
4451f5207bJohn Levon	if (new_name && new_sym)
4461f5207bJohn Levon		set_extra_nomod_helper(new_name, new_sym, expr, state);
4471f5207bJohn Levon	free_string(new_name);
4481f5207bJohn Levon
4491f5207bJohn Levon	if (!estate_related(orig_state)) {
4501f5207bJohn Levon		set_extra_nomod_helper(name, sym, expr, state);
4511f5207bJohn Levon		return;
4521f5207bJohn Levon	}
4531f5207bJohn Levon
4541f5207bJohn Levon	set_related(state, estate_related(orig_state));
4551f5207bJohn Levon	FOR_EACH_PTR(estate_related(orig_state), rel) {
4561f5207bJohn Levon		struct smatch_state *estate;
4571f5207bJohn Levon
4581f5207bJohn Levon		estate = get_state(SMATCH_EXTRA, rel->name, rel->sym);
4591f5207bJohn Levon		if (!estate)
4601f5207bJohn Levon			continue;
4611f5207bJohn Levon		set_extra_nomod_helper(rel->name, rel->sym, expr, clone_estate_cast(estate_type(estate), state));
4621f5207bJohn Levon	} END_FOR_EACH_PTR(rel);
4631f5207bJohn Levon}
4641f5207bJohn Levon
4651f5207bJohn Levonvoid set_extra_nomod_vsl(const char *name, struct symbol *sym, struct var_sym_list *vsl, struct expression *expr, struct smatch_state *state)
4661f5207bJohn Levon{
4671f5207bJohn Levon	struct var_sym *vs;
4681f5207bJohn Levon
4691f5207bJohn Levon	FOR_EACH_PTR(vsl, vs) {
4701f5207bJohn Levon		store_link(link_id, vs->var, vs->sym, name, sym);
4711f5207bJohn Levon	} END_FOR_EACH_PTR(vs);
4721f5207bJohn Levon
4731f5207bJohn Levon	set_extra_nomod(name, sym, expr, state);
4741f5207bJohn Levon}
4751f5207bJohn Levon
4761f5207bJohn Levon/*
4771f5207bJohn Levon * This is for return_implies_state() hooks which modify a SMATCH_EXTRA state
4781f5207bJohn Levon */
4791f5207bJohn Levonvoid set_extra_expr_nomod(struct expression *expr, struct smatch_state *state)
4801f5207bJohn Levon{
4811f5207bJohn Levon	struct var_sym_list *vsl;
4821f5207bJohn Levon	struct var_sym *vs;
4831f5207bJohn Levon	char *name;
4841f5207bJohn Levon	struct symbol *sym;
4851f5207bJohn Levon
4861f5207bJohn Levon	name = expr_to_chunk_sym_vsl(expr, &sym, &vsl);
4871f5207bJohn Levon	if (!name || !vsl)
4881f5207bJohn Levon		goto free;
4891f5207bJohn Levon	FOR_EACH_PTR(vsl, vs) {
4901f5207bJohn Levon		store_link(link_id, vs->var, vs->sym, name, sym);
4911f5207bJohn Levon	} END_FOR_EACH_PTR(vs);
4921f5207bJohn Levon
4931f5207bJohn Levon	set_extra_nomod(name, sym, expr, state);
4941f5207bJohn Levonfree:
4951f5207bJohn Levon	free_string(name);
4961f5207bJohn Levon}
4971f5207bJohn Levon
4981f5207bJohn Levonstatic void set_extra_true_false(const char *name, struct symbol *sym,
4991f5207bJohn Levon			struct smatch_state *true_state,
5001f5207bJohn Levon			struct smatch_state *false_state)
5011f5207bJohn Levon{
5021f5207bJohn Levon	char *new_name;
5031f5207bJohn Levon	struct symbol *new_sym;
5041f5207bJohn Levon	struct relation *rel;
5051f5207bJohn Levon	struct smatch_state *orig_state;
5061f5207bJohn Levon
5071f5207bJohn Levon	if (!true_state && !false_state)
5081f5207bJohn Levon		return;
5091f5207bJohn Levon
5101f5207bJohn Levon	if (in_warn_on_macro())
5111f5207bJohn Levon		return;
5121f5207bJohn Levon
5131f5207bJohn Levon	new_name = get_other_name_sym(name, sym, &new_sym);
5141f5207bJohn Levon	if (new_name && new_sym)
5151f5207bJohn Levon		set_true_false_states(SMATCH_EXTRA, new_name, new_sym, true_state, false_state);
5161f5207bJohn Levon	free_string(new_name);
5171f5207bJohn Levon
5181f5207bJohn Levon	orig_state = get_state(SMATCH_EXTRA, name, sym);
5191f5207bJohn Levon
5201f5207bJohn Levon	if (!estate_related(orig_state)) {
5211f5207bJohn Levon		set_true_false_states(SMATCH_EXTRA, name, sym, true_state, false_state);
5221f5207bJohn Levon		return;
5231f5207bJohn Levon	}
5241f5207bJohn Levon
5251f5207bJohn Levon	if (true_state)
5261f5207bJohn Levon		set_related(true_state, estate_related(orig_state));
5271f5207bJohn Levon	if (false_state)
5281f5207bJohn Levon		set_related(false_state, estate_related(orig_state));
5291f5207bJohn Levon
5301f5207bJohn Levon	FOR_EACH_PTR(estate_related(orig_state), rel) {
5311f5207bJohn Levon		set_true_false_states(SMATCH_EXTRA, rel->name, rel->sym,
5321f5207bJohn Levon				true_state, false_state);
5331f5207bJohn Levon	} END_FOR_EACH_PTR(rel);
5341f5207bJohn Levon}
5351f5207bJohn Levon
5361f5207bJohn Levonstatic void set_extra_chunk_true_false(struct expression *expr,
5371f5207bJohn Levon				       struct smatch_state *true_state,
5381f5207bJohn Levon				       struct smatch_state *false_state)
5391f5207bJohn Levon{
5401f5207bJohn Levon	struct var_sym_list *vsl;
5411f5207bJohn Levon	struct var_sym *vs;
5421f5207bJohn Levon	struct symbol *type;
5431f5207bJohn Levon	char *name;
5441f5207bJohn Levon	struct symbol *sym;
5451f5207bJohn Levon
5461f5207bJohn Levon	if (in_warn_on_macro())
5471f5207bJohn Levon		return;
5481f5207bJohn Levon
5491f5207bJohn Levon	type = get_type(expr);
5501f5207bJohn Levon	if (!type)
5511f5207bJohn Levon		return;
5521f5207bJohn Levon
5531f5207bJohn Levon	name = expr_to_chunk_sym_vsl(expr, &sym, &vsl);
5541f5207bJohn Levon	if (!name || !vsl)
5551f5207bJohn Levon		goto free;
5561f5207bJohn Levon	FOR_EACH_PTR(vsl, vs) {
5571f5207bJohn Levon		store_link(link_id, vs->var, vs->sym, name, sym);
5581f5207bJohn Levon	} END_FOR_EACH_PTR(vs);
5591f5207bJohn Levon
5601f5207bJohn Levon	set_true_false_states(SMATCH_EXTRA, name, sym,
5611f5207bJohn Levon			      clone_estate(true_state),
5621f5207bJohn Levon			      clone_estate(false_state));
5631f5207bJohn Levonfree:
5641f5207bJohn Levon	free_string(name);
5651f5207bJohn Levon}
5661f5207bJohn Levon
5671f5207bJohn Levonstatic void set_extra_expr_true_false(struct expression *expr,
5681f5207bJohn Levon		struct smatch_state *true_state,
5691f5207bJohn Levon		struct smatch_state *false_state)
5701f5207bJohn Levon{
5711f5207bJohn Levon	char *name;
5721f5207bJohn Levon	struct symbol *sym;
5731f5207bJohn Levon	sval_t sval;
5741f5207bJohn Levon
5751f5207bJohn Levon	if (!true_state && !false_state)
5761f5207bJohn Levon		return;
5771f5207bJohn Levon
5781f5207bJohn Levon	if (get_value(expr, &sval))
5791f5207bJohn Levon		return;
5801f5207bJohn Levon
5811f5207bJohn Levon	expr = strip_expr(expr);
5821f5207bJohn Levon	name = expr_to_var_sym(expr, &sym);
5831f5207bJohn Levon	if (!name || !sym) {
5841f5207bJohn Levon		free_string(name);
5851f5207bJohn Levon		set_extra_chunk_true_false(expr, true_state, false_state);
5861f5207bJohn Levon		return;
5871f5207bJohn Levon	}
5881f5207bJohn Levon	set_extra_true_false(name, sym, true_state, false_state);
5891f5207bJohn Levon	free_string(name);
5901f5207bJohn Levon}
5911f5207bJohn Levon
5921f5207bJohn Levonstatic int get_countdown_info(struct expression *condition, struct expression **unop, int *op, sval_t *right)
5931f5207bJohn Levon{
5941f5207bJohn Levon	struct expression *unop_expr;
5951f5207bJohn Levon	int comparison;
5961f5207bJohn Levon	sval_t limit;
5971f5207bJohn Levon
5981f5207bJohn Levon	right->type = &int_ctype;
5991f5207bJohn Levon	right->value = 0;
6001f5207bJohn Levon
6011f5207bJohn Levon	condition = strip_expr(condition);
6021f5207bJohn Levon
6031f5207bJohn Levon	if (condition->type == EXPR_COMPARE) {
6041f5207bJohn Levon		comparison = remove_unsigned_from_comparison(condition->op);
6051f5207bJohn Levon
6061f5207bJohn Levon		if (comparison != SPECIAL_GTE && comparison != '>')
6071f5207bJohn Levon			return 0;
6081f5207bJohn Levon		if (!get_value(condition->right, &limit))
6091f5207bJohn Levon			return 0;
6101f5207bJohn Levon
6111f5207bJohn Levon		unop_expr = condition->left;
6121f5207bJohn Levon		if (unop_expr->type != EXPR_PREOP && unop_expr->type != EXPR_POSTOP)
6131f5207bJohn Levon			return 0;
6141f5207bJohn Levon		if (unop_expr->op != SPECIAL_DECREMENT)
6151f5207bJohn Levon			return 0;
6161f5207bJohn Levon
6171f5207bJohn Levon		*unop = unop_expr;
6181f5207bJohn Levon		*op = comparison;
6191f5207bJohn Levon		*right = limit;
6201f5207bJohn Levon
6211f5207bJohn Levon		return 1;
6221f5207bJohn Levon	}
6231f5207bJohn Levon
6241f5207bJohn Levon	if (condition->type != EXPR_PREOP && condition->type != EXPR_POSTOP)
6251f5207bJohn Levon		return 0;
6261f5207bJohn Levon	if (condition->op != SPECIAL_DECREMENT)
6271f5207bJohn Levon		return 0;
6281f5207bJohn Levon
6291f5207bJohn Levon	*unop = condition;
6301f5207bJohn Levon	*op = '>';
6311f5207bJohn Levon
6321f5207bJohn Levon	return 1;
6331f5207bJohn Levon}
6341f5207bJohn Levon
6351f5207bJohn Levonstatic struct sm_state *handle_canonical_while_count_down(struct statement *loop)
6361f5207bJohn Levon{
6371f5207bJohn Levon	struct expression *iter_var;
6381f5207bJohn Levon	struct expression *condition, *unop;
639efe51d0John Levon	struct symbol *type;
6401f5207bJohn Levon	struct sm_state *sm;
6411f5207bJohn Levon	struct smatch_state *estate;
6421f5207bJohn Levon	int op;
6431f5207bJohn Levon	sval_t start, right;
6441f5207bJohn Levon
6451f5207bJohn Levon	right.type = &int_ctype;
6461f5207bJohn Levon	right.value = 0;
6471f5207bJohn Levon
6481f5207bJohn Levon	condition = strip_expr(loop->iterator_pre_condition);
6491f5207bJohn Levon	if (!condition)
6501f5207bJohn Levon		return NULL;
6511f5207bJohn Levon
6521f5207bJohn Levon	if (!get_countdown_info(condition, &unop, &op, &right))
6531f5207bJohn Levon		return NULL;
6541f5207bJohn Levon
6551f5207bJohn Levon	iter_var = unop->unop;
6561f5207bJohn Levon
6571f5207bJohn Levon	sm = get_sm_state_expr(SMATCH_EXTRA, iter_var);
6581f5207bJohn Levon	if (!sm)
6591f5207bJohn Levon		return NULL;
6601f5207bJohn Levon	if (sval_cmp(estate_min(sm->state), right) < 0)
6611f5207bJohn Levon		return NULL;
6621f5207bJohn Levon	start = estate_max(sm->state);
663efe51d0John Levon
664efe51d0John Levon	type = get_type(iter_var);
665efe51d0John Levon	right = sval_cast(type, right);
666efe51d0John Levon	start = sval_cast(type, start);
667efe51d0John Levon
6681f5207bJohn Levon	if  (sval_cmp(start, right) <= 0)
6691f5207bJohn Levon		return NULL;
6701f5207bJohn Levon	if (!sval_is_max(start))
6711f5207bJohn Levon		start.value--;
6721f5207bJohn Levon
6731f5207bJohn Levon	if (op == SPECIAL_GTE)
6741f5207bJohn Levon		right.value--;
6751f5207bJohn Levon
6761f5207bJohn Levon	if (unop->type == EXPR_PREOP) {
6771f5207bJohn Levon		right.value++;
6781f5207bJohn Levon		estate = alloc_estate_range(right, start);
6791f5207bJohn Levon		if (estate_has_hard_max(sm->state))
6801f5207bJohn Levon			estate_set_hard_max(estate);
6811f5207bJohn Levon		estate_copy_fuzzy_max(estate, sm->state);
6821f5207bJohn Levon		set_extra_expr_mod(iter_var, estate);
6831f5207bJohn Levon	}
6841f5207bJohn Levon	if (unop->type == EXPR_POSTOP) {
6851f5207bJohn Levon		estate = alloc_estate_range(right, start);
6861f5207bJohn Levon		if (estate_has_hard_max(sm->state))
6871f5207bJohn Levon			estate_set_hard_max(estate);
6881f5207bJohn Levon		estate_copy_fuzzy_max(estate, sm->state);
6891f5207bJohn Levon		set_extra_expr_mod(iter_var, estate);
6901f5207bJohn Levon	}
6911f5207bJohn Levon	return get_sm_state_expr(SMATCH_EXTRA, iter_var);
6921f5207bJohn Levon}
6931f5207bJohn Levon
6941f5207bJohn Levonstatic struct sm_state *handle_canonical_for_inc(struct expression *iter_expr,
6951f5207bJohn Levon						struct expression *condition)
6961f5207bJohn Levon{
6971f5207bJohn Levon	struct expression *iter_var;
6981f5207bJohn Levon	struct sm_state *sm;
6991f5207bJohn Levon	struct smatch_state *estate;
7001f5207bJohn Levon	sval_t start, end, max;
701efe51d0John Levon	struct symbol *type;
7021f5207bJohn Levon
7031f5207bJohn Levon	iter_var = iter_expr->unop;
7041f5207bJohn Levon	sm = get_sm_state_expr(SMATCH_EXTRA, iter_var);
7051f5207bJohn Levon	if (!sm)
7061f5207bJohn Levon		return NULL;
7071f5207bJohn Levon	if (!estate_get_single_value(sm->state, &start))
7081f5207bJohn Levon		return NULL;
709efe51d0John Levon	if (!get_implied_value(condition->right, &end))
710efe51d0John Levon		return NULL;
7111f5207bJohn Levon
7121f5207bJohn Levon	if (get_sm_state_expr(SMATCH_EXTRA, condition->left) != sm)
7131f5207bJohn Levon		return NULL;
7141f5207bJohn Levon
7151f5207bJohn Levon	switch (condition->op) {
7161f5207bJohn Levon	case SPECIAL_UNSIGNED_LT:
7171f5207bJohn Levon	case SPECIAL_NOTEQUAL:
7181f5207bJohn Levon	case '<':
7191f5207bJohn Levon		if (!sval_is_min(end))
7201f5207bJohn Levon			end.value--;
7211f5207bJohn Levon		break;
7221f5207bJohn Levon	case SPECIAL_UNSIGNED_LTE:
7231f5207bJohn Levon	case SPECIAL_LTE:
7241f5207bJohn Levon		break;
7251f5207bJohn Levon	default:
7261f5207bJohn Levon		return NULL;
7271f5207bJohn Levon	}
7281f5207bJohn Levon	if (sval_cmp(end, start) < 0)
7291f5207bJohn Levon		return NULL;
730efe51d0John Levon	type = get_type(iter_var);
731efe51d0John Levon	start = sval_cast(type, start);
732efe51d0John Levon	end = sval_cast(type, end);
7331f5207bJohn Levon	estate = alloc_estate_range(start, end);
7341f5207bJohn Levon	if (get_hard_max(condition->right, &max)) {
735efe51d0John Levon		if (!get_macro_name(condition->pos))
736efe51d0John Levon			estate_set_hard_max(estate);
7371f5207bJohn Levon		if (condition->op == '<' ||
7381f5207bJohn Levon		    condition->op == SPECIAL_UNSIGNED_LT ||
7391f5207bJohn Levon		    condition->op == SPECIAL_NOTEQUAL)
7401f5207bJohn Levon			max.value--;
741efe51d0John Levon		max = sval_cast(type, max);
7421f5207bJohn Levon		estate_set_fuzzy_max(estate, max);
7431f5207bJohn Levon	}
7441f5207bJohn Levon	set_extra_expr_mod(iter_var, estate);
7451f5207bJohn Levon	return get_sm_state_expr(SMATCH_EXTRA, iter_var);
7461f5207bJohn Levon}
7471f5207bJohn Levon
7481f5207bJohn Levonstatic struct sm_state *handle_canonical_for_dec(struct expression *iter_expr,
7491f5207bJohn Levon						struct expression *condition)
7501f5207bJohn Levon{
7511f5207bJohn Levon	struct expression *iter_var;
7521f5207bJohn Levon	struct sm_state *sm;
7531f5207bJohn Levon	struct smatch_state *estate;
7541f5207bJohn Levon	sval_t start, end;
7551f5207bJohn Levon
7561f5207bJohn Levon	iter_var = iter_expr->unop;
7571f5207bJohn Levon	sm = get_sm_state_expr(SMATCH_EXTRA, iter_var);
7581f5207bJohn Levon	if (!sm)
7591f5207bJohn Levon		return NULL;
7601f5207bJohn Levon	if (!estate_get_single_value(sm->state, &start))
7611f5207bJohn Levon		return NULL;
7621f5207bJohn Levon	if (!get_implied_min(condition->right, &end))
7631f5207bJohn Levon		end = sval_type_min(get_type(iter_var));
764efe51d0John Levon	end = sval_cast(estate_type(sm->state), end);
7651f5207bJohn Levon	if (get_sm_state_expr(SMATCH_EXTRA, condition->left) != sm)
7661f5207bJohn Levon		return NULL;
7671f5207bJohn Levon
7681f5207bJohn Levon	switch (condition->op) {
7691f5207bJohn Levon	case SPECIAL_NOTEQUAL:
7701f5207bJohn Levon	case '>':
771efe51d0John Levon		if (!sval_is_max(end))
7721f5207bJohn Levon			end.value++;
7731f5207bJohn Levon		break;
7741f5207bJohn Levon	case SPECIAL_GTE:
7751f5207bJohn Levon		break;
7761f5207bJohn Levon	default:
7771f5207bJohn Levon		return NULL;
7781f5207bJohn Levon	}
7791f5207bJohn Levon	if (sval_cmp(end, start) > 0)
7801f5207bJohn Levon		return NULL;
7811f5207bJohn Levon	estate = alloc_estate_range(end, start);
7821f5207bJohn Levon	estate_set_hard_max(estate);
7831f5207bJohn Levon	estate_set_fuzzy_max(estate, estate_get_fuzzy_max(estate));
7841f5207bJohn Levon	set_extra_expr_mod(iter_var, estate);
7851f5207bJohn Levon	return get_sm_state_expr(SMATCH_EXTRA, iter_var);
7861f5207bJohn Levon}
7871f5207bJohn Levon
7881f5207bJohn Levonstatic struct sm_state *handle_canonical_for_loops(struct statement *loop)
7891f5207bJohn Levon{
7901f5207bJohn Levon	struct expression *iter_expr;
7911f5207bJohn Levon	struct expression *condition;
7921f5207bJohn Levon
7931f5207bJohn Levon	if (!loop->iterator_post_statement)
7941f5207bJohn Levon		return NULL;
7951f5207bJohn Levon	if (loop->iterator_post_statement->type != STMT_EXPRESSION)
7961f5207bJohn Levon		return NULL;
7971f5207bJohn Levon	iter_expr = loop->iterator_post_statement->expression;
7981f5207bJohn Levon	if (!loop->iterator_pre_condition)
7991f5207bJohn Levon		return NULL;
8001f5207bJohn Levon	if (loop->iterator_pre_condition->type != EXPR_COMPARE)
8011f5207bJohn Levon		return NULL;
8021f5207bJohn Levon	condition = loop->iterator_pre_condition;
8031f5207bJohn Levon
8041f5207bJohn Levon	if (iter_expr->op == SPECIAL_INCREMENT)
8051f5207bJohn Levon		return handle_canonical_for_inc(iter_expr, condition);
8061f5207bJohn Levon	if (iter_expr->op == SPECIAL_DECREMENT)
8071f5207bJohn Levon		return handle_canonical_for_dec(iter_expr, condition);
8081f5207bJohn Levon	return NULL;
8091f5207bJohn Levon}
8101f5207bJohn Levon
8111f5207bJohn Levonstruct sm_state *__extra_handle_canonical_loops(struct statement *loop, struct stree **stree)
8121f5207bJohn Levon{
8131f5207bJohn Levon	struct sm_state *ret;
8141f5207bJohn Levon
8151f5207bJohn Levon	/*
8161f5207bJohn Levon	 * Canonical loops are a hack.  The proper way to handle this is to
8171f5207bJohn Levon	 * use two passes, but unfortunately, doing two passes makes parsing
8181f5207bJohn Levon	 * code twice as slow.
8191f5207bJohn Levon	 *
8201f5207bJohn Levon	 * What we do is we set the inside state here, which overwrites whatever
8211f5207bJohn Levon	 * __extra_match_condition() does.  Then we set the outside state in
8221f5207bJohn Levon	 * __extra_pre_loop_hook_after().
8231f5207bJohn Levon	 *
8241f5207bJohn Levon	 */
8251f5207bJohn Levon	__push_fake_cur_stree();
8261f5207bJohn Levon	if (!loop->iterator_post_statement)
8271f5207bJohn Levon		ret = handle_canonical_while_count_down(loop);
8281f5207bJohn Levon	else
8291f5207bJohn Levon		ret = handle_canonical_for_loops(loop);
8301f5207bJohn Levon	*stree = __pop_fake_cur_stree();
8311f5207bJohn Levon	return ret;
8321f5207bJohn Levon}
8331f5207bJohn Levon
8341f5207bJohn Levonint __iterator_unchanged(struct sm_state *sm)
8351f5207bJohn Levon{
8361f5207bJohn Levon	if (!sm)
8371f5207bJohn Levon		return 0;
8381f5207bJohn Levon	if (get_sm_state(my_id, sm->name, sm->sym) == sm)
8391f5207bJohn Levon		return 1;
8401f5207bJohn Levon	return 0;
8411f5207bJohn Levon}
8421f5207bJohn Levon
8431f5207bJohn Levonstatic void while_count_down_after(struct sm_state *sm, struct expression *condition)
8441f5207bJohn Levon{
8451f5207bJohn Levon	struct expression *unop;
8461f5207bJohn Levon	int op;
8471f5207bJohn Levon	sval_t limit, after_value;
8481f5207bJohn Levon
8491f5207bJohn Levon	if (!get_countdown_info(condition, &unop, &op, &limit))
8501f5207bJohn Levon		return;
8511f5207bJohn Levon	after_value = estate_min(sm->state);
8521f5207bJohn Levon	after_value.value--;
8531f5207bJohn Levon	set_extra_mod(sm->name, sm->sym, condition->unop, alloc_estate_sval(after_value));
8541f5207bJohn Levon}
8551f5207bJohn Levon
8561f5207bJohn Levonvoid __extra_pre_loop_hook_after(struct sm_state *sm,
8571f5207bJohn Levon				struct statement *iterator,
8581f5207bJohn Levon				struct expression *condition)
8591f5207bJohn Levon{
8601f5207bJohn Levon	struct expression *iter_expr;
8611f5207bJohn Levon	sval_t limit;
8621f5207bJohn Levon	struct smatch_state *state;
8631f5207bJohn Levon
8641f5207bJohn Levon	if (!iterator) {
8651f5207bJohn Levon		while_count_down_after(sm, condition);
8661f5207bJohn Levon		return;
8671f5207bJohn Levon	}
8681f5207bJohn Levon
8691f5207bJohn Levon	iter_expr = iterator->expression;
8701f5207bJohn Levon
8711f5207bJohn Levon	if (condition->type != EXPR_COMPARE)
8721f5207bJohn Levon		return;
8731f5207bJohn Levon	if (iter_expr->op == SPECIAL_INCREMENT) {
8741f5207bJohn Levon		limit = sval_binop(estate_max(sm->state), '+',
8751f5207bJohn Levon				   sval_type_val(estate_type(sm->state), 1));
8761f5207bJohn Levon	} else {
8771f5207bJohn Levon		limit = sval_binop(estate_min(sm->state), '-',
8781f5207bJohn Levon				   sval_type_val(estate_type(sm->state), 1));
8791f5207bJohn Levon	}
880efe51d0John Levon	limit = sval_cast(estate_type(sm->state), limit);
8811f5207bJohn Levon	if (!estate_has_hard_max(sm->state) && !__has_breaks()) {
8821f5207bJohn Levon		if (iter_expr->op == SPECIAL_INCREMENT)
8831f5207bJohn Levon			state = alloc_estate_range(estate_min(sm->state), limit);
8841f5207bJohn Levon		else
8851f5207bJohn Levon			state = alloc_estate_range(limit, estate_max(sm->state));
8861f5207bJohn Levon	} else {
8871f5207bJohn Levon		state = alloc_estate_sval(limit);
8881f5207bJohn Levon	}
8891f5207bJohn Levon	if (!estate_has_hard_max(sm->state)) {
8901f5207bJohn Levon		estate_clear_hard_max(state);
8911f5207bJohn Levon	}
8921f5207bJohn Levon	if (estate_has_fuzzy_max(sm->state)) {
8931f5207bJohn Levon		sval_t hmax = estate_get_fuzzy_max(sm->state);
8941f5207bJohn Levon		sval_t max = estate_max(sm->state);
8951f5207bJohn Levon
8961f5207bJohn Levon		if (sval_cmp(hmax, max) != 0)
8971f5207bJohn Levon			estate_clear_fuzzy_max(state);
8981f5207bJohn Levon	} else if (!estate_has_fuzzy_max(sm->state)) {
8991f5207bJohn Levon		estate_clear_fuzzy_max(state);
9001f5207bJohn Levon	}
9011f5207bJohn Levon
9021f5207bJohn Levon	set_extra_mod(sm->name, sm->sym, iter_expr, state);
9031f5207bJohn Levon}
9041f5207bJohn Levon
905efe51d0John Levonstatic bool get_global_rl(const char *name, struct symbol *sym, struct range_list **rl)
906efe51d0John Levon{
907efe51d0John Levon	struct expression *expr;
908efe51d0John Levon
909efe51d0John Levon	if (!sym || !(sym->ctype.modifiers & MOD_TOPLEVEL) || !sym->ident)
910efe51d0John Levon		return false;
911efe51d0John Levon	if (strcmp(sym->ident->name, name) != 0)
912efe51d0John Levon		return false;
913efe51d0John Levon
914efe51d0John Levon	expr = symbol_expression(sym);
915efe51d0John Levon	return get_implied_rl(expr, rl);
916efe51d0John Levon}
917efe51d0John Levon
9181f5207bJohn Levonstatic struct stree *unmatched_stree;
9191f5207bJohn Levonstatic struct smatch_state *unmatched_state(struct sm_state *sm)
9201f5207bJohn Levon{
9211f5207bJohn Levon	struct smatch_state *state;
922efe51d0John Levon	struct range_list *rl;
9231f5207bJohn Levon
9241f5207bJohn Levon	if (unmatched_stree) {
9251f5207bJohn Levon		state = get_state_stree(unmatched_stree, SMATCH_EXTRA, sm->name, sm->sym);
9261f5207bJohn Levon		if (state)
9271f5207bJohn Levon			return state;
9281f5207bJohn Levon	}
9291f5207bJohn Levon	if (parent_is_gone_var_sym(sm->name, sm->sym))
9301f5207bJohn Levon		return alloc_estate_empty();
931efe51d0John Levon	if (get_global_rl(sm->name, sm->sym, &rl))
932efe51d0John Levon		return alloc_estate_rl(rl);
9331f5207bJohn Levon	return alloc_estate_whole(estate_type(sm->state));
9341f5207bJohn Levon}
9351f5207bJohn Levon
9361f5207bJohn Levonstatic void clear_the_pointed_at(struct expression *expr)
9371f5207bJohn Levon{
9381f5207bJohn Levon	struct stree *stree;
9391f5207bJohn Levon	char *name;
9401f5207bJohn Levon	struct symbol *sym;
9411f5207bJohn Levon	struct sm_state *tmp;
9421f5207bJohn Levon
9431f5207bJohn Levon	name = expr_to_var_sym(expr, &sym);
9441f5207bJohn Levon	if (!name || !sym)
9451f5207bJohn Levon		goto free;
9461f5207bJohn Levon
9471f5207bJohn Levon	stree = __get_cur_stree();
9481f5207bJohn Levon	FOR_EACH_MY_SM(SMATCH_EXTRA, stree, tmp) {
9491f5207bJohn Levon		if (tmp->name[0] != '*')
9501f5207bJohn Levon			continue;
9511f5207bJohn Levon		if (tmp->sym != sym)
9521f5207bJohn Levon			continue;
9531f5207bJohn Levon		if (strcmp(tmp->name + 1, name) != 0)
9541f5207bJohn Levon			continue;
9551f5207bJohn Levon		set_extra_mod(tmp->name, tmp->sym, expr, alloc_estate_whole(estate_type(tmp->state)));
9561f5207bJohn Levon	} END_FOR_EACH_SM(tmp);
9571f5207bJohn Levon
9581f5207bJohn Levonfree:
9591f5207bJohn Levon	free_string(name);
9601f5207bJohn Levon}
9611f5207bJohn Levon
9621f5207bJohn Levonstatic int is_const_param(struct expression *expr, int param)
9631f5207bJohn Levon{
9641f5207bJohn Levon	struct symbol *type;
9651f5207bJohn Levon
9661f5207bJohn Levon	type = get_arg_type(expr, param);
9671f5207bJohn Levon	if (!type)
9681f5207bJohn Levon		return 0;
9691f5207bJohn Levon	if (type->ctype.modifiers & MOD_CONST)
9701f5207bJohn Levon		return 1;
9711f5207bJohn Levon	return 0;
9721f5207bJohn Levon}
9731f5207bJohn Levon
9741f5207bJohn Levonstatic void match_function_call(struct expression *expr)
9751f5207bJohn Levon{
9761f5207bJohn Levon	struct expression *arg;
9771f5207bJohn Levon	struct expression *tmp;
9781f5207bJohn Levon	int param = -1;
9791f5207bJohn Levon
9801f5207bJohn Levon	/* if we have the db this is handled in smatch_function_hooks.c */
9811f5207bJohn Levon	if (!option_no_db)
9821f5207bJohn Levon		return;
9831f5207bJohn Levon	if (inlinable(expr->fn))
9841f5207bJohn Levon		return;
9851f5207bJohn Levon
9861f5207bJohn Levon	FOR_EACH_PTR(expr->args, arg) {
9871f5207bJohn Levon		param++;
9881f5207bJohn Levon		if (is_const_param(expr->fn, param))
9891f5207bJohn Levon			continue;
9901f5207bJohn Levon		tmp = strip_expr(arg);
9911f5207bJohn Levon		if (tmp->type == EXPR_PREOP && tmp->op == '&')
9921f5207bJohn Levon			set_extra_expr_mod(tmp->unop, alloc_estate_whole(get_type(tmp->unop)));
9931f5207bJohn Levon		else
9941f5207bJohn Levon			clear_the_pointed_at(tmp);
9951f5207bJohn Levon	} END_FOR_EACH_PTR(arg);
9961f5207bJohn Levon}
9971f5207bJohn Levon
998efe51d0John Levonint values_fit_type(struct expression *left, struct expression *right)
9991f5207bJohn Levon{
10001f5207bJohn Levon	struct range_list *rl;
10011f5207bJohn Levon	struct symbol *type;
10021f5207bJohn Levon
10031f5207bJohn Levon	type = get_type(left);
10041f5207bJohn Levon	if (!type)
10051f5207bJohn Levon		return 0;
10061f5207bJohn Levon	get_absolute_rl(right, &rl);
1007efe51d0John Levon	if (type == rl_type(rl))
1008efe51d0John Levon		return 1;
10091f5207bJohn Levon	if (type_unsigned(type) && sval_is_negative(rl_min(rl)))
10101f5207bJohn Levon		return 0;
10111f5207bJohn Levon	if (sval_cmp(sval_type_min(type), rl_min(rl)) > 0)
10121f5207bJohn Levon		return 0;
10131f5207bJohn Levon	if (sval_cmp(sval_type_max(type), rl_max(rl)) < 0)
10141f5207bJohn Levon		return 0;
10151f5207bJohn Levon	return 1;
10161f5207bJohn Levon}
10171f5207bJohn Levon
10181f5207bJohn Levonstatic void save_chunk_info(struct expression *left, struct expression *right)
10191f5207bJohn Levon{
10201f5207bJohn Levon	struct var_sym_list *vsl;
10211f5207bJohn Levon	struct var_sym *vs;
10221f5207bJohn Levon	struct expression *add_expr;
10231f5207bJohn Levon	struct symbol *type;
10241f5207bJohn Levon	sval_t sval;
10251f5207bJohn Levon	char *name;
10261f5207bJohn Levon	struct symbol *sym;
1027