db/fixup_kernel.sh: fix clear_user() handling
[smatch.git] / smatch_implied.c
blobcfc1985544c62d13f741449ad4fc62cb6d009bcd
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 <time.h>
60 #include "smatch.h"
61 #include "smatch_slist.h"
62 #include "smatch_extra.h"
64 char *implied_debug_msg;
65 static char *ignore_implications;
67 bool implications_off;
69 bool implied_debug;
71 #define full_debug 0
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];
88 return false;
92 * tmp_range_list():
93 * It messes things up to free range list allocations. This helper fuction
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);
104 return my_list;
107 static const char *show_comparison(int op)
109 if (op == PARAM_LIMIT)
110 return "<lim>";
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)
117 return;
119 if (istrue && isfalse) {
120 printf("%s: %d: does not exist.\n", show_sm(sm), sm->line);
121 } else if (istrue) {
122 printf("'%s = %s' from %d is true. %s[stree %d]\n", sm->name, show_state(sm->state),
123 sm->line, sm->merged ? "[merged]" : "[leaf]",
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),
127 sm->line,
128 sm->merged ? "[merged]" : "[leaf]",
129 get_stree_id(sm->pool));
130 } else {
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 sm->merged ? "[merged]" : "[leaf]",
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);
144 return;
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;
156 sval_t sval;
158 if (is_merged(sm) || sm->left || sm->right)
159 return 0;
160 if (comparison != PARAM_LIMIT && !rl_to_sval(rl, &sval))
161 return 0;
162 if (!estate_rl(sm->state))
163 return 0;
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))
174 return 0;
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.
184 return 0;
187 if (full_debug)
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;
211 sm->leaf = 1;
212 sm->merged = 1;
213 sm->left = true_sm;
214 sm->right = false_sm;
216 return 1;
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)
229 continue;
230 else if (tmp->pool == new->pool) {
231 return;
232 } else {
233 INSERT_CURRENT(new, tmp);
234 return;
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) {
246 if (!tmp->pool)
247 continue;
248 if (tmp->pool == pool)
249 return 1;
250 } END_FOR_EACH_PTR(tmp);
251 return 0;
254 static int remove_pool(struct state_list **pools, struct stree *remove)
256 struct sm_state *tmp;
257 int ret = 0;
259 FOR_EACH_PTR(*pools, tmp) {
260 if (tmp->pool == remove) {
261 DELETE_CURRENT_PTR(tmp);
262 ret = 1;
264 } END_FOR_EACH_PTR(tmp);
266 return ret;
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);
275 if (intersect)
276 return true;
277 return false;
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)
304 int istrue;
305 int isfalse;
306 struct range_list *var_rl;
308 if (!sm->pool)
309 return;
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) {
321 if (mixed)
322 *mixed = 1;
325 if (mixed && !*mixed && !is_merged(sm) && !istrue && !isfalse) {
326 if (!create_fake_history(sm, comparison, rl))
327 *mixed = 1;
330 if (istrue)
331 add_pool(true_stack, sm);
332 else if (isfalse)
333 add_pool(false_stack, sm);
334 else
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) {
343 if (tmp == sm)
344 return 1;
345 } END_FOR_EACH_PTR(tmp);
346 return 0;
350 * separate_pools():
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;
368 if (!sm)
369 return;
371 gettimeofday(&now, NULL);
372 timersub(&now, start_time, &diff);
373 if (diff.tv_sec >= 1) {
374 if (full_debug) {
375 sm_msg("debug: %s: implications taking too long. (%s %s %s)",
376 __func__, sm->state->name, show_comparison(comparison), show_rl(rl));
378 if (mixed)
379 *mixed = 1;
382 if (checked == NULL) {
383 checked = &checked_states;
384 free_checked = 1;
386 if (is_checked(*checked, sm))
387 return;
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);
394 if (free_checked)
395 free_slist(checked);
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);
411 if (full_debug) {
412 struct sm_state *sm;
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) {
445 if (!is_leaf(tmp))
446 continue;
447 old = get_sm_state_stree(tmp->pool, sm->owner, sm->name, sm->sym);
448 if (!old)
449 continue;
450 if (old == sm)
451 return 1;
452 } END_FOR_EACH_PTR(tmp);
453 return 0;
456 static int going_too_slow(void)
458 static void *printed;
460 if (out_of_memory()) {
461 implications_off = true;
462 return 1;
465 if (time_parsing_function() < 60) {
466 implications_off = false;
467 return 0;
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;
475 return 1;
478 static char *sm_state_info(struct sm_state *sm)
480 static char buf[512];
481 int n = 0;
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))
486 return buf;
487 n += snprintf(buf + n, sizeof(buf) - n, "%s ", show_sm(sm));
488 if (n >= sizeof(buf))
489 return 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))
494 return 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);
498 return buf;
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;
518 int removed = 0;
519 struct timeval now, diff;
521 if (!sm)
522 return NULL;
523 if (*bail)
524 return NULL;
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));
529 *bail = 1;
530 return NULL;
532 if ((*recurse_cnt)++ > RECURSE_LIMIT) {
533 DIMPLIED("%s: recursed too far: %s\n", __func__, sm_state_info(sm));
534 *skip = 1;
535 return NULL;
538 if (pool_in_pools(sm->pool, remove_stack)) {
539 DIMPLIED("%s: remove: %s\n", __func__, sm_state_info(sm));
540 *modified = 1;
541 return NULL;
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",
549 sm_state_info(sm));
550 return sm;
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);
555 if (*bail || *skip)
556 return NULL;
557 if (!removed) {
558 DIMPLIED("%s: kept all: %s\n", __func__, sm_state_info(sm));
559 return sm;
561 *modified = 1;
562 if (!left && !right) {
563 DIMPLIED("%s: removed all: %s\n", __func__, sm_state_info(sm));
564 return NULL;
567 if (!left) {
568 ret = clone_sm(right);
569 ret->merged = 1;
570 ret->right = right;
571 ret->left = NULL;
572 } else if (!right) {
573 ret = clone_sm(left);
574 ret->merged = 1;
575 ret->left = left;
576 ret->right = NULL;
577 } else {
578 if (left->sym != sm->sym || strcmp(left->name, sm->name) != 0) {
579 left = clone_sm(left);
580 left->sym = sm->sym;
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));
594 return ret;
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;
605 int modified;
606 int recurse_cnt;
607 struct timeval start;
608 int skip;
609 int bail = 0;
611 if (!remove_stack)
612 return NULL;
614 gettimeofday(&start, NULL);
615 FOR_EACH_SM(pre_stree, tmp) {
616 if (!tmp->merged || sm_in_keep_leafs(tmp, keep_stack))
617 continue;
618 modified = 0;
619 recurse_cnt = 0;
620 skip = 0;
621 filtered_sm = filter_pools(tmp, remove_stack, keep_stack, &modified, &recurse_cnt, &start, &skip, &bail);
622 if (going_too_slow())
623 return NULL;
624 if (bail)
625 return ret; /* Return the implications we figured out before time ran out. */
628 if (skip || !filtered_sm || !modified)
629 continue;
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);
635 return ret;
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,
642 int *mixed)
644 struct state_list *true_stack = NULL;
645 struct state_list *false_stack = NULL;
646 struct timeval time_before;
647 struct timeval time_after;
648 int sec;
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);
657 return;
660 separate_pools(sm, comparison, rl, &true_stack, &false_stack, NULL, mixed);
662 if (full_debug) {
663 struct sm_state *sm;
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;
683 if (sec > 20)
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;
701 return NULL;
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);
710 if (compound)
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)
718 return fake->left;
719 return expr;
722 static int is_merged_expr(struct expression *expr)
724 struct sm_state *sm;
725 sval_t dummy;
727 if (get_value(expr, &dummy))
728 return 0;
729 sm = get_sm_state_expr(SMATCH_EXTRA, expr);
730 if (!sm)
731 return 0;
732 if (is_merged(sm))
733 return 1;
734 return 0;
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);
743 if (!state)
744 return;
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;
763 struct symbol *type;
764 int comparison = expr->op;
765 int mixed = 0;
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);
779 if (!rl || !sm)
780 return 0;
782 type = get_type(expr);
783 if (!type)
784 return 0;
785 if (type_positive_bits(rl_type(rl)) > type_positive_bits(type))
786 type = rl_type(rl);
787 if (type_positive_bits(type) < 31)
788 type = &int_ctype;
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);
795 if (mixed) {
796 delete_gate_sm(implied_true, sm->name, sm->sym);
797 delete_gate_sm(implied_false, sm->name, sm->sym);
800 return 1;
803 static int handle_zero_comparison(struct expression *expr,
804 struct stree **implied_true,
805 struct stree **implied_false)
807 struct symbol *sym;
808 char *name;
809 struct sm_state *sm;
810 int mixed = 0;
811 int ret = 0;
813 if (expr->type == EXPR_POSTOP)
814 expr = strip_expr(expr->unop);
816 name = expr_to_var_sym(expr, &sym);
817 if (!name || !sym)
818 goto free;
819 sm = get_sm_state(SMATCH_EXTRA, name, sym);
820 if (!sm || !sm->merged)
821 goto free;
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);
826 if (mixed) {
827 delete_gate_sm(implied_true, sm->name, sm->sym);
828 delete_gate_sm(implied_false, sm->name, sm->sym);
831 ret = 1;
832 free:
833 free_string(name);
834 return ret;
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);
847 if (!sm)
848 return 0;
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);
866 return 1;
869 static int handled_by_extra_states(struct expression *expr,
870 struct stree **implied_true,
871 struct stree **implied_false)
873 sval_t sval;
875 /* If the expression is known then it has no implications. */
876 if (get_implied_value(expr, &sval))
877 return true;
879 if (expr->type == EXPR_COMPARE)
880 return handle_comparison(expr, implied_true, implied_false);
881 else
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;
892 struct sm_state *sm;
894 sm = parsed_condition_implication_hook(expr, &true_stack, &false_stack);
895 if (!sm)
896 return 0;
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);
907 return 1;
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;
917 struct sm_state *sm;
919 sm = stored_condition_implication_hook(expr, &true_stack, &false_stack);
920 if (!sm)
921 return 0;
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);
932 return 1;
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,
942 int owner)
944 struct sm_state *sm;
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))
972 return;
974 if (handled_by_comparison_hook(expr, implied_true, implied_false)) {
975 separate_implication_states(implied_true, implied_false, comparison_id);
976 return;
979 if (handled_by_extra_states(expr, implied_true, implied_false)) {
980 separate_implication_states(implied_true, implied_false, SMATCH_EXTRA);
981 return;
984 if (handled_by_stored_conditions(expr, implied_true, implied_false))
985 return;
988 static void save_implications_hook(struct expression *expr)
990 if (going_too_slow())
991 return;
992 get_tf_states(expr, &saved_implied_true, &saved_implied_false);
995 static void set_implied_states(struct expression *expr)
997 struct sm_state *sm;
999 if ((full_debug || implied_debug) &&
1000 (saved_implied_true || saved_implied_false)) {
1001 char *name;
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);
1008 free_string(name);
1011 FOR_EACH_SM(saved_implied_true, sm) {
1012 if (implications_turned_off(sm->owner))
1013 continue;
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))
1020 continue;
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;
1039 char *name;
1040 struct symbol *sym;
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;
1048 int mixed = 0;
1050 if (time_parsing_function() > 40)
1051 return;
1053 orig_expr = expr;
1054 while (expr->type == EXPR_ASSIGNMENT)
1055 expr = strip_expr(expr->right);
1056 if (expr->type != EXPR_CALL)
1057 return;
1059 arg = get_argument_from_call_expr(expr->args, param);
1060 if (!arg)
1061 return;
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);
1068 if (!name || !sym)
1069 goto free;
1071 sm = get_sm_state(SMATCH_EXTRA, name, sym);
1072 if (!sm || !sm->merged)
1073 goto free;
1075 if (strcmp(key, "$") == 0)
1076 compare_type = get_arg_type(expr->fn, param);
1077 else
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) {
1092 if (implied_debug)
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))
1096 continue;
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
1101 * PARAM_LIMIT.
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);
1107 continue;
1110 __set_sm(tmp);
1111 } END_FOR_EACH_SM(tmp);
1113 free_stree(&implied_true);
1114 free_stree(&implied_false);
1115 free:
1116 free_string(name);
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)
1124 char *name;
1125 struct symbol *sym;
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);
1135 if (rl)
1136 filter_top_rl(remaining_cases, rl);
1137 else
1138 rl = clone_rl(top_rl(*remaining_cases));
1140 if (name) {
1141 sm = get_sm_state_stree(*raw_stree, SMATCH_EXTRA, name, sym);
1142 if (sm)
1143 separate_and_filter(sm, SPECIAL_EQUAL, rl, *raw_stree, &true_states, &false_states, NULL);
1146 __push_fake_cur_stree();
1147 __unnullify_path();
1148 if (name)
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);
1158 free_string(name);
1159 return ret;
1162 static void match_end_func(struct symbol *sym)
1164 if (__inline_fn)
1165 return;
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)
1174 struct sm_state *tmp;
1175 int possibly_true = 0;
1177 if (!gate_sm)
1178 return;
1180 if (is_leaf(gate_sm) &&
1181 strcmp(gate_sm->state->name, pool_sm->state->name) == 0) {
1182 add_ptr_list(true_stack, pool_sm);
1183 return;
1186 FOR_EACH_PTR(gate_sm->possible, tmp) {
1187 if (strcmp(tmp->state->name, pool_sm->state->name) == 0) {
1188 possibly_true = 1;
1189 break;
1191 } END_FOR_EACH_PTR(tmp);
1193 if (!possibly_true) {
1194 add_ptr_list(false_stack, gate_sm);
1195 return;
1198 get_tf_stacks_from_pool(gate_sm->left, pool_sm, true_stack, false_stack);
1199 get_tf_stacks_from_pool(gate_sm->right, pool_sm, true_stack, false_stack);
1203 * The situation is we have a SMATCH_EXTRA state and we want to break it into
1204 * each of the ->possible states and find the implications of each. The caller
1205 * has to use __push_fake_cur_stree() to preserve the correct states so they
1206 * can be restored later.
1208 void overwrite_states_using_pool(struct sm_state *gate_sm, struct sm_state *pool_sm)
1210 struct state_list *true_stack = NULL;
1211 struct state_list *false_stack = NULL;
1212 struct stree *pre_stree;
1213 struct stree *implied_true;
1214 struct sm_state *tmp;
1216 if (!pool_sm->pool)
1217 return;
1219 get_tf_stacks_from_pool(gate_sm, pool_sm, &true_stack, &false_stack);
1221 pre_stree = clone_stree(__get_cur_stree());
1223 implied_true = filter_stack(gate_sm, pre_stree, false_stack, true_stack);
1225 free_stree(&pre_stree);
1226 free_slist(&true_stack);
1227 free_slist(&false_stack);
1229 FOR_EACH_SM(implied_true, tmp) {
1230 __set_sm(tmp);
1231 } END_FOR_EACH_SM(tmp);
1233 free_stree(&implied_true);
1236 int assume(struct expression *expr)
1238 int orig_final_pass = final_pass;
1240 in_fake_env++;
1241 final_pass = 0;
1242 __push_fake_cur_stree();
1243 __split_whole_condition(expr);
1244 final_pass = orig_final_pass;
1245 in_fake_env--;
1247 return 1;
1250 void end_assume(void)
1252 __discard_false_states();
1253 __free_fake_cur_stree();
1256 int impossible_assumption(struct expression *left, int op, sval_t sval)
1258 struct expression *value;
1259 struct expression *comparison;
1260 int ret;
1262 value = value_expr(sval.value);
1263 comparison = compare_expression(left, op, value);
1265 if (!assume(comparison))
1266 return 0;
1267 ret = is_impossible_path();
1268 end_assume();
1270 return ret;
1273 void __extra_match_condition(struct expression *expr);
1274 void __comparison_match_condition(struct expression *expr);
1275 void __stored_condition(struct expression *expr);
1276 void register_implications(int id)
1278 ignore_implications = malloc(num_checks);
1279 memset(ignore_implications, 0, num_checks);
1281 add_hook(&save_implications_hook, CONDITION_HOOK);
1282 add_hook(&set_implied_states, CONDITION_HOOK);
1283 add_hook(&__extra_match_condition, CONDITION_HOOK);
1284 add_hook(&__comparison_match_condition, CONDITION_HOOK);
1285 add_hook(&set_extra_implied_states, CONDITION_HOOK);
1286 add_hook(&__stored_condition, CONDITION_HOOK);
1287 add_hook(&match_end_func, END_FUNC_HOOK);