xref: /illumos-gate/usr/src/tools/smatch/src/smatch_states.c (revision d3b5f56344d8bfcdd6cfb82446af0e5e55ad9ebe)
1 /*
2  * Copyright (C) 2006 Dan Carpenter.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
16  */
17 
18 /*
19  * You have a lists of states.  kernel = locked, foo = NULL, ...
20  * When you hit an if {} else {} statement then you swap the list
21  * of states for a different list of states.  The lists are stored
22  * on stacks.
23  *
24  * At the beginning of this file there are list of the stacks that
25  * we use.  Each function in this file does something to one of
26  * of the stacks.
27  *
28  * So the smatch_flow.c understands code but it doesn't understand states.
29  * smatch_flow calls functions in this file.  This file calls functions
30  * in smatch_slist.c which just has boring generic plumbing for handling
31  * state lists.  But really it's this file where all the magic happens.
32  */
33 
34 #include <stdlib.h>
35 #include <stdio.h>
36 #include "smatch.h"
37 #include "smatch_slist.h"
38 #include "smatch_extra.h"
39 
40 struct smatch_state undefined = { .name = "undefined" };
41 struct smatch_state ghost = { .name = "ghost" };
42 struct smatch_state merged = { .name = "merged" };
43 struct smatch_state true_state = { .name = "true" };
44 struct smatch_state false_state = { .name = "false" };
45 
46 static struct stree *cur_stree; /* current states */
47 
48 static struct stree_stack *true_stack; /* states after a t/f branch */
49 static struct stree_stack *false_stack;
50 static struct stree_stack *pre_cond_stack; /* states before a t/f branch */
51 
52 static struct stree_stack *cond_true_stack; /* states affected by a branch */
53 static struct stree_stack *cond_false_stack;
54 
55 static struct stree_stack *fake_cur_stree_stack;
56 static int read_only;
57 
58 static struct stree_stack *break_stack;
59 static struct stree_stack *fake_break_stack;
60 static struct stree_stack *switch_stack;
61 static struct range_list_stack *remaining_cases;
62 static struct stree_stack *default_stack;
63 static struct stree_stack *continue_stack;
64 
65 static struct named_stree_stack *goto_stack;
66 
67 static struct ptr_list *backup;
68 
69 int option_debug;
70 
71 void __print_cur_stree(void)
72 {
73 	__print_stree(cur_stree);
74 }
75 
76 int unreachable(void)
77 {
78 	if (!cur_stree)
79 		return 1;
80 	return 0;
81 }
82 
83 struct sm_state *set_state(int owner, const char *name, struct symbol *sym, struct smatch_state *state)
84 {
85 	struct sm_state *ret;
86 
87 	if (!name || !state)
88 		return NULL;
89 
90 	if (read_only)
91 		sm_perror("cur_stree is read only.");
92 
93 	if (option_debug || strcmp(check_name(owner), option_debug_check) == 0) {
94 		struct smatch_state *s;
95 
96 		s = __get_state(owner, name, sym);
97 		if (!s)
98 			sm_msg("%s new [%s] '%s' %s", __func__,
99 			       check_name(owner), name, show_state(state));
100 		else
101 			sm_msg("%s change [%s] '%s' %s => %s",
102 				__func__, check_name(owner), name, show_state(s),
103 				show_state(state));
104 	}
105 
106 	if (owner != -1 && unreachable())
107 		return NULL;
108 
109 	if (fake_cur_stree_stack)
110 		set_state_stree_stack(&fake_cur_stree_stack, owner, name, sym, state);
111 
112 	ret = set_state_stree(&cur_stree, owner, name, sym, state);
113 
114 	return ret;
115 }
116 
117 struct sm_state *set_state_expr(int owner, struct expression *expr, struct smatch_state *state)
118 {
119 	char *name;
120 	struct symbol *sym;
121 	struct sm_state *ret = NULL;
122 
123 	expr = strip_expr(expr);
124 	name = expr_to_var_sym(expr, &sym);
125 	if (!name || !sym)
126 		goto free;
127 	ret = set_state(owner, name, sym, state);
128 free:
129 	free_string(name);
130 	return ret;
131 }
132 
133 void __swap_cur_stree(struct stree *stree)
134 {
135 	free_stree(&cur_stree);
136 	cur_stree = stree;
137 }
138 
139 void __push_fake_cur_stree(void)
140 {
141 	push_stree(&fake_cur_stree_stack, NULL);
142 	__save_pre_cond_states();
143 }
144 
145 struct stree *__pop_fake_cur_stree(void)
146 {
147 	if (!fake_cur_stree_stack)
148 		sm_perror("popping too many fake cur strees.");
149 	__use_pre_cond_states();
150 	return pop_stree(&fake_cur_stree_stack);
151 }
152 
153 void __free_fake_cur_stree(void)
154 {
155 	struct stree *stree;
156 
157 	stree = __pop_fake_cur_stree();
158 	free_stree(&stree);
159 }
160 
161 void __set_fake_cur_stree_fast(struct stree *stree)
162 {
163 	push_stree(&pre_cond_stack, cur_stree);
164 	cur_stree = stree;
165 	read_only = 1;
166 }
167 
168 void __pop_fake_cur_stree_fast(void)
169 {
170 	cur_stree = pop_stree(&pre_cond_stack);
171 	read_only = 0;
172 }
173 
174 void __merge_stree_into_cur(struct stree *stree)
175 {
176 	struct sm_state *sm;
177 	struct sm_state *orig;
178 	struct sm_state *merged;
179 
180 	FOR_EACH_SM(stree, sm) {
181 		orig = get_sm_state(sm->owner, sm->name, sm->sym);
182 		if (orig)
183 			merged = merge_sm_states(orig, sm);
184 		else
185 			merged = sm;
186 		__set_sm(merged);
187 	} END_FOR_EACH_SM(sm);
188 }
189 
190 void __set_sm(struct sm_state *sm)
191 {
192 	if (read_only)
193 		sm_perror("cur_stree is read only.");
194 
195 	if (option_debug ||
196 	    strcmp(check_name(sm->owner), option_debug_check) == 0) {
197 		struct smatch_state *s;
198 
199 		s = __get_state(sm->owner, sm->name, sm->sym);
200 		if (!s)
201 			sm_msg("%s new %s", __func__, show_sm(sm));
202 		else
203 			sm_msg("%s change %s (was %s)",	__func__, show_sm(sm),
204 			       show_state(s));
205 	}
206 
207 	if (unreachable())
208 		return;
209 
210 	if (fake_cur_stree_stack)
211 		overwrite_sm_state_stree_stack(&fake_cur_stree_stack, sm);
212 
213 	overwrite_sm_state_stree(&cur_stree, sm);
214 }
215 
216 void __set_sm_cur_stree(struct sm_state *sm)
217 {
218 	if (read_only)
219 		sm_perror("cur_stree is read only.");
220 
221 	if (option_debug ||
222 	    strcmp(check_name(sm->owner), option_debug_check) == 0) {
223 		struct smatch_state *s;
224 
225 		s = __get_state(sm->owner, sm->name, sm->sym);
226 		if (!s)
227 			sm_msg("%s new %s", __func__, show_sm(sm));
228 		else
229 			sm_msg("%s change %s (was %s)",
230 				__func__, show_sm(sm), show_state(s));
231 	}
232 
233 	if (unreachable())
234 		return;
235 
236 	overwrite_sm_state_stree(&cur_stree, sm);
237 }
238 
239 void __set_sm_fake_stree(struct sm_state *sm)
240 {
241 	if (read_only)
242 		sm_perror("cur_stree is read only.");
243 
244 	if (option_debug ||
245 	    strcmp(check_name(sm->owner), option_debug_check) == 0) {
246 		struct smatch_state *s;
247 
248 		s = __get_state(sm->owner, sm->name, sm->sym);
249 		if (!s)
250 			sm_msg("%s new %s", __func__, show_sm(sm));
251 		else
252 			sm_msg("%s change %s (was %s)",
253 				__func__, show_sm(sm), show_state(s));
254 	}
255 
256 	if (unreachable())
257 		return;
258 
259 	overwrite_sm_state_stree_stack(&fake_cur_stree_stack, sm);
260 }
261 
262 
263 typedef void (get_state_hook)(int owner, const char *name, struct symbol *sym);
264 DECLARE_PTR_LIST(fn_list, get_state_hook *);
265 static struct fn_list *get_state_hooks;
266 
267 void add_get_state_hook(get_state_hook *fn)
268 {
269 	get_state_hook **p = malloc(sizeof(get_state_hook *));
270 	*p = fn;
271 	add_ptr_list(&get_state_hooks, p);
272 }
273 
274 static void call_get_state_hooks(int owner, const char *name, struct symbol *sym)
275 {
276 	static int recursion;
277 	get_state_hook **fn;
278 
279 	if (recursion)
280 		return;
281 	recursion = 1;
282 
283 	FOR_EACH_PTR(get_state_hooks, fn) {
284 		(*fn)(owner, name, sym);
285 	} END_FOR_EACH_PTR(fn);
286 
287 	recursion = 0;
288 }
289 
290 struct smatch_state *__get_state(int owner, const char *name, struct symbol *sym)
291 {
292 	return get_state_stree(cur_stree, owner, name, sym);
293 }
294 
295 struct smatch_state *get_state(int owner, const char *name, struct symbol *sym)
296 {
297 	call_get_state_hooks(owner, name, sym);
298 
299 	return __get_state(owner, name, sym);
300 }
301 
302 struct smatch_state *get_state_expr(int owner, struct expression *expr)
303 {
304 	char *name;
305 	struct symbol *sym;
306 	struct smatch_state *ret = NULL;
307 
308 	expr = strip_expr(expr);
309 	name = expr_to_var_sym(expr, &sym);
310 	if (!name || !sym)
311 		goto free;
312 	ret = get_state(owner, name, sym);
313 free:
314 	free_string(name);
315 	return ret;
316 }
317 
318 struct state_list *get_possible_states(int owner, const char *name, struct symbol *sym)
319 {
320 	struct sm_state *sms;
321 
322 	sms = get_sm_state_stree(cur_stree, owner, name, sym);
323 	if (sms)
324 		return sms->possible;
325 	return NULL;
326 }
327 
328 struct state_list *get_possible_states_expr(int owner, struct expression *expr)
329 {
330 	char *name;
331 	struct symbol *sym;
332 	struct state_list *ret = NULL;
333 
334 	expr = strip_expr(expr);
335 	name = expr_to_var_sym(expr, &sym);
336 	if (!name || !sym)
337 		goto free;
338 	ret = get_possible_states(owner, name, sym);
339 free:
340 	free_string(name);
341 	return ret;
342 }
343 
344 struct sm_state *get_sm_state(int owner, const char *name, struct symbol *sym)
345 {
346 	return get_sm_state_stree(cur_stree, owner, name, sym);
347 }
348 
349 struct sm_state *get_sm_state_expr(int owner, struct expression *expr)
350 {
351 	char *name;
352 	struct symbol *sym;
353 	struct sm_state *ret = NULL;
354 
355 	expr = strip_expr(expr);
356 	name = expr_to_var_sym(expr, &sym);
357 	if (!name || !sym)
358 		goto free;
359 	ret = get_sm_state(owner, name, sym);
360 free:
361 	free_string(name);
362 	return ret;
363 }
364 
365 void delete_state(int owner, const char *name, struct symbol *sym)
366 {
367 	delete_state_stree(&cur_stree, owner, name, sym);
368 	if (cond_true_stack) {
369 		delete_state_stree_stack(&pre_cond_stack, owner, name, sym);
370 		delete_state_stree_stack(&cond_true_stack, owner, name, sym);
371 		delete_state_stree_stack(&cond_false_stack, owner, name, sym);
372 	}
373 }
374 
375 void delete_state_expr(int owner, struct expression *expr)
376 {
377 	char *name;
378 	struct symbol *sym;
379 
380 	expr = strip_expr(expr);
381 	name = expr_to_var_sym(expr, &sym);
382 	if (!name || !sym)
383 		goto free;
384 	delete_state(owner, name, sym);
385 free:
386 	free_string(name);
387 }
388 
389 static void delete_all_states_stree_sym(struct stree **stree, struct symbol *sym)
390 {
391 	struct state_list *slist = NULL;
392 	struct sm_state *sm;
393 
394 	FOR_EACH_SM(*stree, sm) {
395 		if (sm->sym == sym)
396 			add_ptr_list(&slist, sm);
397 	} END_FOR_EACH_SM(sm);
398 
399 	FOR_EACH_PTR(slist, sm) {
400 		delete_state_stree(stree, sm->owner, sm->name, sm->sym);
401 	} END_FOR_EACH_PTR(sm);
402 
403 	free_slist(&slist);
404 }
405 
406 static void delete_all_states_stree_stack_sym(struct stree_stack **stack, struct symbol *sym)
407 {
408 	struct stree *stree;
409 
410 	if (!*stack)
411 		return;
412 
413 	stree = pop_stree(stack);
414 	delete_all_states_stree_sym(&stree, sym);
415 	push_stree(stack, stree);
416 }
417 
418 void __delete_all_states_sym(struct symbol *sym)
419 {
420 	delete_all_states_stree_sym(&cur_stree, sym);
421 
422 	delete_all_states_stree_stack_sym(&true_stack, sym);
423 	delete_all_states_stree_stack_sym(&true_stack, sym);
424 	delete_all_states_stree_stack_sym(&false_stack, sym);
425 	delete_all_states_stree_stack_sym(&pre_cond_stack, sym);
426 	delete_all_states_stree_stack_sym(&cond_true_stack, sym);
427 	delete_all_states_stree_stack_sym(&cond_false_stack, sym);
428 	delete_all_states_stree_stack_sym(&fake_cur_stree_stack, sym);
429 	delete_all_states_stree_stack_sym(&break_stack, sym);
430 	delete_all_states_stree_stack_sym(&fake_break_stack, sym);
431 	delete_all_states_stree_stack_sym(&switch_stack, sym);
432 	delete_all_states_stree_stack_sym(&continue_stack, sym);
433 
434 	/*
435 	 * deleting from the goto stack is problematic because we don't know
436 	 * if the label is in scope and also we need the value for --two-passes.
437 	 */
438 }
439 
440 struct stree *get_all_states_from_stree(int owner, struct stree *source)
441 {
442 	struct stree *ret = NULL;
443 	struct sm_state *tmp;
444 
445 	FOR_EACH_SM(source, tmp) {
446 		if (tmp->owner == owner)
447 			avl_insert(&ret, tmp);
448 	} END_FOR_EACH_SM(tmp);
449 
450 	return ret;
451 }
452 
453 struct stree *get_all_states_stree(int owner)
454 {
455 	return get_all_states_from_stree(owner, cur_stree);
456 }
457 
458 struct stree *__get_cur_stree(void)
459 {
460 	return cur_stree;
461 }
462 
463 int is_reachable(void)
464 {
465 	if (cur_stree)
466 		return 1;
467 	return 0;
468 }
469 
470 void set_true_false_states(int owner, const char *name, struct symbol *sym,
471 			   struct smatch_state *true_state,
472 			   struct smatch_state *false_state)
473 {
474 	if (read_only)
475 		sm_perror("cur_stree is read only.");
476 
477 	if (option_debug || strcmp(check_name(owner), option_debug_check) == 0) {
478 		struct smatch_state *tmp;
479 
480 		tmp = __get_state(owner, name, sym);
481 		sm_msg("%s [%s] '%s'.  Was %s.  Now T:%s F:%s", __func__,
482 		       check_name(owner),  name, show_state(tmp),
483 		       show_state(true_state), show_state(false_state));
484 	}
485 
486 	if (unreachable())
487 		return;
488 
489 	if (!cond_false_stack || !cond_true_stack) {
490 		sm_perror("missing true/false stacks");
491 		return;
492 	}
493 
494 	if (true_state)
495 		set_state_stree_stack(&cond_true_stack, owner, name, sym, true_state);
496 	if (false_state)
497 		set_state_stree_stack(&cond_false_stack, owner, name, sym, false_state);
498 }
499 
500 void set_true_false_states_expr(int owner, struct expression *expr,
501 			   struct smatch_state *true_state,
502 			   struct smatch_state *false_state)
503 {
504 	char *name;
505 	struct symbol *sym;
506 
507 	expr = strip_expr(expr);
508 	name = expr_to_var_sym(expr, &sym);
509 	if (!name || !sym)
510 		goto free;
511 	set_true_false_states(owner, name, sym, true_state, false_state);
512 free:
513 	free_string(name);
514 }
515 
516 void __set_true_false_sm(struct sm_state *true_sm, struct sm_state *false_sm)
517 {
518 	int owner;
519 	const char *name;
520 	struct symbol *sym;
521 
522 	if (!true_sm && !false_sm)
523 		return;
524 
525 	if (unreachable())
526 		return;
527 
528 	owner = true_sm ? true_sm->owner : false_sm->owner;
529 	name = true_sm ? true_sm->name : false_sm->name;
530 	sym = true_sm ? true_sm->sym : false_sm->sym;
531 	if (option_debug || strcmp(check_name(owner), option_debug_check) == 0) {
532 		struct smatch_state *tmp;
533 
534 		tmp = __get_state(owner, name, sym);
535 		sm_msg("%s [%s] '%s'.  Was %s.  Now T:%s F:%s", __func__,
536 		       check_name(owner),  name, show_state(tmp),
537 		       show_state(true_sm ? true_sm->state : NULL),
538 		       show_state(false_sm ? false_sm->state : NULL));
539 	}
540 
541 	if (!cond_false_stack || !cond_true_stack) {
542 		sm_perror("missing true/false stacks");
543 		return;
544 	}
545 
546 	if (true_sm)
547 		overwrite_sm_state_stree_stack(&cond_true_stack, true_sm);
548 	if (false_sm)
549 		overwrite_sm_state_stree_stack(&cond_false_stack, false_sm);
550 }
551 
552 void nullify_path(void)
553 {
554 	if (fake_cur_stree_stack) {
555 		__free_fake_cur_stree();
556 		__push_fake_cur_stree();
557 	}
558 	free_stree(&cur_stree);
559 }
560 
561 void __match_nullify_path_hook(const char *fn, struct expression *expr,
562 			       void *unused)
563 {
564 	nullify_path();
565 }
566 
567 /*
568  * At the start of every function we mark the path
569  * as unnull.  That way there is always at least one state
570  * in the cur_stree until nullify_path is called.  This
571  * is used in merge_slist() for the first null check.
572  */
573 void __unnullify_path(void)
574 {
575 	if (!cur_stree)
576 		set_state(-1, "unnull_path", NULL, &true_state);
577 }
578 
579 int __path_is_null(void)
580 {
581 	if (cur_stree)
582 		return 0;
583 	return 1;
584 }
585 
586 static void check_stree_stack_free(struct stree_stack **stack)
587 {
588 	if (*stack) {
589 		sm_perror("stack not empty");
590 		free_stack_and_strees(stack);
591 	}
592 }
593 
594 void save_all_states(void)
595 {
596 	__add_ptr_list(&backup, cur_stree, 0);
597 	cur_stree = NULL;
598 
599 	__add_ptr_list(&backup, true_stack, 0);
600 	true_stack = NULL;
601 	__add_ptr_list(&backup, false_stack, 0);
602 	false_stack = NULL;
603 	__add_ptr_list(&backup, pre_cond_stack, 0);
604 	pre_cond_stack = NULL;
605 
606 	__add_ptr_list(&backup, cond_true_stack, 0);
607 	cond_true_stack = NULL;
608 	__add_ptr_list(&backup, cond_false_stack, 0);
609 	cond_false_stack = NULL;
610 
611 	__add_ptr_list(&backup, fake_cur_stree_stack, 0);
612 	fake_cur_stree_stack = NULL;
613 
614 	__add_ptr_list(&backup, break_stack, 0);
615 	break_stack = NULL;
616 	__add_ptr_list(&backup, fake_break_stack, 0);
617 	fake_break_stack = NULL;
618 
619 	__add_ptr_list(&backup, switch_stack, 0);
620 	switch_stack = NULL;
621 	__add_ptr_list(&backup, remaining_cases, 0);
622 	remaining_cases = NULL;
623 	__add_ptr_list(&backup, default_stack, 0);
624 	default_stack = NULL;
625 	__add_ptr_list(&backup, continue_stack, 0);
626 	continue_stack = NULL;
627 
628 	__add_ptr_list(&backup, goto_stack, 0);
629 	goto_stack = NULL;
630 }
631 
632 static void *pop_backup(void)
633 {
634 	void *ret;
635 
636 	ret = last_ptr_list(backup);
637 	delete_ptr_list_last(&backup);
638 	return ret;
639 }
640 
641 void restore_all_states(void)
642 {
643 	goto_stack = pop_backup();
644 
645 	continue_stack = pop_backup();
646 	default_stack = pop_backup();
647 	remaining_cases = pop_backup();
648 	switch_stack = pop_backup();
649 	fake_break_stack = pop_backup();
650 	break_stack = pop_backup();
651 
652 	fake_cur_stree_stack = pop_backup();
653 
654 	cond_false_stack = pop_backup();
655 	cond_true_stack = pop_backup();
656 
657 	pre_cond_stack = pop_backup();
658 	false_stack = pop_backup();
659 	true_stack = pop_backup();
660 
661 	cur_stree = pop_backup();
662 }
663 
664 void free_goto_stack(void)
665 {
666 	struct named_stree *named_stree;
667 
668 	FOR_EACH_PTR(goto_stack, named_stree) {
669 		free_stree(&named_stree->stree);
670 	} END_FOR_EACH_PTR(named_stree);
671 	__free_ptr_list((struct ptr_list **)&goto_stack);
672 }
673 
674 void clear_all_states(void)
675 {
676 	nullify_path();
677 	check_stree_stack_free(&true_stack);
678 	check_stree_stack_free(&false_stack);
679 	check_stree_stack_free(&pre_cond_stack);
680 	check_stree_stack_free(&cond_true_stack);
681 	check_stree_stack_free(&cond_false_stack);
682 	check_stree_stack_free(&break_stack);
683 	check_stree_stack_free(&fake_break_stack);
684 	check_stree_stack_free(&switch_stack);
685 	check_stree_stack_free(&continue_stack);
686 	check_stree_stack_free(&fake_cur_stree_stack);
687 
688 	free_goto_stack();
689 
690 	free_every_single_sm_state();
691 	free_tmp_expressions();
692 }
693 
694 void __push_cond_stacks(void)
695 {
696 	push_stree(&cond_true_stack, NULL);
697 	push_stree(&cond_false_stack, NULL);
698 	__push_fake_cur_stree();
699 }
700 
701 void __fold_in_set_states(void)
702 {
703 	struct stree *new_states;
704 	struct sm_state *sm;
705 
706 	new_states = __pop_fake_cur_stree();
707 	FOR_EACH_SM(new_states, sm) {
708 		__set_sm(sm);
709 		__set_true_false_sm(sm, sm);
710 	} END_FOR_EACH_SM(sm);
711 	free_stree(&new_states);
712 }
713 
714 void __free_set_states(void)
715 {
716 	struct stree *new_states;
717 
718 	new_states = __pop_fake_cur_stree();
719 	free_stree(&new_states);
720 }
721 
722 struct stree *__copy_cond_true_states(void)
723 {
724 	struct stree *ret;
725 
726 	ret = pop_stree(&cond_true_stack);
727 	push_stree(&cond_true_stack, clone_stree(ret));
728 	return ret;
729 }
730 
731 struct stree *__copy_cond_false_states(void)
732 {
733 	struct stree *ret;
734 
735 	ret = pop_stree(&cond_false_stack);
736 	push_stree(&cond_false_stack, clone_stree(ret));
737 	return ret;
738 }
739 
740 struct stree *__pop_cond_true_stack(void)
741 {
742 	return pop_stree(&cond_true_stack);
743 }
744 
745 struct stree *__pop_cond_false_stack(void)
746 {
747 	return pop_stree(&cond_false_stack);
748 }
749 
750 /*
751  * This combines the pre cond states with either the true or false states.
752  * For example:
753  * a = kmalloc() ; if (a !! foo(a)
754  * In the pre state a is possibly null.  In the true state it is non null.
755  * In the false state it is null.  Combine the pre and the false to get
756  * that when we call 'foo', 'a' is null.
757  */
758 static void __use_cond_stack(struct stree_stack **stack)
759 {
760 	struct stree *stree;
761 
762 	free_stree(&cur_stree);
763 
764 	cur_stree = pop_stree(&pre_cond_stack);
765 	push_stree(&pre_cond_stack, clone_stree(cur_stree));
766 
767 	stree = pop_stree(stack);
768 	overwrite_stree(stree, &cur_stree);
769 	push_stree(stack, stree);
770 }
771 
772 void __use_pre_cond_states(void)
773 {
774 	free_stree(&cur_stree);
775 	cur_stree = pop_stree(&pre_cond_stack);
776 }
777 
778 void __use_cond_true_states(void)
779 {
780 	__use_cond_stack(&cond_true_stack);
781 }
782 
783 void __use_cond_false_states(void)
784 {
785 	__use_cond_stack(&cond_false_stack);
786 }
787 
788 void __negate_cond_stacks(void)
789 {
790 	struct stree *old_false, *old_true;
791 
792 	old_false = pop_stree(&cond_false_stack);
793 	old_true = pop_stree(&cond_true_stack);
794 	push_stree(&cond_false_stack, old_true);
795 	push_stree(&cond_true_stack, old_false);
796 }
797 
798 void __and_cond_states(void)
799 {
800 	and_stree_stack(&cond_true_stack);
801 	or_stree_stack(&pre_cond_stack, cur_stree, &cond_false_stack);
802 }
803 
804 void __or_cond_states(void)
805 {
806 	or_stree_stack(&pre_cond_stack, cur_stree, &cond_true_stack);
807 	and_stree_stack(&cond_false_stack);
808 }
809 
810 void __save_pre_cond_states(void)
811 {
812 	push_stree(&pre_cond_stack, clone_stree(cur_stree));
813 }
814 
815 void __discard_pre_cond_states(void)
816 {
817 	struct stree *tmp;
818 
819 	tmp = pop_stree(&pre_cond_stack);
820 	free_stree(&tmp);
821 }
822 
823 struct stree *__get_true_states(void)
824 {
825 	return clone_stree(top_stree(cond_true_stack));
826 }
827 
828 struct stree *__get_false_states(void)
829 {
830 	return clone_stree(top_stree(cond_false_stack));
831 }
832 
833 void __use_cond_states(void)
834 {
835 	struct stree *pre, *pre_clone, *true_states, *false_states;
836 
837 	pre = pop_stree(&pre_cond_stack);
838 	pre_clone = clone_stree(pre);
839 
840 	true_states = pop_stree(&cond_true_stack);
841 	overwrite_stree(true_states, &pre);
842 	free_stree(&true_states);
843 	/* we use the true states right away */
844 	free_stree(&cur_stree);
845 	cur_stree = pre;
846 
847 	false_states = pop_stree(&cond_false_stack);
848 	overwrite_stree(false_states, &pre_clone);
849 	free_stree(&false_states);
850 	push_stree(&false_stack, pre_clone);
851 }
852 
853 void __push_true_states(void)
854 {
855 	push_stree(&true_stack, clone_stree(cur_stree));
856 }
857 
858 void __use_false_states(void)
859 {
860 	free_stree(&cur_stree);
861 	cur_stree = pop_stree(&false_stack);
862 }
863 
864 void __discard_false_states(void)
865 {
866 	struct stree *stree;
867 
868 	stree = pop_stree(&false_stack);
869 	free_stree(&stree);
870 }
871 
872 void __merge_false_states(void)
873 {
874 	struct stree *stree;
875 
876 	stree = pop_stree(&false_stack);
877 	merge_stree(&cur_stree, stree);
878 	free_stree(&stree);
879 }
880 
881 /*
882  * This function probably seemed common sensical when I wrote it but, oh wow,
883  * does it look subtle in retrospect.  Say we set a state on one side of the if
884  * else path but not on the other, then what we should record in the fake stree
885  * is the merged state.
886  *
887  * This function relies on the fact that the we always set the cur_stree as well
888  * and we already have the infrastructure to merge things correctly into the
889  * cur_stree.
890  *
891  * So instead of merging fake strees together which is probably a lot of work,
892  * we just use it as a list of set states and look up the actual current values
893  * in the cur_stree.
894  *
895  */
896 static void update_stree_with_merged(struct stree **stree)
897 {
898 	struct state_list *slist = NULL;
899 	struct sm_state *sm, *new;
900 
901 	FOR_EACH_SM(*stree, sm) {
902 		new = get_sm_state(sm->owner, sm->name, sm->sym);
903 		if (!new)  /* This can happen if we go out of scope */
904 			continue;
905 		add_ptr_list(&slist, new);
906 	} END_FOR_EACH_SM(sm);
907 
908 	FOR_EACH_PTR(slist, sm) {
909 		overwrite_sm_state_stree(stree, sm);
910 	} END_FOR_EACH_PTR(sm);
911 
912 	free_slist(&slist);
913 }
914 
915 static void update_fake_stree_with_merged(void)
916 {
917 	struct stree *stree;
918 
919 	if (!fake_cur_stree_stack)
920 		return;
921 	stree = pop_stree(&fake_cur_stree_stack);
922 	update_stree_with_merged(&stree);
923 	push_stree(&fake_cur_stree_stack, stree);
924 }
925 
926 void __merge_true_states(void)
927 {
928 	struct stree *stree;
929 
930 	stree = pop_stree(&true_stack);
931 	merge_stree(&cur_stree, stree);
932 	update_fake_stree_with_merged();
933 	free_stree(&stree);
934 }
935 
936 void __push_continues(void)
937 {
938 	push_stree(&continue_stack, NULL);
939 }
940 
941 void __discard_continues(void)
942 {
943 	struct stree *stree;
944 
945 	stree = pop_stree(&continue_stack);
946 	free_stree(&stree);
947 }
948 
949 void __process_continues(void)
950 {
951 	struct stree *stree;
952 
953 	stree = pop_stree(&continue_stack);
954 	if (!stree)
955 		stree = clone_stree(cur_stree);
956 	else
957 		merge_stree(&stree, cur_stree);
958 
959 	push_stree(&continue_stack, stree);
960 }
961 
962 void __merge_continues(void)
963 {
964 	struct stree *stree;
965 
966 	stree = pop_stree(&continue_stack);
967 	merge_stree(&cur_stree, stree);
968 	free_stree(&stree);
969 }
970 
971 void __push_breaks(void)
972 {
973 	push_stree(&break_stack, NULL);
974 	if (fake_cur_stree_stack)
975 		push_stree(&fake_break_stack, NULL);
976 }
977 
978 void __process_breaks(void)
979 {
980 	struct stree *stree;
981 
982 	stree = pop_stree(&break_stack);
983 	if (!stree)
984 		stree = clone_stree(cur_stree);
985 	else
986 		merge_stree(&stree, cur_stree);
987 	push_stree(&break_stack, stree);
988 
989 	if (!fake_cur_stree_stack)
990 		return;
991 
992 	stree = pop_stree(&fake_break_stack);
993 	if (!stree)
994 		stree = clone_stree(top_stree(fake_cur_stree_stack));
995 	else
996 		merge_stree(&stree, top_stree(fake_cur_stree_stack));
997 	push_stree(&fake_break_stack, stree);
998 }
999 
1000 int __has_breaks(void)
1001 {
1002 	struct stree *stree;
1003 	int ret;
1004 
1005 	stree = pop_stree(&break_stack);
1006 	ret = !!stree;
1007 	push_stree(&break_stack, stree);
1008 	return ret;
1009 }
1010 
1011 void __merge_breaks(void)
1012 {
1013 	struct stree *stree;
1014 	struct sm_state *sm;
1015 
1016 	stree = pop_stree(&break_stack);
1017 	merge_stree(&cur_stree, stree);
1018 	free_stree(&stree);
1019 
1020 	if (!fake_cur_stree_stack)
1021 		return;
1022 
1023 	stree = pop_stree(&fake_break_stack);
1024 	update_stree_with_merged(&stree);
1025 	FOR_EACH_SM(stree, sm) {
1026 		overwrite_sm_state_stree_stack(&fake_cur_stree_stack, sm);
1027 	} END_FOR_EACH_SM(sm);
1028 	free_stree(&stree);
1029 }
1030 
1031 void __use_breaks(void)
1032 {
1033 	struct stree *stree;
1034 	struct sm_state *sm;
1035 
1036 	free_stree(&cur_stree);
1037 	cur_stree = pop_stree(&break_stack);
1038 
1039 	if (!fake_cur_stree_stack)
1040 		return;
1041 	stree = pop_stree(&fake_break_stack);
1042 	FOR_EACH_SM(stree, sm) {
1043 		overwrite_sm_state_stree_stack(&fake_cur_stree_stack, sm);
1044 	} END_FOR_EACH_SM(sm);
1045 	free_stree(&stree);
1046 
1047 
1048 }
1049 
1050 void __save_switch_states(struct expression *switch_expr)
1051 {
1052 	struct range_list *rl;
1053 
1054 	get_absolute_rl(switch_expr, &rl);
1055 
1056 	push_rl(&remaining_cases, rl);
1057 	push_stree(&switch_stack, clone_stree(cur_stree));
1058 }
1059 
1060 int have_remaining_cases(void)
1061 {
1062 	return !!top_rl(remaining_cases);
1063 }
1064 
1065 void __merge_switches(struct expression *switch_expr, struct range_list *case_rl)
1066 {
1067 	struct stree *stree;
1068 	struct stree *implied_stree;
1069 
1070 	stree = pop_stree(&switch_stack);
1071 	implied_stree = __implied_case_stree(switch_expr, case_rl, &remaining_cases, &stree);
1072 	merge_stree(&cur_stree, implied_stree);
1073 	free_stree(&implied_stree);
1074 	push_stree(&switch_stack, stree);
1075 }
1076 
1077 void __discard_switches(void)
1078 {
1079 	struct stree *stree;
1080 
1081 	pop_rl(&remaining_cases);
1082 	stree = pop_stree(&switch_stack);
1083 	free_stree(&stree);
1084 }
1085 
1086 void __push_default(void)
1087 {
1088 	push_stree(&default_stack, NULL);
1089 }
1090 
1091 void __set_default(void)
1092 {
1093 	set_state_stree_stack(&default_stack, 0, "has_default", NULL, &true_state);
1094 }
1095 
1096 int __pop_default(void)
1097 {
1098 	struct stree *stree;
1099 
1100 	stree = pop_stree(&default_stack);
1101 	if (stree) {
1102 		free_stree(&stree);
1103 		return 1;
1104 	}
1105 	return 0;
1106 }
1107 
1108 static struct named_stree *alloc_named_stree(const char *name, struct symbol *sym, struct stree *stree)
1109 {
1110 	struct named_stree *named_stree = __alloc_named_stree(0);
1111 
1112 	named_stree->name = (char *)name;
1113 	named_stree->stree = stree;
1114 	named_stree->sym = sym;
1115 	return named_stree;
1116 }
1117 
1118 void __save_gotos(const char *name, struct symbol *sym)
1119 {
1120 	struct stree **stree;
1121 	struct stree *clone;
1122 
1123 	stree = get_named_stree(goto_stack, name, sym);
1124 	if (stree) {
1125 		merge_stree(stree, cur_stree);
1126 		return;
1127 	} else {
1128 		struct named_stree *named_stree;
1129 
1130 		clone = clone_stree(cur_stree);
1131 		named_stree = alloc_named_stree(name, sym, clone);
1132 		add_ptr_list(&goto_stack, named_stree);
1133 	}
1134 }
1135 
1136 void __merge_gotos(const char *name, struct symbol *sym)
1137 {
1138 	struct stree **stree;
1139 
1140 	stree = get_named_stree(goto_stack, name, sym);
1141 	if (stree)
1142 		merge_stree(&cur_stree, *stree);
1143 }
1144