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