1 /* Optimize and expand sanitizer functions. 2 Copyright (C) 2014-2018 Free Software Foundation, Inc. 3 Contributed by Marek Polacek <polacek@redhat.com> 4 5 This file is part of GCC. 6 7 GCC is free software; you can redistribute it and/or modify it under 8 the terms of the GNU General Public License as published by the Free 9 Software Foundation; either version 3, or (at your option) any later 10 version. 11 12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY 13 WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with GCC; see the file COPYING3. If not see 19 <http://www.gnu.org/licenses/>. */ 20 21 #include "config.h" 22 #include "system.h" 23 #include "coretypes.h" 24 #include "backend.h" 25 #include "tree.h" 26 #include "gimple.h" 27 #include "ssa.h" 28 #include "tree-pass.h" 29 #include "tree-ssa-operands.h" 30 #include "gimple-pretty-print.h" 31 #include "fold-const.h" 32 #include "gimple-iterator.h" 33 #include "stringpool.h" 34 #include "attribs.h" 35 #include "asan.h" 36 #include "ubsan.h" 37 #include "params.h" 38 #include "tree-hash-traits.h" 39 #include "gimple-ssa.h" 40 #include "tree-phinodes.h" 41 #include "ssa-iterators.h" 42 #include "gimplify.h" 43 #include "gimple-iterator.h" 44 #include "gimple-walk.h" 45 #include "cfghooks.h" 46 #include "tree-dfa.h" 47 #include "tree-ssa.h" 48 #include "varasm.h" 49 50 /* This is used to carry information about basic blocks. It is 51 attached to the AUX field of the standard CFG block. */ 52 53 struct sanopt_info 54 { 55 /* True if this BB might call (directly or indirectly) free/munmap 56 or similar operation. */ 57 bool has_freeing_call_p; 58 59 /* True if HAS_FREEING_CALL_P flag has been computed. */ 60 bool has_freeing_call_computed_p; 61 62 /* True if there is a block with HAS_FREEING_CALL_P flag set 63 on any path between an immediate dominator of BB, denoted 64 imm(BB), and BB. */ 65 bool imm_dom_path_with_freeing_call_p; 66 67 /* True if IMM_DOM_PATH_WITH_FREEING_CALL_P has been computed. */ 68 bool imm_dom_path_with_freeing_call_computed_p; 69 70 /* Number of possibly freeing calls encountered in this bb 71 (so far). */ 72 uint64_t freeing_call_events; 73 74 /* True if BB is currently being visited during computation 75 of IMM_DOM_PATH_WITH_FREEING_CALL_P flag. */ 76 bool being_visited_p; 77 78 /* True if this BB has been visited in the dominator walk. */ 79 bool visited_p; 80 }; 81 82 /* If T has a single definition of form T = T2, return T2. */ 83 84 static tree 85 maybe_get_single_definition (tree t) 86 { 87 if (TREE_CODE (t) == SSA_NAME) 88 { 89 gimple *g = SSA_NAME_DEF_STMT (t); 90 if (gimple_assign_single_p (g)) 91 return gimple_assign_rhs1 (g); 92 } 93 return NULL_TREE; 94 } 95 96 /* Tree triplet for vptr_check_map. */ 97 struct sanopt_tree_triplet 98 { 99 tree t1, t2, t3; 100 }; 101 102 /* Traits class for tree triplet hash maps below. */ 103 104 struct sanopt_tree_triplet_hash : typed_noop_remove <sanopt_tree_triplet> 105 { 106 typedef sanopt_tree_triplet value_type; 107 typedef sanopt_tree_triplet compare_type; 108 109 static hashval_t 110 hash (const sanopt_tree_triplet &ref) 111 { 112 inchash::hash hstate (0); 113 inchash::add_expr (ref.t1, hstate); 114 inchash::add_expr (ref.t2, hstate); 115 inchash::add_expr (ref.t3, hstate); 116 return hstate.end (); 117 } 118 119 static bool 120 equal (const sanopt_tree_triplet &ref1, const sanopt_tree_triplet &ref2) 121 { 122 return operand_equal_p (ref1.t1, ref2.t1, 0) 123 && operand_equal_p (ref1.t2, ref2.t2, 0) 124 && operand_equal_p (ref1.t3, ref2.t3, 0); 125 } 126 127 static void 128 mark_deleted (sanopt_tree_triplet &ref) 129 { 130 ref.t1 = reinterpret_cast<tree> (1); 131 } 132 133 static void 134 mark_empty (sanopt_tree_triplet &ref) 135 { 136 ref.t1 = NULL; 137 } 138 139 static bool 140 is_deleted (const sanopt_tree_triplet &ref) 141 { 142 return ref.t1 == reinterpret_cast<tree> (1); 143 } 144 145 static bool 146 is_empty (const sanopt_tree_triplet &ref) 147 { 148 return ref.t1 == NULL; 149 } 150 }; 151 152 /* Tree couple for ptr_check_map. */ 153 struct sanopt_tree_couple 154 { 155 tree ptr; 156 bool pos_p; 157 }; 158 159 /* Traits class for tree triplet hash maps below. */ 160 161 struct sanopt_tree_couple_hash : typed_noop_remove <sanopt_tree_couple> 162 { 163 typedef sanopt_tree_couple value_type; 164 typedef sanopt_tree_couple compare_type; 165 166 static hashval_t 167 hash (const sanopt_tree_couple &ref) 168 { 169 inchash::hash hstate (0); 170 inchash::add_expr (ref.ptr, hstate); 171 hstate.add_int (ref.pos_p); 172 return hstate.end (); 173 } 174 175 static bool 176 equal (const sanopt_tree_couple &ref1, const sanopt_tree_couple &ref2) 177 { 178 return operand_equal_p (ref1.ptr, ref2.ptr, 0) 179 && ref1.pos_p == ref2.pos_p; 180 } 181 182 static void 183 mark_deleted (sanopt_tree_couple &ref) 184 { 185 ref.ptr = reinterpret_cast<tree> (1); 186 } 187 188 static void 189 mark_empty (sanopt_tree_couple &ref) 190 { 191 ref.ptr = NULL; 192 } 193 194 static bool 195 is_deleted (const sanopt_tree_couple &ref) 196 { 197 return ref.ptr == reinterpret_cast<tree> (1); 198 } 199 200 static bool 201 is_empty (const sanopt_tree_couple &ref) 202 { 203 return ref.ptr == NULL; 204 } 205 }; 206 207 /* This is used to carry various hash maps and variables used 208 in sanopt_optimize_walker. */ 209 210 struct sanopt_ctx 211 { 212 /* This map maps a pointer (the first argument of UBSAN_NULL) to 213 a vector of UBSAN_NULL call statements that check this pointer. */ 214 hash_map<tree, auto_vec<gimple *> > null_check_map; 215 216 /* This map maps a pointer (the second argument of ASAN_CHECK) to 217 a vector of ASAN_CHECK call statements that check the access. */ 218 hash_map<tree_operand_hash, auto_vec<gimple *> > asan_check_map; 219 220 /* This map maps a tree triplet (the first, second and fourth argument 221 of UBSAN_VPTR) to a vector of UBSAN_VPTR call statements that check 222 that virtual table pointer. */ 223 hash_map<sanopt_tree_triplet_hash, auto_vec<gimple *> > vptr_check_map; 224 225 /* This map maps a couple (tree and boolean) to a vector of UBSAN_PTR 226 call statements that check that pointer overflow. */ 227 hash_map<sanopt_tree_couple_hash, auto_vec<gimple *> > ptr_check_map; 228 229 /* Number of IFN_ASAN_CHECK statements. */ 230 int asan_num_accesses; 231 232 /* True when the current functions constains an ASAN_MARK. */ 233 bool contains_asan_mark; 234 }; 235 236 /* Return true if there might be any call to free/munmap operation 237 on any path in between DOM (which should be imm(BB)) and BB. */ 238 239 static bool 240 imm_dom_path_with_freeing_call (basic_block bb, basic_block dom) 241 { 242 sanopt_info *info = (sanopt_info *) bb->aux; 243 edge e; 244 edge_iterator ei; 245 246 if (info->imm_dom_path_with_freeing_call_computed_p) 247 return info->imm_dom_path_with_freeing_call_p; 248 249 info->being_visited_p = true; 250 251 FOR_EACH_EDGE (e, ei, bb->preds) 252 { 253 sanopt_info *pred_info = (sanopt_info *) e->src->aux; 254 255 if (e->src == dom) 256 continue; 257 258 if ((pred_info->imm_dom_path_with_freeing_call_computed_p 259 && pred_info->imm_dom_path_with_freeing_call_p) 260 || (pred_info->has_freeing_call_computed_p 261 && pred_info->has_freeing_call_p)) 262 { 263 info->imm_dom_path_with_freeing_call_computed_p = true; 264 info->imm_dom_path_with_freeing_call_p = true; 265 info->being_visited_p = false; 266 return true; 267 } 268 } 269 270 FOR_EACH_EDGE (e, ei, bb->preds) 271 { 272 sanopt_info *pred_info = (sanopt_info *) e->src->aux; 273 274 if (e->src == dom) 275 continue; 276 277 if (pred_info->has_freeing_call_computed_p) 278 continue; 279 280 gimple_stmt_iterator gsi; 281 for (gsi = gsi_start_bb (e->src); !gsi_end_p (gsi); gsi_next (&gsi)) 282 { 283 gimple *stmt = gsi_stmt (gsi); 284 gasm *asm_stmt; 285 286 if ((is_gimple_call (stmt) && !nonfreeing_call_p (stmt)) 287 || ((asm_stmt = dyn_cast <gasm *> (stmt)) 288 && (gimple_asm_clobbers_memory_p (asm_stmt) 289 || gimple_asm_volatile_p (asm_stmt)))) 290 { 291 pred_info->has_freeing_call_p = true; 292 break; 293 } 294 } 295 296 pred_info->has_freeing_call_computed_p = true; 297 if (pred_info->has_freeing_call_p) 298 { 299 info->imm_dom_path_with_freeing_call_computed_p = true; 300 info->imm_dom_path_with_freeing_call_p = true; 301 info->being_visited_p = false; 302 return true; 303 } 304 } 305 306 FOR_EACH_EDGE (e, ei, bb->preds) 307 { 308 if (e->src == dom) 309 continue; 310 311 basic_block src; 312 for (src = e->src; src != dom; ) 313 { 314 sanopt_info *pred_info = (sanopt_info *) src->aux; 315 if (pred_info->being_visited_p) 316 break; 317 basic_block imm = get_immediate_dominator (CDI_DOMINATORS, src); 318 if (imm_dom_path_with_freeing_call (src, imm)) 319 { 320 info->imm_dom_path_with_freeing_call_computed_p = true; 321 info->imm_dom_path_with_freeing_call_p = true; 322 info->being_visited_p = false; 323 return true; 324 } 325 src = imm; 326 } 327 } 328 329 info->imm_dom_path_with_freeing_call_computed_p = true; 330 info->imm_dom_path_with_freeing_call_p = false; 331 info->being_visited_p = false; 332 return false; 333 } 334 335 /* Get the first dominating check from the list of stored checks. 336 Non-dominating checks are silently dropped. */ 337 338 static gimple * 339 maybe_get_dominating_check (auto_vec<gimple *> &v) 340 { 341 for (; !v.is_empty (); v.pop ()) 342 { 343 gimple *g = v.last (); 344 sanopt_info *si = (sanopt_info *) gimple_bb (g)->aux; 345 if (!si->visited_p) 346 /* At this point we shouldn't have any statements 347 that aren't dominating the current BB. */ 348 return g; 349 } 350 return NULL; 351 } 352 353 /* Optimize away redundant UBSAN_NULL calls. */ 354 355 static bool 356 maybe_optimize_ubsan_null_ifn (struct sanopt_ctx *ctx, gimple *stmt) 357 { 358 gcc_assert (gimple_call_num_args (stmt) == 3); 359 tree ptr = gimple_call_arg (stmt, 0); 360 tree cur_align = gimple_call_arg (stmt, 2); 361 gcc_assert (TREE_CODE (cur_align) == INTEGER_CST); 362 bool remove = false; 363 364 auto_vec<gimple *> &v = ctx->null_check_map.get_or_insert (ptr); 365 gimple *g = maybe_get_dominating_check (v); 366 if (!g) 367 { 368 /* For this PTR we don't have any UBSAN_NULL stmts recorded, so there's 369 nothing to optimize yet. */ 370 v.safe_push (stmt); 371 return false; 372 } 373 374 /* We already have recorded a UBSAN_NULL check for this pointer. Perhaps we 375 can drop this one. But only if this check doesn't specify stricter 376 alignment. */ 377 378 tree align = gimple_call_arg (g, 2); 379 int kind = tree_to_shwi (gimple_call_arg (g, 1)); 380 /* If this is a NULL pointer check where we had segv anyway, we can 381 remove it. */ 382 if (integer_zerop (align) 383 && (kind == UBSAN_LOAD_OF 384 || kind == UBSAN_STORE_OF 385 || kind == UBSAN_MEMBER_ACCESS)) 386 remove = true; 387 /* Otherwise remove the check in non-recovering mode, or if the 388 stmts have same location. */ 389 else if (integer_zerop (align)) 390 remove = (flag_sanitize_recover & SANITIZE_NULL) == 0 391 || flag_sanitize_undefined_trap_on_error 392 || gimple_location (g) == gimple_location (stmt); 393 else if (tree_int_cst_le (cur_align, align)) 394 remove = (flag_sanitize_recover & SANITIZE_ALIGNMENT) == 0 395 || flag_sanitize_undefined_trap_on_error 396 || gimple_location (g) == gimple_location (stmt); 397 398 if (!remove && gimple_bb (g) == gimple_bb (stmt) 399 && tree_int_cst_compare (cur_align, align) == 0) 400 v.pop (); 401 402 if (!remove) 403 v.safe_push (stmt); 404 return remove; 405 } 406 407 /* Return true when pointer PTR for a given CUR_OFFSET is already sanitized 408 in a given sanitization context CTX. */ 409 410 static bool 411 has_dominating_ubsan_ptr_check (sanopt_ctx *ctx, tree ptr, 412 offset_int &cur_offset) 413 { 414 bool pos_p = !wi::neg_p (cur_offset); 415 sanopt_tree_couple couple; 416 couple.ptr = ptr; 417 couple.pos_p = pos_p; 418 419 auto_vec<gimple *> &v = ctx->ptr_check_map.get_or_insert (couple); 420 gimple *g = maybe_get_dominating_check (v); 421 if (!g) 422 return false; 423 424 /* We already have recorded a UBSAN_PTR check for this pointer. Perhaps we 425 can drop this one. But only if this check doesn't specify larger offset. 426 */ 427 tree offset = gimple_call_arg (g, 1); 428 gcc_assert (TREE_CODE (offset) == INTEGER_CST); 429 offset_int ooffset = wi::sext (wi::to_offset (offset), POINTER_SIZE); 430 431 if (pos_p) 432 { 433 if (wi::les_p (cur_offset, ooffset)) 434 return true; 435 } 436 else if (!pos_p && wi::les_p (ooffset, cur_offset)) 437 return true; 438 439 return false; 440 } 441 442 /* Record UBSAN_PTR check of given context CTX. Register pointer PTR on 443 a given OFFSET that it's handled by GIMPLE STMT. */ 444 445 static void 446 record_ubsan_ptr_check_stmt (sanopt_ctx *ctx, gimple *stmt, tree ptr, 447 const offset_int &offset) 448 { 449 sanopt_tree_couple couple; 450 couple.ptr = ptr; 451 couple.pos_p = !wi::neg_p (offset); 452 453 auto_vec<gimple *> &v = ctx->ptr_check_map.get_or_insert (couple); 454 v.safe_push (stmt); 455 } 456 457 /* Optimize away redundant UBSAN_PTR calls. */ 458 459 static bool 460 maybe_optimize_ubsan_ptr_ifn (sanopt_ctx *ctx, gimple *stmt) 461 { 462 poly_int64 bitsize, pbitpos; 463 machine_mode mode; 464 int volatilep = 0, reversep, unsignedp = 0; 465 tree offset; 466 467 gcc_assert (gimple_call_num_args (stmt) == 2); 468 tree ptr = gimple_call_arg (stmt, 0); 469 tree off = gimple_call_arg (stmt, 1); 470 471 if (TREE_CODE (off) != INTEGER_CST) 472 return false; 473 474 if (integer_zerop (off)) 475 return true; 476 477 offset_int cur_offset = wi::sext (wi::to_offset (off), POINTER_SIZE); 478 if (has_dominating_ubsan_ptr_check (ctx, ptr, cur_offset)) 479 return true; 480 481 tree base = ptr; 482 if (TREE_CODE (base) == ADDR_EXPR) 483 { 484 base = TREE_OPERAND (base, 0); 485 486 HOST_WIDE_INT bitpos; 487 base = get_inner_reference (base, &bitsize, &pbitpos, &offset, &mode, 488 &unsignedp, &reversep, &volatilep); 489 if ((offset == NULL_TREE || TREE_CODE (offset) == INTEGER_CST) 490 && DECL_P (base) 491 && !DECL_REGISTER (base) 492 && pbitpos.is_constant (&bitpos)) 493 { 494 offset_int expr_offset; 495 if (offset) 496 expr_offset = wi::to_offset (offset) + bitpos / BITS_PER_UNIT; 497 else 498 expr_offset = bitpos / BITS_PER_UNIT; 499 expr_offset = wi::sext (expr_offset, POINTER_SIZE); 500 offset_int total_offset = expr_offset + cur_offset; 501 if (total_offset != wi::sext (total_offset, POINTER_SIZE)) 502 { 503 record_ubsan_ptr_check_stmt (ctx, stmt, ptr, cur_offset); 504 return false; 505 } 506 507 /* If BASE is a fixed size automatic variable or 508 global variable defined in the current TU, we don't have 509 to instrument anything if offset is within address 510 of the variable. */ 511 if ((VAR_P (base) 512 || TREE_CODE (base) == PARM_DECL 513 || TREE_CODE (base) == RESULT_DECL) 514 && DECL_SIZE_UNIT (base) 515 && TREE_CODE (DECL_SIZE_UNIT (base)) == INTEGER_CST 516 && (!is_global_var (base) || decl_binds_to_current_def_p (base))) 517 { 518 offset_int base_size = wi::to_offset (DECL_SIZE_UNIT (base)); 519 if (!wi::neg_p (expr_offset) 520 && wi::les_p (total_offset, base_size)) 521 { 522 if (!wi::neg_p (total_offset) 523 && wi::les_p (total_offset, base_size)) 524 return true; 525 } 526 } 527 528 /* Following expression: UBSAN_PTR (&MEM_REF[ptr + x], y) can be 529 handled as follows: 530 531 1) sign (x) == sign (y), then check for dominating check of (x + y) 532 2) sign (x) != sign (y), then first check if we have a dominating 533 check for ptr + x. If so, then we have 2 situations: 534 a) sign (x) == sign (x + y), here we are done, example: 535 UBSAN_PTR (&MEM_REF[ptr + 100], -50) 536 b) check for dominating check of ptr + x + y. 537 */ 538 539 bool sign_cur_offset = !wi::neg_p (cur_offset); 540 bool sign_expr_offset = !wi::neg_p (expr_offset); 541 542 tree base_addr 543 = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (base)), base); 544 545 bool add = false; 546 if (sign_cur_offset == sign_expr_offset) 547 { 548 if (has_dominating_ubsan_ptr_check (ctx, base_addr, total_offset)) 549 return true; 550 else 551 add = true; 552 } 553 else 554 { 555 if (!has_dominating_ubsan_ptr_check (ctx, base_addr, expr_offset)) 556 ; /* Don't record base_addr + expr_offset, it's not a guarding 557 check. */ 558 else 559 { 560 bool sign_total_offset = !wi::neg_p (total_offset); 561 if (sign_expr_offset == sign_total_offset) 562 return true; 563 else 564 { 565 if (has_dominating_ubsan_ptr_check (ctx, base_addr, 566 total_offset)) 567 return true; 568 else 569 add = true; 570 } 571 } 572 } 573 574 /* Record a new dominating check for base_addr + total_offset. */ 575 if (add && !operand_equal_p (base, base_addr, 0)) 576 record_ubsan_ptr_check_stmt (ctx, stmt, base_addr, 577 total_offset); 578 } 579 } 580 581 /* For this PTR we don't have any UBSAN_PTR stmts recorded, so there's 582 nothing to optimize yet. */ 583 record_ubsan_ptr_check_stmt (ctx, stmt, ptr, cur_offset); 584 585 return false; 586 } 587 588 /* Optimize away redundant UBSAN_VPTR calls. The second argument 589 is the value loaded from the virtual table, so rely on FRE to find out 590 when we can actually optimize. */ 591 592 static bool 593 maybe_optimize_ubsan_vptr_ifn (struct sanopt_ctx *ctx, gimple *stmt) 594 { 595 gcc_assert (gimple_call_num_args (stmt) == 5); 596 sanopt_tree_triplet triplet; 597 triplet.t1 = gimple_call_arg (stmt, 0); 598 triplet.t2 = gimple_call_arg (stmt, 1); 599 triplet.t3 = gimple_call_arg (stmt, 3); 600 601 auto_vec<gimple *> &v = ctx->vptr_check_map.get_or_insert (triplet); 602 gimple *g = maybe_get_dominating_check (v); 603 if (!g) 604 { 605 /* For this PTR we don't have any UBSAN_VPTR stmts recorded, so there's 606 nothing to optimize yet. */ 607 v.safe_push (stmt); 608 return false; 609 } 610 611 return true; 612 } 613 614 /* Returns TRUE if ASan check of length LEN in block BB can be removed 615 if preceded by checks in V. */ 616 617 static bool 618 can_remove_asan_check (auto_vec<gimple *> &v, tree len, basic_block bb) 619 { 620 unsigned int i; 621 gimple *g; 622 gimple *to_pop = NULL; 623 bool remove = false; 624 basic_block last_bb = bb; 625 bool cleanup = false; 626 627 FOR_EACH_VEC_ELT_REVERSE (v, i, g) 628 { 629 basic_block gbb = gimple_bb (g); 630 sanopt_info *si = (sanopt_info *) gbb->aux; 631 if (gimple_uid (g) < si->freeing_call_events) 632 { 633 /* If there is a potentially freeing call after g in gbb, we should 634 remove it from the vector, can't use in optimization. */ 635 cleanup = true; 636 continue; 637 } 638 639 tree glen = gimple_call_arg (g, 2); 640 gcc_assert (TREE_CODE (glen) == INTEGER_CST); 641 642 /* If we've checked only smaller length than we want to check now, 643 we can't remove the current stmt. If g is in the same basic block, 644 we want to remove it though, as the current stmt is better. */ 645 if (tree_int_cst_lt (glen, len)) 646 { 647 if (gbb == bb) 648 { 649 to_pop = g; 650 cleanup = true; 651 } 652 continue; 653 } 654 655 while (last_bb != gbb) 656 { 657 /* Paths from last_bb to bb have been checked before. 658 gbb is necessarily a dominator of last_bb, but not necessarily 659 immediate dominator. */ 660 if (((sanopt_info *) last_bb->aux)->freeing_call_events) 661 break; 662 663 basic_block imm = get_immediate_dominator (CDI_DOMINATORS, last_bb); 664 gcc_assert (imm); 665 if (imm_dom_path_with_freeing_call (last_bb, imm)) 666 break; 667 668 last_bb = imm; 669 } 670 if (last_bb == gbb) 671 remove = true; 672 break; 673 } 674 675 if (cleanup) 676 { 677 unsigned int j = 0, l = v.length (); 678 for (i = 0; i < l; i++) 679 if (v[i] != to_pop 680 && (gimple_uid (v[i]) 681 == ((sanopt_info *) 682 gimple_bb (v[i])->aux)->freeing_call_events)) 683 { 684 if (i != j) 685 v[j] = v[i]; 686 j++; 687 } 688 v.truncate (j); 689 } 690 691 return remove; 692 } 693 694 /* Optimize away redundant ASAN_CHECK calls. */ 695 696 static bool 697 maybe_optimize_asan_check_ifn (struct sanopt_ctx *ctx, gimple *stmt) 698 { 699 gcc_assert (gimple_call_num_args (stmt) == 4); 700 tree ptr = gimple_call_arg (stmt, 1); 701 tree len = gimple_call_arg (stmt, 2); 702 basic_block bb = gimple_bb (stmt); 703 sanopt_info *info = (sanopt_info *) bb->aux; 704 705 if (TREE_CODE (len) != INTEGER_CST) 706 return false; 707 if (integer_zerop (len)) 708 return false; 709 710 gimple_set_uid (stmt, info->freeing_call_events); 711 712 auto_vec<gimple *> *ptr_checks = &ctx->asan_check_map.get_or_insert (ptr); 713 714 tree base_addr = maybe_get_single_definition (ptr); 715 auto_vec<gimple *> *base_checks = NULL; 716 if (base_addr) 717 { 718 base_checks = &ctx->asan_check_map.get_or_insert (base_addr); 719 /* Original pointer might have been invalidated. */ 720 ptr_checks = ctx->asan_check_map.get (ptr); 721 } 722 723 gimple *g = maybe_get_dominating_check (*ptr_checks); 724 gimple *g2 = NULL; 725 726 if (base_checks) 727 /* Try with base address as well. */ 728 g2 = maybe_get_dominating_check (*base_checks); 729 730 if (g == NULL && g2 == NULL) 731 { 732 /* For this PTR we don't have any ASAN_CHECK stmts recorded, so there's 733 nothing to optimize yet. */ 734 ptr_checks->safe_push (stmt); 735 if (base_checks) 736 base_checks->safe_push (stmt); 737 return false; 738 } 739 740 bool remove = false; 741 742 if (ptr_checks) 743 remove = can_remove_asan_check (*ptr_checks, len, bb); 744 745 if (!remove && base_checks) 746 /* Try with base address as well. */ 747 remove = can_remove_asan_check (*base_checks, len, bb); 748 749 if (!remove) 750 { 751 ptr_checks->safe_push (stmt); 752 if (base_checks) 753 base_checks->safe_push (stmt); 754 } 755 756 return remove; 757 } 758 759 /* Try to optimize away redundant UBSAN_NULL and ASAN_CHECK calls. 760 761 We walk blocks in the CFG via a depth first search of the dominator 762 tree; we push unique UBSAN_NULL or ASAN_CHECK statements into a vector 763 in the NULL_CHECK_MAP or ASAN_CHECK_MAP hash maps as we enter the 764 blocks. When leaving a block, we mark the block as visited; then 765 when checking the statements in the vector, we ignore statements that 766 are coming from already visited blocks, because these cannot dominate 767 anything anymore. CTX is a sanopt context. */ 768 769 static void 770 sanopt_optimize_walker (basic_block bb, struct sanopt_ctx *ctx) 771 { 772 basic_block son; 773 gimple_stmt_iterator gsi; 774 sanopt_info *info = (sanopt_info *) bb->aux; 775 bool asan_check_optimize = (flag_sanitize & SANITIZE_ADDRESS) != 0; 776 777 for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi);) 778 { 779 gimple *stmt = gsi_stmt (gsi); 780 bool remove = false; 781 782 if (!is_gimple_call (stmt)) 783 { 784 /* Handle asm volatile or asm with "memory" clobber 785 the same as potentionally freeing call. */ 786 gasm *asm_stmt = dyn_cast <gasm *> (stmt); 787 if (asm_stmt 788 && asan_check_optimize 789 && (gimple_asm_clobbers_memory_p (asm_stmt) 790 || gimple_asm_volatile_p (asm_stmt))) 791 info->freeing_call_events++; 792 gsi_next (&gsi); 793 continue; 794 } 795 796 if (asan_check_optimize && !nonfreeing_call_p (stmt)) 797 info->freeing_call_events++; 798 799 /* If __asan_before_dynamic_init ("module"); is followed by 800 __asan_after_dynamic_init (); without intervening memory loads/stores, 801 there is nothing to guard, so optimize both away. */ 802 if (asan_check_optimize 803 && gimple_call_builtin_p (stmt, BUILT_IN_ASAN_BEFORE_DYNAMIC_INIT)) 804 { 805 use_operand_p use; 806 gimple *use_stmt; 807 if (single_imm_use (gimple_vdef (stmt), &use, &use_stmt)) 808 { 809 if (is_gimple_call (use_stmt) 810 && gimple_call_builtin_p (use_stmt, 811 BUILT_IN_ASAN_AFTER_DYNAMIC_INIT)) 812 { 813 unlink_stmt_vdef (use_stmt); 814 gimple_stmt_iterator gsi2 = gsi_for_stmt (use_stmt); 815 gsi_remove (&gsi2, true); 816 remove = true; 817 } 818 } 819 } 820 821 if (gimple_call_internal_p (stmt)) 822 switch (gimple_call_internal_fn (stmt)) 823 { 824 case IFN_UBSAN_NULL: 825 remove = maybe_optimize_ubsan_null_ifn (ctx, stmt); 826 break; 827 case IFN_UBSAN_VPTR: 828 remove = maybe_optimize_ubsan_vptr_ifn (ctx, stmt); 829 break; 830 case IFN_UBSAN_PTR: 831 remove = maybe_optimize_ubsan_ptr_ifn (ctx, stmt); 832 break; 833 case IFN_ASAN_CHECK: 834 if (asan_check_optimize) 835 remove = maybe_optimize_asan_check_ifn (ctx, stmt); 836 if (!remove) 837 ctx->asan_num_accesses++; 838 break; 839 case IFN_ASAN_MARK: 840 ctx->contains_asan_mark = true; 841 break; 842 default: 843 break; 844 } 845 846 if (remove) 847 { 848 /* Drop this check. */ 849 if (dump_file && (dump_flags & TDF_DETAILS)) 850 { 851 fprintf (dump_file, "Optimizing out: "); 852 print_gimple_stmt (dump_file, stmt, 0, dump_flags); 853 } 854 unlink_stmt_vdef (stmt); 855 gsi_remove (&gsi, true); 856 } 857 else 858 { 859 if (dump_file && (dump_flags & TDF_DETAILS)) 860 { 861 fprintf (dump_file, "Leaving: "); 862 print_gimple_stmt (dump_file, stmt, 0, dump_flags); 863 } 864 865 gsi_next (&gsi); 866 } 867 } 868 869 if (asan_check_optimize) 870 { 871 info->has_freeing_call_p = info->freeing_call_events != 0; 872 info->has_freeing_call_computed_p = true; 873 } 874 875 for (son = first_dom_son (CDI_DOMINATORS, bb); 876 son; 877 son = next_dom_son (CDI_DOMINATORS, son)) 878 sanopt_optimize_walker (son, ctx); 879 880 /* We're leaving this BB, so mark it to that effect. */ 881 info->visited_p = true; 882 } 883 884 /* Try to remove redundant sanitizer checks in function FUN. */ 885 886 static int 887 sanopt_optimize (function *fun, bool *contains_asan_mark) 888 { 889 struct sanopt_ctx ctx; 890 ctx.asan_num_accesses = 0; 891 ctx.contains_asan_mark = false; 892 893 /* Set up block info for each basic block. */ 894 alloc_aux_for_blocks (sizeof (sanopt_info)); 895 896 /* We're going to do a dominator walk, so ensure that we have 897 dominance information. */ 898 calculate_dominance_info (CDI_DOMINATORS); 899 900 /* Recursively walk the dominator tree optimizing away 901 redundant checks. */ 902 sanopt_optimize_walker (ENTRY_BLOCK_PTR_FOR_FN (fun), &ctx); 903 904 free_aux_for_blocks (); 905 906 *contains_asan_mark = ctx.contains_asan_mark; 907 return ctx.asan_num_accesses; 908 } 909 910 /* Perform optimization of sanitize functions. */ 911 912 namespace { 913 914 const pass_data pass_data_sanopt = 915 { 916 GIMPLE_PASS, /* type */ 917 "sanopt", /* name */ 918 OPTGROUP_NONE, /* optinfo_flags */ 919 TV_NONE, /* tv_id */ 920 ( PROP_ssa | PROP_cfg | PROP_gimple_leh ), /* properties_required */ 921 0, /* properties_provided */ 922 0, /* properties_destroyed */ 923 0, /* todo_flags_start */ 924 TODO_update_ssa, /* todo_flags_finish */ 925 }; 926 927 class pass_sanopt : public gimple_opt_pass 928 { 929 public: 930 pass_sanopt (gcc::context *ctxt) 931 : gimple_opt_pass (pass_data_sanopt, ctxt) 932 {} 933 934 /* opt_pass methods: */ 935 virtual bool gate (function *) { return flag_sanitize; } 936 virtual unsigned int execute (function *); 937 938 }; // class pass_sanopt 939 940 /* Sanitize all ASAN_MARK unpoison calls that are not reachable by a BB 941 that contains an ASAN_MARK poison. All these ASAN_MARK unpoison call 942 can be removed as all variables are unpoisoned in a function prologue. */ 943 944 static void 945 sanitize_asan_mark_unpoison (void) 946 { 947 /* 1) Find all BBs that contain an ASAN_MARK poison call. */ 948 auto_sbitmap with_poison (last_basic_block_for_fn (cfun) + 1); 949 bitmap_clear (with_poison); 950 basic_block bb; 951 952 FOR_EACH_BB_FN (bb, cfun) 953 { 954 if (bitmap_bit_p (with_poison, bb->index)) 955 continue; 956 957 gimple_stmt_iterator gsi; 958 for (gsi = gsi_last_bb (bb); !gsi_end_p (gsi); gsi_prev (&gsi)) 959 { 960 gimple *stmt = gsi_stmt (gsi); 961 if (asan_mark_p (stmt, ASAN_MARK_POISON)) 962 { 963 bitmap_set_bit (with_poison, bb->index); 964 break; 965 } 966 } 967 } 968 969 auto_sbitmap poisoned (last_basic_block_for_fn (cfun) + 1); 970 bitmap_clear (poisoned); 971 auto_sbitmap worklist (last_basic_block_for_fn (cfun) + 1); 972 bitmap_copy (worklist, with_poison); 973 974 /* 2) Propagate the information to all reachable blocks. */ 975 while (!bitmap_empty_p (worklist)) 976 { 977 unsigned i = bitmap_first_set_bit (worklist); 978 bitmap_clear_bit (worklist, i); 979 basic_block bb = BASIC_BLOCK_FOR_FN (cfun, i); 980 gcc_assert (bb); 981 982 edge e; 983 edge_iterator ei; 984 FOR_EACH_EDGE (e, ei, bb->succs) 985 if (!bitmap_bit_p (poisoned, e->dest->index)) 986 { 987 bitmap_set_bit (poisoned, e->dest->index); 988 bitmap_set_bit (worklist, e->dest->index); 989 } 990 } 991 992 /* 3) Iterate all BBs not included in POISONED BBs and remove unpoison 993 ASAN_MARK preceding an ASAN_MARK poison (which can still happen). */ 994 FOR_EACH_BB_FN (bb, cfun) 995 { 996 if (bitmap_bit_p (poisoned, bb->index)) 997 continue; 998 999 gimple_stmt_iterator gsi; 1000 for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi);) 1001 { 1002 gimple *stmt = gsi_stmt (gsi); 1003 if (gimple_call_internal_p (stmt, IFN_ASAN_MARK)) 1004 { 1005 if (asan_mark_p (stmt, ASAN_MARK_POISON)) 1006 break; 1007 else 1008 { 1009 if (dump_file) 1010 fprintf (dump_file, "Removing ASAN_MARK unpoison\n"); 1011 unlink_stmt_vdef (stmt); 1012 release_defs (stmt); 1013 gsi_remove (&gsi, true); 1014 continue; 1015 } 1016 } 1017 1018 gsi_next (&gsi); 1019 } 1020 } 1021 } 1022 1023 /* Return true when STMT is either ASAN_CHECK call or a call of a function 1024 that can contain an ASAN_CHECK. */ 1025 1026 static bool 1027 maybe_contains_asan_check (gimple *stmt) 1028 { 1029 if (is_gimple_call (stmt)) 1030 { 1031 if (gimple_call_internal_p (stmt, IFN_ASAN_MARK)) 1032 return false; 1033 else 1034 return !(gimple_call_flags (stmt) & ECF_CONST); 1035 } 1036 else if (is_a<gasm *> (stmt)) 1037 return true; 1038 1039 return false; 1040 } 1041 1042 /* Sanitize all ASAN_MARK poison calls that are not followed by an ASAN_CHECK 1043 call. These calls can be removed. */ 1044 1045 static void 1046 sanitize_asan_mark_poison (void) 1047 { 1048 /* 1) Find all BBs that possibly contain an ASAN_CHECK. */ 1049 auto_sbitmap with_check (last_basic_block_for_fn (cfun) + 1); 1050 bitmap_clear (with_check); 1051 basic_block bb; 1052 1053 FOR_EACH_BB_FN (bb, cfun) 1054 { 1055 gimple_stmt_iterator gsi; 1056 for (gsi = gsi_last_bb (bb); !gsi_end_p (gsi); gsi_prev (&gsi)) 1057 { 1058 gimple *stmt = gsi_stmt (gsi); 1059 if (maybe_contains_asan_check (stmt)) 1060 { 1061 bitmap_set_bit (with_check, bb->index); 1062 break; 1063 } 1064 } 1065 } 1066 1067 auto_sbitmap can_reach_check (last_basic_block_for_fn (cfun) + 1); 1068 bitmap_clear (can_reach_check); 1069 auto_sbitmap worklist (last_basic_block_for_fn (cfun) + 1); 1070 bitmap_copy (worklist, with_check); 1071 1072 /* 2) Propagate the information to all definitions blocks. */ 1073 while (!bitmap_empty_p (worklist)) 1074 { 1075 unsigned i = bitmap_first_set_bit (worklist); 1076 bitmap_clear_bit (worklist, i); 1077 basic_block bb = BASIC_BLOCK_FOR_FN (cfun, i); 1078 gcc_assert (bb); 1079 1080 edge e; 1081 edge_iterator ei; 1082 FOR_EACH_EDGE (e, ei, bb->preds) 1083 if (!bitmap_bit_p (can_reach_check, e->src->index)) 1084 { 1085 bitmap_set_bit (can_reach_check, e->src->index); 1086 bitmap_set_bit (worklist, e->src->index); 1087 } 1088 } 1089 1090 /* 3) Iterate all BBs not included in CAN_REACH_CHECK BBs and remove poison 1091 ASAN_MARK not followed by a call to function having an ASAN_CHECK. */ 1092 FOR_EACH_BB_FN (bb, cfun) 1093 { 1094 if (bitmap_bit_p (can_reach_check, bb->index)) 1095 continue; 1096 1097 gimple_stmt_iterator gsi; 1098 for (gsi = gsi_last_bb (bb); !gsi_end_p (gsi);) 1099 { 1100 gimple *stmt = gsi_stmt (gsi); 1101 if (maybe_contains_asan_check (stmt)) 1102 break; 1103 else if (asan_mark_p (stmt, ASAN_MARK_POISON)) 1104 { 1105 if (dump_file) 1106 fprintf (dump_file, "Removing ASAN_MARK poison\n"); 1107 unlink_stmt_vdef (stmt); 1108 release_defs (stmt); 1109 gimple_stmt_iterator gsi2 = gsi; 1110 gsi_prev (&gsi); 1111 gsi_remove (&gsi2, true); 1112 continue; 1113 } 1114 1115 gsi_prev (&gsi); 1116 } 1117 } 1118 } 1119 1120 /* Rewrite all usages of tree OP which is a PARM_DECL with a VAR_DECL 1121 that is it's DECL_VALUE_EXPR. */ 1122 1123 static tree 1124 rewrite_usage_of_param (tree *op, int *walk_subtrees, void *) 1125 { 1126 if (TREE_CODE (*op) == PARM_DECL && DECL_HAS_VALUE_EXPR_P (*op)) 1127 { 1128 *op = DECL_VALUE_EXPR (*op); 1129 *walk_subtrees = 0; 1130 } 1131 1132 return NULL; 1133 } 1134 1135 /* For a given function FUN, rewrite all addressable parameters so that 1136 a new automatic variable is introduced. Right after function entry 1137 a parameter is assigned to the variable. */ 1138 1139 static void 1140 sanitize_rewrite_addressable_params (function *fun) 1141 { 1142 gimple *g; 1143 gimple_seq stmts = NULL; 1144 bool has_any_addressable_param = false; 1145 auto_vec<tree> clear_value_expr_list; 1146 1147 for (tree arg = DECL_ARGUMENTS (current_function_decl); 1148 arg; arg = DECL_CHAIN (arg)) 1149 { 1150 tree type = TREE_TYPE (arg); 1151 if (TREE_ADDRESSABLE (arg) 1152 && !TREE_ADDRESSABLE (type) 1153 && !TREE_THIS_VOLATILE (arg) 1154 && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST) 1155 { 1156 TREE_ADDRESSABLE (arg) = 0; 1157 /* The parameter is no longer addressable. */ 1158 has_any_addressable_param = true; 1159 1160 /* Create a new automatic variable. */ 1161 tree var = build_decl (DECL_SOURCE_LOCATION (arg), 1162 VAR_DECL, DECL_NAME (arg), type); 1163 TREE_ADDRESSABLE (var) = 1; 1164 DECL_IGNORED_P (var) = 1; 1165 1166 gimple_add_tmp_var (var); 1167 1168 if (dump_file) 1169 fprintf (dump_file, 1170 "Rewriting parameter whose address is taken: %s\n", 1171 IDENTIFIER_POINTER (DECL_NAME (arg))); 1172 1173 gcc_assert (!DECL_HAS_VALUE_EXPR_P (arg)); 1174 1175 SET_DECL_PT_UID (var, DECL_PT_UID (arg)); 1176 1177 /* Assign value of parameter to newly created variable. */ 1178 if ((TREE_CODE (type) == COMPLEX_TYPE 1179 || TREE_CODE (type) == VECTOR_TYPE)) 1180 { 1181 /* We need to create a SSA name that will be used for the 1182 assignment. */ 1183 DECL_GIMPLE_REG_P (arg) = 1; 1184 tree tmp = get_or_create_ssa_default_def (cfun, arg); 1185 g = gimple_build_assign (var, tmp); 1186 gimple_set_location (g, DECL_SOURCE_LOCATION (arg)); 1187 gimple_seq_add_stmt (&stmts, g); 1188 } 1189 else 1190 { 1191 g = gimple_build_assign (var, arg); 1192 gimple_set_location (g, DECL_SOURCE_LOCATION (arg)); 1193 gimple_seq_add_stmt (&stmts, g); 1194 } 1195 1196 if (target_for_debug_bind (arg)) 1197 { 1198 g = gimple_build_debug_bind (arg, var, NULL); 1199 gimple_seq_add_stmt (&stmts, g); 1200 clear_value_expr_list.safe_push (arg); 1201 } 1202 1203 DECL_HAS_VALUE_EXPR_P (arg) = 1; 1204 SET_DECL_VALUE_EXPR (arg, var); 1205 } 1206 } 1207 1208 if (!has_any_addressable_param) 1209 return; 1210 1211 /* Replace all usages of PARM_DECLs with the newly 1212 created variable VAR. */ 1213 basic_block bb; 1214 FOR_EACH_BB_FN (bb, fun) 1215 { 1216 gimple_stmt_iterator gsi; 1217 for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) 1218 { 1219 gimple *stmt = gsi_stmt (gsi); 1220 gimple_stmt_iterator it = gsi_for_stmt (stmt); 1221 walk_gimple_stmt (&it, NULL, rewrite_usage_of_param, NULL); 1222 } 1223 for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi)) 1224 { 1225 gphi *phi = dyn_cast<gphi *> (gsi_stmt (gsi)); 1226 for (unsigned i = 0; i < gimple_phi_num_args (phi); ++i) 1227 { 1228 hash_set<tree> visited_nodes; 1229 walk_tree (gimple_phi_arg_def_ptr (phi, i), 1230 rewrite_usage_of_param, NULL, &visited_nodes); 1231 } 1232 } 1233 } 1234 1235 /* Unset value expr for parameters for which we created debug bind 1236 expressions. */ 1237 unsigned i; 1238 tree arg; 1239 FOR_EACH_VEC_ELT (clear_value_expr_list, i, arg) 1240 { 1241 DECL_HAS_VALUE_EXPR_P (arg) = 0; 1242 SET_DECL_VALUE_EXPR (arg, NULL_TREE); 1243 } 1244 1245 /* Insert default assignments at the beginning of a function. */ 1246 basic_block entry_bb = ENTRY_BLOCK_PTR_FOR_FN (fun); 1247 entry_bb = split_edge (single_succ_edge (entry_bb)); 1248 1249 gimple_stmt_iterator gsi = gsi_start_bb (entry_bb); 1250 gsi_insert_seq_before (&gsi, stmts, GSI_NEW_STMT); 1251 } 1252 1253 unsigned int 1254 pass_sanopt::execute (function *fun) 1255 { 1256 basic_block bb; 1257 int asan_num_accesses = 0; 1258 bool contains_asan_mark = false; 1259 1260 /* Try to remove redundant checks. */ 1261 if (optimize 1262 && (flag_sanitize 1263 & (SANITIZE_NULL | SANITIZE_ALIGNMENT 1264 | SANITIZE_ADDRESS | SANITIZE_VPTR | SANITIZE_POINTER_OVERFLOW))) 1265 asan_num_accesses = sanopt_optimize (fun, &contains_asan_mark); 1266 else if (flag_sanitize & SANITIZE_ADDRESS) 1267 { 1268 gimple_stmt_iterator gsi; 1269 FOR_EACH_BB_FN (bb, fun) 1270 for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) 1271 { 1272 gimple *stmt = gsi_stmt (gsi); 1273 if (gimple_call_internal_p (stmt, IFN_ASAN_CHECK)) 1274 ++asan_num_accesses; 1275 else if (gimple_call_internal_p (stmt, IFN_ASAN_MARK)) 1276 contains_asan_mark = true; 1277 } 1278 } 1279 1280 if (contains_asan_mark) 1281 { 1282 sanitize_asan_mark_unpoison (); 1283 sanitize_asan_mark_poison (); 1284 } 1285 1286 if (asan_sanitize_stack_p ()) 1287 sanitize_rewrite_addressable_params (fun); 1288 1289 bool use_calls = ASAN_INSTRUMENTATION_WITH_CALL_THRESHOLD < INT_MAX 1290 && asan_num_accesses >= ASAN_INSTRUMENTATION_WITH_CALL_THRESHOLD; 1291 1292 hash_map<tree, tree> shadow_vars_mapping; 1293 bool need_commit_edge_insert = false; 1294 FOR_EACH_BB_FN (bb, fun) 1295 { 1296 gimple_stmt_iterator gsi; 1297 for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); ) 1298 { 1299 gimple *stmt = gsi_stmt (gsi); 1300 bool no_next = false; 1301 1302 if (!is_gimple_call (stmt)) 1303 { 1304 gsi_next (&gsi); 1305 continue; 1306 } 1307 1308 if (gimple_call_internal_p (stmt)) 1309 { 1310 enum internal_fn ifn = gimple_call_internal_fn (stmt); 1311 switch (ifn) 1312 { 1313 case IFN_UBSAN_NULL: 1314 no_next = ubsan_expand_null_ifn (&gsi); 1315 break; 1316 case IFN_UBSAN_BOUNDS: 1317 no_next = ubsan_expand_bounds_ifn (&gsi); 1318 break; 1319 case IFN_UBSAN_OBJECT_SIZE: 1320 no_next = ubsan_expand_objsize_ifn (&gsi); 1321 break; 1322 case IFN_UBSAN_PTR: 1323 no_next = ubsan_expand_ptr_ifn (&gsi); 1324 break; 1325 case IFN_UBSAN_VPTR: 1326 no_next = ubsan_expand_vptr_ifn (&gsi); 1327 break; 1328 case IFN_ASAN_CHECK: 1329 no_next = asan_expand_check_ifn (&gsi, use_calls); 1330 break; 1331 case IFN_ASAN_MARK: 1332 no_next = asan_expand_mark_ifn (&gsi); 1333 break; 1334 case IFN_ASAN_POISON: 1335 no_next = asan_expand_poison_ifn (&gsi, 1336 &need_commit_edge_insert, 1337 shadow_vars_mapping); 1338 break; 1339 default: 1340 break; 1341 } 1342 } 1343 else if (gimple_call_builtin_p (stmt, BUILT_IN_NORMAL)) 1344 { 1345 tree callee = gimple_call_fndecl (stmt); 1346 switch (DECL_FUNCTION_CODE (callee)) 1347 { 1348 case BUILT_IN_UNREACHABLE: 1349 if (sanitize_flags_p (SANITIZE_UNREACHABLE)) 1350 no_next = ubsan_instrument_unreachable (&gsi); 1351 break; 1352 default: 1353 break; 1354 } 1355 } 1356 1357 if (dump_file && (dump_flags & TDF_DETAILS)) 1358 { 1359 fprintf (dump_file, "Expanded: "); 1360 print_gimple_stmt (dump_file, stmt, 0, dump_flags); 1361 } 1362 1363 if (!no_next) 1364 gsi_next (&gsi); 1365 } 1366 } 1367 1368 if (need_commit_edge_insert) 1369 gsi_commit_edge_inserts (); 1370 1371 return 0; 1372 } 1373 1374 } // anon namespace 1375 1376 gimple_opt_pass * 1377 make_pass_sanopt (gcc::context *ctxt) 1378 { 1379 return new pass_sanopt (ctxt); 1380 } 1381