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