1 /*
   2  * Copyright (C) 2008 Dan Carpenter.
   3  *
   4  * This program is free software; you can redistribute it and/or
   5  * modify it under the terms of the GNU General Public License
   6  * as published by the Free Software Foundation; either version 2
   7  * of the License, or (at your option) any later version.
   8  *
   9  * This program is distributed in the hope that it will be useful,
  10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  * GNU General Public License for more details.
  13  *
  14  * You should have received a copy of the GNU General Public License
  15  * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
  16  *
  17  * Copyright 2019 Joyent, Inc.
  18  */
  19 
  20 /*
  21  * Imagine we have this code:
  22  * foo = 1;
  23  * if (bar)
  24  *         foo = 99;
  25  * else
  26  *         frob();
  27  *                   //  <-- point #1
  28  * if (foo == 99)    //  <-- point #2
  29  *         bar->baz; //  <-- point #3
  30  *
  31  *
  32  * At point #3 bar is non null and can be dereferenced.
  33  *
  34  * It's smatch_implied.c which sets bar to non null at point #2.
  35  *
  36  * At point #1 merge_slist() stores the list of states from both
  37  * the true and false paths.  On the true path foo == 99 and on
  38  * the false path foo == 1.  merge_slist() sets their pool
  39  * list to show the other states which were there when foo == 99.
  40  *
  41  * When it comes to the if (foo == 99) the smatch implied hook
  42  * looks for all the pools where foo was not 99.  It makes a list
  43  * of those.
  44  *
  45  * Then for bar (and all the other states) it says, ok bar is a
  46  * merged state that came from these previous states.  We'll
  47  * chop out all the states where it came from a pool where
  48  * foo != 99 and merge it all back together.
  49  *
  50  * That is the implied state of bar.
  51  *
  52  * merge_slist() sets up ->pool.  An sm_state only has one ->pool and
  53  *    that is the pool where it was first set.  The my pool gets set when
  54  *    code paths merge.  States that have been set since the last merge do
  55  *    not have a ->pool.
  56  * merge_sm_state() sets ->left and ->right.  (These are the states which were
  57  *    merged to form the current state.)
  58  * a pool:  a pool is an slist that has been merged with another slist.
  59  */
  60 
  61 #include <time.h>
  62 #include "smatch.h"
  63 #include "smatch_slist.h"
  64 #include "smatch_extra.h"
  65 
  66 char *implied_debug_msg;
  67 
  68 bool implications_off;
  69 
  70 #define implied_debug 0
  71 #define DIMPLIED(msg...) do { if (implied_debug) printf(msg); } while (0)
  72 
  73 bool debug_implied(void)
  74 {
  75         return implied_debug;
  76 }
  77 
  78 /*
  79  * tmp_range_list():
  80  * It messes things up to free range list allocations.  This helper fuction
  81  * lets us reuse memory instead of doing new allocations.
  82  */
  83 static struct range_list *tmp_range_list(struct symbol *type, long long num)
  84 {
  85         static struct range_list *my_list = NULL;
  86         static struct data_range *my_range;
  87 
  88         __free_ptr_list((struct ptr_list **)&my_list);
  89         my_range = alloc_range(ll_to_sval(num), ll_to_sval(num));
  90         add_ptr_list(&my_list, my_range);
  91         return my_list;
  92 }
  93 
  94 static void print_debug_tf(struct sm_state *sm, int istrue, int isfalse)
  95 {
  96         if (!implied_debug && !option_debug)
  97                 return;
  98 
  99         if (istrue && isfalse) {
 100                 printf("%s: %d: does not exist.\n", show_sm(sm), sm->line);
 101         } else if (istrue) {
 102                 printf("'%s = %s' from %d is true. %s[stree %d]\n", sm->name, show_state(sm->state),
 103                         sm->line, sm->merged ? "[merged]" : "[leaf]",
 104                         get_stree_id(sm->pool));
 105         } else if (isfalse) {
 106                 printf("'%s = %s' from %d is false. %s[stree %d]\n", sm->name, show_state(sm->state),
 107                         sm->line,
 108                         sm->merged ? "[merged]" : "[leaf]",
 109                         get_stree_id(sm->pool));
 110         } else {
 111                 printf("'%s = %s' from %d could be true or false. %s[stree %d]\n", sm->name,
 112                         show_state(sm->state), sm->line,
 113                         sm->merged ? "[merged]" : "[leaf]",
 114                         get_stree_id(sm->pool));
 115         }
 116 }
 117 
 118 static int create_fake_history(struct sm_state *sm, int comparison, struct range_list *rl)
 119 {
 120         struct range_list *orig_rl;
 121         struct range_list *true_rl, *false_rl;
 122         struct stree *true_stree, *false_stree;
 123         struct sm_state *true_sm, *false_sm;
 124         sval_t sval;
 125 
 126         if (is_merged(sm) || sm->left || sm->right)
 127                 return 0;
 128         if (!rl_to_sval(rl, &sval))
 129                 return 0;
 130         if (!estate_rl(sm->state))
 131                 return 0;
 132 
 133         orig_rl = cast_rl(rl_type(rl), estate_rl(sm->state));
 134         split_comparison_rl(orig_rl, comparison, rl, &true_rl, &false_rl, NULL, NULL);
 135 
 136         true_rl = rl_truncate_cast(estate_type(sm->state), true_rl);
 137         false_rl = rl_truncate_cast(estate_type(sm->state), false_rl);
 138         if (is_whole_rl(true_rl) || is_whole_rl(false_rl) ||
 139             !true_rl || !false_rl ||
 140             rl_equiv(orig_rl, true_rl) || rl_equiv(orig_rl, false_rl) ||
 141             rl_equiv(estate_rl(sm->state), true_rl) || rl_equiv(estate_rl(sm->state), false_rl))
 142                 return 0;
 143 
 144         if (rl_intersection(true_rl, false_rl)) {
 145                 sm_perror("parsing (%s (%s) %s %s)",
 146                         sm->name, sm->state->name, show_special(comparison), show_rl(rl));
 147                 sm_msg("true_rl = %s false_rl = %s intersection = %s",
 148                        show_rl(true_rl), show_rl(false_rl), show_rl(rl_intersection(true_rl, false_rl)));
 149                 return 0;
 150         }
 151 
 152         if (implied_debug)
 153                 sm_msg("fake_history: %s vs %s.  %s %s %s. --> T: %s F: %s",
 154                        sm->name, show_rl(rl), sm->state->name, show_special(comparison), show_rl(rl),
 155                        show_rl(true_rl), show_rl(false_rl));
 156 
 157         true_sm = clone_sm(sm);
 158         false_sm = clone_sm(sm);
 159 
 160         true_sm->state = clone_partial_estate(sm->state, true_rl);
 161         free_slist(&true_sm->possible);
 162         add_possible_sm(true_sm, true_sm);
 163         false_sm->state = clone_partial_estate(sm->state, false_rl);
 164         free_slist(&false_sm->possible);
 165         add_possible_sm(false_sm, false_sm);
 166 
 167         true_stree = clone_stree(sm->pool);
 168         false_stree = clone_stree(sm->pool);
 169 
 170         overwrite_sm_state_stree(&true_stree, true_sm);
 171         overwrite_sm_state_stree(&false_stree, false_sm);
 172 
 173         true_sm->pool = true_stree;
 174         false_sm->pool = false_stree;
 175 
 176         sm->merged = 1;
 177         sm->left = true_sm;
 178         sm->right = false_sm;
 179 
 180         return 1;
 181 }
 182 
 183 /*
 184  * add_pool() adds a slist to *pools. If the slist has already been
 185  * added earlier then it doesn't get added a second time.
 186  */
 187 void add_pool(struct state_list **pools, struct sm_state *new)
 188 {
 189         struct sm_state *tmp;
 190 
 191         FOR_EACH_PTR(*pools, tmp) {
 192                 if (tmp->pool < new->pool)
 193                         continue;
 194                 else if (tmp->pool == new->pool) {
 195                         return;
 196                 } else {
 197                         INSERT_CURRENT(new, tmp);
 198                         return;
 199                 }
 200         } END_FOR_EACH_PTR(tmp);
 201         add_ptr_list(pools, new);
 202 }
 203 
 204 static int pool_in_pools(struct stree *pool,
 205                          const struct state_list *slist)
 206 {
 207         struct sm_state *tmp;
 208 
 209         FOR_EACH_PTR(slist, tmp) {
 210                 if (!tmp->pool)
 211                         continue;
 212                 if (tmp->pool == pool)
 213                         return 1;
 214         } END_FOR_EACH_PTR(tmp);
 215         return 0;
 216 }
 217 
 218 static int remove_pool(struct state_list **pools, struct stree *remove)
 219 {
 220         struct sm_state *tmp;
 221         int ret = 0;
 222 
 223         FOR_EACH_PTR(*pools, tmp) {
 224                 if (tmp->pool == remove) {
 225                         DELETE_CURRENT_PTR(tmp);
 226                         ret = 1;
 227                 }
 228         } END_FOR_EACH_PTR(tmp);
 229 
 230         return ret;
 231 }
 232 
 233 /*
 234  * If 'foo' == 99 add it that pool to the true pools.  If it's false, add it to
 235  * the false pools.  If we're not sure, then we don't add it to either.
 236  */
 237 static void do_compare(struct sm_state *sm, int comparison, struct range_list *rl,
 238                         struct state_list **true_stack,
 239                         struct state_list **maybe_stack,
 240                         struct state_list **false_stack,
 241                         int *mixed, struct sm_state *gate_sm)
 242 {
 243         int istrue;
 244         int isfalse;
 245         struct range_list *var_rl;
 246 
 247         if (!sm->pool)
 248                 return;
 249 
 250         var_rl = cast_rl(rl_type(rl), estate_rl(sm->state));
 251 
 252         istrue = !possibly_false_rl(var_rl, comparison, rl);
 253         isfalse = !possibly_true_rl(var_rl, comparison, rl);
 254 
 255         print_debug_tf(sm, istrue, isfalse);
 256 
 257         /* give up if we have borrowed implications (smatch_equiv.c) */
 258         if (sm->sym != gate_sm->sym ||
 259             strcmp(sm->name, gate_sm->name) != 0) {
 260                 if (mixed)
 261                         *mixed = 1;
 262         }
 263 
 264         if (mixed && !*mixed && !is_merged(sm) && !istrue && !isfalse) {
 265                 if (!create_fake_history(sm, comparison, rl))
 266                         *mixed = 1;
 267         }
 268 
 269         if (istrue)
 270                 add_pool(true_stack, sm);
 271         else if (isfalse)
 272                 add_pool(false_stack, sm);
 273         else
 274                 add_pool(maybe_stack, sm);
 275 }
 276 
 277 static int is_checked(struct state_list *checked, struct sm_state *sm)
 278 {
 279         struct sm_state *tmp;
 280 
 281         FOR_EACH_PTR(checked, tmp) {
 282                 if (tmp == sm)
 283                         return 1;
 284         } END_FOR_EACH_PTR(tmp);
 285         return 0;
 286 }
 287 
 288 /*
 289  * separate_pools():
 290  * Example code:  if (foo == 99) {
 291  *
 292  * Say 'foo' is a merged state that has many possible values.  It is the combination
 293  * of merges.  separate_pools() iterates through the pools recursively and calls
 294  * do_compare() for each time 'foo' was set.
 295  */
 296 static void __separate_pools(struct sm_state *sm, int comparison, struct range_list *rl,
 297                         struct state_list **true_stack,
 298                         struct state_list **maybe_stack,
 299                         struct state_list **false_stack,
 300                         struct state_list **checked, int *mixed, struct sm_state *gate_sm,
 301                         struct timeval *start_time)
 302 {
 303         int free_checked = 0;
 304         struct state_list *checked_states = NULL;
 305         struct timeval now, diff;
 306 
 307         if (!sm)
 308                 return;
 309 
 310         gettimeofday(&now, NULL);
 311         timersub(&now, start_time, &diff);
 312         if (diff.tv_sec >= 1) {
 313                 if (implied_debug) {
 314                         sm_msg("debug: %s: implications taking too long.  (%s %s %s)",
 315                                __func__, sm->state->name, show_special(comparison), show_rl(rl));
 316                 }
 317                 if (mixed)
 318                         *mixed = 1;
 319         }
 320 
 321         if (checked == NULL) {
 322                 checked = &checked_states;
 323                 free_checked = 1;
 324         }
 325         if (is_checked(*checked, sm))
 326                 return;
 327         add_ptr_list(checked, sm);
 328 
 329         do_compare(sm, comparison, rl, true_stack, maybe_stack, false_stack, mixed, gate_sm);
 330 
 331         __separate_pools(sm->left, comparison, rl, true_stack, maybe_stack, false_stack, checked, mixed, gate_sm, start_time);
 332         __separate_pools(sm->right, comparison, rl, true_stack, maybe_stack, false_stack, checked, mixed, gate_sm, start_time);
 333         if (free_checked)
 334                 free_slist(checked);
 335 }
 336 
 337 static void separate_pools(struct sm_state *sm, int comparison, struct range_list *rl,
 338                         struct state_list **true_stack,
 339                         struct state_list **false_stack,
 340                         struct state_list **checked, int *mixed)
 341 {
 342         struct state_list *maybe_stack = NULL;
 343         struct sm_state *tmp;
 344         struct timeval start_time;
 345 
 346 
 347         gettimeofday(&start_time, NULL);
 348         __separate_pools(sm, comparison, rl, true_stack, &maybe_stack, false_stack, checked, mixed, sm, &start_time);
 349 
 350         if (implied_debug) {
 351                 struct sm_state *sm;
 352 
 353                 FOR_EACH_PTR(*true_stack, sm) {
 354                         sm_msg("TRUE %s [stree %d]", show_sm(sm), get_stree_id(sm->pool));
 355                 } END_FOR_EACH_PTR(sm);
 356 
 357                 FOR_EACH_PTR(maybe_stack, sm) {
 358                         sm_msg("MAYBE %s %s[stree %d]",
 359                                show_sm(sm), sm->merged ? "(merged) ": "", get_stree_id(sm->pool));
 360                 } END_FOR_EACH_PTR(sm);
 361 
 362                 FOR_EACH_PTR(*false_stack, sm) {
 363                         sm_msg("FALSE %s [stree %d]", show_sm(sm), get_stree_id(sm->pool));
 364                 } END_FOR_EACH_PTR(sm);
 365         }
 366         /* if it's a maybe then remove it */
 367         FOR_EACH_PTR(maybe_stack, tmp) {
 368                 remove_pool(false_stack, tmp->pool);
 369                 remove_pool(true_stack, tmp->pool);
 370         } END_FOR_EACH_PTR(tmp);
 371 
 372         /* if it's both true and false remove it from both */
 373         FOR_EACH_PTR(*true_stack, tmp) {
 374                 if (remove_pool(false_stack, tmp->pool))
 375                         DELETE_CURRENT_PTR(tmp);
 376         } END_FOR_EACH_PTR(tmp);
 377 }
 378 
 379 static int sm_in_keep_leafs(struct sm_state *sm, const struct state_list *keep_gates)
 380 {
 381         struct sm_state *tmp, *old;
 382 
 383         FOR_EACH_PTR(keep_gates, tmp) {
 384                 if (is_merged(tmp))
 385                         continue;
 386                 old = get_sm_state_stree(tmp->pool, sm->owner, sm->name, sm->sym);
 387                 if (!old)
 388                         continue;
 389                 if (old == sm)
 390                         return 1;
 391         } END_FOR_EACH_PTR(tmp);
 392         return 0;
 393 }
 394 
 395 static int going_too_slow(void)
 396 {
 397         static void *printed;
 398 
 399         if (out_of_memory()) {
 400                 implications_off = true;
 401                 return 1;
 402         }
 403 
 404         if (!option_timeout || time_parsing_function() < option_timeout) {
 405                 implications_off = false;
 406                 return 0;
 407         }
 408 
 409         if (!__inline_fn && printed != cur_func_sym) {
 410                 if (!is_skipped_function())
 411                         sm_perror("turning off implications after %d seconds", option_timeout);
 412                 printed = cur_func_sym;
 413         }
 414         implications_off = true;
 415         return 1;
 416 }
 417 
 418 static char *sm_state_info(struct sm_state *sm)
 419 {
 420         static char buf[512];
 421         int n = 0;
 422 
 423         n += snprintf(buf + n, sizeof(buf) - n, "[stree %d line %d] ",
 424                       get_stree_id(sm->pool),  sm->line);
 425         if (n >= sizeof(buf))
 426                 return buf;
 427         n += snprintf(buf + n, sizeof(buf) - n, "%s ", show_sm(sm));
 428         if (n >= sizeof(buf))
 429                 return buf;
 430         n += snprintf(buf + n, sizeof(buf) - n, "left = %s [stree %d] ",
 431                       sm->left ? sm->left->state->name : "<none>",
 432                       sm->left ? get_stree_id(sm->left->pool) : -1);
 433         if (n >= sizeof(buf))
 434                 return buf;
 435         n += snprintf(buf + n, sizeof(buf) - n, "right = %s [stree %d]",
 436                       sm->right ? sm->right->state->name : "<none>",
 437                       sm->right ? get_stree_id(sm->right->pool) : -1);
 438         return buf;
 439 }
 440 
 441 /*
 442  * NOTE: If a state is in both the keep stack and the remove stack then that is
 443  * a bug.  Only add states which are definitely true or definitely false.  If
 444  * you have a leaf state that could be both true and false, then create a fake
 445  * split history where one side is true and one side is false.  Otherwise, if
 446  * you can't do that, then don't add it to either list.
 447  */
 448 #define RECURSE_LIMIT 300
 449 struct sm_state *filter_pools(struct sm_state *sm,
 450                               const struct state_list *remove_stack,
 451                               const struct state_list *keep_stack,
 452                               int *modified, int *recurse_cnt,
 453                               struct timeval *start, int *skip, int *bail)
 454 {
 455         struct sm_state *ret = NULL;
 456         struct sm_state *left;
 457         struct sm_state *right;
 458         int removed = 0;
 459         struct timeval now, diff;
 460 
 461         if (!sm)
 462                 return NULL;
 463         if (*bail)
 464                 return NULL;
 465         gettimeofday(&now, NULL);
 466         timersub(&now, start, &diff);
 467         if (diff.tv_sec >= 3) {
 468                 DIMPLIED("%s: implications taking too long: %s\n", __func__, sm_state_info(sm));
 469                 *bail = 1;
 470                 return NULL;
 471         }
 472         if ((*recurse_cnt)++ > RECURSE_LIMIT) {
 473                 DIMPLIED("%s: recursed too far:  %s\n", __func__, sm_state_info(sm));
 474                 *skip = 1;
 475                 return NULL;
 476         }
 477 
 478         if (pool_in_pools(sm->pool, remove_stack)) {
 479                 DIMPLIED("%s: remove: %s\n", __func__, sm_state_info(sm));
 480                 *modified = 1;
 481                 return NULL;
 482         }
 483 
 484         if (!is_merged(sm) || pool_in_pools(sm->pool, keep_stack) || sm_in_keep_leafs(sm, keep_stack)) {
 485                 DIMPLIED("%s: keep %s (%s, %s, %s): %s\n", __func__, sm->state->name,
 486                         is_merged(sm) ? "merged" : "not merged",
 487                         pool_in_pools(sm->pool, keep_stack) ? "not in keep pools" : "in keep pools",
 488                         sm_in_keep_leafs(sm, keep_stack) ? "reachable keep leaf" : "no keep leaf",
 489                         sm_state_info(sm));
 490                 return sm;
 491         }
 492 
 493         left = filter_pools(sm->left, remove_stack, keep_stack, &removed, recurse_cnt, start, skip, bail);
 494         right = filter_pools(sm->right, remove_stack, keep_stack, &removed, recurse_cnt, start, skip, bail);
 495         if (*bail || *skip)
 496                 return NULL;
 497         if (!removed) {
 498                 DIMPLIED("%s: kept all: %s\n", __func__, sm_state_info(sm));
 499                 return sm;
 500         }
 501         *modified = 1;
 502         if (!left && !right) {
 503                 DIMPLIED("%s: removed all: %s\n", __func__, sm_state_info(sm));
 504                 return NULL;
 505         }
 506 
 507         if (!left) {
 508                 ret = clone_sm(right);
 509                 ret->merged = 1;
 510                 ret->right = right;
 511                 ret->left = NULL;
 512         } else if (!right) {
 513                 ret = clone_sm(left);
 514                 ret->merged = 1;
 515                 ret->left = left;
 516                 ret->right = NULL;
 517         } else {
 518                 if (left->sym != sm->sym || strcmp(left->name, sm->name) != 0) {
 519                         left = clone_sm(left);
 520                         left->sym = sm->sym;
 521                         left->name = sm->name;
 522                 }
 523                 if (right->sym != sm->sym || strcmp(right->name, sm->name) != 0) {
 524                         right = clone_sm(right);
 525                         right->sym = sm->sym;
 526                         right->name = sm->name;
 527                 }
 528                 ret = merge_sm_states(left, right);
 529         }
 530 
 531         ret->pool = sm->pool;
 532 
 533         DIMPLIED("%s: partial: %s\n", __func__, sm_state_info(sm));
 534         return ret;
 535 }
 536 
 537 static struct stree *filter_stack(struct sm_state *gate_sm,
 538                                        struct stree *pre_stree,
 539                                        const struct state_list *remove_stack,
 540                                        const struct state_list *keep_stack)
 541 {
 542         struct stree *ret = NULL;
 543         struct sm_state *tmp;
 544         struct sm_state *filtered_sm;
 545         int modified;
 546         int recurse_cnt;
 547         struct timeval start;
 548         int skip;
 549         int bail = 0;
 550 
 551         if (!remove_stack)
 552                 return NULL;
 553 
 554         gettimeofday(&start, NULL);
 555         FOR_EACH_SM(pre_stree, tmp) {
 556                 if (!tmp->merged || sm_in_keep_leafs(tmp, keep_stack))
 557                         continue;
 558                 modified = 0;
 559                 recurse_cnt = 0;
 560                 skip = 0;
 561                 filtered_sm = filter_pools(tmp, remove_stack, keep_stack, &modified, &recurse_cnt, &start, &skip, &bail);
 562                 if (going_too_slow())
 563                         return NULL;
 564                 if (bail)
 565                         return ret;  /* Return the implications we figured out before time ran out. */
 566 
 567 
 568                 if (skip || !filtered_sm || !modified)
 569                         continue;
 570                 /* the assignments here are for borrowed implications */
 571                 filtered_sm->name = tmp->name;
 572                 filtered_sm->sym = tmp->sym;
 573                 avl_insert(&ret, filtered_sm);
 574         } END_FOR_EACH_SM(tmp);
 575         return ret;
 576 }
 577 
 578 static void separate_and_filter(struct sm_state *sm, int comparison, struct range_list *rl,
 579                 struct stree *pre_stree,
 580                 struct stree **true_states,
 581                 struct stree **false_states,
 582                 int *mixed)
 583 {
 584         struct state_list *true_stack = NULL;
 585         struct state_list *false_stack = NULL;
 586         struct timeval time_before;
 587         struct timeval time_after;
 588         int sec;
 589 
 590         gettimeofday(&time_before, NULL);
 591 
 592         DIMPLIED("checking implications: (%s (%s) %s %s)\n",
 593                  sm->name, sm->state->name, show_special(comparison), show_rl(rl));
 594 
 595         if (!is_merged(sm)) {
 596                 DIMPLIED("%d '%s' from line %d is not merged.\n", get_lineno(), sm->name, sm->line);
 597                 return;
 598         }
 599 
 600         separate_pools(sm, comparison, rl, &true_stack, &false_stack, NULL, mixed);
 601 
 602         DIMPLIED("filtering true stack.\n");
 603         *true_states = filter_stack(sm, pre_stree, false_stack, true_stack);
 604         DIMPLIED("filtering false stack.\n");
 605         *false_states = filter_stack(sm, pre_stree, true_stack, false_stack);
 606         free_slist(&true_stack);
 607         free_slist(&false_stack);
 608 
 609         gettimeofday(&time_after, NULL);
 610         sec = time_after.tv_sec - time_before.tv_sec;
 611         if (option_timeout && sec > option_timeout) {
 612                 sm_perror("Function too hairy.  Ignoring implications after %d seconds.", sec);
 613         }
 614 }
 615 
 616 static struct expression *get_last_expr(struct statement *stmt)
 617 {
 618         struct statement *last;
 619 
 620         last = last_ptr_list((struct ptr_list *)stmt->stmts);
 621         if (last->type == STMT_EXPRESSION)
 622                 return last->expression;
 623 
 624         if (last->type == STMT_LABEL) {
 625                 if (last->label_statement &&
 626                     last->label_statement->type == STMT_EXPRESSION)
 627                         return last->label_statement->expression;
 628         }
 629 
 630         return NULL;
 631 }
 632 
 633 static struct expression *get_left_most_expr(struct expression *expr)
 634 {
 635         struct statement *compound;
 636 
 637         compound = get_expression_statement(expr);
 638         if (compound)
 639                 return get_last_expr(compound);
 640 
 641         expr = strip_parens(expr);
 642         if (expr->type == EXPR_ASSIGNMENT)
 643                 return get_left_most_expr(expr->left);
 644         return expr;
 645 }
 646 
 647 static int is_merged_expr(struct expression  *expr)
 648 {
 649         struct sm_state *sm;
 650         sval_t dummy;
 651 
 652         if (get_value(expr, &dummy))
 653                 return 0;
 654         sm = get_sm_state_expr(SMATCH_EXTRA, expr);
 655         if (!sm)
 656                 return 0;
 657         if (is_merged(sm))
 658                 return 1;
 659         return 0;
 660 }
 661 
 662 static void delete_gate_sm_equiv(struct stree **stree, const char *name, struct symbol *sym)
 663 {
 664         struct smatch_state *state;
 665         struct relation *rel;
 666 
 667         state = get_state(SMATCH_EXTRA, name, sym);
 668         if (!state)
 669                 return;
 670         FOR_EACH_PTR(estate_related(state), rel) {
 671                 delete_state_stree(stree, SMATCH_EXTRA, rel->name, rel->sym);
 672         } END_FOR_EACH_PTR(rel);
 673 }
 674 
 675 static void delete_gate_sm(struct stree **stree, const char *name, struct symbol *sym)
 676 {
 677         delete_state_stree(stree, SMATCH_EXTRA, name, sym);
 678 }
 679 
 680 static int handle_comparison(struct expression *expr,
 681                               struct stree **implied_true,
 682                               struct stree **implied_false)
 683 {
 684         struct sm_state *sm = NULL;
 685         struct range_list *rl = NULL;
 686         struct expression *left;
 687         struct expression *right;
 688         struct symbol *type;
 689         int comparison = expr->op;
 690         int mixed = 0;
 691 
 692         left = get_left_most_expr(expr->left);
 693         right = get_left_most_expr(expr->right);
 694 
 695         if (is_merged_expr(left)) {
 696                 sm = get_sm_state_expr(SMATCH_EXTRA, left);
 697                 get_implied_rl(right, &rl);
 698         } else if (is_merged_expr(right)) {
 699                 sm = get_sm_state_expr(SMATCH_EXTRA, right);
 700                 get_implied_rl(left, &rl);
 701                 comparison = flip_comparison(comparison);
 702         }
 703 
 704         if (!rl || !sm)
 705                 return 0;
 706 
 707         type = get_type(expr);
 708         if (!type)
 709                 return 0;
 710         if (type_positive_bits(rl_type(rl)) > type_positive_bits(type))
 711                 type = rl_type(rl);
 712         if (type_positive_bits(type) < 31)
 713                 type = &int_ctype;
 714         rl = cast_rl(type, rl);
 715 
 716         separate_and_filter(sm, comparison, rl, __get_cur_stree(), implied_true, implied_false, &mixed);
 717 
 718         delete_gate_sm_equiv(implied_true, sm->name, sm->sym);
 719         delete_gate_sm_equiv(implied_false, sm->name, sm->sym);
 720         if (mixed) {
 721                 delete_gate_sm(implied_true, sm->name, sm->sym);
 722                 delete_gate_sm(implied_false, sm->name, sm->sym);
 723         }
 724 
 725         return 1;
 726 }
 727 
 728 static int handle_zero_comparison(struct expression *expr,
 729                                 struct stree **implied_true,
 730                                 struct stree **implied_false)
 731 {
 732         struct symbol *sym;
 733         char *name;
 734         struct sm_state *sm;
 735         int mixed = 0;
 736         int ret = 0;
 737 
 738         if (expr->type == EXPR_POSTOP)
 739                 expr = strip_expr(expr->unop);
 740 
 741         if (expr->type == EXPR_ASSIGNMENT) {
 742                 /* most of the time ->pools will be empty here because we
 743                    just set the state, but if have assigned a conditional
 744                    function there are implications. */
 745                 expr = expr->left;
 746         }
 747 
 748         name = expr_to_var_sym(expr, &sym);
 749         if (!name || !sym)
 750                 goto free;
 751         sm = get_sm_state(SMATCH_EXTRA, name, sym);
 752         if (!sm)
 753                 goto free;
 754 
 755         separate_and_filter(sm, SPECIAL_NOTEQUAL, tmp_range_list(estate_type(sm->state), 0), __get_cur_stree(), implied_true, implied_false, &mixed);
 756         delete_gate_sm_equiv(implied_true, sm->name, sm->sym);
 757         delete_gate_sm_equiv(implied_false, sm->name, sm->sym);
 758         if (mixed) {
 759                 delete_gate_sm(implied_true, sm->name, sm->sym);
 760                 delete_gate_sm(implied_false, sm->name, sm->sym);
 761         }
 762 
 763         ret = 1;
 764 free:
 765         free_string(name);
 766         return ret;
 767 }
 768 
 769 static int handled_by_comparison_hook(struct expression *expr,
 770                                    struct stree **implied_true,
 771                                    struct stree **implied_false)
 772 {
 773         struct state_list *true_stack = NULL;
 774         struct state_list *false_stack = NULL;
 775         struct stree *pre_stree;
 776         struct sm_state *sm;
 777 
 778         sm = comparison_implication_hook(expr, &true_stack, &false_stack);
 779         if (!sm)
 780                 return 0;
 781 
 782         pre_stree = clone_stree(__get_cur_stree());
 783 
 784         *implied_true = filter_stack(sm, pre_stree, false_stack, true_stack);
 785         *implied_false = filter_stack(sm, pre_stree, true_stack, false_stack);
 786 
 787         free_stree(&pre_stree);
 788         free_slist(&true_stack);
 789         free_slist(&false_stack);
 790 
 791         return 1;
 792 }
 793 
 794 static int handled_by_extra_states(struct expression *expr,
 795                                    struct stree **implied_true,
 796                                    struct stree **implied_false)
 797 {
 798         sval_t sval;
 799 
 800         /* If the expression is known then it has no implications.  */
 801         if (get_implied_value(expr, &sval))
 802                 return true;
 803 
 804         if (expr->type == EXPR_COMPARE)
 805                 return handle_comparison(expr, implied_true, implied_false);
 806         else
 807                 return handle_zero_comparison(expr, implied_true, implied_false);
 808 }
 809 
 810 static int handled_by_stored_conditions(struct expression *expr,
 811                                         struct stree **implied_true,
 812                                         struct stree **implied_false)
 813 {
 814         struct state_list *true_stack = NULL;
 815         struct state_list *false_stack = NULL;
 816         struct stree *pre_stree;
 817         struct sm_state *sm;
 818 
 819         sm = stored_condition_implication_hook(expr, &true_stack, &false_stack);
 820         if (!sm)
 821                 return 0;
 822 
 823         pre_stree = clone_stree(__get_cur_stree());
 824 
 825         *implied_true = filter_stack(sm, pre_stree, false_stack, true_stack);
 826         *implied_false = filter_stack(sm, pre_stree, true_stack, false_stack);
 827 
 828         free_stree(&pre_stree);
 829         free_slist(&true_stack);
 830         free_slist(&false_stack);
 831 
 832         return 1;
 833 }
 834 
 835 static struct stree *saved_implied_true;
 836 static struct stree *saved_implied_false;
 837 static struct stree *extra_saved_implied_true;
 838 static struct stree *extra_saved_implied_false;
 839 
 840 static void separate_extra_states(struct stree **implied_true,
 841                                   struct stree **implied_false)
 842 {
 843         struct sm_state *sm;
 844 
 845         /* We process extra states later to preserve the implications. */
 846         FOR_EACH_SM(*implied_true, sm) {
 847                 if (sm->owner == SMATCH_EXTRA)
 848                         overwrite_sm_state_stree(&extra_saved_implied_true, sm);
 849         } END_FOR_EACH_SM(sm);
 850         FOR_EACH_SM(extra_saved_implied_true, sm) {
 851                 delete_state_stree(implied_true, sm->owner, sm->name, sm->sym);
 852         } END_FOR_EACH_SM(sm);
 853 
 854         FOR_EACH_SM(*implied_false, sm) {
 855                 if (sm->owner == SMATCH_EXTRA)
 856                         overwrite_sm_state_stree(&extra_saved_implied_false, sm);
 857         } END_FOR_EACH_SM(sm);
 858         FOR_EACH_SM(extra_saved_implied_false, sm) {
 859                 delete_state_stree(implied_false, sm->owner, sm->name, sm->sym);
 860         } END_FOR_EACH_SM(sm);
 861 }
 862 
 863 static void get_tf_states(struct expression *expr,
 864                           struct stree **implied_true,
 865                           struct stree **implied_false)
 866 {
 867         if (handled_by_comparison_hook(expr, implied_true, implied_false))
 868                 return;
 869 
 870         if (handled_by_extra_states(expr, implied_true, implied_false)) {
 871                 separate_extra_states(implied_true, implied_false);
 872                 return;
 873         }
 874 
 875         if (handled_by_stored_conditions(expr, implied_true, implied_false))
 876                 return;
 877 }
 878 
 879 static void save_implications_hook(struct expression *expr)
 880 {
 881         if (going_too_slow())
 882                 return;
 883         get_tf_states(expr, &saved_implied_true, &saved_implied_false);
 884 }
 885 
 886 static void set_implied_states(struct expression *expr)
 887 {
 888         struct sm_state *sm;
 889 
 890         if (implied_debug &&
 891             (expr || saved_implied_true || saved_implied_false)) {
 892                 char *name;
 893 
 894                 name = expr_to_str(expr);
 895                 printf("These are the implied states for the true path: (%s)\n", name);
 896                 __print_stree(saved_implied_true);
 897                 printf("These are the implied states for the false path: (%s)\n", name);
 898                 __print_stree(saved_implied_false);
 899                 free_string(name);
 900         }
 901 
 902         FOR_EACH_SM(saved_implied_true, sm) {
 903                 __set_true_false_sm(sm, NULL);
 904         } END_FOR_EACH_SM(sm);
 905         free_stree(&saved_implied_true);
 906 
 907         FOR_EACH_SM(saved_implied_false, sm) {
 908                 __set_true_false_sm(NULL, sm);
 909         } END_FOR_EACH_SM(sm);
 910         free_stree(&saved_implied_false);
 911 }
 912 
 913 static void set_extra_implied_states(struct expression *expr)
 914 {
 915         saved_implied_true = extra_saved_implied_true;
 916         saved_implied_false = extra_saved_implied_false;
 917         extra_saved_implied_true = NULL;
 918         extra_saved_implied_false = NULL;
 919         set_implied_states(NULL);
 920 }
 921 
 922 void param_limit_implications(struct expression *expr, int param, char *key, char *value)
 923 {
 924         struct expression *arg;
 925         struct symbol *compare_type;
 926         char *name;
 927         struct symbol *sym;
 928         struct sm_state *sm;
 929         struct sm_state *tmp;
 930         struct stree *implied_true = NULL;
 931         struct stree *implied_false = NULL;
 932         struct range_list *orig, *limit;
 933 
 934         if (time_parsing_function() > 40)
 935                 return;
 936 
 937         while (expr->type == EXPR_ASSIGNMENT)
 938                 expr = strip_expr(expr->right);
 939         if (expr->type != EXPR_CALL)
 940                 return;
 941 
 942         arg = get_argument_from_call_expr(expr->args, param);
 943         if (!arg)
 944                 return;
 945 
 946         arg = strip_parens(arg);
 947         while (arg->type == EXPR_ASSIGNMENT && arg->op == '=')
 948                 arg = strip_parens(arg->left);
 949 
 950         name = get_variable_from_key(arg, key, &sym);
 951         if (!name || !sym)
 952                 goto free;
 953 
 954         sm = get_sm_state(SMATCH_EXTRA, name, sym);
 955         if (!sm || !sm->merged)
 956                 goto free;
 957 
 958         if (strcmp(key, "$") == 0)
 959                 compare_type = get_arg_type(expr->fn, param);
 960         else
 961                 compare_type = get_member_type_from_key(arg, key);
 962 
 963         orig = estate_rl(sm->state);
 964         orig = cast_rl(compare_type, orig);
 965 
 966         call_results_to_rl(expr, compare_type, value, &limit);
 967 
 968         separate_and_filter(sm, SPECIAL_EQUAL, limit, __get_cur_stree(), &implied_true, &implied_false, NULL);
 969 
 970         FOR_EACH_SM(implied_true, tmp) {
 971                 __set_sm_fake_stree(tmp);
 972         } END_FOR_EACH_SM(tmp);
 973 
 974         free_stree(&implied_true);
 975         free_stree(&implied_false);
 976 free:
 977         free_string(name);
 978 }
 979 
 980 struct stree *__implied_case_stree(struct expression *switch_expr,
 981                                    struct range_list *rl,
 982                                    struct range_list_stack **remaining_cases,
 983                                    struct stree **raw_stree)
 984 {
 985         char *name;
 986         struct symbol *sym;
 987         struct var_sym_list *vsl;
 988         struct sm_state *sm;
 989         struct stree *true_states = NULL;
 990         struct stree *false_states = NULL;
 991         struct stree *extra_states;
 992         struct stree *ret = clone_stree(*raw_stree);
 993 
 994         name = expr_to_chunk_sym_vsl(switch_expr, &sym, &vsl);
 995 
 996         if (rl)
 997                 filter_top_rl(remaining_cases, rl);
 998         else
 999                 rl = clone_rl(top_rl(*remaining_cases));
1000 
1001         if (name) {
1002                 sm = get_sm_state_stree(*raw_stree, SMATCH_EXTRA, name, sym);
1003                 if (sm)
1004                         separate_and_filter(sm, SPECIAL_EQUAL, rl, *raw_stree, &true_states, &false_states, NULL);
1005         }
1006 
1007         __push_fake_cur_stree();
1008         __unnullify_path();
1009         if (name)
1010                 set_extra_nomod_vsl(name, sym, vsl, NULL, alloc_estate_rl(rl));
1011         __pass_case_to_client(switch_expr, rl);
1012         extra_states = __pop_fake_cur_stree();
1013         overwrite_stree(extra_states, &true_states);
1014         overwrite_stree(true_states, &ret);
1015         free_stree(&extra_states);
1016         free_stree(&true_states);
1017         free_stree(&false_states);
1018 
1019         free_string(name);
1020         return ret;
1021 }
1022 
1023 static void match_end_func(struct symbol *sym)
1024 {
1025         if (__inline_fn)
1026                 return;
1027         implied_debug_msg = NULL;
1028 }
1029 
1030 static void get_tf_stacks_from_pool(struct sm_state *gate_sm,
1031                                     struct sm_state *pool_sm,
1032                                     struct state_list **true_stack,
1033                                     struct state_list **false_stack)
1034 {
1035         struct sm_state *tmp;
1036         int possibly_true = 0;
1037 
1038         if (!gate_sm)
1039                 return;
1040 
1041         if (strcmp(gate_sm->state->name, pool_sm->state->name) == 0) {
1042                 add_ptr_list(true_stack, pool_sm);
1043                 return;
1044         }
1045 
1046         FOR_EACH_PTR(gate_sm->possible, tmp) {
1047                 if (strcmp(tmp->state->name, pool_sm->state->name) == 0) {
1048                         possibly_true = 1;
1049                         break;
1050                 }
1051         } END_FOR_EACH_PTR(tmp);
1052 
1053         if (!possibly_true) {
1054                 add_ptr_list(false_stack, gate_sm);
1055                 return;
1056         }
1057 
1058         get_tf_stacks_from_pool(gate_sm->left, pool_sm, true_stack, false_stack);
1059         get_tf_stacks_from_pool(gate_sm->right, pool_sm, true_stack, false_stack);
1060 }
1061 
1062 /*
1063  * The situation is we have a SMATCH_EXTRA state and we want to break it into
1064  * each of the ->possible states and find the implications of each.  The caller
1065  * has to use __push_fake_cur_stree() to preserve the correct states so they
1066  * can be restored later.
1067  */
1068 void overwrite_states_using_pool(struct sm_state *gate_sm, struct sm_state *pool_sm)
1069 {
1070         struct state_list *true_stack = NULL;
1071         struct state_list *false_stack = NULL;
1072         struct stree *pre_stree;
1073         struct stree *implied_true;
1074         struct sm_state *tmp;
1075 
1076         if (!pool_sm->pool)
1077                 return;
1078 
1079         get_tf_stacks_from_pool(gate_sm, pool_sm, &true_stack, &false_stack);
1080 
1081         pre_stree = clone_stree(__get_cur_stree());
1082 
1083         implied_true = filter_stack(gate_sm, pre_stree, false_stack, true_stack);
1084 
1085         free_stree(&pre_stree);
1086         free_slist(&true_stack);
1087         free_slist(&false_stack);
1088 
1089         FOR_EACH_SM(implied_true, tmp) {
1090                 set_state(tmp->owner, tmp->name, tmp->sym, tmp->state);
1091         } END_FOR_EACH_SM(tmp);
1092 
1093         free_stree(&implied_true);
1094 }
1095 
1096 int assume(struct expression *expr)
1097 {
1098         int orig_final_pass = final_pass;
1099 
1100         in_fake_env++;
1101         final_pass = 0;
1102         __push_fake_cur_stree();
1103         __split_whole_condition(expr);
1104         final_pass = orig_final_pass;
1105         in_fake_env--;
1106 
1107         return 1;
1108 }
1109 
1110 void end_assume(void)
1111 {
1112         __discard_false_states();
1113         __free_fake_cur_stree();
1114 }
1115 
1116 int impossible_assumption(struct expression *left, int op, sval_t sval)
1117 {
1118         struct expression *value;
1119         struct expression *comparison;
1120         int ret;
1121 
1122         value = value_expr(sval.value);
1123         comparison = compare_expression(left, op, value);
1124 
1125         if (!assume(comparison))
1126                 return 0;
1127         ret = is_impossible_path();
1128         end_assume();
1129 
1130         return ret;
1131 }
1132 
1133 void __extra_match_condition(struct expression *expr);
1134 void __comparison_match_condition(struct expression *expr);
1135 void __stored_condition(struct expression *expr);
1136 void register_implications(int id)
1137 {
1138         add_hook(&save_implications_hook, CONDITION_HOOK);
1139         add_hook(&set_implied_states, CONDITION_HOOK);
1140         add_hook(&__extra_match_condition, CONDITION_HOOK);
1141         add_hook(&set_extra_implied_states, CONDITION_HOOK);
1142         add_hook(&__comparison_match_condition, CONDITION_HOOK);
1143         add_hook(&__stored_condition, CONDITION_HOOK);
1144         add_hook(&match_end_func, END_FUNC_HOOK);
1145 }