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