implied: fix a type bug
[smatch.git] / smatch_implied.c
blob0708506ac10ea3bdec811b998e3c413d0f382894
1 /*
2 * Copyright (C) 2008 Dan Carpenter.
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.
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.
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
19 * Imagine we have this code:
20 * foo = 1;
21 * if (bar)
22 * foo = 99;
23 * else
24 * frob();
25 * // <-- point #1
26 * if (foo == 99) // <-- point #2
27 * bar->baz; // <-- point #3
30 * At point #3 bar is non null and can be dereferenced.
32 * It's smatch_implied.c which sets bar to non null at point #2.
34 * At point #1 merge_slist() stores the list of states from both
35 * the true and false paths. On the true path foo == 99 and on
36 * the false path foo == 1. merge_slist() sets their pool
37 * list to show the other states which were there when foo == 99.
39 * When it comes to the if (foo == 99) the smatch implied hook
40 * looks for all the pools where foo was not 99. It makes a list
41 * of those.
43 * Then for bar (and all the other states) it says, ok bar is a
44 * merged state that came from these previous states. We'll
45 * chop out all the states where it came from a pool where
46 * foo != 99 and merge it all back together.
48 * That is the implied state of bar.
50 * merge_slist() sets up ->pool. An sm_state only has one ->pool and
51 * that is the pool where it was first set. The my pool gets set when
52 * code paths merge. States that have been set since the last merge do
53 * not have a ->pool.
54 * merge_sm_state() sets ->left and ->right. (These are the states which were
55 * merged to form the current state.)
56 * a pool: a pool is an slist that has been merged with another slist.
59 #include <sys/time.h>
60 #include <time.h>
61 #include "smatch.h"
62 #include "smatch_slist.h"
63 #include "smatch_extra.h"
65 char *implied_debug_msg;
66 #define DIMPLIED(msg...) do { if (option_debug_implied) printf(msg); } while (0)
68 int option_debug_implied = 0;
71 * tmp_range_list():
72 * It messes things up to free range list allocations. This helper fuction
73 * lets us reuse memory instead of doing new allocations.
75 static struct range_list *tmp_range_list(struct symbol *type, long long num)
77 static struct range_list *my_list = NULL;
78 static struct data_range *my_range;
80 __free_ptr_list((struct ptr_list **)&my_list);
81 my_range = alloc_range(ll_to_sval(num), ll_to_sval(num));
82 add_ptr_list(&my_list, my_range);
83 return my_list;
86 static void print_debug_tf(struct sm_state *sm, int istrue, int isfalse)
88 if (!option_debug_implied && !option_debug)
89 return;
91 if (istrue && isfalse) {
92 printf("%s: %d: does not exist.\n", show_sm(sm), sm->line);
93 } else if (istrue) {
94 printf("'%s = %s' from %d is true. %s[stree %d]\n", sm->name, show_state(sm->state),
95 sm->line, sm->merged ? "[merged]" : "[leaf]",
96 get_stree_id(sm->pool));
97 } else if (isfalse) {
98 printf("'%s = %s' from %d is false. %s[stree %d]\n", sm->name, show_state(sm->state),
99 sm->line,
100 sm->merged ? "[merged]" : "[leaf]",
101 get_stree_id(sm->pool));
102 } else {
103 printf("'%s = %s' from %d could be true or false. %s[stree %d]\n", sm->name,
104 show_state(sm->state), sm->line,
105 sm->merged ? "[merged]" : "[leaf]",
106 get_stree_id(sm->pool));
111 * add_pool() adds a slist to *pools. If the slist has already been
112 * added earlier then it doesn't get added a second time.
114 void add_pool(struct stree_stack **pools, struct stree *new)
116 struct stree *tmp;
118 FOR_EACH_PTR(*pools, tmp) {
119 if (tmp < new)
120 continue;
121 else if (tmp == new) {
122 return;
123 } else {
124 INSERT_CURRENT(new, tmp);
125 return;
127 } END_FOR_EACH_PTR(tmp);
128 add_ptr_list(pools, new);
131 static int create_fake_history(struct sm_state *sm, int comparison, struct range_list *rl)
133 struct range_list *orig_rl;
134 struct range_list *true_rl, *false_rl;
135 struct stree *true_stree, *false_stree;
136 struct sm_state *true_sm, *false_sm;
137 sval_t sval;
139 if (is_merged(sm) || sm->left || sm->right)
140 return 0;
141 if (!rl_to_sval(rl, &sval))
142 return 0;
143 if (!estate_rl(sm->state))
144 return 0;
146 orig_rl = cast_rl(rl_type(rl), estate_rl(sm->state));
147 split_comparison_rl(orig_rl, comparison, rl, &true_rl, &false_rl, NULL, NULL);
149 true_rl = rl_truncate_cast(estate_type(sm->state), true_rl);
150 false_rl = rl_truncate_cast(estate_type(sm->state), false_rl);
151 if (is_whole_rl(true_rl) || is_whole_rl(false_rl) ||
152 !true_rl || !false_rl ||
153 rl_equiv(orig_rl, true_rl) || rl_equiv(orig_rl, false_rl) ||
154 rl_equiv(estate_rl(sm->state), true_rl) || rl_equiv(estate_rl(sm->state), false_rl))
155 return 0;
157 if (rl_intersection(true_rl, false_rl)) {
158 sm_msg("internal error parsing (%s (%s) %s %s)",
159 sm->name, sm->state->name, show_special(comparison), show_rl(rl));
160 sm_msg("true_rl = %s false_rl = %s intersection = %s",
161 show_rl(true_rl), show_rl(false_rl), show_rl(rl_intersection(true_rl, false_rl)));
162 return 0;
165 if (option_debug)
166 sm_msg("fake_history: %s vs %s. %s %s %s. --> T: %s F: %s",
167 sm->name, show_rl(rl), sm->state->name, show_special(comparison), show_rl(rl),
168 show_rl(true_rl), show_rl(false_rl));
170 true_sm = clone_sm(sm);
171 false_sm = clone_sm(sm);
173 true_sm->state = alloc_estate_rl(cast_rl(estate_type(sm->state), true_rl));
174 free_slist(&true_sm->possible);
175 add_possible_sm(true_sm, true_sm);
176 false_sm->state = alloc_estate_rl(cast_rl(estate_type(sm->state), false_rl));
177 free_slist(&false_sm->possible);
178 add_possible_sm(false_sm, false_sm);
180 true_stree = clone_stree(sm->pool);
181 false_stree = clone_stree(sm->pool);
183 overwrite_sm_state_stree(&true_stree, true_sm);
184 overwrite_sm_state_stree(&false_stree, false_sm);
186 true_sm->pool = true_stree;
187 false_sm->pool = false_stree;
189 sm->merged = 1;
190 sm->left = true_sm;
191 sm->right = false_sm;
193 return 1;
197 * If 'foo' == 99 add it that pool to the true pools. If it's false, add it to
198 * the false pools. If we're not sure, then we don't add it to either.
200 static void do_compare(struct sm_state *sm, int comparison, struct range_list *rl,
201 struct stree_stack **true_stack,
202 struct stree_stack **false_stack, int *mixed, struct sm_state *gate_sm)
204 struct sm_state *s;
205 int istrue;
206 int isfalse;
207 struct range_list *var_rl;
209 if (!sm->pool)
210 return;
212 if (is_implied(sm)) {
213 s = get_sm_state_stree(sm->pool,
214 sm->owner, sm->name,
215 sm->sym);
216 } else {
217 s = sm;
220 if (!s) {
221 if (option_debug_implied || option_debug)
222 sm_msg("%s from %d, has borrowed implications.",
223 sm->name, sm->line);
224 return;
227 var_rl = cast_rl(rl_type(rl), estate_rl(s->state));
229 istrue = !possibly_false_rl(var_rl, comparison, rl);
230 isfalse = !possibly_true_rl(var_rl, comparison, rl);
232 print_debug_tf(s, istrue, isfalse);
234 /* give up if we have borrowed implications (smatch_equiv.c) */
235 if (sm->sym != gate_sm->sym ||
236 strcmp(sm->name, gate_sm->name) != 0) {
237 if (mixed)
238 *mixed = 1;
241 if (mixed && !*mixed && !is_merged(sm) && !istrue && !isfalse) {
242 if (!create_fake_history(sm, comparison, rl)) {
243 if (mixed)
244 *mixed = 1;
248 if (istrue)
249 add_pool(true_stack, s->pool);
251 if (isfalse)
252 add_pool(false_stack, s->pool);
255 static int pool_in_pools(struct stree *pool,
256 const struct stree_stack *pools)
258 struct stree *tmp;
260 FOR_EACH_PTR(pools, tmp) {
261 if (tmp == pool)
262 return 1;
263 if (tmp > pool)
264 return 0;
265 } END_FOR_EACH_PTR(tmp);
266 return 0;
269 static int is_checked(struct state_list *checked, struct sm_state *sm)
271 struct sm_state *tmp;
273 FOR_EACH_PTR(checked, tmp) {
274 if (tmp == sm)
275 return 1;
276 } END_FOR_EACH_PTR(tmp);
277 return 0;
281 * separate_pools():
282 * Example code: if (foo == 99) {
284 * Say 'foo' is a merged state that has many possible values. It is the combination
285 * of merges. separate_pools() iterates through the pools recursively and calls
286 * do_compare() for each time 'foo' was set.
288 static void __separate_pools(struct sm_state *sm, int comparison, struct range_list *rl,
289 struct stree_stack **true_stack,
290 struct stree_stack **false_stack,
291 struct state_list **checked, int *mixed, struct sm_state *gate_sm)
293 int free_checked = 0;
294 struct state_list *checked_states = NULL;
296 if (!sm)
297 return;
300 * If it looks like this is going to take too long as-is, then don't
301 * create even more fake history.
303 if (mixed && sm->nr_children > 100)
304 *mixed = 1;
307 Sometimes the implications are just too big to deal with
308 so we bail. Theoretically, bailing out here can cause more false
309 positives but won't hide actual bugs.
311 if (sm->nr_children > 4000) {
312 if (option_debug || option_debug_implied) {
313 static char buf[1028];
314 snprintf(buf, sizeof(buf), "debug: %s: nr_children over 4000 (%d). (%s %s)",
315 __func__, sm->nr_children, sm->name, show_state(sm->state));
316 implied_debug_msg = buf;
318 return;
321 if (checked == NULL) {
322 checked = &checked_states;
323 free_checked = 1;
325 if (is_checked(*checked, sm))
326 return;
327 add_ptr_list(checked, sm);
329 do_compare(sm, comparison, rl, true_stack, false_stack, mixed, gate_sm);
331 __separate_pools(sm->left, comparison, rl, true_stack, false_stack, checked, mixed, gate_sm);
332 __separate_pools(sm->right, comparison, rl, true_stack, false_stack, checked, mixed, gate_sm);
333 if (free_checked)
334 free_slist(checked);
337 static void separate_pools(struct sm_state *sm, int comparison, struct range_list *rl,
338 struct stree_stack **true_stack,
339 struct stree_stack **false_stack,
340 struct state_list **checked, int *mixed)
342 __separate_pools(sm, comparison, rl, true_stack, false_stack, checked, mixed, sm);
345 struct sm_state *filter_pools(struct sm_state *sm,
346 const struct stree_stack *remove_stack,
347 const struct stree_stack *keep_stack,
348 int *modified)
350 struct sm_state *ret = NULL;
351 struct sm_state *left;
352 struct sm_state *right;
353 int removed = 0;
355 if (!sm)
356 return NULL;
358 if (sm->nr_children > 4000) {
359 if (option_debug || option_debug_implied) {
360 static char buf[1028];
361 snprintf(buf, sizeof(buf), "debug: %s: nr_children over 4000 (%d). (%s %s)",
362 __func__, sm->nr_children, sm->name, show_state(sm->state));
363 implied_debug_msg = buf;
365 return NULL;
368 if (pool_in_pools(sm->pool, remove_stack)) {
369 DIMPLIED("removed %s from %d [stree %d]\n", show_sm(sm), sm->line, get_stree_id(sm->pool));
370 *modified = 1;
371 return NULL;
374 if (!is_merged(sm) || pool_in_pools(sm->pool, keep_stack)) {
375 DIMPLIED("kept %s from %d [stree %d]\n", show_sm(sm), sm->line, get_stree_id(sm->pool));
376 return sm;
379 DIMPLIED("checking %s from %d (%d) [stree %d] left = %s [stree %d] right = %s [stree %d]\n",
380 show_sm(sm), sm->line, sm->nr_children, get_stree_id(sm->pool),
381 sm->left ? show_sm(sm->left) : "<none>", sm->left ? get_stree_id(sm->left->pool) : -1,
382 sm->right ? show_sm(sm->right) : "<none>", sm->right ? get_stree_id(sm->right->pool) : -1);
383 left = filter_pools(sm->left, remove_stack, keep_stack, &removed);
384 right = filter_pools(sm->right, remove_stack, keep_stack, &removed);
385 if (!removed) {
386 DIMPLIED("kept %s from %d [stree %d]\n", show_sm(sm), sm->line, get_stree_id(sm->pool));
387 return sm;
389 *modified = 1;
390 if (!left && !right) {
391 DIMPLIED("removed %s from %d <none> [stree %d]\n", show_sm(sm), sm->line, get_stree_id(sm->pool));
392 return NULL;
395 if (!left) {
396 ret = clone_sm(right);
397 ret->merged = 1;
398 ret->right = right;
399 ret->left = NULL;
400 } else if (!right) {
401 ret = clone_sm(left);
402 ret->merged = 1;
403 ret->left = left;
404 ret->right = NULL;
405 } else {
406 ret = merge_sm_states(left, right);
409 ret->pool = sm->pool;
411 ret->implied = 1;
412 DIMPLIED("partial %s => ", show_sm(sm));
413 DIMPLIED("%s from %d [stree %d]\n", show_sm(ret), sm->line, get_stree_id(sm->pool));
414 return ret;
417 static int highest_stree_id(struct sm_state *sm)
419 int left = 0;
420 int right = 0;
422 if (!sm->left && !sm->right)
423 return 0;
425 if (sm->left)
426 left = get_stree_id(sm->left->pool);
427 if (sm->right)
428 right = get_stree_id(sm->right->pool);
430 if (right > left)
431 return right;
432 return left;
435 static struct stree *filter_stack(struct sm_state *gate_sm,
436 struct stree *pre_stree,
437 const struct stree_stack *remove_stack,
438 const struct stree_stack *keep_stack)
440 struct stree *ret = NULL;
441 struct sm_state *tmp;
442 struct sm_state *filtered_sm;
443 int modified;
445 if (!remove_stack)
446 return NULL;
448 FOR_EACH_SM(pre_stree, tmp) {
449 if (!tmp->merged)
450 continue;
451 if (highest_stree_id(tmp) < highest_stree_id(gate_sm)) {
452 DIMPLIED("skipping %s. set before. %d vs %d\n",
453 tmp->name, highest_stree_id(tmp),
454 highest_stree_id(gate_sm));
455 continue;
457 modified = 0;
458 filtered_sm = filter_pools(tmp, remove_stack, keep_stack, &modified);
459 if (filtered_sm && modified) {
460 /* the assignments here are for borrowed implications */
461 filtered_sm->name = tmp->name;
462 filtered_sm->sym = tmp->sym;
463 avl_insert(&ret, filtered_sm);
464 if (out_of_memory())
465 return NULL;
468 } END_FOR_EACH_SM(tmp);
469 return ret;
472 static void separate_and_filter(struct sm_state *sm, int comparison, struct range_list *rl,
473 struct stree *pre_stree,
474 struct stree **true_states,
475 struct stree **false_states,
476 int *mixed)
478 struct stree_stack *true_stack = NULL;
479 struct stree_stack *false_stack = NULL;
480 struct timeval time_before;
481 struct timeval time_after;
483 gettimeofday(&time_before, NULL);
485 if (!is_merged(sm)) {
486 DIMPLIED("%d '%s' is not merged.\n", get_lineno(), sm->name);
487 return;
490 if (option_debug_implied || option_debug) {
491 sm_msg("checking implications: (%s %s %s)",
492 sm->name, show_special(comparison), show_rl(rl));
495 separate_pools(sm, comparison, rl, &true_stack, &false_stack, NULL, mixed);
497 DIMPLIED("filtering true stack.\n");
498 *true_states = filter_stack(sm, pre_stree, false_stack, true_stack);
499 DIMPLIED("filtering false stack.\n");
500 *false_states = filter_stack(sm, pre_stree, true_stack, false_stack);
501 free_stree_stack(&true_stack);
502 free_stree_stack(&false_stack);
503 if (option_debug_implied || option_debug) {
504 printf("These are the implied states for the true path:\n");
505 __print_stree(*true_states);
506 printf("These are the implied states for the false path:\n");
507 __print_stree(*false_states);
510 gettimeofday(&time_after, NULL);
511 if (time_after.tv_sec - time_before.tv_sec > 7)
512 __bail_on_rest_of_function = 1;
515 static struct expression *get_left_most_expr(struct expression *expr)
517 expr = strip_parens(expr);
518 if (expr->type == EXPR_ASSIGNMENT)
519 return get_left_most_expr(expr->left);
520 return expr;
523 static int is_merged_expr(struct expression *expr)
525 struct sm_state *sm;
526 sval_t dummy;
528 if (get_value(expr, &dummy))
529 return 0;
530 sm = get_sm_state_expr(SMATCH_EXTRA, expr);
531 if (!sm)
532 return 0;
533 if (is_merged(sm))
534 return 1;
535 return 0;
538 static void delete_gate_sm_equiv(struct stree **stree, const char *name, struct symbol *sym)
540 struct smatch_state *state;
541 struct relation *rel;
543 state = get_state(SMATCH_EXTRA, name, sym);
544 if (!state)
545 return;
546 FOR_EACH_PTR(estate_related(state), rel) {
547 delete_state_stree(stree, SMATCH_EXTRA, rel->name, rel->sym);
548 } END_FOR_EACH_PTR(rel);
551 static void delete_gate_sm(struct stree **stree, const char *name, struct symbol *sym)
553 delete_state_stree(stree, SMATCH_EXTRA, name, sym);
556 static int handle_comparison(struct expression *expr,
557 struct stree **implied_true,
558 struct stree **implied_false)
560 struct sm_state *sm = NULL;
561 struct range_list *rl = NULL;
562 struct expression *left;
563 struct expression *right;
564 struct symbol *type;
565 int comparison = expr->op;
566 int mixed = 0;
568 left = get_left_most_expr(expr->left);
569 right = get_left_most_expr(expr->right);
571 if (is_merged_expr(left)) {
572 sm = get_sm_state_expr(SMATCH_EXTRA, left);
573 get_implied_rl(right, &rl);
574 } else if (is_merged_expr(right)) {
575 sm = get_sm_state_expr(SMATCH_EXTRA, right);
576 get_implied_rl(left, &rl);
577 comparison = flip_comparison(comparison);
580 if (!rl || !sm) {
581 free_rl(&rl);
582 return 0;
585 type = get_type(expr);
586 if (!type)
587 return 0;
588 if (type_positive_bits(rl_type(rl)) > type_positive_bits(type))
589 type = rl_type(rl);
590 if (type_positive_bits(type) < 31)
591 type = &int_ctype;
592 rl = cast_rl(type, rl);
594 separate_and_filter(sm, comparison, rl, __get_cur_stree(), implied_true, implied_false, &mixed);
595 free_rl(&rl);
597 delete_gate_sm_equiv(implied_true, sm->name, sm->sym);
598 delete_gate_sm_equiv(implied_false, sm->name, sm->sym);
599 if (mixed) {
600 delete_gate_sm(implied_true, sm->name, sm->sym);
601 delete_gate_sm(implied_false, sm->name, sm->sym);
604 return 1;
607 static int handle_zero_comparison(struct expression *expr,
608 struct stree **implied_true,
609 struct stree **implied_false)
611 struct symbol *sym;
612 char *name;
613 struct sm_state *sm;
614 int mixed = 0;
615 int ret = 0;
617 if (expr->type == EXPR_POSTOP)
618 expr = strip_expr(expr->unop);
620 if (expr->type == EXPR_ASSIGNMENT) {
621 /* most of the time ->pools will be empty here because we
622 just set the state, but if have assigned a conditional
623 function there are implications. */
624 expr = expr->left;
627 name = expr_to_var_sym(expr, &sym);
628 if (!name || !sym)
629 goto free;
630 sm = get_sm_state(SMATCH_EXTRA, name, sym);
631 if (!sm)
632 goto free;
634 separate_and_filter(sm, SPECIAL_NOTEQUAL, tmp_range_list(estate_type(sm->state), 0), __get_cur_stree(), implied_true, implied_false, &mixed);
635 delete_gate_sm_equiv(implied_true, sm->name, sm->sym);
636 delete_gate_sm_equiv(implied_false, sm->name, sm->sym);
637 if (mixed) {
638 delete_gate_sm(implied_true, sm->name, sm->sym);
639 delete_gate_sm(implied_false, sm->name, sm->sym);
642 ret = 1;
643 free:
644 free_string(name);
645 return ret;
648 static int handled_by_implied_hook(struct expression *expr,
649 struct stree **implied_true,
650 struct stree **implied_false)
652 struct stree_stack *true_stack = NULL;
653 struct stree_stack *false_stack = NULL;
654 struct stree *pre_stree;
655 struct sm_state *sm;
657 sm = comparison_implication_hook(expr, &true_stack, &false_stack);
658 if (!sm)
659 return 0;
661 pre_stree = clone_stree(__get_cur_stree());
663 *implied_true = filter_stack(sm, pre_stree, false_stack, true_stack);
664 *implied_false = filter_stack(sm, pre_stree, true_stack, false_stack);
666 free_stree(&pre_stree);
667 free_stree_stack(&true_stack);
668 free_stree_stack(&false_stack);
670 return 1;
673 static int handled_by_extra_states(struct expression *expr,
674 struct stree **implied_true,
675 struct stree **implied_false)
677 if (expr->type == EXPR_COMPARE)
678 return handle_comparison(expr, implied_true, implied_false);
679 else
680 return handle_zero_comparison(expr, implied_true, implied_false);
683 static int handled_by_stored_conditions(struct expression *expr,
684 struct stree **implied_true,
685 struct stree **implied_false)
687 struct stree_stack *true_stack = NULL;
688 struct stree_stack *false_stack = NULL;
689 struct stree *pre_stree;
690 struct sm_state *sm;
692 sm = stored_condition_implication_hook(expr, &true_stack, &false_stack);
693 if (!sm)
694 return 0;
696 pre_stree = clone_stree(__get_cur_stree());
698 *implied_true = filter_stack(sm, pre_stree, false_stack, true_stack);
699 *implied_false = filter_stack(sm, pre_stree, true_stack, false_stack);
701 free_stree(&pre_stree);
702 free_stree_stack(&true_stack);
703 free_stree_stack(&false_stack);
705 return 1;
708 static int found_implications;
709 static struct stree *saved_implied_true;
710 static struct stree *saved_implied_false;
711 static struct stree *extra_saved_implied_true;
712 static struct stree *extra_saved_implied_false;
714 static void get_tf_states(struct expression *expr,
715 struct stree **implied_true,
716 struct stree **implied_false)
718 if (handled_by_implied_hook(expr, implied_true, implied_false))
719 goto found;
721 if (handled_by_extra_states(expr, implied_true, implied_false)) {
722 /* We process these later. */
723 extra_saved_implied_true = *implied_true;
724 extra_saved_implied_false = *implied_false;
725 *implied_true = NULL;
726 *implied_false = NULL;
727 goto found;
730 if (handled_by_stored_conditions(expr, implied_true, implied_false))
731 goto found;
733 return;
734 found:
735 found_implications = 1;
738 static void save_implications_hook(struct expression *expr)
740 get_tf_states(expr, &saved_implied_true, &saved_implied_false);
743 static void set_implied_states(struct expression *expr)
745 struct sm_state *sm;
747 FOR_EACH_SM(saved_implied_true, sm) {
748 __set_true_false_sm(sm, NULL);
749 } END_FOR_EACH_SM(sm);
750 free_stree(&saved_implied_true);
752 FOR_EACH_SM(saved_implied_false, sm) {
753 __set_true_false_sm(NULL, sm);
754 } END_FOR_EACH_SM(sm);
755 free_stree(&saved_implied_false);
758 static void set_extra_implied_states(struct expression *expr)
760 saved_implied_true = extra_saved_implied_true;
761 saved_implied_false = extra_saved_implied_false;
762 extra_saved_implied_true = NULL;
763 extra_saved_implied_false = NULL;
764 set_implied_states(NULL);
767 void param_limit_implications(struct expression *expr, int param, char *key, char *value)
769 struct expression *arg;
770 struct symbol *compare_type;
771 char *name;
772 struct symbol *sym;
773 struct sm_state *sm;
774 struct sm_state *tmp;
775 struct stree *implied_true = NULL;
776 struct stree *implied_false = NULL;
777 struct range_list *orig, *limit, *rl;
779 while (expr->type == EXPR_ASSIGNMENT)
780 expr = strip_expr(expr->right);
781 if (expr->type != EXPR_CALL)
782 return;
784 arg = get_argument_from_call_expr(expr->args, param);
785 if (!arg)
786 return;
788 name = get_variable_from_key(arg, key, &sym);
789 if (!name || !sym)
790 goto free;
792 sm = get_sm_state(SMATCH_EXTRA, name, sym);
793 if (!sm || !sm->merged)
794 goto free;
796 if (strcmp(key, "$") == 0)
797 compare_type = get_arg_type(expr->fn, param);
798 else
799 compare_type = get_member_type_from_key(arg, key);
801 orig = estate_rl(sm->state);
802 orig = cast_rl(compare_type, orig);
804 call_results_to_rl(expr, compare_type, value, &limit);
805 rl = rl_intersection(orig, limit);
807 separate_and_filter(sm, SPECIAL_EQUAL, rl, __get_cur_stree(), &implied_true, &implied_false, NULL);
809 FOR_EACH_SM(implied_true, tmp) {
810 __set_sm_fake_stree(tmp);
811 } END_FOR_EACH_SM(tmp);
813 free_stree(&implied_true);
814 free_stree(&implied_false);
815 free:
816 free_string(name);
819 struct stree *__implied_case_stree(struct expression *switch_expr,
820 struct range_list *rl,
821 struct range_list_stack **remaining_cases,
822 struct stree **raw_stree)
824 char *name;
825 struct symbol *sym;
826 struct sm_state *sm;
827 struct stree *true_states = NULL;
828 struct stree *false_states = NULL;
829 struct stree *extra_states;
830 struct stree *ret = clone_stree(*raw_stree);
832 name = expr_to_var_sym(switch_expr, &sym);
833 if (!name || !sym)
834 goto free;
836 if (rl)
837 filter_top_rl(remaining_cases, rl);
838 else
839 rl = clone_rl(top_rl(*remaining_cases));
841 sm = get_sm_state_stree(*raw_stree, SMATCH_EXTRA, name, sym);
842 if (sm)
843 separate_and_filter(sm, SPECIAL_EQUAL, rl, *raw_stree, &true_states, &false_states, NULL);
845 __push_fake_cur_stree();
846 __unnullify_path();
847 set_extra_nomod(name, sym, alloc_estate_rl(rl));
848 extra_states = __pop_fake_cur_stree();
849 overwrite_stree(extra_states, &true_states);
850 overwrite_stree(true_states, &ret);
851 free_stree(&extra_states);
852 free_stree(&true_states);
853 free_stree(&false_states);
854 free:
855 free_string(name);
856 return ret;
859 static void match_end_func(struct symbol *sym)
861 if (__inline_fn)
862 return;
863 implied_debug_msg = NULL;
866 static int sm_state_in_slist(struct sm_state *sm, struct state_list *slist)
868 struct sm_state *tmp;
870 FOR_EACH_PTR(slist, tmp) {
871 if (tmp == sm)
872 return 1;
873 } END_FOR_EACH_PTR(tmp);
874 return 0;
878 * The situation is we have a SMATCH_EXTRA state and we want to break it into
879 * each of the ->possible states and find the implications of each. The caller
880 * has to use __push_fake_cur_stree() to preserve the correct states so they
881 * can be restored later.
883 void overwrite_states_using_pool(struct sm_state *sm)
885 struct sm_state *old;
886 struct sm_state *new;
888 if (!sm->pool)
889 return;
891 FOR_EACH_SM(sm->pool, old) {
892 new = get_sm_state(old->owner, old->name, old->sym);
893 if (!new) /* the variable went out of scope */
894 continue;
895 if (sm_state_in_slist(old, new->possible))
896 set_state(old->owner, old->name, old->sym, old->state);
897 } END_FOR_EACH_SM(old);
900 int assume(struct expression *expr)
902 int orig_final_pass = final_pass;
904 final_pass = 0;
905 __push_fake_cur_stree();
906 found_implications = 0;
907 __split_whole_condition(expr);
908 final_pass = orig_final_pass;
910 if (!found_implications) {
911 __discard_false_states();
912 __free_fake_cur_stree();
913 return 0;
916 return 1;
919 void end_assume(void)
921 __discard_false_states();
922 __free_fake_cur_stree();
925 void __extra_match_condition(struct expression *expr);
926 void __comparison_match_condition(struct expression *expr);
927 void __stored_condition(struct expression *expr);
928 void register_implications(int id)
930 add_hook(&save_implications_hook, CONDITION_HOOK);
931 add_hook(&set_implied_states, CONDITION_HOOK);
932 add_hook(&__extra_match_condition, CONDITION_HOOK);
933 add_hook(&set_extra_implied_states, CONDITION_HOOK);
934 add_hook(&__comparison_match_condition, CONDITION_HOOK);
935 add_hook(&__stored_condition, CONDITION_HOOK);
936 add_hook(&match_end_func, END_FUNC_HOOK);