1 /* 2 * Copyright (C) 2012 Oracle. 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 * The point here is to store the relationships between two variables. 20 * Ie: y > x. 21 * To do that we create a state with the two variables in alphabetical order: 22 * ->name = "x vs y" and the state would be "<". On the false path the state 23 * would be ">=". 24 * 25 * Part of the trick of it is that if x or y is modified then we need to reset 26 * the state. We need to keep a list of all the states which depend on x and 27 * all the states which depend on y. The link_id code handles this. 28 * 29 */ 30 31 #include "smatch.h" 32 #include "smatch_extra.h" 33 #include "smatch_slist.h" 34 35 static int compare_id; 36 static int link_id; 37 static int inc_dec_id; 38 static int inc_dec_link_id; 39 40 static void add_comparison(struct expression *left, int comparison, struct expression *right); 41 42 /* for handling for loops */ 43 STATE(start); 44 STATE(incremented); 45 46 ALLOCATOR(compare_data, "compare data"); 47 48 static struct symbol *vsl_to_sym(struct var_sym_list *vsl) 49 { 50 struct var_sym *vs; 51 52 if (!vsl) 53 return NULL; 54 if (ptr_list_size((struct ptr_list *)vsl) != 1) 55 return NULL; 56 vs = first_ptr_list((struct ptr_list *)vsl); 57 return vs->sym; 58 } 59 60 struct smatch_state *alloc_compare_state( 61 struct expression *left, 62 const char *left_var, struct var_sym_list *left_vsl, 63 int comparison, 64 struct expression *right, 65 const char *right_var, struct var_sym_list *right_vsl) 66 { 67 struct smatch_state *state; 68 struct compare_data *data; 69 70 state = __alloc_smatch_state(0); 71 state->name = alloc_sname(show_special(comparison)); 72 data = __alloc_compare_data(0); 73 data->left = left; 74 data->left_var = alloc_sname(left_var); 75 data->left_vsl = clone_var_sym_list(left_vsl); 76 data->comparison = comparison; 77 data->right = right; 78 data->right_var = alloc_sname(right_var); 79 data->right_vsl = clone_var_sym_list(right_vsl); 80 state->data = data; 81 return state; 82 } 83 84 int state_to_comparison(struct smatch_state *state) 85 { 86 if (!state || !state->data) 87 return 0; 88 return ((struct compare_data *)state->data)->comparison; 89 } 90 91 /* 92 * flip_comparison() reverses the op left and right. So "x >= y" becomes "y <= x". 93 */ 94 int flip_comparison(int op) 95 { 96 switch (op) { 97 case 0: 98 return 0; 99 case '<': 100 return '>'; 101 case SPECIAL_UNSIGNED_LT: 102 return SPECIAL_UNSIGNED_GT; 103 case SPECIAL_LTE: 104 return SPECIAL_GTE; 105 case SPECIAL_UNSIGNED_LTE: 106 return SPECIAL_UNSIGNED_GTE; 107 case SPECIAL_EQUAL: 108 return SPECIAL_EQUAL; 109 case SPECIAL_NOTEQUAL: 110 return SPECIAL_NOTEQUAL; 111 case SPECIAL_GTE: 112 return SPECIAL_LTE; 113 case SPECIAL_UNSIGNED_GTE: 114 return SPECIAL_UNSIGNED_LTE; 115 case '>': 116 return '<'; 117 case SPECIAL_UNSIGNED_GT: 118 return SPECIAL_UNSIGNED_LT; 119 default: 120 sm_perror("unhandled comparison %d", op); 121 return op; 122 } 123 } 124 125 int negate_comparison(int op) 126 { 127 switch (op) { 128 case 0: 129 return 0; 130 case '<': 131 return SPECIAL_GTE; 132 case SPECIAL_UNSIGNED_LT: 133 return SPECIAL_UNSIGNED_GTE; 134 case SPECIAL_LTE: 135 return '>'; 136 case SPECIAL_UNSIGNED_LTE: 137 return SPECIAL_UNSIGNED_GT; 138 case SPECIAL_EQUAL: 139 return SPECIAL_NOTEQUAL; 140 case SPECIAL_NOTEQUAL: 141 return SPECIAL_EQUAL; 142 case SPECIAL_GTE: 143 return '<'; 144 case SPECIAL_UNSIGNED_GTE: 145 return SPECIAL_UNSIGNED_LT; 146 case '>': 147 return SPECIAL_LTE; 148 case SPECIAL_UNSIGNED_GT: 149 return SPECIAL_UNSIGNED_LTE; 150 default: 151 sm_perror("unhandled comparison %d", op); 152 return op; 153 } 154 } 155 156 static int rl_comparison(struct range_list *left_rl, struct range_list *right_rl) 157 { 158 sval_t left_min, left_max, right_min, right_max; 159 struct symbol *type = &int_ctype; 160 161 if (!left_rl || !right_rl) 162 return 0; 163 164 if (type_positive_bits(rl_type(left_rl)) > type_positive_bits(type)) 165 type = rl_type(left_rl); 166 if (type_positive_bits(rl_type(right_rl)) > type_positive_bits(type)) 167 type = rl_type(right_rl); 168 169 left_rl = cast_rl(type, left_rl); 170 right_rl = cast_rl(type, right_rl); 171 172 left_min = rl_min(left_rl); 173 left_max = rl_max(left_rl); 174 right_min = rl_min(right_rl); 175 right_max = rl_max(right_rl); 176 177 if (left_min.value == left_max.value && 178 right_min.value == right_max.value && 179 left_min.value == right_min.value) 180 return SPECIAL_EQUAL; 181 182 if (sval_cmp(left_max, right_min) < 0) 183 return '<'; 184 if (sval_cmp(left_max, right_min) == 0) 185 return SPECIAL_LTE; 186 if (sval_cmp(left_min, right_max) > 0) 187 return '>'; 188 if (sval_cmp(left_min, right_max) == 0) 189 return SPECIAL_GTE; 190 191 return 0; 192 } 193 194 static int comparison_from_extra(struct expression *a, struct expression *b) 195 { 196 struct range_list *left, *right; 197 198 if (!get_implied_rl(a, &left)) 199 return 0; 200 if (!get_implied_rl(b, &right)) 201 return 0; 202 203 return rl_comparison(left, right); 204 } 205 206 static struct range_list *get_orig_rl(struct var_sym_list *vsl) 207 { 208 struct symbol *sym; 209 struct smatch_state *state; 210 211 if (!vsl) 212 return NULL; 213 sym = vsl_to_sym(vsl); 214 if (!sym || !sym->ident) 215 return NULL; 216 state = get_orig_estate(sym->ident->name, sym); 217 return estate_rl(state); 218 } 219 220 static struct smatch_state *unmatched_comparison(struct sm_state *sm) 221 { 222 struct compare_data *data = sm->state->data; 223 struct range_list *left_rl, *right_rl; 224 int op; 225 226 if (!data) 227 return &undefined; 228 229 if (strstr(data->left_var, " orig")) 230 left_rl = get_orig_rl(data->left_vsl); 231 else if (!get_implied_rl_var_sym(data->left_var, vsl_to_sym(data->left_vsl), &left_rl)) 232 return &undefined; 233 234 if (strstr(data->right_var, " orig")) 235 right_rl = get_orig_rl(data->right_vsl); 236 else if (!get_implied_rl_var_sym(data->right_var, vsl_to_sym(data->right_vsl), &right_rl)) 237 return &undefined; 238 239 op = rl_comparison(left_rl, right_rl); 240 if (op) 241 return alloc_compare_state( 242 data->left, data->left_var, data->left_vsl, 243 op, 244 data->right, data->right_var, data->right_vsl); 245 246 return &undefined; 247 } 248 249 /* remove_unsigned_from_comparison() is obviously a hack. */ 250 int remove_unsigned_from_comparison(int op) 251 { 252 switch (op) { 253 case SPECIAL_UNSIGNED_LT: 254 return '<'; 255 case SPECIAL_UNSIGNED_LTE: 256 return SPECIAL_LTE; 257 case SPECIAL_UNSIGNED_GTE: 258 return SPECIAL_GTE; 259 case SPECIAL_UNSIGNED_GT: 260 return '>'; 261 default: 262 return op; 263 } 264 } 265 266 /* 267 * This is for when you merge states "a < b" and "a == b", the result is that 268 * we can say for sure, "a <= b" after the merge. 269 */ 270 int merge_comparisons(int one, int two) 271 { 272 int LT, EQ, GT; 273 274 if (!one || !two) 275 return 0; 276 277 one = remove_unsigned_from_comparison(one); 278 two = remove_unsigned_from_comparison(two); 279 280 if (one == two) 281 return one; 282 283 LT = EQ = GT = 0; 284 285 switch (one) { 286 case '<': 287 LT = 1; 288 break; 289 case SPECIAL_LTE: 290 LT = 1; 291 EQ = 1; 292 break; 293 case SPECIAL_EQUAL: 294 EQ = 1; 295 break; 296 case SPECIAL_GTE: 297 GT = 1; 298 EQ = 1; 299 break; 300 case '>': 301 GT = 1; 302 } 303 304 switch (two) { 305 case '<': 306 LT = 1; 307 break; 308 case SPECIAL_LTE: 309 LT = 1; 310 EQ = 1; 311 break; 312 case SPECIAL_EQUAL: 313 EQ = 1; 314 break; 315 case SPECIAL_GTE: 316 GT = 1; 317 EQ = 1; 318 break; 319 case '>': 320 GT = 1; 321 } 322 323 if (LT && EQ && GT) 324 return 0; 325 if (LT && EQ) 326 return SPECIAL_LTE; 327 if (LT && GT) 328 return SPECIAL_NOTEQUAL; 329 if (LT) 330 return '<'; 331 if (EQ && GT) 332 return SPECIAL_GTE; 333 if (GT) 334 return '>'; 335 return 0; 336 } 337 338 /* 339 * This is for if you have "a < b" and "b <= c". Or in other words, 340 * "a < b <= c". You would call this like get_combined_comparison('<', '<='). 341 * The return comparison would be '<'. 342 * 343 * This function is different from merge_comparisons(), for example: 344 * merge_comparison('<', '==') returns '<=' 345 * get_combined_comparison('<', '==') returns '<' 346 */ 347 int combine_comparisons(int left_compare, int right_compare) 348 { 349 int LT, EQ, GT; 350 351 left_compare = remove_unsigned_from_comparison(left_compare); 352 right_compare = remove_unsigned_from_comparison(right_compare); 353 354 LT = EQ = GT = 0; 355 356 switch (left_compare) { 357 case '<': 358 LT++; 359 break; 360 case SPECIAL_LTE: 361 LT++; 362 EQ++; 363 break; 364 case SPECIAL_EQUAL: 365 return right_compare; 366 case SPECIAL_GTE: 367 GT++; 368 EQ++; 369 break; 370 case '>': 371 GT++; 372 } 373 374 switch (right_compare) { 375 case '<': 376 LT++; 377 break; 378 case SPECIAL_LTE: 379 LT++; 380 EQ++; 381 break; 382 case SPECIAL_EQUAL: 383 return left_compare; 384 case SPECIAL_GTE: 385 GT++; 386 EQ++; 387 break; 388 case '>': 389 GT++; 390 } 391 392 if (LT == 2) { 393 if (EQ == 2) 394 return SPECIAL_LTE; 395 return '<'; 396 } 397 398 if (GT == 2) { 399 if (EQ == 2) 400 return SPECIAL_GTE; 401 return '>'; 402 } 403 return 0; 404 } 405 406 int filter_comparison(int orig, int op) 407 { 408 if (orig == op) 409 return orig; 410 411 orig = remove_unsigned_from_comparison(orig); 412 op = remove_unsigned_from_comparison(op); 413 414 switch (orig) { 415 case 0: 416 return op; 417 case '<': 418 switch (op) { 419 case '<': 420 case SPECIAL_LTE: 421 case SPECIAL_NOTEQUAL: 422 return '<'; 423 } 424 return 0; 425 case SPECIAL_LTE: 426 switch (op) { 427 case '<': 428 case SPECIAL_LTE: 429 case SPECIAL_EQUAL: 430 return op; 431 case SPECIAL_NOTEQUAL: 432 return '<'; 433 } 434 return 0; 435 case SPECIAL_EQUAL: 436 switch (op) { 437 case SPECIAL_LTE: 438 case SPECIAL_EQUAL: 439 case SPECIAL_GTE: 440 case SPECIAL_UNSIGNED_LTE: 441 case SPECIAL_UNSIGNED_GTE: 442 return SPECIAL_EQUAL; 443 } 444 return 0; 445 case SPECIAL_NOTEQUAL: 446 switch (op) { 447 case '<': 448 case SPECIAL_LTE: 449 return '<'; 450 case SPECIAL_UNSIGNED_LT: 451 case SPECIAL_UNSIGNED_LTE: 452 return SPECIAL_UNSIGNED_LT; 453 case SPECIAL_NOTEQUAL: 454 return op; 455 case '>': 456 case SPECIAL_GTE: 457 return '>'; 458 case SPECIAL_UNSIGNED_GT: 459 case SPECIAL_UNSIGNED_GTE: 460 return SPECIAL_UNSIGNED_GT; 461 } 462 return 0; 463 case SPECIAL_GTE: 464 switch (op) { 465 case SPECIAL_LTE: 466 return SPECIAL_EQUAL; 467 case '>': 468 case SPECIAL_GTE: 469 case SPECIAL_EQUAL: 470 return op; 471 case SPECIAL_NOTEQUAL: 472 return '>'; 473 } 474 return 0; 475 case '>': 476 switch (op) { 477 case '>': 478 case SPECIAL_GTE: 479 case SPECIAL_NOTEQUAL: 480 return '>'; 481 } 482 return 0; 483 case SPECIAL_UNSIGNED_LT: 484 switch (op) { 485 case SPECIAL_UNSIGNED_LT: 486 case SPECIAL_UNSIGNED_LTE: 487 case SPECIAL_NOTEQUAL: 488 return SPECIAL_UNSIGNED_LT; 489 } 490 return 0; 491 case SPECIAL_UNSIGNED_LTE: 492 switch (op) { 493 case SPECIAL_UNSIGNED_LT: 494 case SPECIAL_UNSIGNED_LTE: 495 case SPECIAL_EQUAL: 496 return op; 497 case SPECIAL_NOTEQUAL: 498 return SPECIAL_UNSIGNED_LT; 499 case SPECIAL_UNSIGNED_GTE: 500 return SPECIAL_EQUAL; 501 } 502 return 0; 503 case SPECIAL_UNSIGNED_GTE: 504 switch (op) { 505 case SPECIAL_UNSIGNED_LTE: 506 return SPECIAL_EQUAL; 507 case SPECIAL_NOTEQUAL: 508 return SPECIAL_UNSIGNED_GT; 509 case SPECIAL_EQUAL: 510 case SPECIAL_UNSIGNED_GTE: 511 case SPECIAL_UNSIGNED_GT: 512 return op; 513 } 514 return 0; 515 case SPECIAL_UNSIGNED_GT: 516 switch (op) { 517 case SPECIAL_UNSIGNED_GT: 518 case SPECIAL_UNSIGNED_GTE: 519 case SPECIAL_NOTEQUAL: 520 return SPECIAL_UNSIGNED_GT; 521 } 522 return 0; 523 } 524 return 0; 525 } 526 527 static void pre_merge_hook(struct sm_state *sm) 528 { 529 struct compare_data *data = sm->state->data; 530 int other; 531 532 if (!data) 533 return; 534 other = get_comparison(data->left, data->right); 535 if (!other) 536 return; 537 538 set_state(compare_id, sm->name, NULL, 539 alloc_compare_state(data->left, data->left_var, data->left_vsl, 540 other, 541 data->right, data->right_var, data->right_vsl)); 542 } 543 544 struct smatch_state *merge_compare_states(struct smatch_state *s1, struct smatch_state *s2) 545 { 546 struct compare_data *data = s1->data; 547 int op; 548 549 op = merge_comparisons(state_to_comparison(s1), state_to_comparison(s2)); 550 if (op) 551 return alloc_compare_state( 552 data->left, data->left_var, data->left_vsl, 553 op, 554 data->right, data->right_var, data->right_vsl); 555 return &undefined; 556 } 557 558 static struct smatch_state *alloc_link_state(struct string_list *links) 559 { 560 struct smatch_state *state; 561 static char buf[256]; 562 char *tmp; 563 int i; 564 565 state = __alloc_smatch_state(0); 566 567 i = 0; 568 FOR_EACH_PTR(links, tmp) { 569 if (!i++) { 570 snprintf(buf, sizeof(buf), "%s", tmp); 571 } else { 572 append(buf, ", ", sizeof(buf)); 573 append(buf, tmp, sizeof(buf)); 574 } 575 } END_FOR_EACH_PTR(tmp); 576 577 state->name = alloc_sname(buf); 578 state->data = links; 579 return state; 580 } 581 582 static void save_start_states(struct statement *stmt) 583 { 584 struct symbol *param; 585 char orig[64]; 586 char state_name[128]; 587 struct smatch_state *state; 588 struct string_list *links; 589 char *link; 590 591 FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, param) { 592 struct var_sym_list *left_vsl = NULL; 593 struct var_sym_list *right_vsl = NULL; 594 595 if (!param->ident) 596 continue; 597 snprintf(orig, sizeof(orig), "%s orig", param->ident->name); 598 snprintf(state_name, sizeof(state_name), "%s vs %s", param->ident->name, orig); 599 add_var_sym(&left_vsl, param->ident->name, param); 600 add_var_sym(&right_vsl, orig, param); 601 state = alloc_compare_state( 602 NULL, param->ident->name, left_vsl, 603 SPECIAL_EQUAL, 604 NULL, alloc_sname(orig), right_vsl); 605 set_state(compare_id, state_name, NULL, state); 606 607 link = alloc_sname(state_name); 608 links = NULL; 609 insert_string(&links, link); 610 state = alloc_link_state(links); 611 set_state(link_id, param->ident->name, param, state); 612 } END_FOR_EACH_PTR(param); 613 } 614 615 static struct smatch_state *merge_links(struct smatch_state *s1, struct smatch_state *s2) 616 { 617 struct smatch_state *ret; 618 struct string_list *links; 619 620 links = combine_string_lists(s1->data, s2->data); 621 ret = alloc_link_state(links); 622 return ret; 623 } 624 625 static void save_link_var_sym(const char *var, struct symbol *sym, const char *link) 626 { 627 struct smatch_state *old_state, *new_state; 628 struct string_list *links; 629 char *new; 630 631 old_state = get_state(link_id, var, sym); 632 if (old_state) 633 links = clone_str_list(old_state->data); 634 else 635 links = NULL; 636 637 new = alloc_sname(link); 638 insert_string(&links, new); 639 640 new_state = alloc_link_state(links); 641 set_state(link_id, var, sym, new_state); 642 } 643 644 static void match_inc(struct sm_state *sm, bool preserve) 645 { 646 struct string_list *links; 647 struct smatch_state *state, *new; 648 struct compare_data *data; 649 char *tmp; 650 int flip; 651 int op; 652 653 links = sm->state->data; 654 655 FOR_EACH_PTR(links, tmp) { 656 state = get_state(compare_id, tmp, NULL); 657 if (!state) 658 continue; 659 data = state->data; 660 if (!data) 661 continue; 662 663 flip = 0; 664 if (strncmp(sm->name, tmp, strlen(sm->name)) != 0 || 665 tmp[strlen(sm->name)] != ' ') 666 flip = 1; 667 668 op = state_to_comparison(state); 669 670 switch (flip ? flip_comparison(op) : op) { 671 case SPECIAL_EQUAL: 672 case SPECIAL_GTE: 673 case SPECIAL_UNSIGNED_GTE: 674 case '>': 675 case SPECIAL_UNSIGNED_GT: 676 if (preserve) 677 break; 678 new = alloc_compare_state( 679 data->left, data->left_var, data->left_vsl, 680 flip ? '<' : '>', 681 data->right, data->right_var, data->right_vsl); 682 set_state(compare_id, tmp, NULL, new); 683 break; 684 case '<': 685 case SPECIAL_UNSIGNED_LT: 686 new = alloc_compare_state( 687 data->left, data->left_var, data->left_vsl, 688 flip ? SPECIAL_GTE : SPECIAL_LTE, 689 data->right, data->right_var, data->right_vsl); 690 set_state(compare_id, tmp, NULL, new); 691 break; 692 default: 693 set_state(compare_id, tmp, NULL, &undefined); 694 } 695 } END_FOR_EACH_PTR(tmp); 696 } 697 698 static void match_dec(struct sm_state *sm, bool preserve) 699 { 700 struct string_list *links; 701 struct smatch_state *state; 702 char *tmp; 703 704 links = sm->state->data; 705 706 FOR_EACH_PTR(links, tmp) { 707 state = get_state(compare_id, tmp, NULL); 708 709 switch (state_to_comparison(state)) { 710 case SPECIAL_EQUAL: 711 case SPECIAL_LTE: 712 case SPECIAL_UNSIGNED_LTE: 713 case '<': 714 case SPECIAL_UNSIGNED_LT: { 715 struct compare_data *data = state->data; 716 struct smatch_state *new; 717 718 if (preserve) 719 break; 720 721 new = alloc_compare_state( 722 data->left, data->left_var, data->left_vsl, 723 '<', 724 data->right, data->right_var, data->right_vsl); 725 set_state(compare_id, tmp, NULL, new); 726 break; 727 } 728 default: 729 set_state(compare_id, tmp, NULL, &undefined); 730 } 731 } END_FOR_EACH_PTR(tmp); 732 } 733 734 static void reset_sm(struct sm_state *sm) 735 { 736 struct string_list *links; 737 char *tmp; 738 739 links = sm->state->data; 740 741 FOR_EACH_PTR(links, tmp) { 742 set_state(compare_id, tmp, NULL, &undefined); 743 } END_FOR_EACH_PTR(tmp); 744 set_state(link_id, sm->name, sm->sym, &undefined); 745 } 746 747 static bool match_add_sub_assign(struct sm_state *sm, struct expression *expr) 748 { 749 struct range_list *rl; 750 sval_t zero = { .type = &int_ctype }; 751 752 if (!expr || expr->type != EXPR_ASSIGNMENT) 753 return false; 754 if (expr->op != SPECIAL_ADD_ASSIGN && expr->op != SPECIAL_SUB_ASSIGN) 755 return false; 756 757 get_absolute_rl(expr->right, &rl); 758 if (sval_is_negative(rl_min(rl))) { 759 reset_sm(sm); 760 return false; 761 } 762 763 if (expr->op == SPECIAL_ADD_ASSIGN) 764 match_inc(sm, rl_has_sval(rl, zero)); 765 else 766 match_dec(sm, rl_has_sval(rl, zero)); 767 return true; 768 } 769 770 static void match_inc_dec(struct sm_state *sm, struct expression *mod_expr) 771 { 772 /* 773 * if (foo > bar) then ++foo is also > bar. 774 */ 775 if (!mod_expr) 776 return; 777 if (match_add_sub_assign(sm, mod_expr)) 778 return; 779 if (mod_expr->type != EXPR_PREOP && mod_expr->type != EXPR_POSTOP) 780 return; 781 782 if (mod_expr->op == SPECIAL_INCREMENT) 783 match_inc(sm, false); 784 else if (mod_expr->op == SPECIAL_DECREMENT) 785 match_dec(sm, false); 786 } 787 788 static int is_self_assign(struct expression *expr) 789 { 790 if (!expr || expr->type != EXPR_ASSIGNMENT || expr->op != '=') 791 return 0; 792 return expr_equiv(expr->left, expr->right); 793 } 794 795 static void match_modify(struct sm_state *sm, struct expression *mod_expr) 796 { 797 if (mod_expr && is_self_assign(mod_expr)) 798 return; 799 800 /* handled by match_inc_dec() */ 801 if (mod_expr && 802 ((mod_expr->type == EXPR_PREOP || mod_expr->type == EXPR_POSTOP) && 803 (mod_expr->op == SPECIAL_INCREMENT || mod_expr->op == SPECIAL_DECREMENT))) 804 return; 805 if (mod_expr && mod_expr->type == EXPR_ASSIGNMENT && 806 (mod_expr->op == SPECIAL_ADD_ASSIGN || mod_expr->op == SPECIAL_SUB_ASSIGN)) 807 return; 808 809 reset_sm(sm); 810 } 811 812 static void match_preop(struct expression *expr) 813 { 814 struct expression *parent; 815 struct range_list *left, *right; 816 int op; 817 818 /* 819 * This is an important special case. Say you have: 820 * 821 * if (++j == limit) 822 * 823 * Assume that we know the range of limit is higher than the start 824 * value for "j". Then the first thing that we process is the ++j. We 825 * have not comparison states set up so it doesn't get caught by the 826 * modification hook. But it does get caught by smatch_extra which sets 827 * j to unknown then we parse the "j == limit" and sets false to != but 828 * really we want false to be <. 829 * 830 * So what we do is we set j < limit here, then the match_modify catches 831 * it and we do a match_inc_dec(). 832 * 833 */ 834 835 if (expr->type != EXPR_PREOP || 836 (expr->op != SPECIAL_INCREMENT && expr->op != SPECIAL_DECREMENT)) 837 return; 838 839 parent = expr_get_parent_expr(expr); 840 if (!parent) 841 return; 842 if (parent->type != EXPR_COMPARE || parent->op != SPECIAL_EQUAL) 843 return; 844 if (parent->left != expr) 845 return; 846 847 if (!get_implied_rl(expr->unop, &left) || 848 !get_implied_rl(parent->right, &right)) 849 return; 850 851 op = rl_comparison(left, right); 852 if (!op) 853 return; 854 855 add_comparison(expr->unop, op, parent->right); 856 } 857 858 static char *chunk_to_var_sym(struct expression *expr, struct symbol **sym) 859 { 860 expr = strip_expr(expr); 861 if (!expr) 862 return NULL; 863 if (sym) 864 *sym = NULL; 865 866 if (expr->type == EXPR_PREOP && 867 (expr->op == SPECIAL_INCREMENT || 868 expr->op == SPECIAL_DECREMENT)) 869 expr = strip_expr(expr->unop); 870 871 if (expr->type == EXPR_CALL) { 872 char buf[64]; 873 874 snprintf(buf, sizeof(buf), "return %p", expr); 875 return alloc_string(buf); 876 } 877 878 return expr_to_chunk_sym_vsl(expr, sym, NULL); 879 } 880 881 static char *chunk_to_var(struct expression *expr) 882 { 883 return chunk_to_var_sym(expr, NULL); 884 } 885 886 static struct smatch_state *get_state_chunk(int owner, struct expression *expr) 887 { 888 char *name; 889 struct symbol *sym; 890 struct smatch_state *ret; 891 892 name = chunk_to_var_sym(expr, &sym); 893 if (!name) 894 return NULL; 895 896 ret = get_state(owner, name, sym); 897 free_string(name); 898 return ret; 899 } 900 901 static void save_link(struct expression *expr, char *link) 902 { 903 char *var; 904 struct symbol *sym; 905 906 expr = strip_expr(expr); 907 if (expr->type == EXPR_BINOP) { 908 char *chunk; 909 910 chunk = chunk_to_var(expr); 911 if (!chunk) 912 return; 913 914 save_link(expr->left, link); 915 save_link(expr->right, link); 916 save_link_var_sym(chunk, NULL, link); 917 return; 918 } 919 920 var = chunk_to_var_sym(expr, &sym); 921 if (!var) 922 return; 923 924 save_link_var_sym(var, sym, link); 925 free_string(var); 926 } 927 928 static int get_orig_comparison(struct stree *pre_stree, const char *left, const char *right) 929 { 930 struct smatch_state *state; 931 struct compare_data *data; 932 int flip = 0; 933 char state_name[256]; 934 935 if (strcmp(left, right) > 0) { 936 const char *tmp = right; 937 938 flip = 1; 939 right = left; 940 left = tmp; 941 } 942 943 snprintf(state_name, sizeof(state_name), "%s vs %s", left, right); 944 state = get_state_stree(pre_stree, compare_id, state_name, NULL); 945 if (!state || !state->data) 946 return 0; 947 data = state->data; 948 if (flip) 949 return flip_comparison(data->comparison); 950 return data->comparison; 951 952 } 953 954 static int have_common_var_sym(struct var_sym_list *left_vsl, struct var_sym_list *right_vsl) 955 { 956 struct var_sym *tmp; 957 958 FOR_EACH_PTR(left_vsl, tmp) { 959 if (in_var_sym_list(right_vsl, tmp->var, tmp->sym)) 960 return 1; 961 } END_FOR_EACH_PTR(tmp); 962 963 return 0; 964 } 965 966 /* 967 * The idea here is that we take a comparison "a < b" and then we look at all 968 * the things which "b" is compared against "b < c" and we say that that implies 969 * a relationship "a < c". 970 * 971 * The names here about because the comparisons are organized like this 972 * "a < b < c". 973 * 974 */ 975 static void update_tf_links(struct stree *pre_stree, 976 struct expression *left_expr, 977 const char *left_var, struct var_sym_list *left_vsl, 978 int left_comparison, int left_false_comparison, 979 const char *mid_var, struct var_sym_list *mid_vsl, 980 struct string_list *links) 981 { 982 struct smatch_state *state; 983 struct smatch_state *true_state, *false_state; 984 struct compare_data *data; 985 struct expression *right_expr; 986 const char *right_var; 987 struct var_sym_list *right_vsl; 988 int orig_comparison; 989 int right_comparison; 990 int true_comparison; 991 int false_comparison; 992 char *tmp; 993 char state_name[256]; 994 struct var_sym *vs; 995 996 FOR_EACH_PTR(links, tmp) { 997 state = get_state_stree(pre_stree, compare_id, tmp, NULL); 998 if (!state || !state->data) 999 continue; 1000 data = state->data; 1001 right_comparison = data->comparison; 1002 right_expr = data->right; 1003 right_var = data->right_var; 1004 right_vsl = data->right_vsl; 1005 if (strcmp(mid_var, right_var) == 0) { 1006 right_expr = data->left; 1007 right_var = data->left_var; 1008 right_vsl = data->left_vsl; 1009 right_comparison = flip_comparison(right_comparison); 1010 } 1011 if (have_common_var_sym(left_vsl, right_vsl)) 1012 continue; 1013 1014 orig_comparison = get_orig_comparison(pre_stree, left_var, right_var); 1015 1016 true_comparison = combine_comparisons(left_comparison, right_comparison); 1017 false_comparison = combine_comparisons(left_false_comparison, right_comparison); 1018 1019 true_comparison = filter_comparison(orig_comparison, true_comparison); 1020 false_comparison = filter_comparison(orig_comparison, false_comparison); 1021 1022 if (strcmp(left_var, right_var) > 0) { 1023 struct expression *tmp_expr = left_expr; 1024 const char *tmp_var = left_var; 1025 struct var_sym_list *tmp_vsl = left_vsl; 1026 1027 left_expr = right_expr; 1028 left_var = right_var; 1029 left_vsl = right_vsl; 1030 right_expr = tmp_expr; 1031 right_var = tmp_var; 1032 right_vsl = tmp_vsl; 1033 true_comparison = flip_comparison(true_comparison); 1034 false_comparison = flip_comparison(false_comparison); 1035 } 1036 1037 if (!true_comparison && !false_comparison) 1038 continue; 1039 1040 if (true_comparison) 1041 true_state = alloc_compare_state( 1042 left_expr, left_var, left_vsl, 1043 true_comparison, 1044 right_expr, right_var, right_vsl); 1045 else 1046 true_state = NULL; 1047 if (false_comparison) 1048 false_state = alloc_compare_state( 1049 left_expr, left_var, left_vsl, 1050 false_comparison, 1051 right_expr, right_var, right_vsl); 1052 else 1053 false_state = NULL; 1054 1055 snprintf(state_name, sizeof(state_name), "%s vs %s", left_var, right_var); 1056 set_true_false_states(compare_id, state_name, NULL, true_state, false_state); 1057 FOR_EACH_PTR(left_vsl, vs) { 1058 save_link_var_sym(vs->var, vs->sym, state_name); 1059 } END_FOR_EACH_PTR(vs); 1060 FOR_EACH_PTR(right_vsl, vs) { 1061 save_link_var_sym(vs->var, vs->sym, state_name); 1062 } END_FOR_EACH_PTR(vs); 1063 if (!vsl_to_sym(left_vsl)) 1064 save_link_var_sym(left_var, NULL, state_name); 1065 if (!vsl_to_sym(right_vsl)) 1066 save_link_var_sym(right_var, NULL, state_name); 1067 } END_FOR_EACH_PTR(tmp); 1068 } 1069 1070 static void update_tf_data(struct stree *pre_stree, 1071 struct expression *left_expr, 1072 const char *left_name, struct var_sym_list *left_vsl, 1073 struct expression *right_expr, 1074 const char *right_name, struct var_sym_list *right_vsl, 1075 int true_comparison, int false_comparison) 1076 { 1077 struct smatch_state *state; 1078 1079 state = get_state_stree(pre_stree, link_id, right_name, vsl_to_sym(right_vsl)); 1080 if (state) 1081 update_tf_links(pre_stree, left_expr, left_name, left_vsl, true_comparison, false_comparison, right_name, right_vsl, state->data); 1082 1083 state = get_state_stree(pre_stree, link_id, left_name, vsl_to_sym(left_vsl)); 1084 if (state) 1085 update_tf_links(pre_stree, right_expr, right_name, right_vsl, flip_comparison(true_comparison), flip_comparison(false_comparison), left_name, left_vsl, state->data); 1086 } 1087 1088 static void iter_modify(struct sm_state *sm, struct expression *mod_expr) 1089 { 1090 if (sm->state != &start || 1091 !mod_expr || 1092 (mod_expr->type != EXPR_PREOP && mod_expr->type != EXPR_POSTOP) || 1093 mod_expr->op != SPECIAL_INCREMENT) 1094 set_state(inc_dec_id, sm->name, sm->sym, &undefined); 1095 else 1096 set_state(inc_dec_id, sm->name, sm->sym, &incremented); 1097 } 1098 1099 static void handle_for_loops(struct expression *expr, char *state_name, struct smatch_state *false_state) 1100 { 1101 sval_t sval; 1102 char *iter_name, *cap_name; 1103 struct symbol *iter_sym, *cap_sym; 1104 struct compare_data *data; 1105 1106 if (expr->op != '<' && expr->op != SPECIAL_UNSIGNED_LT) 1107 return; 1108 1109 if (!__cur_stmt || !__prev_stmt) 1110 return; 1111 if (__cur_stmt->type != STMT_ITERATOR) 1112 return; 1113 if (__cur_stmt->iterator_pre_condition != expr) 1114 return; 1115 1116 /* literals are handled in smatch_extra.c */ 1117 if (get_value(expr->right, &sval)) 1118 return; 1119 1120 /* First time checking the condition */ 1121 if (__prev_stmt == __cur_stmt->iterator_pre_statement) { 1122 if (!get_implied_value(expr->left, &sval) || 1123 sval.value != 0) 1124 return; 1125 1126 iter_name = expr_to_var_sym(expr->left, &iter_sym); 1127 cap_name = expr_to_var_sym(expr->right, &cap_sym); 1128 if (!iter_name || !cap_name || !iter_sym || !cap_sym) { 1129 free_string(iter_name); 1130 free_string(cap_name); 1131 return; 1132 } 1133 1134 set_state(inc_dec_id, iter_name, iter_sym, &start); 1135 store_link(inc_dec_link_id, cap_name, cap_sym, iter_name, iter_sym); 1136 1137 free_string(iter_name); 1138 free_string(cap_name); 1139 return; 1140 } 1141 1142 /* Second time checking the condtion */ 1143 if (__prev_stmt != __cur_stmt->iterator_post_statement) 1144 return; 1145 1146 if (get_state_chunk(inc_dec_id, expr->left) != &incremented) 1147 return; 1148 1149 data = false_state->data; 1150 false_state = alloc_compare_state( 1151 data->left, data->left_var, data->left_vsl, 1152 SPECIAL_EQUAL, 1153 data->right, data->right_var, data->right_vsl); 1154 1155 set_true_false_states(compare_id, state_name, NULL, NULL, false_state); 1156 } 1157 1158 static int is_plus_one(struct expression *expr) 1159 { 1160 sval_t sval; 1161 1162 if (expr->type != EXPR_BINOP || expr->op != '+') 1163 return 0; 1164 if (!get_implied_value(expr->right, &sval) || sval.value != 1) 1165 return 0; 1166 return 1; 1167 } 1168 1169 static int is_minus_one(struct expression *expr) 1170 { 1171 sval_t sval; 1172 1173 if (expr->type != EXPR_BINOP || expr->op != '-') 1174 return 0; 1175 if (!get_implied_value(expr->right, &sval) || sval.value != 1) 1176 return 0; 1177 return 1; 1178 } 1179 1180 static void move_plus_to_minus_helper(struct expression **left_p, struct expression **right_p) 1181 { 1182 struct expression *left = *left_p; 1183 struct expression *right = *right_p; 1184 1185 /* 1186 * These two are basically equivalent: "foo + 1 != bar" and 1187 * "foo != bar - 1". There are issues with signedness and integer 1188 * overflows. There are also issues with type as well. But let's 1189 * pretend we can ignore all that stuff for now. 1190 * 1191 */ 1192 1193 if (!is_plus_one(left)) 1194 return; 1195 1196 *left_p = left->left; 1197 *right_p = binop_expression(right, '-', left->right); 1198 } 1199 1200 static void move_plus_to_minus(struct expression **left_p, struct expression **right_p) 1201 { 1202 if (is_plus_one(*left_p) && is_plus_one(*right_p)) 1203 return; 1204 1205 move_plus_to_minus_helper(left_p, right_p); 1206 move_plus_to_minus_helper(right_p, left_p); 1207 } 1208 1209 static void handle_comparison(struct expression *left_expr, int op, struct expression *right_expr, char **_state_name, struct smatch_state **_false_state) 1210 { 1211 char *left = NULL; 1212 char *right = NULL; 1213 struct symbol *left_sym, *right_sym; 1214 struct var_sym_list *left_vsl = NULL; 1215 struct var_sym_list *right_vsl = NULL; 1216 int false_op; 1217 int orig_comparison; 1218 struct smatch_state *true_state, *false_state; 1219 static char state_name[256]; 1220 struct stree *pre_stree; 1221 sval_t sval; 1222 1223 if (!left_expr || !right_expr) 1224 return; 1225 1226 left_expr = strip_parens(left_expr); 1227 right_expr = strip_parens(right_expr); 1228 1229 while (left_expr->type == EXPR_ASSIGNMENT) 1230 left_expr = strip_parens(left_expr->left); 1231 while (right_expr->type == EXPR_ASSIGNMENT) 1232 right_expr = strip_parens(right_expr->left); 1233 1234 false_op = negate_comparison(op); 1235 1236 move_plus_to_minus(&left_expr, &right_expr); 1237 1238 if (op == SPECIAL_UNSIGNED_LT && 1239 get_implied_value(left_expr, &sval) && 1240 sval.value == 0) 1241 false_op = SPECIAL_EQUAL; 1242 1243 if (op == SPECIAL_UNSIGNED_GT && 1244 get_implied_value(right_expr, &sval) && 1245 sval.value == 0) 1246 false_op = SPECIAL_EQUAL; 1247 1248 left = chunk_to_var_sym(left_expr, &left_sym); 1249 if (!left) 1250 goto free; 1251 if (left_sym) 1252 add_var_sym(&left_vsl, left, left_sym); 1253 else 1254 left_vsl = expr_to_vsl(left_expr); 1255 right = chunk_to_var_sym(right_expr, &right_sym); 1256 if (!right) 1257 goto free; 1258 if (right_sym) 1259 add_var_sym(&right_vsl, right, right_sym); 1260 else 1261 right_vsl = expr_to_vsl(right_expr); 1262 1263 if (strcmp(left, right) > 0) { 1264 char *tmp_name = left; 1265 struct var_sym_list *tmp_vsl = left_vsl; 1266 struct expression *tmp_expr = left_expr; 1267 1268 left = right; 1269 left_vsl = right_vsl; 1270 left_expr = right_expr; 1271 right = tmp_name; 1272 right_vsl = tmp_vsl; 1273 right_expr = tmp_expr; 1274 op = flip_comparison(op); 1275 false_op = flip_comparison(false_op); 1276 } 1277 1278 orig_comparison = get_comparison(left_expr, right_expr); 1279 op = filter_comparison(orig_comparison, op); 1280 false_op = filter_comparison(orig_comparison, false_op); 1281 1282 snprintf(state_name, sizeof(state_name), "%s vs %s", left, right); 1283 true_state = alloc_compare_state( 1284 left_expr, left, left_vsl, 1285 op, 1286 right_expr, right, right_vsl); 1287 false_state = alloc_compare_state( 1288 left_expr, left, left_vsl, 1289 false_op, 1290 right_expr, right, right_vsl); 1291 1292 pre_stree = clone_stree(__get_cur_stree()); 1293 update_tf_data(pre_stree, left_expr, left, left_vsl, right_expr, right, right_vsl, op, false_op); 1294 free_stree(&pre_stree); 1295 1296 set_true_false_states(compare_id, state_name, NULL, true_state, false_state); 1297 __compare_param_limit_hook(left_expr, right_expr, state_name, true_state, false_state); 1298 save_link(left_expr, state_name); 1299 save_link(right_expr, state_name); 1300 1301 if (_false_state) 1302 *_false_state = false_state; 1303 if (_state_name) 1304 *_state_name = state_name; 1305 free: 1306 free_string(left); 1307 free_string(right); 1308 } 1309 1310 void __comparison_match_condition(struct expression *expr) 1311 { 1312 struct expression *left, *right, *new_left, *new_right, *tmp; 1313 struct smatch_state *false_state = NULL; 1314 char *state_name = NULL; 1315 int redo, count; 1316 1317 if (expr->type != EXPR_COMPARE) 1318 return; 1319 1320 handle_comparison(expr->left, expr->op, expr->right, &state_name, &false_state); 1321 if (false_state && state_name) 1322 handle_for_loops(expr, state_name, false_state); 1323 1324 left = strip_parens(expr->left); 1325 right = strip_parens(expr->right); 1326 1327 if (left->type == EXPR_BINOP && left->op == '+') { 1328 new_left = left->left; 1329 new_right = binop_expression(right, '-', left->right); 1330 handle_comparison(new_left, expr->op, new_right, NULL, NULL); 1331 1332 new_left = left->right; 1333 new_right = binop_expression(right, '-', left->left); 1334 handle_comparison(new_left, expr->op, new_right, NULL, NULL); 1335 } 1336 1337 1338 redo = 0; 1339 left = strip_parens(expr->left); 1340 right = strip_parens(expr->right); 1341 if (get_last_expr_from_expression_stmt(expr->left)) { 1342 left = get_last_expr_from_expression_stmt(expr->left); 1343 redo = 1; 1344 } 1345 if (get_last_expr_from_expression_stmt(expr->right)) { 1346 right = get_last_expr_from_expression_stmt(expr->right); 1347 redo = 1; 1348 } 1349 1350 if (!redo) 1351 return; 1352 1353 count = 0; 1354 while ((tmp = get_assigned_expr(left))) { 1355 if (count++ > 3) 1356 break; 1357 left = strip_expr(tmp); 1358 } 1359 count = 0; 1360 while ((tmp = get_assigned_expr(right))) { 1361 if (count++ > 3) 1362 break; 1363 right = strip_expr(tmp); 1364 } 1365 1366 handle_comparison(left, expr->op, right, NULL, NULL); 1367 } 1368 1369 static void add_comparison_var_sym( 1370 struct expression *left_expr, 1371 const char *left_name, struct var_sym_list *left_vsl, 1372 int comparison, 1373 struct expression *right_expr, 1374 const char *right_name, struct var_sym_list *right_vsl) 1375 { 1376 struct smatch_state *state; 1377 struct var_sym *vs; 1378 char state_name[256]; 1379 1380 if (strcmp(left_name, right_name) > 0) { 1381 struct expression *tmp_expr = left_expr; 1382 const char *tmp_name = left_name; 1383 struct var_sym_list *tmp_vsl = left_vsl; 1384 1385 left_expr = right_expr; 1386 left_name = right_name; 1387 left_vsl = right_vsl; 1388 right_expr = tmp_expr; 1389 right_name = tmp_name; 1390 right_vsl = tmp_vsl; 1391 comparison = flip_comparison(comparison); 1392 } 1393 snprintf(state_name, sizeof(state_name), "%s vs %s", left_name, right_name); 1394 state = alloc_compare_state( 1395 left_expr, left_name, left_vsl, 1396 comparison, 1397 right_expr, right_name, right_vsl); 1398 1399 set_state(compare_id, state_name, NULL, state); 1400 1401 FOR_EACH_PTR(left_vsl, vs) { 1402 save_link_var_sym(vs->var, vs->sym, state_name); 1403 } END_FOR_EACH_PTR(vs); 1404 FOR_EACH_PTR(right_vsl, vs) { 1405 save_link_var_sym(vs->var, vs->sym, state_name); 1406 } END_FOR_EACH_PTR(vs); 1407 } 1408 1409 static void add_comparison(struct expression *left, int comparison, struct expression *right) 1410 { 1411 char *left_name = NULL; 1412 char *right_name = NULL; 1413 struct symbol *left_sym, *right_sym; 1414 struct var_sym_list *left_vsl, *right_vsl; 1415 struct smatch_state *state; 1416 char state_name[256]; 1417 1418 left_name = chunk_to_var_sym(left, &left_sym); 1419 if (!left_name) 1420 goto free; 1421 left_vsl = expr_to_vsl(left); 1422 right_name = chunk_to_var_sym(right, &right_sym); 1423 if (!right_name) 1424 goto free; 1425 right_vsl = expr_to_vsl(right); 1426 1427 if (strcmp(left_name, right_name) > 0) { 1428 struct expression *tmp_expr = left; 1429 struct symbol *tmp_sym = left_sym; 1430 char *tmp_name = left_name; 1431 struct var_sym_list *tmp_vsl = left_vsl; 1432 1433 left = right; 1434 left_name = right_name; 1435 left_sym = right_sym; 1436 left_vsl = right_vsl; 1437 right = tmp_expr; 1438 right_name = tmp_name; 1439 right_sym = tmp_sym; 1440 right_vsl = tmp_vsl; 1441 comparison = flip_comparison(comparison); 1442 } 1443 snprintf(state_name, sizeof(state_name), "%s vs %s", left_name, right_name); 1444 state = alloc_compare_state( 1445 left, left_name, left_vsl, 1446 comparison, 1447 right, right_name, right_vsl); 1448 1449 set_state(compare_id, state_name, NULL, state); 1450 save_link(left, state_name); 1451 save_link(right, state_name); 1452 1453 free: 1454 free_string(left_name); 1455 free_string(right_name); 1456 } 1457 1458 static void match_assign_add(struct expression *expr) 1459 { 1460 struct expression *right; 1461 struct expression *r_left, *r_right; 1462 sval_t left_tmp, right_tmp; 1463 1464 right = strip_expr(expr->right); 1465 r_left = strip_expr(right->left); 1466 r_right = strip_expr(right->right); 1467 1468 get_absolute_min(r_left, &left_tmp); 1469 get_absolute_min(r_right, &right_tmp); 1470 1471 if (left_tmp.value > 0) 1472 add_comparison(expr->left, '>', r_right); 1473 else if (left_tmp.value == 0) 1474 add_comparison(expr->left, SPECIAL_GTE, r_right); 1475 1476 if (right_tmp.value > 0) 1477 add_comparison(expr->left, '>', r_left); 1478 else if (right_tmp.value == 0) 1479 add_comparison(expr->left, SPECIAL_GTE, r_left); 1480 } 1481 1482 static void match_assign_sub(struct expression *expr) 1483 { 1484 struct expression *right; 1485 struct expression *r_left, *r_right; 1486 int comparison; 1487 sval_t min; 1488 1489 right = strip_expr(expr->right); 1490 r_left = strip_expr(right->left); 1491 r_right = strip_expr(right->right); 1492 1493 if (get_absolute_min(r_right, &min) && sval_is_negative(min)) 1494 return; 1495 1496 comparison = get_comparison(r_left, r_right); 1497 1498 switch (comparison) { 1499 case '>': 1500 case SPECIAL_GTE: 1501 if (implied_not_equal(r_right, 0)) 1502 add_comparison(expr->left, '>', r_left); 1503 else 1504 add_comparison(expr->left, SPECIAL_GTE, r_left); 1505 return; 1506 } 1507 } 1508 1509 static void match_assign_divide(struct expression *expr) 1510 { 1511 struct expression *right; 1512 struct expression *r_left, *r_right; 1513 sval_t min; 1514 1515 right = strip_expr(expr->right); 1516 r_left = strip_expr(right->left); 1517 r_right = strip_expr(right->right); 1518 if (!get_implied_min(r_right, &min) || min.value <= 1) 1519 return; 1520 1521 add_comparison(expr->left, '<', r_left); 1522 } 1523 1524 static void match_binop_assign(struct expression *expr) 1525 { 1526 struct expression *right; 1527 1528 right = strip_expr(expr->right); 1529 if (right->op == '+') 1530 match_assign_add(expr); 1531 if (right->op == '-') 1532 match_assign_sub(expr); 1533 if (right->op == '/') 1534 match_assign_divide(expr); 1535 } 1536 1537 static void copy_comparisons(struct expression *left, struct expression *right) 1538 { 1539 struct string_list *links; 1540 struct smatch_state *state; 1541 struct compare_data *data; 1542 struct symbol *left_sym, *right_sym; 1543 char *left_var = NULL; 1544 char *right_var = NULL; 1545 struct var_sym_list *left_vsl; 1546 struct expression *expr; 1547 const char *var; 1548 struct var_sym_list *vsl; 1549 int comparison; 1550 char *tmp; 1551 1552 left_var = chunk_to_var_sym(left, &left_sym); 1553 if (!left_var) 1554 goto done; 1555 left_vsl = expr_to_vsl(left); 1556 right_var = chunk_to_var_sym(right, &right_sym); 1557 if (!right_var) 1558 goto done; 1559 1560 state = get_state(link_id, right_var, right_sym); 1561 if (!state) 1562 return; 1563 links = state->data; 1564 1565 FOR_EACH_PTR(links, tmp) { 1566 state = get_state(compare_id, tmp, NULL); 1567 if (!state || !state->data) 1568 continue; 1569 data = state->data; 1570 comparison = data->comparison; 1571 expr = data->right; 1572 var = data->right_var; 1573 vsl = data->right_vsl; 1574 if (strcmp(var, right_var) == 0) { 1575 expr = data->left; 1576 var = data->left_var; 1577 vsl = data->left_vsl; 1578 comparison = flip_comparison(comparison); 1579 } 1580 /* n = copy_from_user(dest, src, n); leads to n <= n which is nonsense */ 1581 if (strcmp(left_var, var) == 0) 1582 continue; 1583 add_comparison_var_sym(left, left_var, left_vsl, comparison, expr, var, vsl); 1584 } END_FOR_EACH_PTR(tmp); 1585 1586 done: 1587 free_string(right_var); 1588 } 1589 1590 static void match_assign(struct expression *expr) 1591 { 1592 struct expression *right; 1593 1594 if (expr->op != '=') 1595 return; 1596 if (__in_fake_assign || outside_of_function()) 1597 return; 1598 1599 if (is_struct(expr->left)) 1600 return; 1601 1602 if (is_self_assign(expr)) 1603 return; 1604 1605 copy_comparisons(expr->left, expr->right); 1606 add_comparison(expr->left, SPECIAL_EQUAL, expr->right); 1607 1608 right = strip_expr(expr->right); 1609 if (right->type == EXPR_BINOP) 1610 match_binop_assign(expr); 1611 } 1612 1613 int get_comparison_strings(const char *one, const char *two) 1614 { 1615 char buf[256]; 1616 struct smatch_state *state; 1617 int invert = 0; 1618 int ret = 0; 1619 1620 if (!one || !two) 1621 return 0; 1622 1623 if (strcmp(one, two) == 0) 1624 return SPECIAL_EQUAL; 1625 1626 if (strcmp(one, two) > 0) { 1627 const char *tmp = one; 1628 1629 one = two; 1630 two = tmp; 1631 invert = 1; 1632 } 1633 1634 snprintf(buf, sizeof(buf), "%s vs %s", one, two); 1635 state = get_state(compare_id, buf, NULL); 1636 if (state) 1637 ret = state_to_comparison(state); 1638 1639 if (invert) 1640 ret = flip_comparison(ret); 1641 1642 return ret; 1643 } 1644 1645 static int get_comparison_helper(struct expression *a, struct expression *b, bool use_extra) 1646 { 1647 char *one = NULL; 1648 char *two = NULL; 1649 int ret = 0; 1650 1651 if (!a || !b) 1652 return 0; 1653 1654 a = strip_parens(a); 1655 b = strip_parens(b); 1656 1657 move_plus_to_minus(&a, &b); 1658 1659 one = chunk_to_var(a); 1660 if (!one) 1661 goto free; 1662 two = chunk_to_var(b); 1663 if (!two) 1664 goto free; 1665 1666 ret = get_comparison_strings(one, two); 1667 if (ret) 1668 goto free; 1669 1670 if (is_plus_one(a) || is_minus_one(a)) { 1671 free_string(one); 1672 one = chunk_to_var(a->left); 1673 ret = get_comparison_strings(one, two); 1674 } else if (is_plus_one(b) || is_minus_one(b)) { 1675 free_string(two); 1676 two = chunk_to_var(b->left); 1677 ret = get_comparison_strings(one, two); 1678 } 1679 1680 if (!ret) 1681 goto free; 1682 1683 if ((is_plus_one(a) || is_minus_one(b)) && ret == '<') 1684 ret = SPECIAL_LTE; 1685 else if ((is_minus_one(a) || is_plus_one(b)) && ret == '>') 1686 ret = SPECIAL_GTE; 1687 else 1688 ret = 0; 1689 1690 free: 1691 free_string(one); 1692 free_string(two); 1693 1694 if (!ret && use_extra) 1695 return comparison_from_extra(a, b); 1696 return ret; 1697 } 1698 1699 int get_comparison(struct expression *a, struct expression *b) 1700 { 1701 return get_comparison_helper(a, b, true); 1702 } 1703 1704 int get_comparison_no_extra(struct expression *a, struct expression *b) 1705 { 1706 return get_comparison_helper(a, b, false); 1707 } 1708 1709 int possible_comparison(struct expression *a, int comparison, struct expression *b) 1710 { 1711 char *one = NULL; 1712 char *two = NULL; 1713 int ret = 0; 1714 char buf[256]; 1715 struct sm_state *sm; 1716 int saved; 1717 1718 one = chunk_to_var(a); 1719 if (!one) 1720 goto free; 1721 two = chunk_to_var(b); 1722 if (!two) 1723 goto free; 1724 1725 1726 if (strcmp(one, two) == 0 && comparison == SPECIAL_EQUAL) { 1727 ret = 1; 1728 goto free; 1729 } 1730 1731 if (strcmp(one, two) > 0) { 1732 char *tmp = one; 1733 1734 one = two; 1735 two = tmp; 1736 comparison = flip_comparison(comparison); 1737 } 1738 1739 snprintf(buf, sizeof(buf), "%s vs %s", one, two); 1740 sm = get_sm_state(compare_id, buf, NULL); 1741 if (!sm) 1742 goto free; 1743 1744 FOR_EACH_PTR(sm->possible, sm) { 1745 if (!sm->state->data) 1746 continue; 1747 saved = ((struct compare_data *)sm->state->data)->comparison; 1748 if (saved == comparison) 1749 ret = 1; 1750 if (comparison == SPECIAL_EQUAL && 1751 (saved == SPECIAL_LTE || 1752 saved == SPECIAL_GTE || 1753 saved == SPECIAL_UNSIGNED_LTE || 1754 saved == SPECIAL_UNSIGNED_GTE)) 1755 ret = 1; 1756 if (ret == 1) 1757 goto free; 1758 } END_FOR_EACH_PTR(sm); 1759 1760 return ret; 1761 free: 1762 free_string(one); 1763 free_string(two); 1764 return ret; 1765 } 1766 1767 struct state_list *get_all_comparisons(struct expression *expr) 1768 { 1769 struct smatch_state *state; 1770 struct string_list *links; 1771 struct state_list *ret = NULL; 1772 struct sm_state *sm; 1773 char *tmp; 1774 1775 state = get_state_chunk(link_id, expr); 1776 if (!state) 1777 return NULL; 1778 links = state->data; 1779 1780 FOR_EACH_PTR(links, tmp) { 1781 sm = get_sm_state(compare_id, tmp, NULL); 1782 if (!sm) 1783 continue; 1784 // FIXME have to compare name with vsl 1785 add_ptr_list(&ret, sm); 1786 } END_FOR_EACH_PTR(tmp); 1787 1788 return ret; 1789 } 1790 1791 struct state_list *get_all_possible_equal_comparisons(struct expression *expr) 1792 { 1793 struct smatch_state *state; 1794 struct string_list *links; 1795 struct state_list *ret = NULL; 1796 struct sm_state *sm; 1797 char *tmp; 1798 1799 state = get_state_chunk(link_id, expr); 1800 if (!state) 1801 return NULL; 1802 links = state->data; 1803 1804 FOR_EACH_PTR(links, tmp) { 1805 sm = get_sm_state(compare_id, tmp, NULL); 1806 if (!sm) 1807 continue; 1808 if (!strchr(sm->state->name, '=')) 1809 continue; 1810 if (strcmp(sm->state->name, "!=") == 0) 1811 continue; 1812 add_ptr_list(&ret, sm); 1813 } END_FOR_EACH_PTR(tmp); 1814 1815 return ret; 1816 } 1817 1818 struct state_list *get_all_possible_not_equal_comparisons(struct expression *expr) 1819 { 1820 struct smatch_state *state; 1821 struct string_list *links; 1822 struct state_list *ret = NULL; 1823 struct sm_state *sm; 1824 struct sm_state *possible; 1825 char *link; 1826 1827 return NULL; 1828 1829 state = get_state_chunk(link_id, expr); 1830 if (!state) 1831 return NULL; 1832 links = state->data; 1833 1834 FOR_EACH_PTR(links, link) { 1835 sm = get_sm_state(compare_id, link, NULL); 1836 if (!sm) 1837 continue; 1838 FOR_EACH_PTR(sm->possible, possible) { 1839 if (strcmp(possible->state->name, "!=") != 0) 1840 continue; 1841 add_ptr_list(&ret, sm); 1842 break; 1843 } END_FOR_EACH_PTR(link); 1844 } END_FOR_EACH_PTR(link); 1845 1846 return ret; 1847 } 1848 1849 static void update_links_from_call(struct expression *left, 1850 int left_compare, 1851 struct expression *right) 1852 { 1853 struct string_list *links; 1854 struct smatch_state *state; 1855 struct compare_data *data; 1856 struct symbol *left_sym, *right_sym; 1857 char *left_var = NULL; 1858 char *right_var = NULL; 1859 struct var_sym_list *left_vsl; 1860 struct expression *expr; 1861 const char *var; 1862 struct var_sym_list *vsl; 1863 int comparison; 1864 char *tmp; 1865 1866 left_var = chunk_to_var_sym(left, &left_sym); 1867 if (!left_var) 1868 goto done; 1869 left_vsl = expr_to_vsl(left); 1870 right_var = chunk_to_var_sym(right, &right_sym); 1871 if (!right_var) 1872 goto done; 1873 1874 state = get_state(link_id, right_var, right_sym); 1875 if (!state) 1876 return; 1877 links = state->data; 1878 1879 FOR_EACH_PTR(links, tmp) { 1880 state = get_state(compare_id, tmp, NULL); 1881 if (!state || !state->data) 1882 continue; 1883 data = state->data; 1884 comparison = data->comparison; 1885 expr = data->right; 1886 var = data->right_var; 1887 vsl = data->right_vsl; 1888 if (strcmp(var, right_var) == 0) { 1889 expr = data->left; 1890 var = data->left_var; 1891 vsl = data->left_vsl; 1892 comparison = flip_comparison(comparison); 1893 } 1894 comparison = combine_comparisons(left_compare, comparison); 1895 if (!comparison) 1896 continue; 1897 add_comparison_var_sym(left, left_var, left_vsl, comparison, expr, var, vsl); 1898 } END_FOR_EACH_PTR(tmp); 1899 1900 done: 1901 free_string(right_var); 1902 } 1903 1904 void __add_return_comparison(struct expression *call, const char *range) 1905 { 1906 struct expression *arg; 1907 int comparison; 1908 char buf[4]; 1909 1910 if (!str_to_comparison_arg(range, call, &comparison, &arg)) 1911 return; 1912 snprintf(buf, sizeof(buf), "%s", show_special(comparison)); 1913 update_links_from_call(call, comparison, arg); 1914 add_comparison(call, comparison, arg); 1915 } 1916 1917 void __add_comparison_info(struct expression *expr, struct expression *call, const char *range) 1918 { 1919 copy_comparisons(expr, call); 1920 } 1921 1922 static char *get_mask_comparison(struct expression *expr, int ignore) 1923 { 1924 struct expression *tmp, *right; 1925 int count, param; 1926 char buf[256]; 1927 1928 /* The return value for "return foo & param;" is <= param */ 1929 1930 count = 0; 1931 while ((tmp = get_assigned_expr(expr))) { 1932 expr = strip_expr(tmp); 1933 if (count++ > 4) 1934 break; 1935 } 1936 1937 if (expr->type != EXPR_BINOP || expr->op != '&') 1938 return NULL; 1939 1940 right = strip_expr(expr->right); 1941 param = get_param_num(right); 1942 if (param < 0 || param == ignore) 1943 return NULL; 1944 1945 snprintf(buf, sizeof(buf), "[<=$%d]", param); 1946 return alloc_sname(buf); 1947 } 1948 1949 static char *range_comparison_to_param_helper(struct expression *expr, char starts_with, int ignore) 1950 { 1951 struct symbol *param; 1952 char *var = NULL; 1953 char buf[256]; 1954 char *ret_str = NULL; 1955 int compare; 1956 int i; 1957 1958 if (!expr) 1959 return NULL; 1960 1961 var = chunk_to_var(expr); 1962 if (!var) 1963 goto try_mask; 1964 1965 i = -1; 1966 FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, param) { 1967 i++; 1968 if (i == ignore) 1969 continue; 1970 if (!param->ident) 1971 continue; 1972 snprintf(buf, sizeof(buf), "%s orig", param->ident->name); 1973 compare = get_comparison_strings(var, buf); 1974 if (!compare) 1975 continue; 1976 if (show_special(compare)[0] != starts_with) 1977 continue; 1978 snprintf(buf, sizeof(buf), "[%s$%d]", show_special(compare), i); 1979 ret_str = alloc_sname(buf); 1980 break; 1981 } END_FOR_EACH_PTR(param); 1982 1983 free_string(var); 1984 if (!ret_str) 1985 goto try_mask; 1986 1987 return ret_str; 1988 1989 try_mask: 1990 if (starts_with == '<') 1991 ret_str = get_mask_comparison(expr, ignore); 1992 return ret_str; 1993 } 1994 1995 char *name_sym_to_param_comparison(const char *name, struct symbol *sym) 1996 { 1997 struct symbol *param; 1998 char buf[256]; 1999 int compare; 2000 int i; 2001 2002 i = -1; 2003 FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, param) { 2004 i++; 2005 if (!param->ident) 2006 continue; 2007 snprintf(buf, sizeof(buf), "%s orig", param->ident->name); 2008 compare = get_comparison_strings(name, buf); 2009 if (!compare) 2010 continue; 2011 snprintf(buf, sizeof(buf), "[%s$%d]", show_special(compare), i); 2012 return alloc_sname(buf); 2013 } END_FOR_EACH_PTR(param); 2014 2015 return NULL; 2016 } 2017 2018 char *expr_equal_to_param(struct expression *expr, int ignore) 2019 { 2020 return range_comparison_to_param_helper(expr, '=', ignore); 2021 } 2022 2023 char *expr_lte_to_param(struct expression *expr, int ignore) 2024 { 2025 return range_comparison_to_param_helper(expr, '<', ignore); 2026 } 2027 2028 char *expr_param_comparison(struct expression *expr, int ignore) 2029 { 2030 struct symbol *param; 2031 char *var = NULL; 2032 char buf[256]; 2033 char *ret_str = NULL; 2034 int compare; 2035 int i; 2036 2037 var = chunk_to_var(expr); 2038 if (!var) 2039 goto free; 2040 2041 i = -1; 2042 FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, param) { 2043 i++; 2044 if (i == ignore) 2045 continue; 2046 if (!param->ident) 2047 continue; 2048 snprintf(buf, sizeof(buf), "%s orig", param->ident->name); 2049 compare = get_comparison_strings(var, buf); 2050 if (!compare) 2051 continue; 2052 snprintf(buf, sizeof(buf), "[%s$%d]", show_special(compare), i); 2053 ret_str = alloc_sname(buf); 2054 break; 2055 } END_FOR_EACH_PTR(param); 2056 2057 free: 2058 free_string(var); 2059 return ret_str; 2060 } 2061 2062 char *get_printed_param_name(struct expression *call, const char *param_name, struct symbol *param_sym) 2063 { 2064 struct expression *arg; 2065 char *name; 2066 struct symbol *sym; 2067 static char buf[256]; 2068 int len; 2069 int i; 2070 2071 i = -1; 2072 FOR_EACH_PTR(call->args, arg) { 2073 i++; 2074 2075 name = expr_to_var_sym(arg, &sym); 2076 if (!name || !sym) 2077 continue; 2078 if (sym != param_sym) 2079 continue; 2080 2081 len = strlen(name); 2082 if (strncmp(name, param_name, len) != 0) 2083 continue; 2084 if (param_name[len] == '\0') { 2085 snprintf(buf, sizeof(buf), "$%d", i); 2086 return buf; 2087 } 2088 if (param_name[len] != '-') 2089 continue; 2090 snprintf(buf, sizeof(buf), "$%d%s", i, param_name + len); 2091 return buf; 2092 } END_FOR_EACH_PTR(arg); 2093 2094 return NULL; 2095 } 2096 2097 static void match_call_info(struct expression *expr) 2098 { 2099 struct expression *arg; 2100 struct smatch_state *state; 2101 struct sm_state *sm; 2102 struct compare_data *data; 2103 int comparison; 2104 struct string_list *links; 2105 char *arg_name; 2106 const char *right_name; 2107 char *link; 2108 char info_buf[256]; 2109 int i; 2110 2111 i = -1; 2112 FOR_EACH_PTR(expr->args, arg) { 2113 i++; 2114 2115 state = get_state_chunk(link_id, arg); 2116 if (!state) 2117 continue; 2118 2119 links = state->data; 2120 FOR_EACH_PTR(links, link) { 2121 struct var_sym_list *right_vsl; 2122 struct var_sym *right_vs; 2123 2124 2125 if (strstr(link, " orig")) 2126 continue; 2127 sm = get_sm_state(compare_id, link, NULL); 2128 if (!sm) 2129 continue; 2130 data = sm->state->data; 2131 if (!data || !data->comparison) 2132 continue; 2133 arg_name = expr_to_var(arg); 2134 if (!arg_name) 2135 continue; 2136 2137 right_vsl = NULL; 2138 if (strcmp(data->left_var, arg_name) == 0) { 2139 comparison = data->comparison; 2140 right_name = data->right_var; 2141 right_vsl = data->right_vsl; 2142 } else if (strcmp(data->right_var, arg_name) == 0) { 2143 comparison = flip_comparison(data->comparison); 2144 right_name = data->left_var; 2145 right_vsl = data->left_vsl; 2146 } 2147 if (!right_vsl || ptr_list_size((struct ptr_list *)right_vsl) != 1) 2148 goto free; 2149 2150 right_vs = first_ptr_list((struct ptr_list *)right_vsl); 2151 if (strcmp(right_vs->var, right_name) != 0) 2152 goto free; 2153 right_name = get_printed_param_name(expr, right_vs->var, right_vs->sym); 2154 if (!right_name) 2155 goto free; 2156 snprintf(info_buf, sizeof(info_buf), "%s %s", show_special(comparison), right_name); 2157 sql_insert_caller_info(expr, PARAM_COMPARE, i, "$", info_buf); 2158 2159 free: 2160 free_string(arg_name); 2161 } END_FOR_EACH_PTR(link); 2162 } END_FOR_EACH_PTR(arg); 2163 } 2164 2165 static void struct_member_callback(struct expression *call, int param, char *printed_name, struct sm_state *link_sm) 2166 { 2167 struct sm_state *compare_sm; 2168 struct string_list *links; 2169 char *link; 2170 struct compare_data *data; 2171 struct var_sym *left, *right; 2172 static char info_buf[256]; 2173 const char *right_name; 2174 2175 if (strstr(printed_name, " orig")) 2176 return; 2177 2178 links = link_sm->state->data; 2179 FOR_EACH_PTR(links, link) { 2180 compare_sm = get_sm_state(compare_id, link, NULL); 2181 if (!compare_sm) 2182 continue; 2183 data = compare_sm->state->data; 2184 if (!data || !data->comparison) 2185 continue; 2186 2187 if (ptr_list_size((struct ptr_list *)data->left_vsl) != 1 || 2188 ptr_list_size((struct ptr_list *)data->right_vsl) != 1) 2189 continue; 2190 left = first_ptr_list((struct ptr_list *)data->left_vsl); 2191 right = first_ptr_list((struct ptr_list *)data->right_vsl); 2192 if (left->sym == right->sym && 2193 strcmp(left->var, right->var) == 0) 2194 continue; 2195 /* 2196 * Both parameters link to this comparison so only 2197 * record the first one. 2198 */ 2199 if (left->sym != link_sm->sym || 2200 strcmp(left->var, link_sm->name) != 0) 2201 continue; 2202 2203 right_name = get_printed_param_name(call, right->var, right->sym); 2204 if (!right_name) 2205 continue; 2206 snprintf(info_buf, sizeof(info_buf), "%s %s", show_special(data->comparison), right_name); 2207 sql_insert_caller_info(call, PARAM_COMPARE, param, printed_name, info_buf); 2208 } END_FOR_EACH_PTR(link); 2209 } 2210 2211 static void print_return_value_comparison(int return_id, char *return_ranges, struct expression *expr) 2212 { 2213 char *name; 2214 const char *tmp_name; 2215 struct symbol *sym; 2216 int param; 2217 char info_buf[256]; 2218 2219 /* 2220 * TODO: This only prints == comparisons. That's probably the most 2221 * useful comparison because == max has lots of implications. But it 2222 * would be good to capture the rest as well. 2223 * 2224 * This information is already in the DB but it's in the parameter math 2225 * bits and it's awkward to use it. This is is the simpler, possibly 2226 * cleaner way, but not necessarily the best, I don't know. 2227 */ 2228 2229 if (!expr) 2230 return; 2231 name = expr_to_var_sym(expr, &sym); 2232 if (!name || !sym) 2233 goto free; 2234 2235 param = get_param_num_from_sym(sym); 2236 if (param < 0) 2237 goto free; 2238 if (param_was_set_var_sym(name, sym)) 2239 goto free; 2240 2241 tmp_name = get_param_name_var_sym(name, sym); 2242 if (!tmp_name) 2243 goto free; 2244 2245 snprintf(info_buf, sizeof(info_buf), "== $%d%s", param, tmp_name + 1); 2246 sql_insert_return_states(return_id, return_ranges, 2247 PARAM_COMPARE, -1, "$", info_buf); 2248 free: 2249 free_string(name); 2250 } 2251 2252 static void print_return_comparison(int return_id, char *return_ranges, struct expression *expr) 2253 { 2254 struct sm_state *tmp; 2255 struct string_list *links; 2256 char *link; 2257 struct sm_state *sm; 2258 struct compare_data *data; 2259 struct var_sym *left, *right; 2260 int left_param, right_param; 2261 char left_buf[256]; 2262 char right_buf[256]; 2263 char info_buf[258]; 2264 const char *tmp_name; 2265 2266 print_return_value_comparison(return_id, return_ranges, expr); 2267 2268 FOR_EACH_MY_SM(link_id, __get_cur_stree(), tmp) { 2269 if (get_param_num_from_sym(tmp->sym) < 0) 2270 continue; 2271 links = tmp->state->data; 2272 FOR_EACH_PTR(links, link) { 2273 sm = get_sm_state(compare_id, link, NULL); 2274 if (!sm) 2275 continue; 2276 data = sm->state->data; 2277 if (!data || !data->comparison) 2278 continue; 2279 if (ptr_list_size((struct ptr_list *)data->left_vsl) != 1 || 2280 ptr_list_size((struct ptr_list *)data->right_vsl) != 1) 2281 continue; 2282 left = first_ptr_list((struct ptr_list *)data->left_vsl); 2283 right = first_ptr_list((struct ptr_list *)data->right_vsl); 2284 if (left->sym == right->sym && 2285 strcmp(left->var, right->var) == 0) 2286 continue; 2287 /* 2288 * Both parameters link to this comparison so only 2289 * record the first one. 2290 */ 2291 if (left->sym != tmp->sym || 2292 strcmp(left->var, tmp->name) != 0) 2293 continue; 2294 2295 if (strstr(right->var, " orig")) 2296 continue; 2297 2298 left_param = get_param_num_from_sym(left->sym); 2299 right_param = get_param_num_from_sym(right->sym); 2300 if (left_param < 0 || right_param < 0) 2301 continue; 2302 2303 tmp_name = get_param_name_var_sym(left->var, left->sym); 2304 if (!tmp_name) 2305 continue; 2306 snprintf(left_buf, sizeof(left_buf), "%s", tmp_name); 2307 2308 tmp_name = get_param_name_var_sym(right->var, right->sym); 2309 if (!tmp_name || tmp_name[0] != '$') 2310 continue; 2311 snprintf(right_buf, sizeof(right_buf), "$%d%s", right_param, tmp_name + 1); 2312 2313 /* 2314 * FIXME: this should reject $ type variables (as 2315 * opposed to $->foo type). Those should come from 2316 * smatch_param_compare_limit.c. 2317 */ 2318 2319 snprintf(info_buf, sizeof(info_buf), "%s %s", show_special(data->comparison), right_buf); 2320 sql_insert_return_states(return_id, return_ranges, 2321 PARAM_COMPARE, left_param, left_buf, info_buf); 2322 } END_FOR_EACH_PTR(link); 2323 2324 } END_FOR_EACH_SM(tmp); 2325 } 2326 2327 static int parse_comparison(char **value, int *op) 2328 { 2329 2330 *op = **value; 2331 2332 switch (*op) { 2333 case '<': 2334 (*value)++; 2335 if (**value == '=') { 2336 (*value)++; 2337 *op = SPECIAL_LTE; 2338 } 2339 break; 2340 case '=': 2341 (*value)++; 2342 (*value)++; 2343 *op = SPECIAL_EQUAL; 2344 break; 2345 case '!': 2346 (*value)++; 2347 (*value)++; 2348 *op = SPECIAL_NOTEQUAL; 2349 break; 2350 case '>': 2351 (*value)++; 2352 if (**value == '=') { 2353 (*value)++; 2354 *op = SPECIAL_GTE; 2355 } 2356 break; 2357 default: 2358 return 0; 2359 } 2360 2361 if (**value != ' ') { 2362 sm_perror("parsing comparison. %s", *value); 2363 return 0; 2364 } 2365 2366 (*value)++; 2367 return 1; 2368 } 2369 2370 static int split_op_param_key(char *value, int *op, int *param, char **key) 2371 { 2372 static char buf[256]; 2373 char *p; 2374 2375 if (!parse_comparison(&value, op)) 2376 return 0; 2377 2378 snprintf(buf, sizeof(buf), "%s", value); 2379 2380 p = buf; 2381 if (*p++ != '$') 2382 return 0; 2383 2384 *param = atoi(p); 2385 if (*param < 0 || *param > 99) 2386 return 0; 2387 p++; 2388 if (*param > 9) 2389 p++; 2390 p--; 2391 *p = '$'; 2392 *key = p; 2393 2394 return 1; 2395 } 2396 2397 static void db_return_comparison(struct expression *expr, int left_param, char *key, char *value) 2398 { 2399 struct expression *left_arg, *right_arg; 2400 char *left_name = NULL; 2401 struct symbol *left_sym; 2402 char *right_name = NULL; 2403 struct symbol *right_sym; 2404 int op; 2405 int right_param; 2406 char *right_key; 2407 struct var_sym_list *left_vsl = NULL, *right_vsl = NULL; 2408 2409 if (left_param == -1) { 2410 if (expr->type != EXPR_ASSIGNMENT) 2411 return; 2412 left_arg = strip_expr(expr->left); 2413 2414 while (expr->type == EXPR_ASSIGNMENT) 2415 expr = strip_expr(expr->right); 2416 if (expr->type != EXPR_CALL) 2417 return; 2418 } else { 2419 while (expr->type == EXPR_ASSIGNMENT) 2420 expr = strip_expr(expr->right); 2421 if (expr->type != EXPR_CALL) 2422 return; 2423 2424 left_arg = get_argument_from_call_expr(expr->args, left_param); 2425 if (!left_arg) 2426 return; 2427 } 2428 2429 if (!split_op_param_key(value, &op, &right_param, &right_key)) 2430 return; 2431 2432 right_arg = get_argument_from_call_expr(expr->args, right_param); 2433 if (!right_arg) 2434 return; 2435 2436 left_name = get_variable_from_key(left_arg, key, &left_sym); 2437 if (!left_name || !left_sym) 2438 goto free; 2439 2440 right_name = get_variable_from_key(right_arg, right_key, &right_sym); 2441 if (!right_name || !right_sym) 2442 goto free; 2443 2444 add_var_sym(&left_vsl, left_name, left_sym); 2445 add_var_sym(&right_vsl, right_name, right_sym); 2446 2447 add_comparison_var_sym(NULL, left_name, left_vsl, op, NULL, right_name, right_vsl); 2448 2449 free: 2450 free_string(left_name); 2451 free_string(right_name); 2452 } 2453 2454 int param_compare_limit_is_impossible(struct expression *expr, int left_param, char *left_key, char *value) 2455 { 2456 struct smatch_state *state; 2457 char *left_name = NULL; 2458 char *right_name = NULL; 2459 struct symbol *left_sym, *right_sym; 2460 struct expression *left_arg, *right_arg; 2461 int op, state_op; 2462 int right_param; 2463 char *right_key; 2464 int ret = 0; 2465 char buf[256]; 2466 2467 while (expr->type == EXPR_ASSIGNMENT) 2468 expr = strip_expr(expr->right); 2469 if (expr->type != EXPR_CALL) 2470 return 0; 2471 2472 if (!split_op_param_key(value, &op, &right_param, &right_key)) 2473 return 0; 2474 2475 left_arg = get_argument_from_call_expr(expr->args, left_param); 2476 if (!left_arg) 2477 return 0; 2478 2479 right_arg = get_argument_from_call_expr(expr->args, right_param); 2480 if (!right_arg) 2481 return 0; 2482 2483 left_name = get_variable_from_key(left_arg, left_key, &left_sym); 2484 right_name = get_variable_from_key(right_arg, right_key, &right_sym); 2485 if (!left_name || !right_name) 2486 goto free; 2487 2488 snprintf(buf, sizeof(buf), "%s vs %s", left_name, right_name); 2489 state = get_state(compare_id, buf, NULL); 2490 if (!state) 2491 goto free; 2492 state_op = state_to_comparison(state); 2493 if (!state_op) 2494 goto free; 2495 2496 if (!filter_comparison(remove_unsigned_from_comparison(state_op), op)) 2497 ret = 1; 2498 free: 2499 free_string(left_name); 2500 free_string(right_name); 2501 return ret; 2502 } 2503 2504 int impossibly_high_comparison(struct expression *expr) 2505 { 2506 struct smatch_state *link_state; 2507 struct sm_state *sm; 2508 struct string_list *links; 2509 char *link; 2510 struct compare_data *data; 2511 2512 link_state = get_state_expr(link_id, expr); 2513 if (!link_state) { 2514 if (expr->type == EXPR_BINOP && 2515 (impossibly_high_comparison(expr->left) || 2516 impossibly_high_comparison(expr->right))) 2517 return 1; 2518 return 0; 2519 } 2520 2521 links = link_state->data; 2522 FOR_EACH_PTR(links, link) { 2523 sm = get_sm_state(compare_id, link, NULL); 2524 if (!sm) 2525 continue; 2526 data = sm->state->data; 2527 if (!data) 2528 continue; 2529 if (!possibly_true(data->left, data->comparison, data->right)) 2530 return 1; 2531 } END_FOR_EACH_PTR(link); 2532 2533 return 0; 2534 } 2535 2536 static void free_data(struct symbol *sym) 2537 { 2538 if (__inline_fn) 2539 return; 2540 clear_compare_data_alloc(); 2541 } 2542 2543 void register_comparison(int id) 2544 { 2545 compare_id = id; 2546 set_dynamic_states(compare_id); 2547 add_hook(&save_start_states, AFTER_DEF_HOOK); 2548 add_unmatched_state_hook(compare_id, unmatched_comparison); 2549 add_pre_merge_hook(compare_id, &pre_merge_hook); 2550 add_merge_hook(compare_id, &merge_compare_states); 2551 add_hook(&free_data, AFTER_FUNC_HOOK); 2552 add_hook(&match_call_info, FUNCTION_CALL_HOOK); 2553 add_split_return_callback(&print_return_comparison); 2554 2555 select_return_states_hook(PARAM_COMPARE, &db_return_comparison); 2556 add_hook(&match_preop, OP_HOOK); 2557 } 2558 2559 void register_comparison_late(int id) 2560 { 2561 add_hook(&match_assign, ASSIGNMENT_HOOK); 2562 } 2563 2564 void register_comparison_links(int id) 2565 { 2566 link_id = id; 2567 db_ignore_states(link_id); 2568 set_dynamic_states(link_id); 2569 add_merge_hook(link_id, &merge_links); 2570 add_modification_hook(link_id, &match_modify); 2571 add_modification_hook_late(link_id, match_inc_dec); 2572 2573 add_member_info_callback(link_id, struct_member_callback); 2574 } 2575 2576 void register_comparison_inc_dec(int id) 2577 { 2578 inc_dec_id = id; 2579 add_modification_hook_late(inc_dec_id, &iter_modify); 2580 } 2581 2582 void register_comparison_inc_dec_links(int id) 2583 { 2584 inc_dec_link_id = id; 2585 set_dynamic_states(inc_dec_link_id); 2586 set_up_link_functions(inc_dec_id, inc_dec_link_id); 2587 } 2588 2589 static void filter_by_sm(struct sm_state *sm, int op, 2590 struct state_list **true_stack, 2591 struct state_list **false_stack) 2592 { 2593 struct compare_data *data; 2594 int istrue = 0; 2595 int isfalse = 0; 2596 2597 if (!sm) 2598 return; 2599 data = sm->state->data; 2600 if (!data) { 2601 if (sm->merged) { 2602 filter_by_sm(sm->left, op, true_stack, false_stack); 2603 filter_by_sm(sm->right, op, true_stack, false_stack); 2604 } 2605 return; 2606 } 2607 2608 if (data->comparison && 2609 data->comparison == filter_comparison(data->comparison, op)) 2610 istrue = 1; 2611 2612 if (data->comparison && 2613 data->comparison == filter_comparison(data->comparison, negate_comparison(op))) 2614 isfalse = 1; 2615 2616 if (istrue) 2617 add_ptr_list(true_stack, sm); 2618 if (isfalse) 2619 add_ptr_list(false_stack, sm); 2620 2621 if (sm->merged) { 2622 filter_by_sm(sm->left, op, true_stack, false_stack); 2623 filter_by_sm(sm->right, op, true_stack, false_stack); 2624 } 2625 } 2626 2627 struct sm_state *comparison_implication_hook(struct expression *expr, 2628 struct state_list **true_stack, 2629 struct state_list **false_stack) 2630 { 2631 struct sm_state *sm; 2632 char *left, *right; 2633 int op; 2634 static char buf[256]; 2635 2636 if (expr->type != EXPR_COMPARE) 2637 return NULL; 2638 2639 op = expr->op; 2640 2641 left = expr_to_var(expr->left); 2642 right = expr_to_var(expr->right); 2643 if (!left || !right) { 2644 free_string(left); 2645 free_string(right); 2646 return NULL; 2647 } 2648 2649 if (strcmp(left, right) > 0) { 2650 char *tmp = left; 2651 2652 left = right; 2653 right = tmp; 2654 op = flip_comparison(op); 2655 } 2656 2657 snprintf(buf, sizeof(buf), "%s vs %s", left, right); 2658 sm = get_sm_state(compare_id, buf, NULL); 2659 if (!sm) 2660 return NULL; 2661 if (!sm->merged) 2662 return NULL; 2663 2664 filter_by_sm(sm, op, true_stack, false_stack); 2665 if (!*true_stack && !*false_stack) 2666 return NULL; 2667 2668 if (option_debug) 2669 sm_msg("implications from comparison: (%s)", show_sm(sm)); 2670 2671 return sm; 2672 }