1 /*
   2  * Copyright (C) 2008,2009 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 #include <stdlib.h>
  19 #include <stdio.h>
  20 #include "smatch.h"
  21 #include "smatch_slist.h"
  22 
  23 #undef CHECKORDER
  24 
  25 ALLOCATOR(smatch_state, "smatch state");
  26 ALLOCATOR(sm_state, "sm state");
  27 ALLOCATOR(named_stree, "named slist");
  28 __DO_ALLOCATOR(char, 1, 4, "state names", sname);
  29 
  30 int sm_state_counter;
  31 
  32 static struct stree_stack *all_pools;
  33 
  34 const char *show_sm(struct sm_state *sm)
  35 {
  36         static char buf[256];
  37         struct sm_state *tmp;
  38         int pos;
  39         int i;
  40 
  41         if (!sm)
  42                 return "<none>";
  43 
  44         pos = snprintf(buf, sizeof(buf), "[%s] %s = '%s'%s",
  45                        check_name(sm->owner), sm->name, show_state(sm->state),
  46                        sm->merged ? " [merged]" : "");
  47         if (pos > sizeof(buf))
  48                 goto truncate;
  49 
  50         if (ptr_list_size((struct ptr_list *)sm->possible) == 1)
  51                 return buf;
  52 
  53         pos += snprintf(buf + pos, sizeof(buf) - pos, " (");
  54         if (pos > sizeof(buf))
  55                 goto truncate;
  56         i = 0;
  57         FOR_EACH_PTR(sm->possible, tmp) {
  58                 if (i++)
  59                         pos += snprintf(buf + pos, sizeof(buf) - pos, ", ");
  60                 if (pos > sizeof(buf))
  61                         goto truncate;
  62                 pos += snprintf(buf + pos, sizeof(buf) - pos, "%s",
  63                                show_state(tmp->state));
  64                 if (pos > sizeof(buf))
  65                         goto truncate;
  66         } END_FOR_EACH_PTR(tmp);
  67         snprintf(buf + pos, sizeof(buf) - pos, ")");
  68 
  69         return buf;
  70 
  71 truncate:
  72         for (i = 0; i < 3; i++)
  73                 buf[sizeof(buf) - 2 - i] = '.';
  74         return buf;
  75 }
  76 
  77 void __print_stree(struct stree *stree)
  78 {
  79         struct sm_state *sm;
  80 
  81         printf("dumping stree at %d [%ld states]\n", get_lineno(), stree_count(stree));
  82         FOR_EACH_SM(stree, sm) {
  83                 printf("%s\n", show_sm(sm));
  84         } END_FOR_EACH_SM(sm);
  85         printf("---\n");
  86 }
  87 
  88 /* NULL states go at the end to simplify merge_slist */
  89 int cmp_tracker(const struct sm_state *a, const struct sm_state *b)
  90 {
  91         int ret;
  92 
  93         if (a == b)
  94                 return 0;
  95         if (!b)
  96                 return -1;
  97         if (!a)
  98                 return 1;
  99 
 100         if (a->owner < b->owner)
 101                 return -1;
 102         if (a->owner > b->owner)
 103                 return 1;
 104 
 105         ret = strcmp(a->name, b->name);
 106         if (ret < 0)
 107                 return -1;
 108         if (ret > 0)
 109                 return 1;
 110 
 111         if (!b->sym && a->sym)
 112                 return -1;
 113         if (!a->sym && b->sym)
 114                 return 1;
 115         if (a->sym < b->sym)
 116                 return -1;
 117         if (a->sym > b->sym)
 118                 return 1;
 119 
 120         return 0;
 121 }
 122 
 123 int *dynamic_states;
 124 void allocate_dynamic_states_array(int num_checks)
 125 {
 126         dynamic_states = calloc(num_checks + 1, sizeof(int));
 127 }
 128 
 129 void set_dynamic_states(unsigned short owner)
 130 {
 131         dynamic_states[owner] = true;
 132 }
 133 
 134 bool has_dynamic_states(unsigned short owner)
 135 {
 136         if (owner >= num_checks)
 137                 return false;
 138         return dynamic_states[owner];
 139 }
 140 
 141 static int cmp_possible_sm(const struct sm_state *a, const struct sm_state *b, int preserve)
 142 {
 143         int ret;
 144 
 145         if (a == b)
 146                 return 0;
 147 
 148         if (!has_dynamic_states(a->owner)) {
 149                 if (a->state > b->state)
 150                         return -1;
 151                 if (a->state < b->state)
 152                         return 1;
 153                 return 0;
 154         }
 155 
 156         if (a->owner == SMATCH_EXTRA) {
 157                 /*
 158                  * In Smatch extra you can have borrowed implications.
 159                  *
 160                  * FIXME: review how borrowed implications work and if they
 161                  * are the best way.  See also smatch_implied.c.
 162                  *
 163                  */
 164                 ret = cmp_tracker(a, b);
 165                 if (ret)
 166                         return ret;
 167 
 168                 /*
 169                  * We want to preserve leaf states.  They're use to split
 170                  * returns in smatch_db.c.
 171                  *
 172                  */
 173                 if (preserve) {
 174                         if (a->merged && !b->merged)
 175                                 return -1;
 176                         if (!a->merged)
 177                                 return 1;
 178                 }
 179         }
 180         if (!a->state->name || !b->state->name)
 181                 return 0;
 182 
 183         return strcmp(a->state->name, b->state->name);
 184 }
 185 
 186 struct sm_state *alloc_sm_state(int owner, const char *name,
 187                                 struct symbol *sym, struct smatch_state *state)
 188 {
 189         struct sm_state *sm_state = __alloc_sm_state(0);
 190 
 191         sm_state_counter++;
 192 
 193         sm_state->name = alloc_sname(name);
 194         sm_state->owner = owner;
 195         sm_state->sym = sym;
 196         sm_state->state = state;
 197         sm_state->line = get_lineno();
 198         sm_state->merged = 0;
 199         sm_state->pool = NULL;
 200         sm_state->left = NULL;
 201         sm_state->right = NULL;
 202         sm_state->possible = NULL;
 203         add_ptr_list(&sm_state->possible, sm_state);
 204         return sm_state;
 205 }
 206 
 207 static struct sm_state *alloc_state_no_name(int owner, const char *name,
 208                                      struct symbol *sym,
 209                                      struct smatch_state *state)
 210 {
 211         struct sm_state *tmp;
 212 
 213         tmp = alloc_sm_state(owner, NULL, sym, state);
 214         tmp->name = name;
 215         return tmp;
 216 }
 217 
 218 int too_many_possible(struct sm_state *sm)
 219 {
 220         if (ptr_list_size((struct ptr_list *)sm->possible) >= 100)
 221                 return 1;
 222         return 0;
 223 }
 224 
 225 void add_possible_sm(struct sm_state *to, struct sm_state *new)
 226 {
 227         struct sm_state *tmp;
 228         int preserve = 1;
 229         int cmp;
 230 
 231         if (too_many_possible(to))
 232                 preserve = 0;
 233 
 234         FOR_EACH_PTR(to->possible, tmp) {
 235                 cmp = cmp_possible_sm(tmp, new, preserve);
 236                 if (cmp < 0)
 237                         continue;
 238                 else if (cmp == 0) {
 239                         return;
 240                 } else {
 241                         INSERT_CURRENT(new, tmp);
 242                         return;
 243                 }
 244         } END_FOR_EACH_PTR(tmp);
 245         add_ptr_list(&to->possible, new);
 246 }
 247 
 248 static void copy_possibles(struct sm_state *to, struct sm_state *one, struct sm_state *two)
 249 {
 250         struct sm_state *large = one;
 251         struct sm_state *small = two;
 252         struct sm_state *tmp;
 253 
 254         /*
 255          * We spend a lot of time copying the possible lists.  I've tried to
 256          * optimize the process a bit.
 257          *
 258          */
 259 
 260         if (ptr_list_size((struct ptr_list *)two->possible) >
 261             ptr_list_size((struct ptr_list *)one->possible)) {
 262                 large = two;
 263                 small = one;
 264         }
 265 
 266         to->possible = clone_slist(large->possible);
 267         add_possible_sm(to, to);
 268         FOR_EACH_PTR(small->possible, tmp) {
 269                 add_possible_sm(to, tmp);
 270         } END_FOR_EACH_PTR(tmp);
 271 }
 272 
 273 char *alloc_sname(const char *str)
 274 {
 275         char *tmp;
 276 
 277         if (!str)
 278                 return NULL;
 279         tmp = __alloc_sname(strlen(str) + 1);
 280         strcpy(tmp, str);
 281         return tmp;
 282 }
 283 
 284 static struct symbol *oom_func;
 285 static int oom_limit = 3000000;  /* Start with a 3GB limit */
 286 int out_of_memory(void)
 287 {
 288         if (oom_func)
 289                 return 1;
 290 
 291         /*
 292          * I decided to use 50M here based on trial and error.
 293          * It works out OK for the kernel and so it should work
 294          * for most other projects as well.
 295          */
 296         if (sm_state_counter * sizeof(struct sm_state) >= 100000000)
 297                 return 1;
 298 
 299         /*
 300          * We're reading from statm to figure out how much memory we
 301          * are using.  The problem is that at the end of the function
 302          * we release the memory, so that it can be re-used but it
 303          * stays in cache, it's not released to the OS.  So then if
 304          * we allocate memory for different purposes we can easily
 305          * hit the 3GB limit on the next function, so that's why I give
 306          * the next function an extra 100MB to work with.
 307          *
 308          */
 309         if (get_mem_kb() > oom_limit) {
 310                 oom_func = cur_func_sym;
 311                 final_pass++;
 312                 sm_perror("OOM: %luKb sm_state_count = %d", get_mem_kb(), sm_state_counter);
 313                 final_pass--;
 314                 return 1;
 315         }
 316 
 317         return 0;
 318 }
 319 
 320 int low_on_memory(void)
 321 {
 322         if (sm_state_counter * sizeof(struct sm_state) >= 25000000)
 323                 return 1;
 324         return 0;
 325 }
 326 
 327 static void free_sm_state(struct sm_state *sm)
 328 {
 329         free_slist(&sm->possible);
 330         /*
 331          * fixme.  Free the actual state.
 332          * Right now we leave it until the end of the function
 333          * because we don't want to double free it.
 334          * Use the freelist to not double free things
 335          */
 336 }
 337 
 338 static void free_all_sm_states(struct allocation_blob *blob)
 339 {
 340         unsigned int size = sizeof(struct sm_state);
 341         unsigned int offset = 0;
 342 
 343         while (offset < blob->offset) {
 344                 free_sm_state((struct sm_state *)(blob->data + offset));
 345                 offset += size;
 346         }
 347 }
 348 
 349 /* At the end of every function we free all the sm_states */
 350 void free_every_single_sm_state(void)
 351 {
 352         struct allocator_struct *desc = &sm_state_allocator;
 353         struct allocation_blob *blob = desc->blobs;
 354 
 355         desc->blobs = NULL;
 356         desc->allocations = 0;
 357         desc->total_bytes = 0;
 358         desc->useful_bytes = 0;
 359         desc->freelist = NULL;
 360         while (blob) {
 361                 struct allocation_blob *next = blob->next;
 362                 free_all_sm_states(blob);
 363                 blob_free(blob, desc->chunking);
 364                 blob = next;
 365         }
 366         clear_sname_alloc();
 367         clear_smatch_state_alloc();
 368 
 369         free_stack_and_strees(&all_pools);
 370         sm_state_counter = 0;
 371         if (oom_func) {
 372                 oom_limit += 100000;
 373                 oom_func = NULL;
 374         }
 375 }
 376 
 377 unsigned long get_pool_count(void)
 378 {
 379         return ptr_list_size((struct ptr_list *)all_pools);
 380 }
 381 
 382 struct sm_state *clone_sm(struct sm_state *s)
 383 {
 384         struct sm_state *ret;
 385 
 386         ret = alloc_state_no_name(s->owner, s->name, s->sym, s->state);
 387         ret->merged = s->merged;
 388         ret->line = s->line;
 389         /* clone_sm() doesn't copy the pools.  Each state needs to have
 390            only one pool. */
 391         ret->possible = clone_slist(s->possible);
 392         ret->left = s->left;
 393         ret->right = s->right;
 394         return ret;
 395 }
 396 
 397 int is_merged(struct sm_state *sm)
 398 {
 399         return sm->merged;
 400 }
 401 
 402 int is_leaf(struct sm_state *sm)
 403 {
 404         return !sm->merged;
 405 }
 406 
 407 int slist_has_state(struct state_list *slist, struct smatch_state *state)
 408 {
 409         struct sm_state *tmp;
 410 
 411         FOR_EACH_PTR(slist, tmp) {
 412                 if (tmp->state == state)
 413                         return 1;
 414         } END_FOR_EACH_PTR(tmp);
 415         return 0;
 416 }
 417 
 418 struct state_list *clone_slist(struct state_list *from_slist)
 419 {
 420         struct sm_state *sm;
 421         struct state_list *to_slist = NULL;
 422 
 423         FOR_EACH_PTR(from_slist, sm) {
 424                 add_ptr_list(&to_slist, sm);
 425         } END_FOR_EACH_PTR(sm);
 426         return to_slist;
 427 }
 428 
 429 static struct smatch_state *merge_states(int owner, const char *name,
 430                                          struct symbol *sym,
 431                                          struct smatch_state *state1,
 432                                          struct smatch_state *state2)
 433 {
 434         struct smatch_state *ret;
 435 
 436         if (state1 == state2)
 437                 ret = state1;
 438         else if (__has_merge_function(owner))
 439                 ret = __client_merge_function(owner, state1, state2);
 440         else if (state1 == &ghost)
 441                 ret = state2;
 442         else if (state2 == &ghost)
 443                 ret = state1;
 444         else if (!state1 || !state2)
 445                 ret = &undefined;
 446         else
 447                 ret = &merged;
 448         return ret;
 449 }
 450 
 451 struct sm_state *merge_sm_states(struct sm_state *one, struct sm_state *two)
 452 {
 453         struct smatch_state *s;
 454         struct sm_state *result;
 455         static int warned;
 456 
 457         if (one == two)
 458                 return one;
 459         if (out_of_memory()) {
 460                 if (!warned)
 461                         sm_warning("Function too hairy.  No more merges.");
 462                 warned = 1;
 463                 return one;
 464         }
 465         warned = 0;
 466         s = merge_states(one->owner, one->name, one->sym, one->state, two->state);
 467         result = alloc_state_no_name(one->owner, one->name, one->sym, s);
 468         result->merged = 1;
 469         result->left = one;
 470         result->right = two;
 471 
 472         copy_possibles(result, one, two);
 473 
 474         /*
 475          * The ->line information is used by deref_check where we complain about
 476          * checking pointers that have already been dereferenced.  Let's say we
 477          * dereference a pointer on both the true and false paths and then merge
 478          * the states here.  The result state is &derefed, but the ->line number
 479          * is on the line where the pointer is merged not where it was
 480          * dereferenced..
 481          *
 482          * So in that case, let's just pick one dereference and set the ->line
 483          * to point at it.
 484          *
 485          */
 486 
 487         if (result->state == one->state)
 488                 result->line = one->line;
 489         if (result->state == two->state)
 490                 result->line = two->line;
 491 
 492         if (option_debug ||
 493             strcmp(check_name(one->owner), option_debug_check) == 0) {
 494                 struct sm_state *tmp;
 495                 int i = 0;
 496 
 497                 printf("%s:%d %s() merge [%s] '%s' %s(L %d) + %s(L %d) => %s (",
 498                         get_filename(), get_lineno(), get_function(),
 499                         check_name(one->owner), one->name,
 500                         show_state(one->state), one->line,
 501                         show_state(two->state), two->line,
 502                         show_state(s));
 503 
 504                 FOR_EACH_PTR(result->possible, tmp) {
 505                         if (i++)
 506                                 printf(", ");
 507                         printf("%s", show_state(tmp->state));
 508                 } END_FOR_EACH_PTR(tmp);
 509                 printf(")\n");
 510         }
 511 
 512         return result;
 513 }
 514 
 515 struct sm_state *get_sm_state_stree(struct stree *stree, int owner, const char *name,
 516                                 struct symbol *sym)
 517 {
 518         struct tracker tracker = {
 519                 .owner = owner,
 520                 .name = (char *)name,
 521                 .sym = sym,
 522         };
 523 
 524         if (!name)
 525                 return NULL;
 526 
 527 
 528         return avl_lookup(stree, (struct sm_state *)&tracker);
 529 }
 530 
 531 struct smatch_state *get_state_stree(struct stree *stree,
 532                                 int owner, const char *name,
 533                                 struct symbol *sym)
 534 {
 535         struct sm_state *sm;
 536 
 537         sm = get_sm_state_stree(stree, owner, name, sym);
 538         if (sm)
 539                 return sm->state;
 540         return NULL;
 541 }
 542 
 543 /* FIXME: this is almost exactly the same as set_sm_state_slist() */
 544 void overwrite_sm_state_stree(struct stree **stree, struct sm_state *new)
 545 {
 546         avl_insert(stree, new);
 547 }
 548 
 549 void overwrite_sm_state_stree_stack(struct stree_stack **stack,
 550                         struct sm_state *sm)
 551 {
 552         struct stree *stree;
 553 
 554         stree = pop_stree(stack);
 555         overwrite_sm_state_stree(&stree, sm);
 556         push_stree(stack, stree);
 557 }
 558 
 559 struct sm_state *set_state_stree(struct stree **stree, int owner, const char *name,
 560                      struct symbol *sym, struct smatch_state *state)
 561 {
 562         struct sm_state *new = alloc_sm_state(owner, name, sym, state);
 563 
 564         avl_insert(stree, new);
 565         return new;
 566 }
 567 
 568 void set_state_stree_perm(struct stree **stree, int owner, const char *name,
 569                      struct symbol *sym, struct smatch_state *state)
 570 {
 571         struct sm_state *sm;
 572 
 573         sm = malloc(sizeof(*sm) + strlen(name) + 1);
 574         memset(sm, 0, sizeof(*sm));
 575         sm->owner = owner;
 576         sm->name = (char *)(sm + 1);
 577         strcpy((char *)sm->name, name);
 578         sm->sym = sym;
 579         sm->state = state;
 580 
 581         overwrite_sm_state_stree(stree, sm);
 582 }
 583 
 584 void delete_state_stree(struct stree **stree, int owner, const char *name,
 585                         struct symbol *sym)
 586 {
 587         struct tracker tracker = {
 588                 .owner = owner,
 589                 .name = (char *)name,
 590                 .sym = sym,
 591         };
 592 
 593         avl_remove(stree, (struct sm_state *)&tracker);
 594 }
 595 
 596 void delete_state_stree_stack(struct stree_stack **stack, int owner, const char *name,
 597                         struct symbol *sym)
 598 {
 599         struct stree *stree;
 600 
 601         stree = pop_stree(stack);
 602         delete_state_stree(&stree, owner, name, sym);
 603         push_stree(stack, stree);
 604 }
 605 
 606 void push_stree(struct stree_stack **stack, struct stree *stree)
 607 {
 608         add_ptr_list(stack, stree);
 609 }
 610 
 611 struct stree *pop_stree(struct stree_stack **stack)
 612 {
 613         struct stree *stree;
 614 
 615         stree = last_ptr_list((struct ptr_list *)*stack);
 616         delete_ptr_list_last((struct ptr_list **)stack);
 617         return stree;
 618 }
 619 
 620 struct stree *top_stree(struct stree_stack *stack)
 621 {
 622         return last_ptr_list((struct ptr_list *)stack);
 623 }
 624 
 625 void free_slist(struct state_list **slist)
 626 {
 627         __free_ptr_list((struct ptr_list **)slist);
 628 }
 629 
 630 void free_stree_stack(struct stree_stack **stack)
 631 {
 632         __free_ptr_list((struct ptr_list **)stack);
 633 }
 634 
 635 void free_stack_and_strees(struct stree_stack **stree_stack)
 636 {
 637         struct stree *stree;
 638 
 639         FOR_EACH_PTR(*stree_stack, stree) {
 640                 free_stree(&stree);
 641         } END_FOR_EACH_PTR(stree);
 642         free_stree_stack(stree_stack);
 643 }
 644 
 645 struct sm_state *set_state_stree_stack(struct stree_stack **stack, int owner, const char *name,
 646                                 struct symbol *sym, struct smatch_state *state)
 647 {
 648         struct stree *stree;
 649         struct sm_state *sm;
 650 
 651         stree = pop_stree(stack);
 652         sm = set_state_stree(&stree, owner, name, sym, state);
 653         push_stree(stack, stree);
 654 
 655         return sm;
 656 }
 657 
 658 /*
 659  * get_sm_state_stack() gets the state for the top slist on the stack.
 660  */
 661 struct sm_state *get_sm_state_stree_stack(struct stree_stack *stack,
 662                                 int owner, const char *name,
 663                                 struct symbol *sym)
 664 {
 665         struct stree *stree;
 666         struct sm_state *ret;
 667 
 668         stree = pop_stree(&stack);
 669         ret = get_sm_state_stree(stree, owner, name, sym);
 670         push_stree(&stack, stree);
 671         return ret;
 672 }
 673 
 674 struct smatch_state *get_state_stree_stack(struct stree_stack *stack,
 675                                 int owner, const char *name,
 676                                 struct symbol *sym)
 677 {
 678         struct sm_state *sm;
 679 
 680         sm = get_sm_state_stree_stack(stack, owner, name, sym);
 681         if (sm)
 682                 return sm->state;
 683         return NULL;
 684 }
 685 
 686 static void match_states_stree(struct stree **one, struct stree **two)
 687 {
 688         struct smatch_state *tmp_state;
 689         struct sm_state *sm;
 690         struct state_list *add_to_one = NULL;
 691         struct state_list *add_to_two = NULL;
 692         AvlIter one_iter;
 693         AvlIter two_iter;
 694 
 695         __set_cur_stree_readonly();
 696 
 697         avl_iter_begin(&one_iter, *one, FORWARD);
 698         avl_iter_begin(&two_iter, *two, FORWARD);
 699 
 700         for (;;) {
 701                 if (!one_iter.sm && !two_iter.sm)
 702                         break;
 703                 if (cmp_tracker(one_iter.sm, two_iter.sm) < 0) {
 704                         __set_fake_cur_stree_fast(*two);
 705                         __in_unmatched_hook++;
 706                         tmp_state = __client_unmatched_state_function(one_iter.sm);
 707                         __in_unmatched_hook--;
 708                         __pop_fake_cur_stree_fast();
 709                         sm = alloc_state_no_name(one_iter.sm->owner, one_iter.sm->name,
 710                                                   one_iter.sm->sym, tmp_state);
 711                         add_ptr_list(&add_to_two, sm);
 712                         avl_iter_next(&one_iter);
 713                 } else if (cmp_tracker(one_iter.sm, two_iter.sm) == 0) {
 714                         avl_iter_next(&one_iter);
 715                         avl_iter_next(&two_iter);
 716                 } else {
 717                         __set_fake_cur_stree_fast(*one);
 718                         __in_unmatched_hook++;
 719                         tmp_state = __client_unmatched_state_function(two_iter.sm);
 720                         __in_unmatched_hook--;
 721                         __pop_fake_cur_stree_fast();
 722                         sm = alloc_state_no_name(two_iter.sm->owner, two_iter.sm->name,
 723                                                   two_iter.sm->sym, tmp_state);
 724                         add_ptr_list(&add_to_one, sm);
 725                         avl_iter_next(&two_iter);
 726                 }
 727         }
 728 
 729         __set_cur_stree_writable();
 730 
 731         FOR_EACH_PTR(add_to_one, sm) {
 732                 avl_insert(one, sm);
 733         } END_FOR_EACH_PTR(sm);
 734 
 735         FOR_EACH_PTR(add_to_two, sm) {
 736                 avl_insert(two, sm);
 737         } END_FOR_EACH_PTR(sm);
 738 
 739         free_slist(&add_to_one);
 740         free_slist(&add_to_two);
 741 }
 742 
 743 static void call_pre_merge_hooks(struct stree **one, struct stree **two)
 744 {
 745         struct sm_state *sm, *cur;
 746         struct stree *new;
 747 
 748         __in_unmatched_hook++;
 749 
 750         __set_fake_cur_stree_fast(*one);
 751         __push_fake_cur_stree();
 752         FOR_EACH_SM(*two, sm) {
 753                 cur = get_sm_state(sm->owner, sm->name, sm->sym);
 754                 if (cur == sm)
 755                         continue;
 756                 call_pre_merge_hook(cur, sm);
 757         } END_FOR_EACH_SM(sm);
 758         new = __pop_fake_cur_stree();
 759         overwrite_stree(new, one);
 760         free_stree(&new);
 761         __pop_fake_cur_stree_fast();
 762 
 763         __set_fake_cur_stree_fast(*two);
 764         __push_fake_cur_stree();
 765         FOR_EACH_SM(*one, sm) {
 766                 cur = get_sm_state(sm->owner, sm->name, sm->sym);
 767                 if (cur == sm)
 768                         continue;
 769                 call_pre_merge_hook(cur, sm);
 770         } END_FOR_EACH_SM(sm);
 771         new = __pop_fake_cur_stree();
 772         overwrite_stree(new, two);
 773         free_stree(&new);
 774         __pop_fake_cur_stree_fast();
 775 
 776         __in_unmatched_hook--;
 777 }
 778 
 779 static void clone_pool_havers_stree(struct stree **stree)
 780 {
 781         struct sm_state *sm, *tmp;
 782         struct state_list *slist = NULL;
 783 
 784         FOR_EACH_SM(*stree, sm) {
 785                 if (sm->pool) {
 786                         tmp = clone_sm(sm);
 787                         add_ptr_list(&slist, tmp);
 788                 }
 789         } END_FOR_EACH_SM(sm);
 790 
 791         FOR_EACH_PTR(slist, sm) {
 792                 avl_insert(stree, sm);
 793         } END_FOR_EACH_PTR(sm);
 794 
 795         free_slist(&slist);
 796 }
 797 
 798 int __stree_id;
 799 
 800 /*
 801  * merge_slist() is called whenever paths merge, such as after
 802  * an if statement.  It takes the two slists and creates one.
 803  */
 804 static void __merge_stree(struct stree **to, struct stree *stree, int add_pool)
 805 {
 806         struct stree *results = NULL;
 807         struct stree *implied_one = NULL;
 808         struct stree *implied_two = NULL;
 809         AvlIter one_iter;
 810         AvlIter two_iter;
 811         struct sm_state *one, *two, *res;
 812 
 813         if (out_of_memory())
 814                 return;
 815 
 816         /* merging a null and nonnull path gives you only the nonnull path */
 817         if (!stree)
 818                 return;
 819         if (*to == stree)
 820                 return;
 821 
 822         if (!*to) {
 823                 *to = clone_stree(stree);
 824                 return;
 825         }
 826 
 827         implied_one = clone_stree(*to);
 828         implied_two = clone_stree(stree);
 829 
 830         match_states_stree(&implied_one, &implied_two);
 831         call_pre_merge_hooks(&implied_one, &implied_two);
 832 
 833         if (add_pool) {
 834                 clone_pool_havers_stree(&implied_one);
 835                 clone_pool_havers_stree(&implied_two);
 836 
 837                 set_stree_id(&implied_one, ++__stree_id);
 838                 set_stree_id(&implied_two, ++__stree_id);
 839                 if (implied_one->base_stree)
 840                         set_stree_id(&implied_one->base_stree, ++__stree_id);
 841                 if (implied_two->base_stree)
 842                         set_stree_id(&implied_two->base_stree, ++__stree_id);
 843         }
 844 
 845         push_stree(&all_pools, implied_one);
 846         push_stree(&all_pools, implied_two);
 847 
 848         avl_iter_begin(&one_iter, implied_one, FORWARD);
 849         avl_iter_begin(&two_iter, implied_two, FORWARD);
 850 
 851         for (;;) {
 852                 if (!one_iter.sm || !two_iter.sm)
 853                         break;
 854 
 855                 one = one_iter.sm;
 856                 two = two_iter.sm;
 857 
 858                 if (one == two) {
 859                         avl_insert(&results, one);
 860                         goto next;
 861                 }
 862 
 863                 if (add_pool) {
 864                         one->pool = implied_one;
 865                         if (implied_one->base_stree)
 866                                 one->pool = implied_one->base_stree;
 867                         two->pool = implied_two;
 868                         if (implied_two->base_stree)
 869                                 two->pool = implied_two->base_stree;
 870                 }
 871                 res = merge_sm_states(one, two);
 872                 add_possible_sm(res, one);
 873                 add_possible_sm(res, two);
 874                 avl_insert(&results, res);
 875 next:
 876                 avl_iter_next(&one_iter);
 877                 avl_iter_next(&two_iter);
 878         }
 879 
 880         free_stree(to);
 881         *to = results;
 882 }
 883 
 884 void merge_stree(struct stree **to, struct stree *stree)
 885 {
 886         __merge_stree(to, stree, 1);
 887 }
 888 
 889 void merge_stree_no_pools(struct stree **to, struct stree *stree)
 890 {
 891         __merge_stree(to, stree, 0);
 892 }
 893 
 894 /*
 895  * This is unfortunately a bit subtle...  The problem is that if a
 896  * state is set on one fake stree but not the other then we should
 897  * look up the the original state and use that as the unset state.
 898  * Fortunately, after you pop your fake stree then the cur_slist should
 899  * reflect the original state.
 900  */
 901 void merge_fake_stree(struct stree **to, struct stree *stree)
 902 {
 903         struct stree *one = *to;
 904         struct stree *two = stree;
 905         struct sm_state *sm;
 906         struct state_list *add_to_one = NULL;
 907         struct state_list *add_to_two = NULL;
 908         AvlIter one_iter;
 909         AvlIter two_iter;
 910 
 911         if (!stree)
 912                 return;
 913         if (*to == stree)
 914                 return;
 915         if (!*to) {
 916                 *to = clone_stree(stree);
 917                 return;
 918         }
 919 
 920         avl_iter_begin(&one_iter, one, FORWARD);
 921         avl_iter_begin(&two_iter, two, FORWARD);
 922 
 923         for (;;) {
 924                 if (!one_iter.sm && !two_iter.sm)
 925                         break;
 926                 if (cmp_tracker(one_iter.sm, two_iter.sm) < 0) {
 927                         sm = get_sm_state(one_iter.sm->owner, one_iter.sm->name,
 928                                           one_iter.sm->sym);
 929                         if (sm)
 930                                 add_ptr_list(&add_to_two, sm);
 931                         avl_iter_next(&one_iter);
 932                 } else if (cmp_tracker(one_iter.sm, two_iter.sm) == 0) {
 933                         avl_iter_next(&one_iter);
 934                         avl_iter_next(&two_iter);
 935                 } else {
 936                         sm = get_sm_state(two_iter.sm->owner, two_iter.sm->name,
 937                                           two_iter.sm->sym);
 938                         if (sm)
 939                                 add_ptr_list(&add_to_one, sm);
 940                         avl_iter_next(&two_iter);
 941                 }
 942         }
 943 
 944         FOR_EACH_PTR(add_to_one, sm) {
 945                 avl_insert(&one, sm);
 946         } END_FOR_EACH_PTR(sm);
 947 
 948         FOR_EACH_PTR(add_to_two, sm) {
 949                 avl_insert(&two, sm);
 950         } END_FOR_EACH_PTR(sm);
 951 
 952         one->base_stree = clone_stree(__get_cur_stree());
 953         FOR_EACH_SM(one, sm) {
 954                 avl_insert(&one->base_stree, sm);
 955         } END_FOR_EACH_SM(sm);
 956 
 957         two->base_stree = clone_stree(__get_cur_stree());
 958         FOR_EACH_SM(two, sm) {
 959                 avl_insert(&two->base_stree, sm);
 960         } END_FOR_EACH_SM(sm);
 961 
 962         free_slist(&add_to_one);
 963         free_slist(&add_to_two);
 964 
 965         __merge_stree(&one, two, 1);
 966 
 967         *to = one;
 968 }
 969 
 970 /*
 971  * filter_slist() removes any sm states "slist" holds in common with "filter"
 972  */
 973 void filter_stree(struct stree **stree, struct stree *filter)
 974 {
 975         struct stree *results = NULL;
 976         AvlIter one_iter;
 977         AvlIter two_iter;
 978 
 979         avl_iter_begin(&one_iter, *stree, FORWARD);
 980         avl_iter_begin(&two_iter, filter, FORWARD);
 981 
 982         /* FIXME: This should probably be re-written with trees in mind */
 983 
 984         for (;;) {
 985                 if (!one_iter.sm && !two_iter.sm)
 986                         break;
 987                 if (cmp_tracker(one_iter.sm, two_iter.sm) < 0) {
 988                         avl_insert(&results, one_iter.sm);
 989                         avl_iter_next(&one_iter);
 990                 } else if (cmp_tracker(one_iter.sm, two_iter.sm) == 0) {
 991                         if (one_iter.sm != two_iter.sm)
 992                                 avl_insert(&results, one_iter.sm);
 993                         avl_iter_next(&one_iter);
 994                         avl_iter_next(&two_iter);
 995                 } else {
 996                         avl_iter_next(&two_iter);
 997                 }
 998         }
 999 
1000         free_stree(stree);
1001         *stree = results;
1002 }
1003 
1004 
1005 /*
1006  * and_slist_stack() pops the top two slists, overwriting the one with
1007  * the other and pushing it back on the stack.
1008  */
1009 void and_stree_stack(struct stree_stack **stack)
1010 {
1011         struct sm_state *tmp;
1012         struct stree *right_stree = pop_stree(stack);
1013 
1014         FOR_EACH_SM(right_stree, tmp) {
1015                 overwrite_sm_state_stree_stack(stack, tmp);
1016         } END_FOR_EACH_SM(tmp);
1017         free_stree(&right_stree);
1018 }
1019 
1020 /*
1021  * or_slist_stack() is for if we have:  if (foo || bar) { foo->baz;
1022  * It pops the two slists from the top of the stack and merges them
1023  * together in a way that preserves the things they have in common
1024  * but creates a merged state for most of the rest.
1025  * You could have code that had:  if (foo || foo) { foo->baz;
1026  * It's this function which ensures smatch does the right thing.
1027  */
1028 void or_stree_stack(struct stree_stack **pre_conds,
1029                     struct stree *cur_stree,
1030                     struct stree_stack **stack)
1031 {
1032         struct stree *new;
1033         struct stree *old;
1034         struct stree *pre_stree;
1035         struct stree *res;
1036         struct stree *tmp_stree;
1037 
1038         new = pop_stree(stack);
1039         old = pop_stree(stack);
1040 
1041         pre_stree = pop_stree(pre_conds);
1042         push_stree(pre_conds, clone_stree(pre_stree));
1043 
1044         res = clone_stree(pre_stree);
1045         overwrite_stree(old, &res);
1046 
1047         tmp_stree = clone_stree(cur_stree);
1048         overwrite_stree(new, &tmp_stree);
1049 
1050         merge_stree(&res, tmp_stree);
1051         filter_stree(&res, pre_stree);
1052 
1053         push_stree(stack, res);
1054         free_stree(&tmp_stree);
1055         free_stree(&pre_stree);
1056         free_stree(&new);
1057         free_stree(&old);
1058 }
1059 
1060 /*
1061  * get_named_stree() is only used for gotos.
1062  */
1063 struct stree **get_named_stree(struct named_stree_stack *stack,
1064                                const char *name,
1065                                struct symbol *sym)
1066 {
1067         struct named_stree *tmp;
1068 
1069         FOR_EACH_PTR(stack, tmp) {
1070                 if (tmp->sym == sym &&
1071                     strcmp(tmp->name, name) == 0)
1072                         return &tmp->stree;
1073         } END_FOR_EACH_PTR(tmp);
1074         return NULL;
1075 }
1076 
1077 /* FIXME:  These parameters are in a different order from expected */
1078 void overwrite_stree(struct stree *from, struct stree **to)
1079 {
1080         struct sm_state *tmp;
1081 
1082         FOR_EACH_SM(from, tmp) {
1083                 overwrite_sm_state_stree(to, tmp);
1084         } END_FOR_EACH_SM(tmp);
1085 }
1086