sanopt.c 26.1 KB
Newer Older
1
/* Optimize and expand sanitizer functions.
2
   Copyright (C) 2014-2017 Free Software Foundation, Inc.
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
   Contributed by Marek Polacek <polacek@redhat.com>

This file is part of GCC.

GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.

GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.

You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3.  If not see
<http://www.gnu.org/licenses/>.  */

#include "config.h"
#include "system.h"
#include "coretypes.h"
24
#include "backend.h"
25
#include "tree.h"
26
#include "gimple.h"
27
#include "ssa.h"
28 29 30
#include "tree-pass.h"
#include "tree-ssa-operands.h"
#include "gimple-pretty-print.h"
31
#include "fold-const.h"
32 33 34 35
#include "gimple-iterator.h"
#include "asan.h"
#include "ubsan.h"
#include "params.h"
36
#include "tree-hash-traits.h"
37 38 39
#include "gimple-ssa.h"
#include "tree-phinodes.h"
#include "ssa-iterators.h"
40 41 42 43 44 45

/* This is used to carry information about basic blocks.  It is
   attached to the AUX field of the standard CFG block.  */

struct sanopt_info
{
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
  /* True if this BB might call (directly or indirectly) free/munmap
     or similar operation.  */
  bool has_freeing_call_p;

  /* True if HAS_FREEING_CALL_P flag has been computed.  */
  bool has_freeing_call_computed_p;

  /* True if there is a block with HAS_FREEING_CALL_P flag set
     on any path between an immediate dominator of BB, denoted
     imm(BB), and BB.  */
  bool imm_dom_path_with_freeing_call_p;

  /* True if IMM_DOM_PATH_WITH_FREEING_CALL_P has been computed.  */
  bool imm_dom_path_with_freeing_call_computed_p;

  /* Number of possibly freeing calls encountered in this bb
     (so far).  */
  uint64_t freeing_call_events;

  /* True if BB is currently being visited during computation
     of IMM_DOM_PATH_WITH_FREEING_CALL_P flag.  */
  bool being_visited_p;

  /* True if this BB has been visited in the dominator walk.  */
70 71 72
  bool visited_p;
};

73 74 75 76 77 78 79
/* If T has a single definition of form T = T2, return T2.  */

static tree
maybe_get_single_definition (tree t)
{
  if (TREE_CODE (t) == SSA_NAME)
    {
80
      gimple *g = SSA_NAME_DEF_STMT (t);
81 82 83 84 85 86
      if (gimple_assign_single_p (g))
	return gimple_assign_rhs1 (g);
    }
  return NULL_TREE;
}

87 88 89 90 91 92 93 94
/* Tree triplet for vptr_check_map.  */
struct sanopt_tree_triplet
{
  tree t1, t2, t3;
};

/* Traits class for tree triplet hash maps below.  */

95
struct sanopt_tree_triplet_hash : typed_noop_remove <sanopt_tree_triplet>
96
{
97 98 99
  typedef sanopt_tree_triplet value_type;
  typedef sanopt_tree_triplet compare_type;

100 101 102 103 104 105 106 107 108 109 110
  static inline hashval_t
  hash (const sanopt_tree_triplet &ref)
  {
    inchash::hash hstate (0);
    inchash::add_expr (ref.t1, hstate);
    inchash::add_expr (ref.t2, hstate);
    inchash::add_expr (ref.t3, hstate);
    return hstate.end ();
  }

  static inline bool
111
  equal (const sanopt_tree_triplet &ref1, const sanopt_tree_triplet &ref2)
112 113 114 115 116 117 118
  {
    return operand_equal_p (ref1.t1, ref2.t1, 0)
	   && operand_equal_p (ref1.t2, ref2.t2, 0)
	   && operand_equal_p (ref1.t3, ref2.t3, 0);
  }

  static inline void
119
  mark_deleted (sanopt_tree_triplet &ref)
120
  {
121
    ref.t1 = reinterpret_cast<tree> (1);
122 123 124
  }

  static inline void
125
  mark_empty (sanopt_tree_triplet &ref)
126
  {
127
    ref.t1 = NULL;
128 129 130
  }

  static inline bool
131
  is_deleted (const sanopt_tree_triplet &ref)
132
  {
133
    return ref.t1 == (void *) 1;
134 135 136
  }

  static inline bool
137
  is_empty (const sanopt_tree_triplet &ref)
138
  {
139
    return ref.t1 == NULL;
140 141 142
  }
};

143 144 145 146 147 148 149
/* This is used to carry various hash maps and variables used
   in sanopt_optimize_walker.  */

struct sanopt_ctx
{
  /* This map maps a pointer (the first argument of UBSAN_NULL) to
     a vector of UBSAN_NULL call statements that check this pointer.  */
150
  hash_map<tree, auto_vec<gimple *> > null_check_map;
151

152 153
  /* This map maps a pointer (the second argument of ASAN_CHECK) to
     a vector of ASAN_CHECK call statements that check the access.  */
154
  hash_map<tree_operand_hash, auto_vec<gimple *> > asan_check_map;
155 156 157 158

  /* This map maps a tree triplet (the first, second and fourth argument
     of UBSAN_VPTR) to a vector of UBSAN_VPTR call statements that check
     that virtual table pointer.  */
159
  hash_map<sanopt_tree_triplet_hash, auto_vec<gimple *> > vptr_check_map;
160

161 162 163
  /* Number of IFN_ASAN_CHECK statements.  */
  int asan_num_accesses;

164 165 166
  /* True when the current functions constains an ASAN_MARK.  */
  bool contains_asan_mark;
};
167

168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
/* Return true if there might be any call to free/munmap operation
   on any path in between DOM (which should be imm(BB)) and BB.  */

static bool
imm_dom_path_with_freeing_call (basic_block bb, basic_block dom)
{
  sanopt_info *info = (sanopt_info *) bb->aux;
  edge e;
  edge_iterator ei;

  if (info->imm_dom_path_with_freeing_call_computed_p)
    return info->imm_dom_path_with_freeing_call_p;

  info->being_visited_p = true;

  FOR_EACH_EDGE (e, ei, bb->preds)
    {
      sanopt_info *pred_info = (sanopt_info *) e->src->aux;

      if (e->src == dom)
	continue;

      if ((pred_info->imm_dom_path_with_freeing_call_computed_p
	  && pred_info->imm_dom_path_with_freeing_call_p)
	  || (pred_info->has_freeing_call_computed_p
	      && pred_info->has_freeing_call_p))
	{
	  info->imm_dom_path_with_freeing_call_computed_p = true;
	  info->imm_dom_path_with_freeing_call_p = true;
	  info->being_visited_p = false;
	  return true;
	}
    }

  FOR_EACH_EDGE (e, ei, bb->preds)
    {
      sanopt_info *pred_info = (sanopt_info *) e->src->aux;

      if (e->src == dom)
	continue;

      if (pred_info->has_freeing_call_computed_p)
	continue;

      gimple_stmt_iterator gsi;
      for (gsi = gsi_start_bb (e->src); !gsi_end_p (gsi); gsi_next (&gsi))
	{
215
	  gimple *stmt = gsi_stmt (gsi);
216
	  gasm *asm_stmt;
217

218 219 220 221
	  if ((is_gimple_call (stmt) && !nonfreeing_call_p (stmt))
	      || ((asm_stmt = dyn_cast <gasm *> (stmt))
		  && (gimple_asm_clobbers_memory_p (asm_stmt)
		      || gimple_asm_volatile_p (asm_stmt))))
222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266
	    {
	      pred_info->has_freeing_call_p = true;
	      break;
	    }
	}

      pred_info->has_freeing_call_computed_p = true;
      if (pred_info->has_freeing_call_p)
	{
	  info->imm_dom_path_with_freeing_call_computed_p = true;
	  info->imm_dom_path_with_freeing_call_p = true;
	  info->being_visited_p = false;
	  return true;
	}
    }

  FOR_EACH_EDGE (e, ei, bb->preds)
    {
      if (e->src == dom)
	continue;

      basic_block src;
      for (src = e->src; src != dom; )
	{
	  sanopt_info *pred_info = (sanopt_info *) src->aux;
	  if (pred_info->being_visited_p)
	    break;
	  basic_block imm = get_immediate_dominator (CDI_DOMINATORS, src);
	  if (imm_dom_path_with_freeing_call (src, imm))
	    {
	      info->imm_dom_path_with_freeing_call_computed_p = true;
	      info->imm_dom_path_with_freeing_call_p = true;
	      info->being_visited_p = false;
	      return true;
	    }
	  src = imm;
	}
    }

  info->imm_dom_path_with_freeing_call_computed_p = true;
  info->imm_dom_path_with_freeing_call_p = false;
  info->being_visited_p = false;
  return false;
}

267 268 269
/* Get the first dominating check from the list of stored checks.
   Non-dominating checks are silently dropped.  */

270 271
static gimple *
maybe_get_dominating_check (auto_vec<gimple *> &v)
272 273 274
{
  for (; !v.is_empty (); v.pop ())
    {
275
      gimple *g = v.last ();
276 277 278 279 280 281 282 283 284
      sanopt_info *si = (sanopt_info *) gimple_bb (g)->aux;
      if (!si->visited_p)
	/* At this point we shouldn't have any statements
	   that aren't dominating the current BB.  */
	return g;
    }
  return NULL;
}

285 286 287
/* Optimize away redundant UBSAN_NULL calls.  */

static bool
288
maybe_optimize_ubsan_null_ifn (struct sanopt_ctx *ctx, gimple *stmt)
289 290 291 292 293 294 295
{
  gcc_assert (gimple_call_num_args (stmt) == 3);
  tree ptr = gimple_call_arg (stmt, 0);
  tree cur_align = gimple_call_arg (stmt, 2);
  gcc_assert (TREE_CODE (cur_align) == INTEGER_CST);
  bool remove = false;

296 297
  auto_vec<gimple *> &v = ctx->null_check_map.get_or_insert (ptr);
  gimple *g = maybe_get_dominating_check (v);
298
  if (!g)
299 300 301 302 303 304 305 306 307 308 309
    {
      /* For this PTR we don't have any UBSAN_NULL stmts recorded, so there's
	 nothing to optimize yet.  */
      v.safe_push (stmt);
      return false;
    }

  /* We already have recorded a UBSAN_NULL check for this pointer. Perhaps we
     can drop this one.  But only if this check doesn't specify stricter
     alignment.  */

310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332
  tree align = gimple_call_arg (g, 2);
  int kind = tree_to_shwi (gimple_call_arg (g, 1));
  /* If this is a NULL pointer check where we had segv anyway, we can
     remove it.  */
  if (integer_zerop (align)
      && (kind == UBSAN_LOAD_OF
	  || kind == UBSAN_STORE_OF
	  || kind == UBSAN_MEMBER_ACCESS))
    remove = true;
  /* Otherwise remove the check in non-recovering mode, or if the
     stmts have same location.  */
  else if (integer_zerop (align))
    remove = (flag_sanitize_recover & SANITIZE_NULL) == 0
	      || flag_sanitize_undefined_trap_on_error
	      || gimple_location (g) == gimple_location (stmt);
  else if (tree_int_cst_le (cur_align, align))
    remove = (flag_sanitize_recover & SANITIZE_ALIGNMENT) == 0
	      || flag_sanitize_undefined_trap_on_error
	      || gimple_location (g) == gimple_location (stmt);

  if (!remove && gimple_bb (g) == gimple_bb (stmt)
      && tree_int_cst_compare (cur_align, align) == 0)
    v.pop ();
333 334 335 336 337 338

  if (!remove)
    v.safe_push (stmt);
  return remove;
}

339 340 341 342 343
/* Optimize away redundant UBSAN_VPTR calls.  The second argument
   is the value loaded from the virtual table, so rely on FRE to find out
   when we can actually optimize.  */

static bool
344
maybe_optimize_ubsan_vptr_ifn (struct sanopt_ctx *ctx, gimple *stmt)
345 346 347 348 349 350 351
{
  gcc_assert (gimple_call_num_args (stmt) == 5);
  sanopt_tree_triplet triplet;
  triplet.t1 = gimple_call_arg (stmt, 0);
  triplet.t2 = gimple_call_arg (stmt, 1);
  triplet.t3 = gimple_call_arg (stmt, 3);

352 353
  auto_vec<gimple *> &v = ctx->vptr_check_map.get_or_insert (triplet);
  gimple *g = maybe_get_dominating_check (v);
354 355 356 357 358 359 360 361 362 363 364
  if (!g)
    {
      /* For this PTR we don't have any UBSAN_VPTR stmts recorded, so there's
	 nothing to optimize yet.  */
      v.safe_push (stmt);
      return false;
    }

  return true;
}

365 366
/* Returns TRUE if ASan check of length LEN in block BB can be removed
   if preceded by checks in V.  */
367 368

static bool
369
can_remove_asan_check (auto_vec<gimple *> &v, tree len, basic_block bb)
370 371
{
  unsigned int i;
372 373
  gimple *g;
  gimple *to_pop = NULL;
374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390
  bool remove = false;
  basic_block last_bb = bb;
  bool cleanup = false;

  FOR_EACH_VEC_ELT_REVERSE (v, i, g)
    {
      basic_block gbb = gimple_bb (g);
      sanopt_info *si = (sanopt_info *) gbb->aux;
      if (gimple_uid (g) < si->freeing_call_events)
	{
	  /* If there is a potentially freeing call after g in gbb, we should
	     remove it from the vector, can't use in optimization.  */
	  cleanup = true;
	  continue;
	}

      tree glen = gimple_call_arg (g, 2);
391 392
      gcc_assert (TREE_CODE (glen) == INTEGER_CST);

393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441
      /* If we've checked only smaller length than we want to check now,
	 we can't remove the current stmt.  If g is in the same basic block,
	 we want to remove it though, as the current stmt is better.  */
      if (tree_int_cst_lt (glen, len))
	{
	  if (gbb == bb)
	    {
	      to_pop = g;
	      cleanup = true;
	    }
	  continue;
	}

      while (last_bb != gbb)
	{
	  /* Paths from last_bb to bb have been checked before.
	     gbb is necessarily a dominator of last_bb, but not necessarily
	     immediate dominator.  */
	  if (((sanopt_info *) last_bb->aux)->freeing_call_events)
	    break;

	  basic_block imm = get_immediate_dominator (CDI_DOMINATORS, last_bb);
	  gcc_assert (imm);
	  if (imm_dom_path_with_freeing_call (last_bb, imm))
	    break;

	  last_bb = imm;
	}
      if (last_bb == gbb)
	remove = true;
      break;
    }

  if (cleanup)
    {
      unsigned int j = 0, l = v.length ();
      for (i = 0; i < l; i++)
	if (v[i] != to_pop
	    && (gimple_uid (v[i])
		== ((sanopt_info *)
		    gimple_bb (v[i])->aux)->freeing_call_events))
	  {
	    if (i != j)
	      v[j] = v[i];
	    j++;
	  }
      v.truncate (j);
    }

442 443 444 445 446 447
  return remove;
}

/* Optimize away redundant ASAN_CHECK calls.  */

static bool
448
maybe_optimize_asan_check_ifn (struct sanopt_ctx *ctx, gimple *stmt)
449 450 451 452 453 454 455 456 457 458 459 460 461 462
{
  gcc_assert (gimple_call_num_args (stmt) == 4);
  tree ptr = gimple_call_arg (stmt, 1);
  tree len = gimple_call_arg (stmt, 2);
  basic_block bb = gimple_bb (stmt);
  sanopt_info *info = (sanopt_info *) bb->aux;

  if (TREE_CODE (len) != INTEGER_CST)
    return false;
  if (integer_zerop (len))
    return false;

  gimple_set_uid (stmt, info->freeing_call_events);

463
  auto_vec<gimple *> *ptr_checks = &ctx->asan_check_map.get_or_insert (ptr);
464 465

  tree base_addr = maybe_get_single_definition (ptr);
466
  auto_vec<gimple *> *base_checks = NULL;
467 468 469 470 471 472 473
  if (base_addr)
    {
      base_checks = &ctx->asan_check_map.get_or_insert (base_addr);
      /* Original pointer might have been invalidated.  */
      ptr_checks = ctx->asan_check_map.get (ptr);
    }

474 475
  gimple *g = maybe_get_dominating_check (*ptr_checks);
  gimple *g2 = NULL;
476

477
  if (base_checks)
478
    /* Try with base address as well.  */
479
    g2 = maybe_get_dominating_check (*base_checks);
480

481
  if (g == NULL && g2 == NULL)
482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499
    {
      /* For this PTR we don't have any ASAN_CHECK stmts recorded, so there's
	 nothing to optimize yet.  */
      ptr_checks->safe_push (stmt);
      if (base_checks)
	base_checks->safe_push (stmt);
      return false;
    }

  bool remove = false;

  if (ptr_checks)
    remove = can_remove_asan_check (*ptr_checks, len, bb);

  if (!remove && base_checks)
    /* Try with base address as well.  */
    remove = can_remove_asan_check (*base_checks, len, bb);

500
  if (!remove)
501 502 503 504 505 506
    {
      ptr_checks->safe_push (stmt);
      if (base_checks)
	base_checks->safe_push (stmt);
    }

507 508 509 510 511
  return remove;
}

/* Try to optimize away redundant UBSAN_NULL and ASAN_CHECK calls.

512
   We walk blocks in the CFG via a depth first search of the dominator
513 514 515 516 517 518
   tree; we push unique UBSAN_NULL or ASAN_CHECK statements into a vector
   in the NULL_CHECK_MAP or ASAN_CHECK_MAP hash maps as we enter the
   blocks.  When leaving a block, we mark the block as visited; then
   when checking the statements in the vector, we ignore statements that
   are coming from already visited blocks, because these cannot dominate
   anything anymore.  CTX is a sanopt context.  */
519 520 521 522 523 524

static void
sanopt_optimize_walker (basic_block bb, struct sanopt_ctx *ctx)
{
  basic_block son;
  gimple_stmt_iterator gsi;
525
  sanopt_info *info = (sanopt_info *) bb->aux;
526
  bool asan_check_optimize = (flag_sanitize & SANITIZE_ADDRESS) != 0;
527 528 529

  for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi);)
    {
530
      gimple *stmt = gsi_stmt (gsi);
531 532
      bool remove = false;

533 534 535 536
      if (!is_gimple_call (stmt))
	{
	  /* Handle asm volatile or asm with "memory" clobber
	     the same as potentionally freeing call.  */
537 538
	  gasm *asm_stmt = dyn_cast <gasm *> (stmt);
	  if (asm_stmt
539
	      && asan_check_optimize
540 541
	      && (gimple_asm_clobbers_memory_p (asm_stmt)
		  || gimple_asm_volatile_p (asm_stmt)))
542 543 544 545 546 547 548 549
	    info->freeing_call_events++;
	  gsi_next (&gsi);
	  continue;
	}

      if (asan_check_optimize && !nonfreeing_call_p (stmt))
	info->freeing_call_events++;

550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571
      /* If __asan_before_dynamic_init ("module"); is followed by
	 __asan_after_dynamic_init (); without intervening memory loads/stores,
	 there is nothing to guard, so optimize both away.  */
      if (asan_check_optimize
	  && gimple_call_builtin_p (stmt, BUILT_IN_ASAN_BEFORE_DYNAMIC_INIT))
	{
	  use_operand_p use;
	  gimple *use_stmt;
	  if (single_imm_use (gimple_vdef (stmt), &use, &use_stmt))
	    {
	      if (is_gimple_call (use_stmt)
		  && gimple_call_builtin_p (use_stmt,
					    BUILT_IN_ASAN_AFTER_DYNAMIC_INIT))
		{
		  unlink_stmt_vdef (use_stmt);
		  gimple_stmt_iterator gsi2 = gsi_for_stmt (use_stmt);
		  gsi_remove (&gsi2, true);
		  remove = true;
		}
	    }
	}

572
      if (gimple_call_internal_p (stmt))
573 574 575
	switch (gimple_call_internal_fn (stmt))
	  {
	  case IFN_UBSAN_NULL:
576 577
	    remove = maybe_optimize_ubsan_null_ifn (ctx, stmt);
	    break;
578 579 580
	  case IFN_UBSAN_VPTR:
	    remove = maybe_optimize_ubsan_vptr_ifn (ctx, stmt);
	    break;
581
	  case IFN_ASAN_CHECK:
582 583 584 585
	    if (asan_check_optimize)
	      remove = maybe_optimize_asan_check_ifn (ctx, stmt);
	    if (!remove)
	      ctx->asan_num_accesses++;
586
	    break;
587 588 589
	  case IFN_ASAN_MARK:
	    ctx->contains_asan_mark = true;
	    break;
590 591 592 593
	  default:
	    break;
	  }

594 595 596 597 598 599 600 601 602 603 604 605 606
      if (remove)
	{
	  /* Drop this check.  */
	  if (dump_file && (dump_flags & TDF_DETAILS))
	    {
	      fprintf (dump_file, "Optimizing out\n  ");
	      print_gimple_stmt (dump_file, stmt, 0, dump_flags);
	      fprintf (dump_file, "\n");
	    }
	  unlink_stmt_vdef (stmt);
	  gsi_remove (&gsi, true);
	}
      else
607 608 609
	gsi_next (&gsi);
    }

610 611 612 613 614 615
  if (asan_check_optimize)
    {
      info->has_freeing_call_p = info->freeing_call_events != 0;
      info->has_freeing_call_computed_p = true;
    }

616 617 618 619 620 621 622 623 624 625 626 627
  for (son = first_dom_son (CDI_DOMINATORS, bb);
       son;
       son = next_dom_son (CDI_DOMINATORS, son))
    sanopt_optimize_walker (son, ctx);

  /* We're leaving this BB, so mark it to that effect.  */
  info->visited_p = true;
}

/* Try to remove redundant sanitizer checks in function FUN.  */

static int
628
sanopt_optimize (function *fun, bool *contains_asan_mark)
629 630 631
{
  struct sanopt_ctx ctx;
  ctx.asan_num_accesses = 0;
632
  ctx.contains_asan_mark = false;
633 634 635 636 637 638 639 640 641 642 643 644 645 646

  /* Set up block info for each basic block.  */
  alloc_aux_for_blocks (sizeof (sanopt_info));

  /* We're going to do a dominator walk, so ensure that we have
     dominance information.  */
  calculate_dominance_info (CDI_DOMINATORS);

  /* Recursively walk the dominator tree optimizing away
     redundant checks.  */
  sanopt_optimize_walker (ENTRY_BLOCK_PTR_FOR_FN (fun), &ctx);

  free_aux_for_blocks ();

647
  *contains_asan_mark = ctx.contains_asan_mark;
648 649 650 651 652
  return ctx.asan_num_accesses;
}

/* Perform optimization of sanitize functions.  */

653 654 655
namespace {

const pass_data pass_data_sanopt =
656 657 658 659 660 661 662 663 664 665 666 667
{
  GIMPLE_PASS, /* type */
  "sanopt", /* name */
  OPTGROUP_NONE, /* optinfo_flags */
  TV_NONE, /* tv_id */
  ( PROP_ssa | PROP_cfg | PROP_gimple_leh ), /* properties_required */
  0, /* properties_provided */
  0, /* properties_destroyed */
  0, /* todo_flags_start */
  TODO_update_ssa, /* todo_flags_finish */
};

668
class pass_sanopt : public gimple_opt_pass
669 670 671 672 673 674 675 676 677 678 679 680
{
public:
  pass_sanopt (gcc::context *ctxt)
    : gimple_opt_pass (pass_data_sanopt, ctxt)
  {}

  /* opt_pass methods: */
  virtual bool gate (function *) { return flag_sanitize; }
  virtual unsigned int execute (function *);

}; // class pass_sanopt

681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754
/* Sanitize all ASAN_MARK unpoison calls that are not reachable by a BB
   that contains an ASAN_MARK poison.  All these ASAN_MARK unpoison call
   can be removed as all variables are unpoisoned in a function prologue.  */

static void
sanitize_asan_mark_unpoison (void)
{
  /* 1) Find all BBs that contain an ASAN_MARK poison call.  */
  auto_sbitmap with_poison (last_basic_block_for_fn (cfun) + 1);
  bitmap_clear (with_poison);
  basic_block bb;

  FOR_EACH_BB_FN (bb, cfun)
    {
      if (bitmap_bit_p (with_poison, bb->index))
	continue;

      gimple_stmt_iterator gsi;
      for (gsi = gsi_last_bb (bb); !gsi_end_p (gsi); gsi_prev (&gsi))
	{
	  gimple *stmt = gsi_stmt (gsi);
	  if (asan_mark_p (stmt, ASAN_MARK_POISON))
	    {
	      bitmap_set_bit (with_poison, bb->index);
	      break;
	    }
	}
    }

  auto_sbitmap poisoned (last_basic_block_for_fn (cfun) + 1);
  bitmap_clear (poisoned);
  auto_sbitmap worklist (last_basic_block_for_fn (cfun) + 1);
  bitmap_copy (worklist, with_poison);

  /* 2) Propagate the information to all reachable blocks.  */
  while (!bitmap_empty_p (worklist))
    {
      unsigned i = bitmap_first_set_bit (worklist);
      bitmap_clear_bit (worklist, i);
      basic_block bb = BASIC_BLOCK_FOR_FN (cfun, i);
      gcc_assert (bb);

      edge e;
      edge_iterator ei;
      FOR_EACH_EDGE (e, ei, bb->succs)
	if (!bitmap_bit_p (poisoned, e->dest->index))
	  {
	    bitmap_set_bit (poisoned, e->dest->index);
	    bitmap_set_bit (worklist, e->dest->index);
	  }
    }

  /* 3) Iterate all BBs not included in POISONED BBs and remove unpoison
	ASAN_MARK preceding an ASAN_MARK poison (which can still happen).  */
  FOR_EACH_BB_FN (bb, cfun)
    {
      if (bitmap_bit_p (poisoned, bb->index))
	continue;

      gimple_stmt_iterator gsi;
      for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi);)
	{
	  gimple *stmt = gsi_stmt (gsi);
	  if (gimple_call_internal_p (stmt, IFN_ASAN_MARK))
	    {
	      if (asan_mark_p (stmt, ASAN_MARK_POISON))
		break;
	      else
		{
		  if (dump_file)
		    fprintf (dump_file, "Removing ASAN_MARK unpoison\n");
		  unlink_stmt_vdef (stmt);
		  release_defs (stmt);
		  gsi_remove (&gsi, true);
755
		  continue;
756 757 758
		}
	    }

759
	  gsi_next (&gsi);
760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849
	}
    }
}

/* Return true when STMT is either ASAN_CHECK call or a call of a function
   that can contain an ASAN_CHECK.  */

static bool
maybe_contains_asan_check (gimple *stmt)
{
  if (is_gimple_call (stmt))
    {
      if (gimple_call_internal_p (stmt, IFN_ASAN_MARK))
	return false;
      else
	return !(gimple_call_flags (stmt) & ECF_CONST);
    }
  else if (is_a<gasm *> (stmt))
    return true;

  return false;
}

/* Sanitize all ASAN_MARK poison calls that are not followed by an ASAN_CHECK
   call.  These calls can be removed.  */

static void
sanitize_asan_mark_poison (void)
{
  /* 1) Find all BBs that possibly contain an ASAN_CHECK.  */
  auto_sbitmap with_check (last_basic_block_for_fn (cfun) + 1);
  bitmap_clear (with_check);
  basic_block bb;

  FOR_EACH_BB_FN (bb, cfun)
    {
      gimple_stmt_iterator gsi;
      for (gsi = gsi_last_bb (bb); !gsi_end_p (gsi); gsi_prev (&gsi))
	{
	  gimple *stmt = gsi_stmt (gsi);
	  if (maybe_contains_asan_check (stmt))
	    {
	      bitmap_set_bit (with_check, bb->index);
	      break;
	    }
	}
    }

  auto_sbitmap can_reach_check (last_basic_block_for_fn (cfun) + 1);
  bitmap_clear (can_reach_check);
  auto_sbitmap worklist (last_basic_block_for_fn (cfun) + 1);
  bitmap_copy (worklist, with_check);

  /* 2) Propagate the information to all definitions blocks.  */
  while (!bitmap_empty_p (worklist))
    {
      unsigned i = bitmap_first_set_bit (worklist);
      bitmap_clear_bit (worklist, i);
      basic_block bb = BASIC_BLOCK_FOR_FN (cfun, i);
      gcc_assert (bb);

      edge e;
      edge_iterator ei;
      FOR_EACH_EDGE (e, ei, bb->preds)
	if (!bitmap_bit_p (can_reach_check, e->src->index))
	  {
	    bitmap_set_bit (can_reach_check, e->src->index);
	    bitmap_set_bit (worklist, e->src->index);
	  }
    }

  /* 3) Iterate all BBs not included in CAN_REACH_CHECK BBs and remove poison
	ASAN_MARK not followed by a call to function having an ASAN_CHECK.  */
  FOR_EACH_BB_FN (bb, cfun)
    {
      if (bitmap_bit_p (can_reach_check, bb->index))
	continue;

      gimple_stmt_iterator gsi;
      for (gsi = gsi_last_bb (bb); !gsi_end_p (gsi);)
	{
	  gimple *stmt = gsi_stmt (gsi);
	  if (maybe_contains_asan_check (stmt))
	    break;
	  else if (asan_mark_p (stmt, ASAN_MARK_POISON))
	    {
	      if (dump_file)
		fprintf (dump_file, "Removing ASAN_MARK poison\n");
	      unlink_stmt_vdef (stmt);
	      release_defs (stmt);
850 851 852 853
	      gimple_stmt_iterator gsi2 = gsi;
	      gsi_prev (&gsi);
	      gsi_remove (&gsi2, true);
	      continue;
854 855
	    }

856
	  gsi_prev (&gsi);
857 858 859 860
	}
    }
}

861 862 863 864 865
unsigned int
pass_sanopt::execute (function *fun)
{
  basic_block bb;
  int asan_num_accesses = 0;
866
  bool contains_asan_mark = false;
867 868 869

  /* Try to remove redundant checks.  */
  if (optimize
870
      && (flag_sanitize
871 872
	  & (SANITIZE_NULL | SANITIZE_ALIGNMENT
	     | SANITIZE_ADDRESS | SANITIZE_VPTR)))
873
    asan_num_accesses = sanopt_optimize (fun, &contains_asan_mark);
874 875 876 877 878 879
  else if (flag_sanitize & SANITIZE_ADDRESS)
    {
      gimple_stmt_iterator gsi;
      FOR_EACH_BB_FN (bb, fun)
	for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
	  {
880
	    gimple *stmt = gsi_stmt (gsi);
881
	    if (gimple_call_internal_p (stmt, IFN_ASAN_CHECK))
882
	      ++asan_num_accesses;
883 884
	    else if (gimple_call_internal_p (stmt, IFN_ASAN_MARK))
	      contains_asan_mark = true;
885 886 887
	  }
    }

888 889 890 891 892 893
  if (contains_asan_mark)
    {
      sanitize_asan_mark_unpoison ();
      sanitize_asan_mark_poison ();
    }

894 895 896
  bool use_calls = ASAN_INSTRUMENTATION_WITH_CALL_THRESHOLD < INT_MAX
    && asan_num_accesses >= ASAN_INSTRUMENTATION_WITH_CALL_THRESHOLD;

897 898
  hash_map<tree, tree> shadow_vars_mapping;
  bool need_commit_edge_insert = false;
899 900 901 902 903
  FOR_EACH_BB_FN (bb, fun)
    {
      gimple_stmt_iterator gsi;
      for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); )
	{
904
	  gimple *stmt = gsi_stmt (gsi);
905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926
	  bool no_next = false;

	  if (!is_gimple_call (stmt))
	    {
	      gsi_next (&gsi);
	      continue;
	    }

	  if (gimple_call_internal_p (stmt))
	    {
	      enum internal_fn ifn = gimple_call_internal_fn (stmt);
	      switch (ifn)
		{
		case IFN_UBSAN_NULL:
		  no_next = ubsan_expand_null_ifn (&gsi);
		  break;
		case IFN_UBSAN_BOUNDS:
		  no_next = ubsan_expand_bounds_ifn (&gsi);
		  break;
		case IFN_UBSAN_OBJECT_SIZE:
		  no_next = ubsan_expand_objsize_ifn (&gsi);
		  break;
927 928 929
		case IFN_UBSAN_VPTR:
		  no_next = ubsan_expand_vptr_ifn (&gsi);
		  break;
930 931 932
		case IFN_ASAN_CHECK:
		  no_next = asan_expand_check_ifn (&gsi, use_calls);
		  break;
933 934 935
		case IFN_ASAN_MARK:
		  no_next = asan_expand_mark_ifn (&gsi);
		  break;
936 937 938 939 940
		case IFN_ASAN_POISON:
		  no_next = asan_expand_poison_ifn (&gsi,
						    &need_commit_edge_insert,
						    shadow_vars_mapping);
		  break;
941 942 943 944
		default:
		  break;
		}
	    }
945 946 947 948 949 950 951 952 953 954 955 956 957 958 959
	  else if (gimple_call_builtin_p (stmt, BUILT_IN_NORMAL))
	    {
	      tree callee = gimple_call_fndecl (stmt);
	      switch (DECL_FUNCTION_CODE (callee))
		{
		case BUILT_IN_UNREACHABLE:
		  if (flag_sanitize & SANITIZE_UNREACHABLE
		      && !lookup_attribute ("no_sanitize_undefined",
					    DECL_ATTRIBUTES (fun->decl)))
		    no_next = ubsan_instrument_unreachable (&gsi);
		  break;
		default:
		  break;
		}
	    }
960 961 962 963 964 965 966 967 968 969 970 971

	  if (dump_file && (dump_flags & TDF_DETAILS))
	    {
	      fprintf (dump_file, "Expanded\n  ");
	      print_gimple_stmt (dump_file, stmt, 0, dump_flags);
	      fprintf (dump_file, "\n");
	    }

	  if (!no_next)
	    gsi_next (&gsi);
	}
    }
972 973 974 975

  if (need_commit_edge_insert)
    gsi_commit_edge_inserts ();

976 977 978
  return 0;
}

979 980
} // anon namespace

981 982 983 984 985
gimple_opt_pass *
make_pass_sanopt (gcc::context *ctxt)
{
  return new pass_sanopt (ctxt);
}