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:
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
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
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.
61 #include "smatch_slist.h"
62 #include "smatch_extra.h"
64 char *implied_debug_msg
;
65 static char *ignore_implications
;
67 bool implications_off
;
72 #define DIMPLIED(msg...) do { if (full_debug) printf(msg); } while (0)
74 bool debug_implied(void)
76 return option_debug
|| implied_debug
|| full_debug
;
79 void turn_off_implications(int id
)
81 ignore_implications
[id
] = true;
84 static bool implications_turned_off(int owner
)
86 if (owner
>= 0 && owner
< num_checks
)
87 return ignore_implications
[owner
];
93 * It messes things up to free range list allocations. This helper function
94 * lets us reuse memory instead of doing new allocations.
96 static struct range_list
*tmp_range_list(struct symbol
*type
, long long num
)
98 static struct range_list
*my_list
= NULL
;
99 static struct data_range
*my_range
;
101 __free_ptr_list((struct ptr_list
**)&my_list
);
102 my_range
= alloc_range(ll_to_sval(num
), ll_to_sval(num
));
103 add_ptr_list(&my_list
, my_range
);
107 static const char *show_comparison(int op
)
109 if (op
== PARAM_LIMIT
)
111 return show_special(op
);
114 static void print_debug_tf(struct sm_state
*sm
, int istrue
, int isfalse
)
116 if (!full_debug
&& !option_debug
)
119 if (istrue
&& isfalse
) {
120 printf("%s: %d: does not exist.\n", show_sm(sm
), sm
->line
);
122 printf("'%s = %s' from %d is true. %s[stree %d]\n", sm
->name
, show_state(sm
->state
),
123 sm
->line
, is_leaf(sm
) ? "[leaf]" : "[merged]",
124 get_stree_id(sm
->pool
));
125 } else if (isfalse
) {
126 printf("'%s = %s' from %d is false. %s[stree %d]\n", sm
->name
, show_state(sm
->state
),
128 is_leaf(sm
) ? "[leaf]" : "[merged]",
129 get_stree_id(sm
->pool
));
131 printf("'%s = %s' from %d could be true or false. %s[stree %d]\n", sm
->name
,
132 show_state(sm
->state
), sm
->line
,
133 is_leaf(sm
) ? "[leaf]" : "[merged]",
134 get_stree_id(sm
->pool
));
138 void split_comparison_helper(struct range_list
*left_orig
, int op
, struct range_list
*right_orig
,
139 struct range_list
**left_true_rl
, struct range_list
**left_false_rl
)
141 if (op
== PARAM_LIMIT
) {
142 *left_true_rl
= rl_intersection(left_orig
, right_orig
);
143 *left_false_rl
= rl_filter(left_orig
, right_orig
);
147 split_comparison_rl(left_orig
, op
, right_orig
, left_true_rl
, left_false_rl
, NULL
, NULL
);
150 static int create_fake_history(struct sm_state
*sm
, int comparison
, struct range_list
*rl
)
152 struct range_list
*orig_rl
;
153 struct range_list
*true_rl
, *false_rl
;
154 struct stree
*true_stree
, *false_stree
;
155 struct sm_state
*true_sm
, *false_sm
;
158 if (is_merged(sm
) || sm
->left
|| sm
->right
)
160 if (comparison
!= PARAM_LIMIT
&& !rl_to_sval(rl
, &sval
))
162 if (!estate_rl(sm
->state
))
165 orig_rl
= cast_rl(rl_type(rl
), estate_rl(sm
->state
));
166 split_comparison_helper(orig_rl
, comparison
, rl
, &true_rl
, &false_rl
);
168 true_rl
= rl_truncate_cast(estate_type(sm
->state
), true_rl
);
169 false_rl
= rl_truncate_cast(estate_type(sm
->state
), false_rl
);
170 if (is_whole_rl(true_rl
) || is_whole_rl(false_rl
) ||
171 !true_rl
|| !false_rl
||
172 rl_equiv(orig_rl
, true_rl
) || rl_equiv(orig_rl
, false_rl
) ||
173 rl_equiv(estate_rl(sm
->state
), true_rl
) || rl_equiv(estate_rl(sm
->state
), false_rl
))
176 if (rl_intersection(true_rl
, false_rl
)) {
178 * Normally these won't intersect, but one exception is when
179 * we're dealing with mtags. We have a long list of mtags and
180 * then negate the list. Now it's over the limit for mtag list
181 * length and we squash it down to 4096-ptr_max. So then it's
182 * possible for the true and false rl to overlap.
188 sm_msg("fake_history: %s vs %s. %s %s %s. --> T: %s F: %s",
189 sm
->name
, show_rl(rl
), sm
->state
->name
, show_comparison(comparison
), show_rl(rl
),
190 show_rl(true_rl
), show_rl(false_rl
));
192 true_sm
= clone_sm(sm
);
193 false_sm
= clone_sm(sm
);
195 true_sm
->state
= clone_partial_estate(sm
->state
, true_rl
);
196 free_slist(&true_sm
->possible
);
197 add_possible_sm(true_sm
, true_sm
);
198 false_sm
->state
= clone_partial_estate(sm
->state
, false_rl
);
199 free_slist(&false_sm
->possible
);
200 add_possible_sm(false_sm
, false_sm
);
202 true_stree
= clone_stree(sm
->pool
);
203 false_stree
= clone_stree(sm
->pool
);
205 overwrite_sm_state_stree(&true_stree
, true_sm
);
206 overwrite_sm_state_stree(&false_stree
, false_sm
);
208 true_sm
->pool
= true_stree
;
209 false_sm
->pool
= false_stree
;
214 sm
->right
= false_sm
;
220 * add_pool() adds a slist to *pools. If the slist has already been
221 * added earlier then it doesn't get added a second time.
223 void add_pool(struct state_list
**pools
, struct sm_state
*new)
225 struct sm_state
*tmp
;
227 FOR_EACH_PTR(*pools
, tmp
) {
228 if (tmp
->pool
< new->pool
)
230 else if (tmp
->pool
== new->pool
) {
233 INSERT_CURRENT(new, tmp
);
236 } END_FOR_EACH_PTR(tmp
);
237 add_ptr_list(pools
, new);
240 static int pool_in_pools(struct stree
*pool
,
241 const struct state_list
*slist
)
243 struct sm_state
*tmp
;
245 FOR_EACH_PTR(slist
, tmp
) {
248 if (tmp
->pool
== pool
)
250 } END_FOR_EACH_PTR(tmp
);
254 static int remove_pool(struct state_list
**pools
, struct stree
*remove
)
256 struct sm_state
*tmp
;
259 FOR_EACH_PTR(*pools
, tmp
) {
260 if (tmp
->pool
== remove
) {
261 DELETE_CURRENT_PTR(tmp
);
264 } END_FOR_EACH_PTR(tmp
);
269 static bool possibly_true_helper(struct range_list
*var_rl
, int comparison
, struct range_list
*rl
)
271 if (comparison
== PARAM_LIMIT
) {
272 struct range_list
*intersect
;
274 intersect
= rl_intersection(var_rl
, rl
);
279 return possibly_true_rl(var_rl
, comparison
, rl
);
282 static bool possibly_false_helper(struct range_list
*var_rl
, int comparison
, struct range_list
*rl
)
284 if (comparison
== PARAM_LIMIT
) {
285 struct range_list
*intersect
;
287 intersect
= rl_intersection(var_rl
, rl
);
288 /* if it's not equiv then it's possibly false */
289 return !rl_equiv(var_rl
, intersect
);
291 return possibly_false_rl(var_rl
, comparison
, rl
);
295 * If 'foo' == 99 add it that pool to the true pools. If it's false, add it to
296 * the false pools. If we're not sure, then we don't add it to either.
298 static void do_compare(struct sm_state
*sm
, int comparison
, struct range_list
*rl
,
299 struct state_list
**true_stack
,
300 struct state_list
**maybe_stack
,
301 struct state_list
**false_stack
,
302 int *mixed
, struct sm_state
*gate_sm
)
306 struct range_list
*var_rl
;
311 var_rl
= cast_rl(rl_type(rl
), estate_rl(sm
->state
));
313 istrue
= !possibly_false_helper(var_rl
, comparison
, rl
);
314 isfalse
= !possibly_true_helper(var_rl
, comparison
, rl
);
316 print_debug_tf(sm
, istrue
, isfalse
);
318 /* give up if we have borrowed implications (smatch_equiv.c) */
319 if (sm
->sym
!= gate_sm
->sym
||
320 strcmp(sm
->name
, gate_sm
->name
) != 0) {
325 if (mixed
&& !*mixed
&& !is_merged(sm
) && !istrue
&& !isfalse
) {
326 if (!create_fake_history(sm
, comparison
, rl
))
331 add_pool(true_stack
, sm
);
333 add_pool(false_stack
, sm
);
335 add_pool(maybe_stack
, sm
);
338 static int is_checked(struct state_list
*checked
, struct sm_state
*sm
)
340 struct sm_state
*tmp
;
342 FOR_EACH_PTR(checked
, tmp
) {
345 } END_FOR_EACH_PTR(tmp
);
351 * Example code: if (foo == 99) {
353 * Say 'foo' is a merged state that has many possible values. It is the combination
354 * of merges. separate_pools() iterates through the pools recursively and calls
355 * do_compare() for each time 'foo' was set.
357 static void __separate_pools(struct sm_state
*sm
, int comparison
, struct range_list
*rl
,
358 struct state_list
**true_stack
,
359 struct state_list
**maybe_stack
,
360 struct state_list
**false_stack
,
361 struct state_list
**checked
, int *mixed
, struct sm_state
*gate_sm
,
362 struct timeval
*start_time
)
364 int free_checked
= 0;
365 struct state_list
*checked_states
= NULL
;
366 struct timeval now
, diff
;
371 gettimeofday(&now
, NULL
);
372 timersub(&now
, start_time
, &diff
);
373 if (diff
.tv_sec
>= 1) {
375 sm_msg("debug: %s: implications taking too long. (%s %s %s)",
376 __func__
, sm
->state
->name
, show_comparison(comparison
), show_rl(rl
));
382 if (checked
== NULL
) {
383 checked
= &checked_states
;
386 if (is_checked(*checked
, sm
))
388 add_ptr_list(checked
, sm
);
390 do_compare(sm
, comparison
, rl
, true_stack
, maybe_stack
, false_stack
, mixed
, gate_sm
);
392 __separate_pools(sm
->left
, comparison
, rl
, true_stack
, maybe_stack
, false_stack
, checked
, mixed
, gate_sm
, start_time
);
393 __separate_pools(sm
->right
, comparison
, rl
, true_stack
, maybe_stack
, false_stack
, checked
, mixed
, gate_sm
, start_time
);
398 static void separate_pools(struct sm_state
*sm
, int comparison
, struct range_list
*rl
,
399 struct state_list
**true_stack
,
400 struct state_list
**false_stack
,
401 struct state_list
**checked
, int *mixed
)
403 struct state_list
*maybe_stack
= NULL
;
404 struct sm_state
*tmp
;
405 struct timeval start_time
;
408 gettimeofday(&start_time
, NULL
);
409 __separate_pools(sm
, comparison
, rl
, true_stack
, &maybe_stack
, false_stack
, checked
, mixed
, sm
, &start_time
);
414 FOR_EACH_PTR(*true_stack
, sm
) {
415 sm_msg("TRUE %s [stree %d %p]", show_sm(sm
), get_stree_id(sm
->pool
), sm
->pool
);
416 } END_FOR_EACH_PTR(sm
);
418 FOR_EACH_PTR(maybe_stack
, sm
) {
419 sm_msg("MAYBE %s %s[stree %d %p]",
420 show_sm(sm
), sm
->merged
? "(merged) ": "", get_stree_id(sm
->pool
), sm
->pool
);
421 } END_FOR_EACH_PTR(sm
);
423 FOR_EACH_PTR(*false_stack
, sm
) {
424 sm_msg("FALSE %s [stree %d %p]", show_sm(sm
), get_stree_id(sm
->pool
), sm
->pool
);
425 } END_FOR_EACH_PTR(sm
);
427 /* if it's a maybe then remove it */
428 FOR_EACH_PTR(maybe_stack
, tmp
) {
429 remove_pool(false_stack
, tmp
->pool
);
430 remove_pool(true_stack
, tmp
->pool
);
431 } END_FOR_EACH_PTR(tmp
);
433 /* if it's both true and false remove it from both */
434 FOR_EACH_PTR(*true_stack
, tmp
) {
435 if (remove_pool(false_stack
, tmp
->pool
))
436 DELETE_CURRENT_PTR(tmp
);
437 } END_FOR_EACH_PTR(tmp
);
440 static int sm_in_keep_leafs(struct sm_state
*sm
, const struct state_list
*keep_gates
)
442 struct sm_state
*tmp
, *old
;
444 FOR_EACH_PTR(keep_gates
, tmp
) {
447 old
= get_sm_state_stree(tmp
->pool
, sm
->owner
, sm
->name
, sm
->sym
);
452 } END_FOR_EACH_PTR(tmp
);
456 static int going_too_slow(void)
458 static void *printed
;
460 if (out_of_memory()) {
461 implications_off
= true;
465 if (time_parsing_function() < 60) {
466 implications_off
= false;
470 if (!__inline_fn
&& printed
!= cur_func_sym
) {
471 sm_perror("turning off implications after 60 seconds");
472 printed
= cur_func_sym
;
474 implications_off
= true;
478 static char *sm_state_info(struct sm_state
*sm
)
480 static char buf
[512];
483 n
+= snprintf(buf
+ n
, sizeof(buf
) - n
, "[stree %d line %d] ",
484 get_stree_id(sm
->pool
), sm
->line
);
485 if (n
>= sizeof(buf
))
487 n
+= snprintf(buf
+ n
, sizeof(buf
) - n
, "%s ", show_sm(sm
));
488 if (n
>= sizeof(buf
))
490 n
+= snprintf(buf
+ n
, sizeof(buf
) - n
, "left = %s [stree %d] ",
491 sm
->left
? sm
->left
->state
->name
: "<none>",
492 sm
->left
? get_stree_id(sm
->left
->pool
) : -1);
493 if (n
>= sizeof(buf
))
495 n
+= snprintf(buf
+ n
, sizeof(buf
) - n
, "right = %s [stree %d]",
496 sm
->right
? sm
->right
->state
->name
: "<none>",
497 sm
->right
? get_stree_id(sm
->right
->pool
) : -1);
502 * NOTE: If a state is in both the keep stack and the remove stack then that is
503 * a bug. Only add states which are definitely true or definitely false. If
504 * you have a leaf state that could be both true and false, then create a fake
505 * split history where one side is true and one side is false. Otherwise, if
506 * you can't do that, then don't add it to either list.
508 #define RECURSE_LIMIT 300
509 struct sm_state
*filter_pools(struct sm_state
*sm
,
510 const struct state_list
*remove_stack
,
511 const struct state_list
*keep_stack
,
512 int *modified
, int *recurse_cnt
,
513 struct timeval
*start
, int *skip
, int *bail
)
515 struct sm_state
*ret
= NULL
;
516 struct sm_state
*left
;
517 struct sm_state
*right
;
519 struct timeval now
, diff
;
525 gettimeofday(&now
, NULL
);
526 timersub(&now
, start
, &diff
);
527 if (diff
.tv_sec
>= 3) {
528 DIMPLIED("%s: implications taking too long: %s\n", __func__
, sm_state_info(sm
));
532 if ((*recurse_cnt
)++ > RECURSE_LIMIT
) {
533 DIMPLIED("%s: recursed too far: %s\n", __func__
, sm_state_info(sm
));
538 if (pool_in_pools(sm
->pool
, remove_stack
)) {
539 DIMPLIED("%s: remove: %s\n", __func__
, sm_state_info(sm
));
544 if (!is_merged(sm
) || pool_in_pools(sm
->pool
, keep_stack
) || sm_in_keep_leafs(sm
, keep_stack
)) {
545 DIMPLIED("%s: keep %s (%s, %s, %s): %s\n", __func__
, sm
->state
->name
,
546 is_merged(sm
) ? "merged" : "not merged",
547 pool_in_pools(sm
->pool
, keep_stack
) ? "in keep pools" : "not in keep pools",
548 sm_in_keep_leafs(sm
, keep_stack
) ? "reachable keep leaf" : "no keep leaf",
553 left
= filter_pools(sm
->left
, remove_stack
, keep_stack
, &removed
, recurse_cnt
, start
, skip
, bail
);
554 right
= filter_pools(sm
->right
, remove_stack
, keep_stack
, &removed
, recurse_cnt
, start
, skip
, bail
);
558 DIMPLIED("%s: kept all: %s\n", __func__
, sm_state_info(sm
));
562 if (!left
&& !right
) {
563 DIMPLIED("%s: removed all: %s\n", __func__
, sm_state_info(sm
));
568 ret
= clone_sm(right
);
573 ret
= clone_sm(left
);
578 if (left
->sym
!= sm
->sym
|| strcmp(left
->name
, sm
->name
) != 0) {
579 left
= clone_sm(left
);
581 left
->name
= sm
->name
;
583 if (right
->sym
!= sm
->sym
|| strcmp(right
->name
, sm
->name
) != 0) {
584 right
= clone_sm(right
);
585 right
->sym
= sm
->sym
;
586 right
->name
= sm
->name
;
588 ret
= merge_sm_states(left
, right
);
591 ret
->pool
= sm
->pool
;
593 DIMPLIED("%s: partial: %s\n", __func__
, sm_state_info(sm
));
597 static struct stree
*filter_stack(struct sm_state
*gate_sm
,
598 struct stree
*pre_stree
,
599 const struct state_list
*remove_stack
,
600 const struct state_list
*keep_stack
)
602 struct stree
*ret
= NULL
;
603 struct sm_state
*tmp
;
604 struct sm_state
*filtered_sm
;
607 struct timeval start
;
614 gettimeofday(&start
, NULL
);
615 FOR_EACH_SM(pre_stree
, tmp
) {
616 if (!tmp
->merged
|| sm_in_keep_leafs(tmp
, keep_stack
))
621 filtered_sm
= filter_pools(tmp
, remove_stack
, keep_stack
, &modified
, &recurse_cnt
, &start
, &skip
, &bail
);
622 if (going_too_slow())
625 return ret
; /* Return the implications we figured out before time ran out. */
628 if (skip
|| !filtered_sm
|| !modified
)
630 /* the assignments here are for borrowed implications */
631 filtered_sm
->name
= tmp
->name
;
632 filtered_sm
->sym
= tmp
->sym
;
633 avl_insert(&ret
, filtered_sm
);
634 } END_FOR_EACH_SM(tmp
);
638 static void separate_and_filter(struct sm_state
*sm
, int comparison
, struct range_list
*rl
,
639 struct stree
*pre_stree
,
640 struct stree
**true_states
,
641 struct stree
**false_states
,
644 struct state_list
*true_stack
= NULL
;
645 struct state_list
*false_stack
= NULL
;
646 struct timeval time_before
;
647 struct timeval time_after
;
650 gettimeofday(&time_before
, NULL
);
652 DIMPLIED("checking implications: (%s (%s) %s %s)\n",
653 sm
->name
, sm
->state
->name
, show_comparison(comparison
), show_rl(rl
));
655 if (!is_merged(sm
)) {
656 DIMPLIED("%d '%s' from line %d is not merged.\n", get_lineno(), sm
->name
, sm
->line
);
660 separate_pools(sm
, comparison
, rl
, &true_stack
, &false_stack
, NULL
, mixed
);
665 FOR_EACH_PTR(true_stack
, sm
) {
666 sm_msg("TRUE POOL: %p", sm
->pool
);
667 } END_FOR_EACH_PTR(sm
);
669 FOR_EACH_PTR(false_stack
, sm
) {
670 sm_msg("FALSE POOL: %p", sm
->pool
);
671 } END_FOR_EACH_PTR(sm
);
674 DIMPLIED("filtering true stack.\n");
675 *true_states
= filter_stack(sm
, pre_stree
, false_stack
, true_stack
);
676 DIMPLIED("filtering false stack.\n");
677 *false_states
= filter_stack(sm
, pre_stree
, true_stack
, false_stack
);
678 free_slist(&true_stack
);
679 free_slist(&false_stack
);
681 gettimeofday(&time_after
, NULL
);
682 sec
= time_after
.tv_sec
- time_before
.tv_sec
;
684 sm_perror("Function too hairy. Ignoring implications after %d seconds.", sec
);
687 static struct expression
*get_last_expr(struct statement
*stmt
)
689 struct statement
*last
;
691 last
= last_ptr_list((struct ptr_list
*)stmt
->stmts
);
692 if (last
->type
== STMT_EXPRESSION
)
693 return last
->expression
;
695 if (last
->type
== STMT_LABEL
) {
696 if (last
->label_statement
&&
697 last
->label_statement
->type
== STMT_EXPRESSION
)
698 return last
->label_statement
->expression
;
704 static struct expression
*get_left_most_expr(struct expression
*expr
)
706 struct statement
*compound
;
707 struct expression
*fake
;
709 compound
= get_expression_statement(expr
);
711 return get_last_expr(compound
);
713 expr
= strip_parens(expr
);
714 if (expr
->type
== EXPR_ASSIGNMENT
)
715 return get_left_most_expr(expr
->left
);
716 fake
= expr_get_fake_parent_expr(expr
);
717 if (fake
&& fake
->type
== EXPR_ASSIGNMENT
)
722 static int is_merged_expr(struct expression
*expr
)
727 if (get_value(expr
, &dummy
))
729 sm
= get_sm_state_expr(SMATCH_EXTRA
, expr
);
737 static void delete_gate_sm_equiv(struct stree
**stree
, const char *name
, struct symbol
*sym
)
739 struct smatch_state
*state
;
740 struct relation
*rel
;
742 state
= get_state(SMATCH_EXTRA
, name
, sym
);
745 FOR_EACH_PTR(estate_related(state
), rel
) {
746 delete_state_stree(stree
, SMATCH_EXTRA
, rel
->name
, rel
->sym
);
747 } END_FOR_EACH_PTR(rel
);
750 static void delete_gate_sm(struct stree
**stree
, const char *name
, struct symbol
*sym
)
752 delete_state_stree(stree
, SMATCH_EXTRA
, name
, sym
);
755 static int handle_comparison(struct expression
*expr
,
756 struct stree
**implied_true
,
757 struct stree
**implied_false
)
759 struct sm_state
*sm
= NULL
;
760 struct range_list
*rl
= NULL
;
761 struct expression
*left
;
762 struct expression
*right
;
764 int comparison
= expr
->op
;
767 left
= get_left_most_expr(expr
->left
);
768 right
= get_left_most_expr(expr
->right
);
770 if (is_merged_expr(left
)) {
771 sm
= get_sm_state_expr(SMATCH_EXTRA
, left
);
772 get_implied_rl(right
, &rl
);
773 } else if (is_merged_expr(right
)) {
774 sm
= get_sm_state_expr(SMATCH_EXTRA
, right
);
775 get_implied_rl(left
, &rl
);
776 comparison
= flip_comparison(comparison
);
782 type
= get_type(expr
);
785 if (type_positive_bits(rl_type(rl
)) > type_positive_bits(type
))
787 if (type_positive_bits(type
) < 31)
789 rl
= cast_rl(type
, rl
);
791 separate_and_filter(sm
, comparison
, rl
, __get_cur_stree(), implied_true
, implied_false
, &mixed
);
793 delete_gate_sm_equiv(implied_true
, sm
->name
, sm
->sym
);
794 delete_gate_sm_equiv(implied_false
, sm
->name
, sm
->sym
);
796 delete_gate_sm(implied_true
, sm
->name
, sm
->sym
);
797 delete_gate_sm(implied_false
, sm
->name
, sm
->sym
);
803 static int handle_zero_comparison(struct expression
*expr
,
804 struct stree
**implied_true
,
805 struct stree
**implied_false
)
813 if (expr
->type
== EXPR_POSTOP
)
814 expr
= strip_expr(expr
->unop
);
816 name
= expr_to_var_sym(expr
, &sym
);
819 sm
= get_sm_state(SMATCH_EXTRA
, name
, sym
);
820 if (!sm
|| !sm
->merged
)
823 separate_and_filter(sm
, SPECIAL_NOTEQUAL
, tmp_range_list(estate_type(sm
->state
), 0), __get_cur_stree(), implied_true
, implied_false
, &mixed
);
824 delete_gate_sm_equiv(implied_true
, sm
->name
, sm
->sym
);
825 delete_gate_sm_equiv(implied_false
, sm
->name
, sm
->sym
);
827 delete_gate_sm(implied_true
, sm
->name
, sm
->sym
);
828 delete_gate_sm(implied_false
, sm
->name
, sm
->sym
);
837 static int handled_by_comparison_hook(struct expression
*expr
,
838 struct stree
**implied_true
,
839 struct stree
**implied_false
)
841 struct sm_state
*sm
, *true_sm
, *false_sm
;
842 struct state_list
*true_stack
= NULL
;
843 struct state_list
*false_stack
= NULL
;
844 struct stree
*pre_stree
;
846 sm
= comparison_implication_hook(expr
, &true_stack
, &false_stack
);
850 pre_stree
= clone_stree(__get_cur_stree());
852 *implied_true
= filter_stack(sm
, pre_stree
, false_stack
, true_stack
);
853 *implied_false
= filter_stack(sm
, pre_stree
, true_stack
, false_stack
);
855 true_sm
= get_sm_state_stree(*implied_true
, sm
->owner
, sm
->name
, sm
->sym
);
856 false_sm
= get_sm_state_stree(*implied_false
, sm
->owner
, sm
->name
, sm
->sym
);
857 if (true_sm
&& strcmp(true_sm
->state
->name
, "unknown") == 0)
858 delete_state_stree(implied_true
, sm
->owner
, sm
->name
, sm
->sym
);
859 if (false_sm
&& strcmp(false_sm
->state
->name
, "unknown") == 0)
860 delete_state_stree(implied_false
, sm
->owner
, sm
->name
, sm
->sym
);
862 free_stree(&pre_stree
);
863 free_slist(&true_stack
);
864 free_slist(&false_stack
);
869 static int handled_by_extra_states(struct expression
*expr
,
870 struct stree
**implied_true
,
871 struct stree
**implied_false
)
875 /* If the expression is known then it has no implications. */
876 if (get_implied_value(expr
, &sval
))
879 if (expr
->type
== EXPR_COMPARE
)
880 return handle_comparison(expr
, implied_true
, implied_false
);
882 return handle_zero_comparison(expr
, implied_true
, implied_false
);
885 static int handled_by_parsed_conditions(struct expression
*expr
,
886 struct stree
**implied_true
,
887 struct stree
**implied_false
)
889 struct state_list
*true_stack
= NULL
;
890 struct state_list
*false_stack
= NULL
;
891 struct stree
*pre_stree
;
894 sm
= parsed_condition_implication_hook(expr
, &true_stack
, &false_stack
);
898 pre_stree
= clone_stree(__get_cur_stree());
900 *implied_true
= filter_stack(sm
, pre_stree
, false_stack
, true_stack
);
901 *implied_false
= filter_stack(sm
, pre_stree
, true_stack
, false_stack
);
903 free_stree(&pre_stree
);
904 free_slist(&true_stack
);
905 free_slist(&false_stack
);
910 static int handled_by_stored_conditions(struct expression
*expr
,
911 struct stree
**implied_true
,
912 struct stree
**implied_false
)
914 struct state_list
*true_stack
= NULL
;
915 struct state_list
*false_stack
= NULL
;
916 struct stree
*pre_stree
;
919 sm
= stored_condition_implication_hook(expr
, &true_stack
, &false_stack
);
923 pre_stree
= clone_stree(__get_cur_stree());
925 *implied_true
= filter_stack(sm
, pre_stree
, false_stack
, true_stack
);
926 *implied_false
= filter_stack(sm
, pre_stree
, true_stack
, false_stack
);
928 free_stree(&pre_stree
);
929 free_slist(&true_stack
);
930 free_slist(&false_stack
);
935 static struct stree
*saved_implied_true
;
936 static struct stree
*saved_implied_false
;
937 static struct stree
*extra_saved_implied_true
;
938 static struct stree
*extra_saved_implied_false
;
940 static void separate_implication_states(struct stree
**implied_true
,
941 struct stree
**implied_false
,
946 /* We process these states later to preserve the implications. */
947 FOR_EACH_SM(*implied_true
, sm
) {
948 if (sm
->owner
== owner
)
949 overwrite_sm_state_stree(&extra_saved_implied_true
, sm
);
950 } END_FOR_EACH_SM(sm
);
951 FOR_EACH_SM(extra_saved_implied_true
, sm
) {
952 delete_state_stree(implied_true
, sm
->owner
, sm
->name
, sm
->sym
);
953 } END_FOR_EACH_SM(sm
);
955 FOR_EACH_SM(*implied_false
, sm
) {
956 if (sm
->owner
== owner
)
957 overwrite_sm_state_stree(&extra_saved_implied_false
, sm
);
958 } END_FOR_EACH_SM(sm
);
959 FOR_EACH_SM(extra_saved_implied_false
, sm
) {
960 delete_state_stree(implied_false
, sm
->owner
, sm
->name
, sm
->sym
);
961 } END_FOR_EACH_SM(sm
);
964 static void get_tf_states(struct expression
*expr
,
965 struct stree
**implied_true
,
966 struct stree
**implied_false
)
968 while (expr
->type
== EXPR_ASSIGNMENT
&& expr
->op
== '=')
969 expr
= strip_parens(expr
->left
);
971 if (handled_by_parsed_conditions(expr
, implied_true
, implied_false
))
974 if (handled_by_comparison_hook(expr
, implied_true
, implied_false
)) {
975 separate_implication_states(implied_true
, implied_false
, comparison_id
);
979 if (handled_by_extra_states(expr
, implied_true
, implied_false
)) {
980 separate_implication_states(implied_true
, implied_false
, SMATCH_EXTRA
);
984 if (handled_by_stored_conditions(expr
, implied_true
, implied_false
))
988 static void save_implications_hook(struct expression
*expr
)
990 if (going_too_slow())
992 get_tf_states(expr
, &saved_implied_true
, &saved_implied_false
);
995 static void set_implied_states(struct expression
*expr
)
999 if ((full_debug
|| implied_debug
) &&
1000 (saved_implied_true
|| saved_implied_false
)) {
1003 name
= expr_to_str(expr
);
1004 printf("These are the implied states for the true path: (%s)\n", name
);
1005 __print_stree(saved_implied_true
);
1006 printf("These are the implied states for the false path: (%s)\n", name
);
1007 __print_stree(saved_implied_false
);
1011 FOR_EACH_SM(saved_implied_true
, sm
) {
1012 if (implications_turned_off(sm
->owner
))
1014 __set_true_false_sm(sm
, NULL
);
1015 } END_FOR_EACH_SM(sm
);
1016 free_stree(&saved_implied_true
);
1018 FOR_EACH_SM(saved_implied_false
, sm
) {
1019 if (implications_turned_off(sm
->owner
))
1021 __set_true_false_sm(NULL
, sm
);
1022 } END_FOR_EACH_SM(sm
);
1023 free_stree(&saved_implied_false
);
1026 static void set_extra_implied_states(struct expression
*expr
)
1028 saved_implied_true
= extra_saved_implied_true
;
1029 saved_implied_false
= extra_saved_implied_false
;
1030 extra_saved_implied_true
= NULL
;
1031 extra_saved_implied_false
= NULL
;
1032 set_implied_states(expr
);
1035 void param_limit_implications(struct expression
*expr
, int param
, char *key
, char *value
, struct stree
**implied
)
1037 struct expression
*orig_expr
, *arg
;
1038 struct symbol
*compare_type
;
1041 struct sm_state
*sm
;
1042 struct sm_state
*tmp
;
1043 struct stree
*implied_true
= NULL
;
1044 struct stree
*implied_false
= NULL
;
1045 struct range_list
*orig
, *limit
;
1046 char *left_name
= NULL
;
1047 struct symbol
*left_sym
= NULL
;
1050 if (time_parsing_function() > 40)
1054 while (expr
->type
== EXPR_ASSIGNMENT
)
1055 expr
= strip_expr(expr
->right
);
1056 if (expr
->type
!= EXPR_CALL
)
1059 arg
= get_argument_from_call_expr(expr
->args
, param
);
1063 arg
= strip_parens(arg
);
1064 while (arg
->type
== EXPR_ASSIGNMENT
&& arg
->op
== '=')
1065 arg
= strip_parens(arg
->left
);
1067 name
= get_variable_from_key(arg
, key
, &sym
);
1071 sm
= get_sm_state(SMATCH_EXTRA
, name
, sym
);
1072 if (!sm
|| !sm
->merged
)
1075 if (strcmp(key
, "$") == 0)
1076 compare_type
= get_arg_type(expr
->fn
, param
);
1078 compare_type
= get_member_type_from_key(arg
, key
);
1080 orig
= estate_rl(sm
->state
);
1081 orig
= cast_rl(compare_type
, orig
);
1083 call_results_to_rl(expr
, compare_type
, value
, &limit
);
1085 separate_and_filter(sm
, PARAM_LIMIT
, limit
, __get_cur_stree(), &implied_true
, &implied_false
, &mixed
);
1087 if (orig_expr
->type
== EXPR_ASSIGNMENT
)
1088 left_name
= expr_to_var_sym(orig_expr
->left
, &left_sym
);
1090 FOR_EACH_SM(implied_true
, tmp
) {
1093 sm_msg("param_implication: param='%s' limit='%s' sm='%s'", name
, show_rl(limit
), show_sm(tmp
));
1095 if (implications_turned_off(tmp
->owner
))
1099 * What we're trying to do here is preserve the sm state so that
1100 * smatch extra doesn't create a new sm state when it parses the
1103 if (!mixed
&& tmp
->sym
== sym
&&
1104 strcmp(tmp
->name
, name
) == 0 &&
1105 (!left_name
|| strcmp(left_name
, name
) != 0)) {
1106 overwrite_sm_state_stree(implied
, tmp
);
1111 } END_FOR_EACH_SM(tmp
);
1113 free_stree(&implied_true
);
1114 free_stree(&implied_false
);
1119 struct stree
*__implied_case_stree(struct expression
*switch_expr
,
1120 struct range_list
*rl
,
1121 struct range_list_stack
**remaining_cases
,
1122 struct stree
**raw_stree
)
1126 struct var_sym_list
*vsl
;
1127 struct sm_state
*sm
;
1128 struct stree
*true_states
= NULL
;
1129 struct stree
*false_states
= NULL
;
1130 struct stree
*extra_states
;
1131 struct stree
*ret
= clone_stree(*raw_stree
);
1133 name
= expr_to_chunk_sym_vsl(switch_expr
, &sym
, &vsl
);
1136 filter_top_rl(remaining_cases
, rl
);
1138 rl
= clone_rl(top_rl(*remaining_cases
));
1141 sm
= get_sm_state_stree(*raw_stree
, SMATCH_EXTRA
, name
, sym
);
1143 separate_and_filter(sm
, SPECIAL_EQUAL
, rl
, *raw_stree
, &true_states
, &false_states
, NULL
);
1146 __push_fake_cur_stree();
1149 set_extra_nomod_vsl(name
, sym
, vsl
, NULL
, alloc_estate_rl(rl
));
1150 __pass_case_to_client(switch_expr
, rl
);
1151 extra_states
= __pop_fake_cur_stree();
1152 overwrite_stree(extra_states
, &true_states
);
1153 overwrite_stree(true_states
, &ret
);
1154 free_stree(&extra_states
);
1155 free_stree(&true_states
);
1156 free_stree(&false_states
);
1162 static void match_end_func(struct symbol
*sym
)
1166 implied_debug_msg
= NULL
;
1169 static void get_tf_stacks_from_pool(struct sm_state
*gate_sm
,
1170 struct sm_state
*pool_sm
,
1171 struct state_list
**true_stack
,
1172 struct state_list
**false_stack
,
1175 struct sm_state
*tmp
;
1176 int possibly_true
= 0;
1178 if ((*recurse_cnt
)++ >= 100)
1184 if (is_leaf(gate_sm
) &&
1185 strcmp(gate_sm
->state
->name
, pool_sm
->state
->name
) == 0) {
1186 add_ptr_list(true_stack
, pool_sm
);
1190 FOR_EACH_PTR(gate_sm
->possible
, tmp
) {
1191 if (strcmp(tmp
->state
->name
, pool_sm
->state
->name
) == 0) {
1195 } END_FOR_EACH_PTR(tmp
);
1197 if (!possibly_true
) {
1198 add_ptr_list(false_stack
, gate_sm
);
1202 get_tf_stacks_from_pool(gate_sm
->left
, pool_sm
, true_stack
, false_stack
, recurse_cnt
);
1203 get_tf_stacks_from_pool(gate_sm
->right
, pool_sm
, true_stack
, false_stack
, recurse_cnt
);
1207 * The situation is we have a SMATCH_EXTRA state and we want to break it into
1208 * each of the ->possible states and find the implications of each. The caller
1209 * has to use __push_fake_cur_stree() to preserve the correct states so they
1210 * can be restored later.
1212 void overwrite_states_using_pool(struct sm_state
*gate_sm
, struct sm_state
*pool_sm
)
1214 struct state_list
*true_stack
= NULL
;
1215 struct state_list
*false_stack
= NULL
;
1216 struct stree
*pre_stree
;
1217 struct stree
*implied_true
;
1218 struct sm_state
*tmp
;
1219 int recurse_cnt
= 0;
1224 get_tf_stacks_from_pool(gate_sm
, pool_sm
, &true_stack
, &false_stack
, &recurse_cnt
);
1226 pre_stree
= clone_stree(__get_cur_stree());
1228 implied_true
= filter_stack(gate_sm
, pre_stree
, false_stack
, true_stack
);
1230 free_stree(&pre_stree
);
1231 free_slist(&true_stack
);
1232 free_slist(&false_stack
);
1234 FOR_EACH_SM(implied_true
, tmp
) {
1236 } END_FOR_EACH_SM(tmp
);
1238 free_stree(&implied_true
);
1241 int assume(struct expression
*expr
)
1243 int orig_final_pass
= final_pass
;
1247 __push_fake_cur_stree();
1248 __split_whole_condition(expr
);
1249 final_pass
= orig_final_pass
;
1255 void end_assume(void)
1257 __discard_false_states();
1258 __free_fake_cur_stree();
1261 int impossible_assumption(struct expression
*left
, int op
, sval_t sval
)
1263 struct expression
*value
;
1264 struct expression
*comparison
;
1267 value
= value_expr(sval
.value
);
1268 comparison
= compare_expression(left
, op
, value
);
1270 if (!assume(comparison
))
1272 ret
= is_impossible_path();
1278 void __extra_match_condition(struct expression
*expr
);
1279 void __comparison_match_condition(struct expression
*expr
);
1280 void __stored_condition(struct expression
*expr
);
1281 void register_implications(int id
)
1283 ignore_implications
= malloc(num_checks
);
1284 memset(ignore_implications
, 0, num_checks
);
1286 add_hook(&save_implications_hook
, CONDITION_HOOK
);
1287 add_hook(&set_implied_states
, CONDITION_HOOK
);
1288 add_hook(&__extra_match_condition
, CONDITION_HOOK
);
1289 add_hook(&__comparison_match_condition
, CONDITION_HOOK
);
1290 add_hook(&set_extra_implied_states
, CONDITION_HOOK
);
1291 add_hook(&__stored_condition
, CONDITION_HOOK
);
1292 add_hook(&match_end_func
, END_FUNC_HOOK
);