]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/asan.c
Update copyright years.
[thirdparty/gcc.git] / gcc / asan.c
index 76f21bd7020fe596a28c6b19376f370ecefa6b7e..5f48875a3c0803f8cceeabfab122761197f1dfde 100644 (file)
@@ -1,5 +1,5 @@
 /* AddressSanitizer, a fast memory error detector.
-   Copyright (C) 2012-2014 Free Software Foundation, Inc.
+   Copyright (C) 2012-2017 Free Software Foundation, Inc.
    Contributed by Kostya Serebryany <kcc@google.com>
 
 This file is part of GCC.
@@ -22,40 +22,43 @@ along with GCC; see the file COPYING3.  If not see
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
+#include "backend.h"
+#include "target.h"
+#include "rtl.h"
 #include "tree.h"
-#include "hash-table.h"
-#include "basic-block.h"
-#include "tree-ssa-alias.h"
-#include "internal-fn.h"
-#include "gimple-expr.h"
-#include "is-a.h"
-#include "inchash.h"
 #include "gimple.h"
+#include "cfghooks.h"
+#include "alloc-pool.h"
+#include "tree-pass.h"
+#include "memmodel.h"
+#include "tm_p.h"
+#include "stringpool.h"
+#include "tree-vrp.h"
+#include "tree-ssanames.h"
+#include "optabs.h"
+#include "emit-rtl.h"
+#include "cgraph.h"
+#include "gimple-pretty-print.h"
+#include "alias.h"
+#include "fold-const.h"
+#include "cfganal.h"
 #include "gimplify.h"
 #include "gimple-iterator.h"
-#include "calls.h"
 #include "varasm.h"
 #include "stor-layout.h"
 #include "tree-iterator.h"
-#include "cgraph.h"
-#include "stringpool.h"
-#include "tree-ssanames.h"
-#include "tree-pass.h"
 #include "asan.h"
-#include "gimple-pretty-print.h"
-#include "target.h"
+#include "dojump.h"
+#include "explow.h"
 #include "expr.h"
-#include "optabs.h"
 #include "output.h"
-#include "tm_p.h"
 #include "langhooks.h"
-#include "alloc-pool.h"
 #include "cfgloop.h"
 #include "gimple-builder.h"
 #include "ubsan.h"
-#include "predict.h"
 #include "params.h"
 #include "builtins.h"
+#include "fnmatch.h"
 
 /* AddressSanitizer finds out-of-bounds and use-after-free bugs
    with <2x slowdown on average.
@@ -143,7 +146,7 @@ along with GCC; see the file COPYING3.  If not see
 
        where '(...){n}' means the content inside the parenthesis occurs 'n'
        times, with 'n' being the number of variables on the stack.
-     
+
      3/ The following 8 bytes contain the PC of the current function which
      will be used by the run-time library to print an error message.
 
@@ -230,33 +233,117 @@ along with GCC; see the file COPYING3.  If not see
 
        // 1 if it has dynamic initialization, 0 otherwise.
        uptr __has_dynamic_init;
+
+       // A pointer to struct that contains source location, could be NULL.
+       __asan_global_source_location *__location;
      }
 
    A destructor function that calls the runtime asan library function
    _asan_unregister_globals is also installed.  */
 
-alias_set_type asan_shadow_set = -1;
+static unsigned HOST_WIDE_INT asan_shadow_offset_value;
+static bool asan_shadow_offset_computed;
+static vec<char *> sanitized_sections;
 
-/* Pointer types to 1 resp. 2 byte integers in shadow memory.  A separate
-   alias set is used for all shadow memory accesses.  */
-static GTY(()) tree shadow_ptr_types[2];
+/* Set of variable declarations that are going to be guarded by
+   use-after-scope sanitizer.  */
 
-/* Decl for __asan_option_detect_stack_use_after_return.  */
-static GTY(()) tree asan_detect_stack_use_after_return;
+static hash_set<tree> *asan_handled_variables = NULL;
+
+hash_set <tree> *asan_used_labels = NULL;
+
+/* Sets shadow offset to value in string VAL.  */
+
+bool
+set_asan_shadow_offset (const char *val)
+{
+  char *endp;
+
+  errno = 0;
+#ifdef HAVE_LONG_LONG
+  asan_shadow_offset_value = strtoull (val, &endp, 0);
+#else
+  asan_shadow_offset_value = strtoul (val, &endp, 0);
+#endif
+  if (!(*val != '\0' && *endp == '\0' && errno == 0))
+    return false;
 
-/* Number of instrumentations in current function so far.  */
+  asan_shadow_offset_computed = true;
 
-static int asan_num_accesses;
+  return true;
+}
+
+/* Set list of user-defined sections that need to be sanitized.  */
+
+void
+set_sanitized_sections (const char *sections)
+{
+  char *pat;
+  unsigned i;
+  FOR_EACH_VEC_ELT (sanitized_sections, i, pat)
+    free (pat);
+  sanitized_sections.truncate (0);
+
+  for (const char *s = sections; *s; )
+    {
+      const char *end;
+      for (end = s; *end && *end != ','; ++end);
+      size_t len = end - s;
+      sanitized_sections.safe_push (xstrndup (s, len));
+      s = *end ? end + 1 : end;
+    }
+}
+
+bool
+asan_mark_p (gimple *stmt, enum asan_mark_flags flag)
+{
+  return (gimple_call_internal_p (stmt, IFN_ASAN_MARK)
+         && tree_to_uhwi (gimple_call_arg (stmt, 0)) == flag);
+}
+
+bool
+asan_sanitize_stack_p (void)
+{
+  return ((flag_sanitize & SANITIZE_ADDRESS)
+         && ASAN_STACK
+         && !asan_no_sanitize_address_p ());
+}
+
+/* Checks whether section SEC should be sanitized.  */
+
+static bool
+section_sanitized_p (const char *sec)
+{
+  char *pat;
+  unsigned i;
+  FOR_EACH_VEC_ELT (sanitized_sections, i, pat)
+    if (fnmatch (pat, sec, FNM_PERIOD) == 0)
+      return true;
+  return false;
+}
 
-/* Check whether we should replace inline instrumentation with calls.  */
+/* Returns Asan shadow offset.  */
 
-static inline bool
-use_calls_p ()
+static unsigned HOST_WIDE_INT
+asan_shadow_offset ()
 {
-  return ASAN_INSTRUMENTATION_WITH_CALL_THRESHOLD < INT_MAX
-    && asan_num_accesses >= ASAN_INSTRUMENTATION_WITH_CALL_THRESHOLD;
+  if (!asan_shadow_offset_computed)
+    {
+      asan_shadow_offset_computed = true;
+      asan_shadow_offset_value = targetm.asan_shadow_offset ();
+    }
+  return asan_shadow_offset_value;
 }
 
+alias_set_type asan_shadow_set = -1;
+
+/* Pointer types to 1, 2 or 4 byte integers in shadow memory.  A separate
+   alias set is used for all shadow memory accesses.  */
+static GTY(()) tree shadow_ptr_types[3];
+
+/* Decl for __asan_option_detect_stack_use_after_return.  */
+static GTY(()) tree asan_detect_stack_use_after_return;
+
 /* Hashtable support for memory references used by gimple
    statements.  */
 
@@ -270,21 +357,7 @@ struct asan_mem_ref
   HOST_WIDE_INT access_size;
 };
 
-static alloc_pool asan_mem_ref_alloc_pool;
-
-/* This creates the alloc pool used to store the instances of
-   asan_mem_ref that are stored in the hash table asan_mem_ref_ht.  */
-
-static alloc_pool
-asan_mem_ref_get_alloc_pool ()
-{
-  if (asan_mem_ref_alloc_pool == NULL)
-    asan_mem_ref_alloc_pool = create_alloc_pool ("asan_mem_ref",
-                                                sizeof (asan_mem_ref),
-                                                10);
-  return asan_mem_ref_alloc_pool;
-    
-}
+object_allocator <asan_mem_ref> asan_mem_ref_pool ("asan_mem_ref");
 
 /* Initializes an instance of asan_mem_ref.  */
 
@@ -304,8 +377,7 @@ asan_mem_ref_init (asan_mem_ref *ref, tree start, HOST_WIDE_INT access_size)
 static asan_mem_ref*
 asan_mem_ref_new (tree start, HOST_WIDE_INT access_size)
 {
-  asan_mem_ref *ref =
-    (asan_mem_ref *) pool_alloc (asan_mem_ref_get_alloc_pool ());
+  asan_mem_ref *ref = asan_mem_ref_pool.allocate ();
 
   asan_mem_ref_init (ref, start, access_size);
   return ref;
@@ -320,6 +392,9 @@ asan_mem_ref_get_end (tree start, tree len)
   if (len == NULL_TREE || integer_zerop (len))
     return start;
 
+  if (!ptrofftype_p (len))
+    len = convert_to_ptrofftype (len);
+
   return fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (start), start, len);
 }
 
@@ -333,14 +408,10 @@ asan_mem_ref_get_end (const asan_mem_ref *ref, tree len)
   return asan_mem_ref_get_end (ref->start, len);
 }
 
-struct asan_mem_ref_hasher
-  : typed_noop_remove <asan_mem_ref>
+struct asan_mem_ref_hasher : nofree_ptr_hash <asan_mem_ref>
 {
-  typedef asan_mem_ref value_type;
-  typedef asan_mem_ref compare_type;
-
-  static inline hashval_t hash (const value_type *);
-  static inline bool equal (const value_type *, const compare_type *);
+  static inline hashval_t hash (const asan_mem_ref *);
+  static inline bool equal (const asan_mem_ref *, const asan_mem_ref *);
 };
 
 /* Hash a memory reference.  */
@@ -348,10 +419,7 @@ struct asan_mem_ref_hasher
 inline hashval_t
 asan_mem_ref_hasher::hash (const asan_mem_ref *mem_ref)
 {
-  inchash::hash hstate;
-  inchash::add_expr (mem_ref->start, hstate);
-  hstate.add_wide_int (mem_ref->access_size);
-  return hstate.end ();
+  return iterative_hash_expr (mem_ref->start, 0);
 }
 
 /* Compare two memory references.  We accept the length of either
@@ -361,8 +429,7 @@ inline bool
 asan_mem_ref_hasher::equal (const asan_mem_ref *m1,
                            const asan_mem_ref *m2)
 {
-  return (m1->access_size == m2->access_size
-         && operand_equal_p (m1->start, m2->start, 0));
+  return operand_equal_p (m1->start, m2->start, 0);
 }
 
 static hash_table<asan_mem_ref_hasher> *asan_mem_ref_ht;
@@ -398,11 +465,7 @@ free_mem_ref_resources ()
   delete asan_mem_ref_ht;
   asan_mem_ref_ht = NULL;
 
-  if (asan_mem_ref_alloc_pool)
-    {
-      free_alloc_pool (asan_mem_ref_alloc_pool);
-      asan_mem_ref_alloc_pool = NULL;
-    }
+  asan_mem_ref_pool.release ();
 }
 
 /* Return true iff the memory reference REF has been instrumented.  */
@@ -413,7 +476,8 @@ has_mem_ref_been_instrumented (tree ref, HOST_WIDE_INT access_size)
   asan_mem_ref r;
   asan_mem_ref_init (&r, ref, access_size);
 
-  return (get_mem_ref_hash_table ()->find (&r) != NULL);
+  asan_mem_ref *saved_ref = get_mem_ref_hash_table ()->find (&r);
+  return saved_ref && saved_ref->access_size >= access_size;
 }
 
 /* Return true iff the memory reference REF has been instrumented.  */
@@ -430,19 +494,11 @@ has_mem_ref_been_instrumented (const asan_mem_ref *ref)
 static bool
 has_mem_ref_been_instrumented (const asan_mem_ref *ref, tree len)
 {
-  /* First let's see if the address of the beginning of REF has been
-     instrumented.  */
-  if (!has_mem_ref_been_instrumented (ref))
-    return false;
+  HOST_WIDE_INT size_in_bytes
+    = tree_fits_shwi_p (len) ? tree_to_shwi (len) : -1;
 
-  if (len != 0)
-    {
-      /* Let's see if the end of the region has been instrumented.  */
-      if (!has_mem_ref_been_instrumented (asan_mem_ref_get_end (ref, len),
-                                         ref->access_size))
-       return false;
-    }
-  return true;
+  return size_in_bytes != -1
+    && has_mem_ref_been_instrumented (ref->start, size_in_bytes);
 }
 
 /* Set REF to the memory reference present in a gimple assignment
@@ -450,7 +506,7 @@ has_mem_ref_been_instrumented (const asan_mem_ref *ref, tree len)
    otherwise.  */
 
 static bool
-get_mem_ref_of_assignment (const gimple assignment,
+get_mem_ref_of_assignment (const gassign *assignment,
                           asan_mem_ref *ref,
                           bool *ref_is_store)
 {
@@ -478,7 +534,7 @@ get_mem_ref_of_assignment (const gimple assignment,
    representing a builtin call that has to do with memory access.  */
 
 static bool
-get_mem_refs_of_builtin_call (const gimple call,
+get_mem_refs_of_builtin_call (const gcall *call,
                              asan_mem_ref *src0,
                              tree *src0_len,
                              bool *src0_is_store,
@@ -488,7 +544,8 @@ get_mem_refs_of_builtin_call (const gimple call,
                              asan_mem_ref *dst,
                              tree *dst_len,
                              bool *dst_is_store,
-                             bool *dest_is_deref)
+                             bool *dest_is_deref,
+                             bool *intercepted_p)
 {
   gcc_checking_assert (gimple_call_builtin_p (call, BUILT_IN_NORMAL));
 
@@ -498,6 +555,8 @@ get_mem_refs_of_builtin_call (const gimple call,
   bool is_store = true, got_reference_p = false;
   HOST_WIDE_INT access_size = 1;
 
+  *intercepted_p = asan_intercepted_p ((DECL_FUNCTION_CODE (callee)));
+
   switch (DECL_FUNCTION_CODE (callee))
     {
       /* (s, s, n) style memops.  */
@@ -810,7 +869,7 @@ get_mem_refs_of_builtin_call (const gimple call,
    contains.  */
 
 static bool
-has_stmt_been_instrumented_p (gimple stmt)
+has_stmt_been_instrumented_p (gimple *stmt)
 {
   if (gimple_assign_single_p (stmt))
     {
@@ -818,7 +877,8 @@ has_stmt_been_instrumented_p (gimple stmt)
       asan_mem_ref r;
       asan_mem_ref_init (&r, NULL, 1);
 
-      if (get_mem_ref_of_assignment (stmt, &r, &r_is_store))
+      if (get_mem_ref_of_assignment (as_a <gassign *> (stmt), &r,
+                                    &r_is_store))
        return has_mem_ref_been_instrumented (&r);
     }
   else if (gimple_call_builtin_p (stmt, BUILT_IN_NORMAL))
@@ -830,12 +890,12 @@ has_stmt_been_instrumented_p (gimple stmt)
 
       tree src0_len = NULL_TREE, src1_len = NULL_TREE, dest_len = NULL_TREE;
       bool src0_is_store = false, src1_is_store = false,
-       dest_is_store = false, dest_is_deref = false;
-      if (get_mem_refs_of_builtin_call (stmt,
+       dest_is_store = false, dest_is_deref = false, intercepted_p = true;
+      if (get_mem_refs_of_builtin_call (as_a <gcall *> (stmt),
                                        &src0, &src0_len, &src0_is_store,
                                        &src1, &src1_len, &src1_is_store,
                                        &dest, &dest_len, &dest_is_store,
-                                       &dest_is_deref))
+                                       &dest_is_deref, &intercepted_p))
        {
          if (src0.start != NULL_TREE
              && !has_mem_ref_been_instrumented (&src0, src0_len))
@@ -852,6 +912,16 @@ has_stmt_been_instrumented_p (gimple stmt)
          return true;
        }
     }
+  else if (is_gimple_call (stmt) && gimple_store_p (stmt))
+    {
+      asan_mem_ref r;
+      asan_mem_ref_init (&r, NULL, 1);
+
+      r.start = gimple_call_lhs (stmt);
+      r.access_size = int_size_in_bytes (TREE_TYPE (r.start));
+      return has_mem_ref_been_instrumented (&r);
+    }
+
   return false;
 }
 
@@ -866,7 +936,7 @@ update_mem_ref_hash_table (tree ref, HOST_WIDE_INT access_size)
   asan_mem_ref_init (&r, ref, access_size);
 
   asan_mem_ref **slot = ht->find_slot (&r, INSERT);
-  if (*slot == NULL)
+  if (*slot == NULL || (*slot)->access_size < access_size)
     *slot = asan_mem_ref_new (ref, access_size);
 }
 
@@ -876,12 +946,16 @@ static void
 asan_init_shadow_ptr_types (void)
 {
   asan_shadow_set = new_alias_set ();
-  shadow_ptr_types[0] = build_distinct_type_copy (signed_char_type_node);
-  TYPE_ALIAS_SET (shadow_ptr_types[0]) = asan_shadow_set;
-  shadow_ptr_types[0] = build_pointer_type (shadow_ptr_types[0]);
-  shadow_ptr_types[1] = build_distinct_type_copy (short_integer_type_node);
-  TYPE_ALIAS_SET (shadow_ptr_types[1]) = asan_shadow_set;
-  shadow_ptr_types[1] = build_pointer_type (shadow_ptr_types[1]);
+  tree types[3] = { signed_char_type_node, short_integer_type_node,
+                   integer_type_node };
+
+  for (unsigned i = 0; i < 3; i++)
+    {
+      shadow_ptr_types[i] = build_distinct_type_copy (types[i]);
+      TYPE_ALIAS_SET (shadow_ptr_types[i]) = asan_shadow_set;
+      shadow_ptr_types[i] = build_pointer_type (shadow_ptr_types[i]);
+    }
+
   initialize_sanitizer_builtins ();
 }
 
@@ -921,7 +995,9 @@ asan_shadow_cst (unsigned char shadow_bytes[4])
 static void
 asan_clear_shadow (rtx shadow_mem, HOST_WIDE_INT len)
 {
-  rtx insn, insns, top_label, end, addr, tmp, jump;
+  rtx_insn *insn, *insns, *jump;
+  rtx_code_label *top_label;
+  rtx end, addr, tmp;
 
   start_sequence ();
   clear_storage (shadow_mem, GEN_INT (len), BLOCK_OP_NORMAL);
@@ -945,7 +1021,7 @@ asan_clear_shadow (rtx shadow_mem, HOST_WIDE_INT len)
 
   emit_move_insn (shadow_mem, const0_rtx);
   tmp = expand_simple_binop (Pmode, PLUS, addr, gen_int_mode (4, Pmode), addr,
-                             true, OPTAB_LIB_WIDEN);
+                            true, OPTAB_LIB_WIDEN);
   if (tmp != addr)
     emit_move_insn (addr, tmp);
   emit_cmp_and_jump_insns (addr, end, LT, NULL_RTX, Pmode, true, top_label);
@@ -960,7 +1036,16 @@ asan_function_start (void)
   section *fnsec = function_section (current_function_decl);
   switch_to_section (fnsec);
   ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LASANPC",
-                         current_function_funcdef_no);
+                        current_function_funcdef_no);
+}
+
+/* Return number of shadow bytes that are occupied by a local variable
+   of SIZE bytes.  */
+
+static unsigned HOST_WIDE_INT
+shadow_mem_size (unsigned HOST_WIDE_INT size)
+{
+  return ROUND_UP (size, ASAN_SHADOW_GRANULARITY) / ASAN_SHADOW_GRANULARITY;
 }
 
 /* Insert code to protect stack vars.  The prologue sequence should be emitted
@@ -976,17 +1061,19 @@ asan_function_start (void)
    assigned to PBASE, when not doing use after return protection, or
    corresponding address based on __asan_stack_malloc* return value.  */
 
-rtx
+rtx_insn *
 asan_emit_stack_protection (rtx base, rtx pbase, unsigned int alignb,
                            HOST_WIDE_INT *offsets, tree *decls, int length)
 {
-  rtx shadow_base, shadow_mem, ret, mem, orig_base, lab;
+  rtx shadow_base, shadow_mem, ret, mem, orig_base;
+  rtx_code_label *lab;
+  rtx_insn *insns;
   char buf[30];
   unsigned char shadow_bytes[4];
   HOST_WIDE_INT base_offset = offsets[length - 1];
   HOST_WIDE_INT base_align_bias = 0, offset, prev_offset;
   HOST_WIDE_INT asan_frame_size = offsets[0] - base_offset;
-  HOST_WIDE_INT last_offset, last_size;
+  HOST_WIDE_INT last_offset;
   int l;
   unsigned char cur_shadow_byte = ASAN_STACK_MAGIC_LEFT;
   tree str_cst, decl, id;
@@ -1025,7 +1112,7 @@ asan_emit_stack_protection (rtx base, rtx pbase, unsigned int alignb,
     {
       use_after_return_class = floor_log2 (asan_frame_size - 1) - 5;
       /* __asan_stack_malloc_N guarantees alignment
-         N < 6 ? (64 << N) : 4096 bytes.  */
+        N < 6 ? (64 << N) : 4096 bytes.  */
       if (alignb > (use_after_return_class < 6
                    ? (64U << use_after_return_class) : 4096U))
        use_after_return_class = -1;
@@ -1075,12 +1162,16 @@ asan_emit_stack_protection (rtx base, rtx pbase, unsigned int alignb,
       snprintf (buf, sizeof buf, "__asan_stack_malloc_%d",
                use_after_return_class);
       ret = init_one_libfunc (buf);
-      rtx addr = convert_memory_address (ptr_mode, base);
-      ret = emit_library_call_value (ret, NULL_RTX, LCT_NORMAL, ptr_mode, 2,
+      ret = emit_library_call_value (ret, NULL_RTX, LCT_NORMAL, ptr_mode, 1,
                                     GEN_INT (asan_frame_size
                                              + base_align_bias),
-                                    TYPE_MODE (pointer_sized_int_node),
-                                    addr, ptr_mode);
+                                    TYPE_MODE (pointer_sized_int_node));
+      /* __asan_stack_malloc_[n] returns a pointer to fake stack if succeeded
+        and NULL otherwise.  Check RET value is NULL here and jump over the
+        BASE reassignment in this case.  Otherwise, reassign BASE to RET.  */
+      int very_unlikely = REG_BR_PROB_BASE / 2000 - 1;
+      emit_cmp_and_jump_insns (ret, const0_rtx, EQ, NULL_RTX,
+                              VOIDmode, 0, lab, very_unlikely);
       ret = convert_memory_address (Pmode, ret);
       emit_move_insn (base, ret);
       emit_label (lab);
@@ -1098,7 +1189,7 @@ asan_emit_stack_protection (rtx base, rtx pbase, unsigned int alignb,
   ASM_GENERATE_INTERNAL_LABEL (buf, "LASANPC", current_function_funcdef_no);
   id = get_identifier (buf);
   decl = build_decl (DECL_SOURCE_LOCATION (current_function_decl),
-                    VAR_DECL, id, char_type_node);
+                   VAR_DECL, id, char_type_node);
   SET_DECL_ASSEMBLER_NAME (decl, id);
   TREE_ADDRESSABLE (decl) = 1;
   TREE_READONLY (decl) = 1;
@@ -1116,7 +1207,7 @@ asan_emit_stack_protection (rtx base, rtx pbase, unsigned int alignb,
                              NULL_RTX, 1, OPTAB_DIRECT);
   shadow_base
     = plus_constant (Pmode, shadow_base,
-                    targetm.asan_shadow_offset ()
+                    asan_shadow_offset ()
                     + (base_align_bias >> ASAN_SHADOW_SHIFT));
   gcc_assert (asan_shadow_set != -1
              && (ASAN_RED_ZONE_SIZE >> ASAN_SHADOW_SHIFT) == 4);
@@ -1140,16 +1231,16 @@ asan_emit_stack_protection (rtx base, rtx pbase, unsigned int alignb,
                                       (aoff - prev_offset)
                                       >> ASAN_SHADOW_SHIFT);
          prev_offset = aoff;
-         for (i = 0; i < 4; i++, aoff += (1 << ASAN_SHADOW_SHIFT))
+         for (i = 0; i < 4; i++, aoff += ASAN_SHADOW_GRANULARITY)
            if (aoff < offset)
              {
-               if (aoff < offset - (1 << ASAN_SHADOW_SHIFT) + 1)
+               if (aoff < offset - (HOST_WIDE_INT)ASAN_SHADOW_GRANULARITY + 1)
                  shadow_bytes[i] = 0;
                else
                  shadow_bytes[i] = offset - aoff;
              }
            else
-             shadow_bytes[i] = ASAN_STACK_MAGIC_PARTIAL;
+             shadow_bytes[i] = ASAN_STACK_MAGIC_MIDDLE;
          emit_move_insn (shadow_mem, asan_shadow_cst (shadow_bytes));
          offset = aoff;
        }
@@ -1170,10 +1261,10 @@ asan_emit_stack_protection (rtx base, rtx pbase, unsigned int alignb,
   /* Construct epilogue sequence.  */
   start_sequence ();
 
-  lab = NULL_RTX;  
+  lab = NULL;
   if (use_after_return_class != -1)
     {
-      rtx lab2 = gen_label_rtx ();
+      rtx_code_label *lab2 = gen_label_rtx ();
       char c = (char) ASAN_STACK_MAGIC_USE_AFTER_RET;
       int very_likely = REG_BR_PROB_BASE - (REG_BR_PROB_BASE / 2000 - 1);
       emit_cmp_and_jump_insns (orig_base, base, EQ, NULL_RTX,
@@ -1217,42 +1308,73 @@ asan_emit_stack_protection (rtx base, rtx pbase, unsigned int alignb,
   if (STRICT_ALIGNMENT)
     set_mem_align (shadow_mem, (GET_MODE_ALIGNMENT (SImode)));
 
-  prev_offset = base_offset;
+  /* Unpoison shadow memory of a stack at the very end of a function.
+     As we're poisoning stack variables at the end of their scope,
+     shadow memory must be properly unpoisoned here.  The easiest approach
+     would be to collect all variables that should not be unpoisoned and
+     we unpoison shadow memory of the whole stack except ranges
+     occupied by these variables.  */
   last_offset = base_offset;
-  last_size = 0;
-  for (l = length; l; l -= 2)
+  HOST_WIDE_INT current_offset = last_offset;
+  if (length)
     {
-      offset = base_offset + ((offsets[l - 1] - base_offset)
-                            & ~(ASAN_RED_ZONE_SIZE - HOST_WIDE_INT_1));
-      if (last_offset + last_size != offset)
+      HOST_WIDE_INT var_end_offset = 0;
+      HOST_WIDE_INT stack_start = offsets[length - 1];
+      gcc_assert (last_offset == stack_start);
+
+      for (int l = length - 2; l > 0; l -= 2)
        {
-         shadow_mem = adjust_address (shadow_mem, VOIDmode,
-                                      (last_offset - prev_offset)
-                                      >> ASAN_SHADOW_SHIFT);
-         prev_offset = last_offset;
-         asan_clear_shadow (shadow_mem, last_size >> ASAN_SHADOW_SHIFT);
-         last_offset = offset;
-         last_size = 0;
+         HOST_WIDE_INT var_offset = offsets[l];
+         current_offset = var_offset;
+         var_end_offset = offsets[l - 1];
+         HOST_WIDE_INT rounded_size = ROUND_UP (var_end_offset - var_offset,
+                                            BITS_PER_UNIT);
+
+         /* Should we unpoison the variable?  */
+         if (asan_handled_variables != NULL
+             && asan_handled_variables->contains (decl))
+           {
+             if (dump_file && (dump_flags & TDF_DETAILS))
+               {
+                 const char *n = (DECL_NAME (decl)
+                                  ? IDENTIFIER_POINTER (DECL_NAME (decl))
+                                  : "<unknown>");
+                 fprintf (dump_file, "Unpoisoning shadow stack for variable: "
+                          "%s (%" PRId64 "B)\n", n,
+                          var_end_offset - var_offset);
+               }
+
+             unsigned HOST_WIDE_INT s
+               = shadow_mem_size (current_offset - last_offset);
+             asan_clear_shadow (shadow_mem, s);
+             HOST_WIDE_INT shift
+               = shadow_mem_size (current_offset - last_offset + rounded_size);
+             shadow_mem = adjust_address (shadow_mem, VOIDmode, shift);
+             last_offset = var_offset + rounded_size;
+             current_offset = last_offset;
+           }
+
        }
-      last_size += base_offset + ((offsets[l - 2] - base_offset)
-                                 & ~(ASAN_RED_ZONE_SIZE - HOST_WIDE_INT_1))
-                  - offset;
-    }
-  if (last_size)
-    {
-      shadow_mem = adjust_address (shadow_mem, VOIDmode,
-                                  (last_offset - prev_offset)
-                                  >> ASAN_SHADOW_SHIFT);
-      asan_clear_shadow (shadow_mem, last_size >> ASAN_SHADOW_SHIFT);
+
+      /* Handle last redzone.  */
+      current_offset = offsets[0];
+      asan_clear_shadow (shadow_mem,
+                        shadow_mem_size (current_offset - last_offset));
     }
 
+  /* Clean-up set with instrumented stack variables.  */
+  delete asan_handled_variables;
+  asan_handled_variables = NULL;
+  delete asan_used_labels;
+  asan_used_labels = NULL;
+
   do_pending_stack_adjust ();
   if (lab)
     emit_label (lab);
 
-  ret = get_insns ();
+  insns = get_insns ();
   end_sequence ();
-  return ret;
+  return insns;
 }
 
 /* Return true if DECL, a global var, might be overridden and needs
@@ -1264,6 +1386,16 @@ asan_needs_local_alias (tree decl)
   return DECL_WEAK (decl) || !targetm.binds_local_p (decl);
 }
 
+/* Return true if DECL, a global var, is an artificial ODR indicator symbol
+   therefore doesn't need protection.  */
+
+static bool
+is_odr_indicator (tree decl)
+{
+  return (DECL_ARTIFICIAL (decl)
+         && lookup_attribute ("asan odr indicator", DECL_ATTRIBUTES (decl)));
+}
+
 /* Return true if DECL is a VAR_DECL that should be protected
    by Address Sanitizer, by appending a red zone with protected
    shadow memory after it and aligning it to at least
@@ -1287,7 +1419,7 @@ asan_protect_global (tree decl)
        return false;
       return true;
     }
-  if (TREE_CODE (decl) != VAR_DECL
+  if (!VAR_P (decl)
       /* TLS vars aren't statically protectable.  */
       || DECL_THREAD_LOCAL_P (decl)
       /* Externs will be protected elsewhere.  */
@@ -1297,18 +1429,23 @@ asan_protect_global (tree decl)
         the var that is selected by the linker will have
         padding or not.  */
       || DECL_ONE_ONLY (decl)
-      /* Similarly for common vars.  People can use -fno-common.  */
+      /* Similarly for common vars.  People can use -fno-common.
+        Note: Linux kernel is built with -fno-common, so we do instrument
+        globals there even if it is C.  */
       || (DECL_COMMON (decl) && TREE_PUBLIC (decl))
       /* Don't protect if using user section, often vars placed
         into user section from multiple TUs are then assumed
         to be an array of such vars, putting padding in there
         breaks this assumption.  */
       || (DECL_SECTION_NAME (decl) != NULL
-         && !symtab_node::get (decl)->implicit_section)
+         && !symtab_node::get (decl)->implicit_section
+         && !section_sanitized_p (DECL_SECTION_NAME (decl)))
       || DECL_SIZE (decl) == 0
       || ASAN_RED_ZONE_SIZE * BITS_PER_UNIT > MAX_OFILE_ALIGNMENT
       || !valid_constant_size_p (DECL_SIZE_UNIT (decl))
-      || DECL_ALIGN_UNIT (decl) > 2 * ASAN_RED_ZONE_SIZE)
+      || DECL_ALIGN_UNIT (decl) > 2 * ASAN_RED_ZONE_SIZE
+      || TREE_TYPE (decl) == ubsan_get_source_location_type ()
+      || is_odr_indicator (decl))
     return false;
 
   rtl = DECL_RTL (decl);
@@ -1335,44 +1472,72 @@ asan_protect_global (tree decl)
    IS_STORE is either 1 (for a store) or 0 (for a load).  */
 
 static tree
-report_error_func (bool is_store, HOST_WIDE_INT size_in_bytes, int *nargs)
-{
-  static enum built_in_function report[2][6]
-    = { { BUILT_IN_ASAN_REPORT_LOAD1, BUILT_IN_ASAN_REPORT_LOAD2,
-         BUILT_IN_ASAN_REPORT_LOAD4, BUILT_IN_ASAN_REPORT_LOAD8,
-         BUILT_IN_ASAN_REPORT_LOAD16, BUILT_IN_ASAN_REPORT_LOAD_N },
-       { BUILT_IN_ASAN_REPORT_STORE1, BUILT_IN_ASAN_REPORT_STORE2,
-         BUILT_IN_ASAN_REPORT_STORE4, BUILT_IN_ASAN_REPORT_STORE8,
-         BUILT_IN_ASAN_REPORT_STORE16, BUILT_IN_ASAN_REPORT_STORE_N } };
+report_error_func (bool is_store, bool recover_p, HOST_WIDE_INT size_in_bytes,
+                  int *nargs)
+{
+  static enum built_in_function report[2][2][6]
+    = { { { BUILT_IN_ASAN_REPORT_LOAD1, BUILT_IN_ASAN_REPORT_LOAD2,
+           BUILT_IN_ASAN_REPORT_LOAD4, BUILT_IN_ASAN_REPORT_LOAD8,
+           BUILT_IN_ASAN_REPORT_LOAD16, BUILT_IN_ASAN_REPORT_LOAD_N },
+         { BUILT_IN_ASAN_REPORT_STORE1, BUILT_IN_ASAN_REPORT_STORE2,
+           BUILT_IN_ASAN_REPORT_STORE4, BUILT_IN_ASAN_REPORT_STORE8,
+           BUILT_IN_ASAN_REPORT_STORE16, BUILT_IN_ASAN_REPORT_STORE_N } },
+       { { BUILT_IN_ASAN_REPORT_LOAD1_NOABORT,
+           BUILT_IN_ASAN_REPORT_LOAD2_NOABORT,
+           BUILT_IN_ASAN_REPORT_LOAD4_NOABORT,
+           BUILT_IN_ASAN_REPORT_LOAD8_NOABORT,
+           BUILT_IN_ASAN_REPORT_LOAD16_NOABORT,
+           BUILT_IN_ASAN_REPORT_LOAD_N_NOABORT },
+         { BUILT_IN_ASAN_REPORT_STORE1_NOABORT,
+           BUILT_IN_ASAN_REPORT_STORE2_NOABORT,
+           BUILT_IN_ASAN_REPORT_STORE4_NOABORT,
+           BUILT_IN_ASAN_REPORT_STORE8_NOABORT,
+           BUILT_IN_ASAN_REPORT_STORE16_NOABORT,
+           BUILT_IN_ASAN_REPORT_STORE_N_NOABORT } } };
   if (size_in_bytes == -1)
     {
       *nargs = 2;
-      return builtin_decl_implicit (report[is_store][5]);
+      return builtin_decl_implicit (report[recover_p][is_store][5]);
     }
   *nargs = 1;
-  return builtin_decl_implicit (report[is_store][exact_log2 (size_in_bytes)]);
+  int size_log2 = exact_log2 (size_in_bytes);
+  return builtin_decl_implicit (report[recover_p][is_store][size_log2]);
 }
 
 /* Construct a function tree for __asan_{load,store}{1,2,4,8,16,_n}.
    IS_STORE is either 1 (for a store) or 0 (for a load).  */
 
 static tree
-check_func (bool is_store, int size_in_bytes, int *nargs)
-{
-  static enum built_in_function check[2][6]
-    = { { BUILT_IN_ASAN_LOAD1, BUILT_IN_ASAN_LOAD2,
-      BUILT_IN_ASAN_LOAD4, BUILT_IN_ASAN_LOAD8,
-      BUILT_IN_ASAN_LOAD16, BUILT_IN_ASAN_LOADN },
-       { BUILT_IN_ASAN_STORE1, BUILT_IN_ASAN_STORE2,
-      BUILT_IN_ASAN_STORE4, BUILT_IN_ASAN_STORE8,
-      BUILT_IN_ASAN_STORE16, BUILT_IN_ASAN_STOREN } };
+check_func (bool is_store, bool recover_p, HOST_WIDE_INT size_in_bytes,
+           int *nargs)
+{
+  static enum built_in_function check[2][2][6]
+    = { { { BUILT_IN_ASAN_LOAD1, BUILT_IN_ASAN_LOAD2,
+           BUILT_IN_ASAN_LOAD4, BUILT_IN_ASAN_LOAD8,
+           BUILT_IN_ASAN_LOAD16, BUILT_IN_ASAN_LOADN },
+         { BUILT_IN_ASAN_STORE1, BUILT_IN_ASAN_STORE2,
+           BUILT_IN_ASAN_STORE4, BUILT_IN_ASAN_STORE8,
+           BUILT_IN_ASAN_STORE16, BUILT_IN_ASAN_STOREN } },
+       { { BUILT_IN_ASAN_LOAD1_NOABORT,
+           BUILT_IN_ASAN_LOAD2_NOABORT,
+           BUILT_IN_ASAN_LOAD4_NOABORT,
+           BUILT_IN_ASAN_LOAD8_NOABORT,
+           BUILT_IN_ASAN_LOAD16_NOABORT,
+           BUILT_IN_ASAN_LOADN_NOABORT },
+         { BUILT_IN_ASAN_STORE1_NOABORT,
+           BUILT_IN_ASAN_STORE2_NOABORT,
+           BUILT_IN_ASAN_STORE4_NOABORT,
+           BUILT_IN_ASAN_STORE8_NOABORT,
+           BUILT_IN_ASAN_STORE16_NOABORT,
+           BUILT_IN_ASAN_STOREN_NOABORT } } };
   if (size_in_bytes == -1)
     {
       *nargs = 2;
-      return builtin_decl_implicit (check[is_store][5]);
+      return builtin_decl_implicit (check[recover_p][is_store][5]);
     }
   *nargs = 1;
-  return builtin_decl_implicit (check[is_store][exact_log2 (size_in_bytes)]);
+  int size_log2 = exact_log2 (size_in_bytes);
+  return builtin_decl_implicit (check[recover_p][is_store][size_log2]);
 }
 
 /* Split the current basic block and create a condition statement
@@ -1477,7 +1642,7 @@ create_cond_insert_point (gimple_stmt_iterator *iter,
    pointing to initially.  */
 
 static void
-insert_if_then_before_iter (gimple cond,
+insert_if_then_before_iter (gcond *cond,
                            gimple_stmt_iterator *iter,
                            bool then_more_likely_p,
                            basic_block *then_bb,
@@ -1493,44 +1658,45 @@ insert_if_then_before_iter (gimple cond,
   gsi_insert_after (&cond_insert_point, cond, GSI_NEW_STMT);
 }
 
-/* Build
-   (base_addr >> ASAN_SHADOW_SHIFT) + targetm.asan_shadow_offset ().  */
+/* Build (base_addr >> ASAN_SHADOW_SHIFT) + asan_shadow_offset ().
+   If RETURN_ADDRESS is set to true, return memory location instread
+   of a value in the shadow memory.  */
 
 static tree
 build_shadow_mem_access (gimple_stmt_iterator *gsi, location_t location,
-                        tree base_addr, tree shadow_ptr_type)
+                        tree base_addr, tree shadow_ptr_type,
+                        bool return_address = false)
 {
   tree t, uintptr_type = TREE_TYPE (base_addr);
   tree shadow_type = TREE_TYPE (shadow_ptr_type);
-  gimple g;
+  gimple *g;
 
   t = build_int_cst (uintptr_type, ASAN_SHADOW_SHIFT);
-  g = gimple_build_assign_with_ops (RSHIFT_EXPR,
-                                   make_ssa_name (uintptr_type, NULL),
-                                   base_addr, t);
+  g = gimple_build_assign (make_ssa_name (uintptr_type), RSHIFT_EXPR,
+                          base_addr, t);
   gimple_set_location (g, location);
   gsi_insert_after (gsi, g, GSI_NEW_STMT);
 
-  t = build_int_cst (uintptr_type, targetm.asan_shadow_offset ());
-  g = gimple_build_assign_with_ops (PLUS_EXPR,
-                                   make_ssa_name (uintptr_type, NULL),
-                                   gimple_assign_lhs (g), t);
+  t = build_int_cst (uintptr_type, asan_shadow_offset ());
+  g = gimple_build_assign (make_ssa_name (uintptr_type), PLUS_EXPR,
+                          gimple_assign_lhs (g), t);
   gimple_set_location (g, location);
   gsi_insert_after (gsi, g, GSI_NEW_STMT);
 
-  g = gimple_build_assign_with_ops (NOP_EXPR,
-                                   make_ssa_name (shadow_ptr_type, NULL),
-                                   gimple_assign_lhs (g), NULL_TREE);
+  g = gimple_build_assign (make_ssa_name (shadow_ptr_type), NOP_EXPR,
+                          gimple_assign_lhs (g));
   gimple_set_location (g, location);
   gsi_insert_after (gsi, g, GSI_NEW_STMT);
 
-  t = build2 (MEM_REF, shadow_type, gimple_assign_lhs (g),
-             build_int_cst (shadow_ptr_type, 0));
-  g = gimple_build_assign_with_ops (MEM_REF,
-                                   make_ssa_name (shadow_type, NULL),
-                                   t, NULL_TREE);
-  gimple_set_location (g, location);
-  gsi_insert_after (gsi, g, GSI_NEW_STMT);
+  if (!return_address)
+    {
+      t = build2 (MEM_REF, shadow_type, gimple_assign_lhs (g),
+                 build_int_cst (shadow_ptr_type, 0));
+      g = gimple_build_assign (make_ssa_name (shadow_type), MEM_REF, t);
+      gimple_set_location (g, location);
+      gsi_insert_after (gsi, g, GSI_NEW_STMT);
+    }
+
   return gimple_assign_lhs (g);
 }
 
@@ -1543,10 +1709,8 @@ maybe_create_ssa_name (location_t loc, tree base, gimple_stmt_iterator *iter,
 {
   if (TREE_CODE (base) == SSA_NAME)
     return base;
-  gimple g
-    = gimple_build_assign_with_ops (TREE_CODE (base),
-                                   make_ssa_name (TREE_TYPE (base), NULL),
-                                   base, NULL_TREE);
+  gimple *g = gimple_build_assign (make_ssa_name (TREE_TYPE (base)),
+                                 TREE_CODE (base), base);
   gimple_set_location (g, loc);
   if (before_p)
     gsi_insert_before (iter, g, GSI_SAME_STMT);
@@ -1555,53 +1719,23 @@ maybe_create_ssa_name (location_t loc, tree base, gimple_stmt_iterator *iter,
   return gimple_assign_lhs (g);
 }
 
-/* Instrument the memory access instruction using callbacks.
-   Parameters are similar to BUILD_CHECK_STMT.  */
+/* LEN can already have necessary size and precision;
+   in that case, do not create a new variable.  */
 
-static void
-build_check_stmt_with_calls (location_t loc, tree base, tree len,
-                            HOST_WIDE_INT size_in_bytes, gimple_stmt_iterator *iter,
-                            bool before_p, bool is_store, bool is_scalar_access)
+tree
+maybe_cast_to_ptrmode (location_t loc, tree len, gimple_stmt_iterator *iter,
+                      bool before_p)
 {
-  gimple_stmt_iterator gsi = *iter;
-  tree base_ssa = maybe_create_ssa_name (loc, base, &gsi, before_p);
-
-  gimple g
-    = gimple_build_assign_with_ops (NOP_EXPR,
-                                   make_ssa_name (pointer_sized_int_node, NULL),
-                                   base_ssa, NULL_TREE);
+  if (ptrofftype_p (len))
+    return len;
+  gimple *g = gimple_build_assign (make_ssa_name (pointer_sized_int_node),
+                                 NOP_EXPR, len);
   gimple_set_location (g, loc);
   if (before_p)
-    gsi_insert_before (&gsi, g, GSI_NEW_STMT);
-  else
-    gsi_insert_after (&gsi, g, GSI_NEW_STMT);
-  tree base_addr = gimple_assign_lhs (g);
-
-  int nargs;
-  tree fun
-    = check_func (is_store, is_scalar_access ? size_in_bytes : -1, &nargs);
-  if (nargs == 1)
-    g = gimple_build_call (fun, 1, base_addr);
+    gsi_insert_before (iter, g, GSI_SAME_STMT);
   else
-    {
-      gcc_assert (nargs == 2);
-      g = gimple_build_assign_with_ops (NOP_EXPR,
-                                       make_ssa_name (pointer_sized_int_node,
-                                                      NULL),
-                                       len, NULL_TREE);
-      gimple_set_location (g, loc);
-      gsi_insert_after (&gsi, g, GSI_NEW_STMT);
-      tree sz_arg = gimple_assign_lhs (g);
-      g = gimple_build_call (fun, nargs, base_addr, sz_arg);
-    }
-  gimple_set_location (g, loc);
-  gsi_insert_after (&gsi, g, GSI_NEW_STMT);
-
-  if (!before_p)
-    {
-      gsi_next (&gsi);
-      *iter = gsi;
-    }
+    gsi_insert_after (iter, g, GSI_NEW_STMT);
+  return gimple_assign_lhs (g);
 }
 
 /* Instrument the memory access instruction BASE.  Insert new
@@ -1624,29 +1758,26 @@ build_check_stmt_with_calls (location_t loc, tree base, tree len,
    otherwise, it points to the statement logically following it.  */
 
 static void
-build_check_stmt (location_t location, tree base, tree len,
+build_check_stmt (location_t loc, tree base, tree len,
                  HOST_WIDE_INT size_in_bytes, gimple_stmt_iterator *iter,
-                 bool non_zero_len_p, bool before_p, bool is_store,
-                 bool is_scalar_access, unsigned int align = 0,
-                 bool start_instrumented = false,
-                 bool end_instrumented = false)
+                 bool is_non_zero_len, bool before_p, bool is_store,
+                 bool is_scalar_access, unsigned int align = 0)
 {
   gimple_stmt_iterator gsi = *iter;
-  gimple g;
-  tree uintptr_type
-    = build_nonstandard_integer_type (TYPE_PRECISION (TREE_TYPE (base)), 1);
+  gimple *g;
 
-  gcc_assert (!(size_in_bytes > 0 && !non_zero_len_p));
+  gcc_assert (!(size_in_bytes > 0 && !is_non_zero_len));
 
-  if (start_instrumented && end_instrumented)
-    {
-      if (!before_p)
-        gsi_next (iter);
-      return;
-    }
+  gsi = *iter;
+
+  base = unshare_expr (base);
+  base = maybe_create_ssa_name (loc, base, &gsi, before_p);
 
   if (len)
-    len = unshare_expr (len);
+    {
+      len = unshare_expr (len);
+      len = maybe_cast_to_ptrmode (loc, len, iter, before_p);
+    }
   else
     {
       gcc_assert (size_in_bytes != -1);
@@ -1656,9 +1787,8 @@ build_check_stmt (location_t location, tree base, tree len,
   if (size_in_bytes > 1)
     {
       if ((size_in_bytes & (size_in_bytes - 1)) != 0
-         || !is_scalar_access
          || size_in_bytes > 16)
-       size_in_bytes = -1;
+       is_scalar_access = false;
       else if (align && align < size_in_bytes * BITS_PER_UNIT)
        {
          /* On non-strict alignment targets, if
@@ -1669,249 +1799,93 @@ build_check_stmt (location_t location, tree base, tree len,
          if (size_in_bytes != 16
              || STRICT_ALIGNMENT
              || align < 8 * BITS_PER_UNIT)
-           size_in_bytes = -1;
+           is_scalar_access = false;
        }
     }
 
-  HOST_WIDE_INT real_size_in_bytes = size_in_bytes == -1 ? 1 : size_in_bytes;
-
-  tree shadow_ptr_type = shadow_ptr_types[real_size_in_bytes == 16 ? 1 : 0];
-  tree shadow_type = TREE_TYPE (shadow_ptr_type);
-
-  base = unshare_expr (base);
-
-  if (use_calls_p ())
+  HOST_WIDE_INT flags = 0;
+  if (is_store)
+    flags |= ASAN_CHECK_STORE;
+  if (is_non_zero_len)
+    flags |= ASAN_CHECK_NON_ZERO_LEN;
+  if (is_scalar_access)
+    flags |= ASAN_CHECK_SCALAR_ACCESS;
+
+  g = gimple_build_call_internal (IFN_ASAN_CHECK, 4,
+                                 build_int_cst (integer_type_node, flags),
+                                 base, len,
+                                 build_int_cst (integer_type_node,
+                                                align / BITS_PER_UNIT));
+  gimple_set_location (g, loc);
+  if (before_p)
+    gsi_insert_before (&gsi, g, GSI_SAME_STMT);
+  else
     {
-      gsi = *iter;
-      build_check_stmt_with_calls (location, base, len, size_in_bytes, iter,
-                                  before_p, is_store, is_scalar_access);
-      return;
+      gsi_insert_after (&gsi, g, GSI_NEW_STMT);
+      gsi_next (&gsi);
+      *iter = gsi;
     }
+}
 
-  ++asan_num_accesses;
-
-  if (!non_zero_len_p)
-    {
-      gcc_assert (before_p);
-
-      /* So, the length of the memory area to asan-protect is
-        non-constant.  Let's guard the generated instrumentation code
-        like:
-
-        if (len != 0)
-          {
-            //asan instrumentation code goes here.
-          }
-        // falltrough instructions, starting with *ITER.  */
+/* If T represents a memory access, add instrumentation code before ITER.
+   LOCATION is source code location.
+   IS_STORE is either TRUE (for a store) or FALSE (for a load).  */
 
-      g = gimple_build_cond (NE_EXPR,
-                            len,
-                            build_int_cst (TREE_TYPE (len), 0),
-                            NULL_TREE, NULL_TREE);
-      gimple_set_location (g, location);
+static void
+instrument_derefs (gimple_stmt_iterator *iter, tree t,
+                  location_t location, bool is_store)
+{
+  if (is_store && !ASAN_INSTRUMENT_WRITES)
+    return;
+  if (!is_store && !ASAN_INSTRUMENT_READS)
+    return;
 
-      basic_block then_bb, fallthrough_bb;
-      insert_if_then_before_iter (g, iter, /*then_more_likely_p=*/true,
-                                 &then_bb, &fallthrough_bb);
-      /* Note that fallthrough_bb starts with the statement that was
-        pointed to by ITER.  */
+  tree type, base;
+  HOST_WIDE_INT size_in_bytes;
+  if (location == UNKNOWN_LOCATION)
+    location = EXPR_LOCATION (t);
 
-      /* The 'then block' of the 'if (len != 0) condition is where
-        we'll generate the asan instrumentation code now.  */
-      gsi = gsi_last_bb (then_bb);
-      build_check_stmt (location, base, len, size_in_bytes, &gsi,
-                       /*non_zero_len_p*/true, /*before_p*/true, is_store,
-                       is_scalar_access, align,
-                       start_instrumented, end_instrumented);
+  type = TREE_TYPE (t);
+  switch (TREE_CODE (t))
+    {
+    case ARRAY_REF:
+    case COMPONENT_REF:
+    case INDIRECT_REF:
+    case MEM_REF:
+    case VAR_DECL:
+    case BIT_FIELD_REF:
+      break;
+      /* FALLTHRU */
+    default:
       return;
     }
 
-  /* Get an iterator on the point where we can add the condition
-     statement for the instrumentation.  */
-  basic_block then_bb, else_bb;
-  gsi = create_cond_insert_point (&gsi, before_p,
-                                 /*then_more_likely_p=*/false,
-                                 /*create_then_fallthru_edge=*/false,
-                                 &then_bb,
-                                 &else_bb);
-
-  tree base_ssa = maybe_create_ssa_name (location, base, &gsi,
-                                        /*before_p*/false);
+  size_in_bytes = int_size_in_bytes (type);
+  if (size_in_bytes <= 0)
+    return;
 
-  g = gimple_build_assign_with_ops (NOP_EXPR,
-                                   make_ssa_name (uintptr_type, NULL),
-                                   base_ssa, NULL_TREE);
-  gimple_set_location (g, location);
-  gsi_insert_after (&gsi, g, GSI_NEW_STMT);
-  tree base_addr = gimple_assign_lhs (g);
+  HOST_WIDE_INT bitsize, bitpos;
+  tree offset;
+  machine_mode mode;
+  int unsignedp, reversep, volatilep = 0;
+  tree inner = get_inner_reference (t, &bitsize, &bitpos, &offset, &mode,
+                                   &unsignedp, &reversep, &volatilep);
 
-  tree t = NULL_TREE;
-  if (real_size_in_bytes >= 8)
+  if (TREE_CODE (t) == COMPONENT_REF
+      && DECL_BIT_FIELD_REPRESENTATIVE (TREE_OPERAND (t, 1)) != NULL_TREE)
     {
-      tree shadow = build_shadow_mem_access (&gsi, location, base_addr,
-                                            shadow_ptr_type);
-      t = shadow;
+      tree repr = DECL_BIT_FIELD_REPRESENTATIVE (TREE_OPERAND (t, 1));
+      instrument_derefs (iter, build3 (COMPONENT_REF, TREE_TYPE (repr),
+                                      TREE_OPERAND (t, 0), repr,
+                                      NULL_TREE), location, is_store);
+      return;
     }
-  else
-    {
-      /* Slow path for 1, 2 and 4 byte accesses.  */
 
-      if (!start_instrumented)
-       {
-         /* Test (shadow != 0)
-                 & ((base_addr & 7) + (real_size_in_bytes - 1)) >= shadow).  */
-         tree shadow = build_shadow_mem_access (&gsi, location, base_addr,
-                                                shadow_ptr_type);
-         gimple shadow_test = build_assign (NE_EXPR, shadow, 0);
-         gimple_seq seq = NULL;
-         gimple_seq_add_stmt (&seq, shadow_test);
-         gimple_seq_add_stmt (&seq, build_assign (BIT_AND_EXPR, base_addr, 7));
-         gimple_seq_add_stmt (&seq, build_type_cast (shadow_type,
-                                                     gimple_seq_last (seq)));
-         if (real_size_in_bytes > 1)
-           gimple_seq_add_stmt (&seq,
-                                build_assign (PLUS_EXPR, gimple_seq_last (seq),
-                                              real_size_in_bytes - 1));
-         gimple_seq_add_stmt (&seq, build_assign (GE_EXPR,
-                                                  gimple_seq_last (seq),
-                                                  shadow));
-         gimple_seq_add_stmt (&seq, build_assign (BIT_AND_EXPR, shadow_test,
-                                                  gimple_seq_last (seq)));
-         t = gimple_assign_lhs (gimple_seq_last (seq));
-         gimple_seq_set_location (seq, location);
-         gsi_insert_seq_after (&gsi, seq, GSI_CONTINUE_LINKING);
-       }
+  if (bitpos % BITS_PER_UNIT
+      || bitsize != size_in_bytes * BITS_PER_UNIT)
+    return;
 
-      /* For non-constant, misaligned or otherwise weird access sizes,
-        check first and last byte.  */
-      if (size_in_bytes == -1 && !end_instrumented)
-       {
-         g = gimple_build_assign_with_ops (MINUS_EXPR,
-                                           make_ssa_name (uintptr_type, NULL),
-                                           len,
-                                           build_int_cst (uintptr_type, 1));
-         gimple_set_location (g, location);
-         gsi_insert_after (&gsi, g, GSI_NEW_STMT);
-         tree last = gimple_assign_lhs (g);
-         g = gimple_build_assign_with_ops (PLUS_EXPR,
-                                           make_ssa_name (uintptr_type, NULL),
-                                           base_addr,
-                                           last);
-         gimple_set_location (g, location);
-         gsi_insert_after (&gsi, g, GSI_NEW_STMT);
-         tree base_end_addr = gimple_assign_lhs (g);
-
-         tree shadow = build_shadow_mem_access (&gsi, location, base_end_addr,
-                                                shadow_ptr_type);
-         gimple shadow_test = build_assign (NE_EXPR, shadow, 0);
-         gimple_seq seq = NULL;
-         gimple_seq_add_stmt (&seq, shadow_test);
-         gimple_seq_add_stmt (&seq, build_assign (BIT_AND_EXPR,
-                                                  base_end_addr, 7));
-         gimple_seq_add_stmt (&seq, build_type_cast (shadow_type,
-                                                     gimple_seq_last (seq)));
-         gimple_seq_add_stmt (&seq, build_assign (GE_EXPR,
-                                                  gimple_seq_last (seq),
-                                                  shadow));
-         gimple_seq_add_stmt (&seq, build_assign (BIT_AND_EXPR, shadow_test,
-                                                  gimple_seq_last (seq)));
-         if (!start_instrumented)
-           gimple_seq_add_stmt (&seq, build_assign (BIT_IOR_EXPR, t,
-                                                    gimple_seq_last (seq)));
-         t = gimple_assign_lhs (gimple_seq_last (seq));
-         gimple_seq_set_location (seq, location);
-         gsi_insert_seq_after (&gsi, seq, GSI_CONTINUE_LINKING);
-       }
-    }
-
-  g = gimple_build_cond (NE_EXPR, t, build_int_cst (TREE_TYPE (t), 0),
-                        NULL_TREE, NULL_TREE);
-  gimple_set_location (g, location);
-  gsi_insert_after (&gsi, g, GSI_NEW_STMT);
-
-  /* Generate call to the run-time library (e.g. __asan_report_load8).  */
-  gsi = gsi_start_bb (then_bb);
-  int nargs;
-  tree fun = report_error_func (is_store, is_scalar_access ? size_in_bytes : -1,
-                               &nargs);
-  if (nargs == 1)
-      g = gimple_build_call (fun, 1, base_addr);
-  else
-    {
-      gcc_assert (nargs == 2);
-      g = gimple_build_assign_with_ops (NOP_EXPR,
-                                       make_ssa_name (pointer_sized_int_node,
-                                                      NULL),
-                                       len, NULL_TREE);
-      gimple_set_location (g, location);
-      gsi_insert_after (&gsi, g, GSI_NEW_STMT);
-      tree sz_arg = gimple_assign_lhs (g);
-      g = gimple_build_call (fun, nargs, base_addr, sz_arg);
-    }
-  gimple_set_location (g, location);
-  gsi_insert_after (&gsi, g, GSI_NEW_STMT);
-
-  *iter = gsi_start_bb (else_bb);
-}
-
-/* If T represents a memory access, add instrumentation code before ITER.
-   LOCATION is source code location.
-   IS_STORE is either TRUE (for a store) or FALSE (for a load).  */
-
-static void
-instrument_derefs (gimple_stmt_iterator *iter, tree t,
-                  location_t location, bool is_store)
-{
-  if (is_store && !ASAN_INSTRUMENT_WRITES)
-    return;
-  if (!is_store && !ASAN_INSTRUMENT_READS)
-    return;
-
-  tree type, base;
-  HOST_WIDE_INT size_in_bytes;
-
-  type = TREE_TYPE (t);
-  switch (TREE_CODE (t))
-    {
-    case ARRAY_REF:
-    case COMPONENT_REF:
-    case INDIRECT_REF:
-    case MEM_REF:
-    case VAR_DECL:
-      break;
-      /* FALLTHRU */
-    default:
-      return;
-    }
-
-  size_in_bytes = int_size_in_bytes (type);
-  if (size_in_bytes <= 0)
-    return;
-
-  HOST_WIDE_INT bitsize, bitpos;
-  tree offset;
-  enum machine_mode mode;
-  int volatilep = 0, unsignedp = 0;
-  tree inner = get_inner_reference (t, &bitsize, &bitpos, &offset,
-                                   &mode, &unsignedp, &volatilep, false);
-  if (((size_in_bytes & (size_in_bytes - 1)) == 0
-       && (bitpos % (size_in_bytes * BITS_PER_UNIT)))
-      || bitsize != size_in_bytes * BITS_PER_UNIT)
-    {
-      if (TREE_CODE (t) == COMPONENT_REF
-         && DECL_BIT_FIELD_REPRESENTATIVE (TREE_OPERAND (t, 1)) != NULL_TREE)
-       {
-         tree repr = DECL_BIT_FIELD_REPRESENTATIVE (TREE_OPERAND (t, 1));
-         instrument_derefs (iter, build3 (COMPONENT_REF, TREE_TYPE (repr),
-                                          TREE_OPERAND (t, 0), repr,
-                                          NULL_TREE), location, is_store);
-       }
-      return;
-    }
-  if (bitpos % BITS_PER_UNIT)
-    return;
-
-  if (TREE_CODE (inner) == VAR_DECL
+  if (VAR_P (inner)
       && offset == NULL_TREE
       && bitpos >= 0
       && DECL_SIZE (inner)
@@ -1920,11 +1894,15 @@ instrument_derefs (gimple_stmt_iterator *iter, tree t,
     {
       if (DECL_THREAD_LOCAL_P (inner))
        return;
+      if (!ASAN_GLOBALS && is_global_var (inner))
+        return;
       if (!TREE_STATIC (inner))
        {
          /* Automatic vars in the current function will be always
             accessible.  */
-         if (decl_function_context (inner) == current_function_decl)
+         if (decl_function_context (inner) == current_function_decl
+             && (!asan_sanitize_use_after_scope ()
+                 || !TREE_ADDRESSABLE (inner)))
            return;
        }
       /* Always instrument external vars, they might be dynamically
@@ -1944,7 +1922,7 @@ instrument_derefs (gimple_stmt_iterator *iter, tree t,
     {
       unsigned int align = get_object_alignment (t);
       build_check_stmt (location, base, NULL_TREE, size_in_bytes, iter,
-                       /*non_zero_len_p*/size_in_bytes > 0, /*before_p=*/true,
+                       /*is_non_zero_len*/size_in_bytes > 0, /*before_p=*/true,
                        is_store, /*is_scalar_access*/true, align);
       update_mem_ref_hash_table (base, size_in_bytes);
       update_mem_ref_hash_table (t, size_in_bytes);
@@ -1952,6 +1930,22 @@ instrument_derefs (gimple_stmt_iterator *iter, tree t,
 
 }
 
+/*  Insert a memory reference into the hash table if access length
+    can be determined in compile time.  */
+
+static void
+maybe_update_mem_ref_hash_table (tree base, tree len)
+{
+  if (!POINTER_TYPE_P (TREE_TYPE (base))
+      || !INTEGRAL_TYPE_P (TREE_TYPE (len)))
+    return;
+
+  HOST_WIDE_INT size_in_bytes = tree_fits_shwi_p (len) ? tree_to_shwi (len) : -1;
+
+  if (size_in_bytes != -1)
+    update_mem_ref_hash_table (base, size_in_bytes);
+}
+
 /* Instrument an access to a contiguous memory region that starts at
    the address pointed to by BASE, over a length of LEN (expressed in
    the sizeof (*BASE) bytes).  ITER points to the instruction before
@@ -1970,94 +1964,20 @@ instrument_mem_region_access (tree base, tree len,
       || integer_zerop (len))
     return;
 
-  /* If the beginning of the memory region has already been
-     instrumented, do not instrument it.  */
-  bool start_instrumented = has_mem_ref_been_instrumented (base, 1);
-
-  /* If the end of the memory region has already been instrumented, do
-     not instrument it.  */
-  tree end = asan_mem_ref_get_end (base, len);
-  bool end_instrumented = has_mem_ref_been_instrumented (end, 1);
-
   HOST_WIDE_INT size_in_bytes = tree_fits_shwi_p (len) ? tree_to_shwi (len) : -1;
 
-  build_check_stmt (location, base, len, size_in_bytes, iter,
-                   /*non_zero_len_p*/size_in_bytes > 0, /*before_p*/true,
-                   is_store, /*is_scalar_access*/false, /*align*/0,
-                   start_instrumented, end_instrumented);
-
-  update_mem_ref_hash_table (base, 1);
-  if (size_in_bytes != -1)
-    update_mem_ref_hash_table (end, 1);
+  if ((size_in_bytes == -1)
+      || !has_mem_ref_been_instrumented (base, size_in_bytes))
+    {
+      build_check_stmt (location, base, len, size_in_bytes, iter,
+                       /*is_non_zero_len*/size_in_bytes > 0, /*before_p*/true,
+                       is_store, /*is_scalar_access*/false, /*align*/0);
+    }
 
+  maybe_update_mem_ref_hash_table (base, len);
   *iter = gsi_for_stmt (gsi_stmt (*iter));
 }
 
-/* Instrument the call (to the builtin strlen function) pointed to by
-   ITER.
-
-   This function instruments the access to the first byte of the
-   argument, right before the call.  After the call it instruments the
-   access to the last byte of the argument; it uses the result of the
-   call to deduce the offset of that last byte.
-
-   Upon completion, iff the call has actually been instrumented, this
-   function returns TRUE and *ITER points to the statement logically
-   following the built-in strlen function call *ITER was initially
-   pointing to.  Otherwise, the function returns FALSE and *ITER
-   remains unchanged.  */
-
-static bool
-instrument_strlen_call (gimple_stmt_iterator *iter)
-{
-  gimple call = gsi_stmt (*iter);
-  gcc_assert (is_gimple_call (call));
-
-  tree callee = gimple_call_fndecl (call);
-  gcc_assert (is_builtin_fn (callee)
-             && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL
-             && DECL_FUNCTION_CODE (callee) == BUILT_IN_STRLEN);
-
-  tree len = gimple_call_lhs (call);
-  if (len == NULL)
-    /* Some passes might clear the return value of the strlen call;
-       bail out in that case.  Return FALSE as we are not advancing
-       *ITER.  */
-    return false;
-  gcc_assert (INTEGRAL_TYPE_P (TREE_TYPE (len)));
-
-  location_t loc = gimple_location (call);
-  tree str_arg = gimple_call_arg (call, 0);
-  bool start_instrumented = has_mem_ref_been_instrumented (str_arg, 1);
-
-  tree cptr_type = build_pointer_type (char_type_node);
-  gimple str_arg_ssa =
-    gimple_build_assign_with_ops (NOP_EXPR,
-                                 make_ssa_name (cptr_type, NULL),
-                                 str_arg, NULL);
-  gimple_set_location (str_arg_ssa, loc);
-  gsi_insert_before (iter, str_arg_ssa, GSI_SAME_STMT);
-
-  build_check_stmt (loc, gimple_assign_lhs (str_arg_ssa), NULL_TREE, 1, iter,
-                   /*non_zero_len_p*/true, /*before_p=*/true,
-                   /*is_store=*/false, /*is_scalar_access*/true, /*align*/0,
-                   start_instrumented, start_instrumented);
-
-  gimple g =
-    gimple_build_assign_with_ops (POINTER_PLUS_EXPR,
-                                 make_ssa_name (cptr_type, NULL),
-                                 gimple_assign_lhs (str_arg_ssa),
-                                 len);
-  gimple_set_location (g, loc);
-  gsi_insert_after (iter, g, GSI_NEW_STMT);
-
-  build_check_stmt (loc, gimple_assign_lhs (g), NULL_TREE, 1, iter,
-                   /*non_zero_len_p*/true, /*before_p=*/false,
-                   /*is_store=*/false, /*is_scalar_access*/true, /*align*/0);
-
-  return true;
-}
-
 /* Instrument the call to a built-in memory access function that is
    pointed to by the iterator ITER.
 
@@ -2071,53 +1991,58 @@ instrument_builtin_call (gimple_stmt_iterator *iter)
     return false;
 
   bool iter_advanced_p = false;
-  gimple call = gsi_stmt (*iter);
+  gcall *call = as_a <gcall *> (gsi_stmt (*iter));
 
   gcc_checking_assert (gimple_call_builtin_p (call, BUILT_IN_NORMAL));
 
-  tree callee = gimple_call_fndecl (call);
   location_t loc = gimple_location (call);
 
-  if (DECL_FUNCTION_CODE (callee) == BUILT_IN_STRLEN)
-    iter_advanced_p = instrument_strlen_call (iter);
-  else
-    {
-      asan_mem_ref src0, src1, dest;
-      asan_mem_ref_init (&src0, NULL, 1);
-      asan_mem_ref_init (&src1, NULL, 1);
-      asan_mem_ref_init (&dest, NULL, 1);
+  asan_mem_ref src0, src1, dest;
+  asan_mem_ref_init (&src0, NULL, 1);
+  asan_mem_ref_init (&src1, NULL, 1);
+  asan_mem_ref_init (&dest, NULL, 1);
 
-      tree src0_len = NULL_TREE, src1_len = NULL_TREE, dest_len = NULL_TREE;
-      bool src0_is_store = false, src1_is_store = false,
-       dest_is_store = false, dest_is_deref = false;
+  tree src0_len = NULL_TREE, src1_len = NULL_TREE, dest_len = NULL_TREE;
+  bool src0_is_store = false, src1_is_store = false, dest_is_store = false,
+    dest_is_deref = false, intercepted_p = true;
 
-      if (get_mem_refs_of_builtin_call (call,
-                                       &src0, &src0_len, &src0_is_store,
-                                       &src1, &src1_len, &src1_is_store,
-                                       &dest, &dest_len, &dest_is_store,
-                                       &dest_is_deref))
+  if (get_mem_refs_of_builtin_call (call,
+                                   &src0, &src0_len, &src0_is_store,
+                                   &src1, &src1_len, &src1_is_store,
+                                   &dest, &dest_len, &dest_is_store,
+                                   &dest_is_deref, &intercepted_p))
+    {
+      if (dest_is_deref)
        {
-         if (dest_is_deref)
-           {
-             instrument_derefs (iter, dest.start, loc, dest_is_store);
-             gsi_next (iter);
-             iter_advanced_p = true;
-           }
-         else if (src0_len || src1_len || dest_len)
-           {
-             if (src0.start != NULL_TREE)
-               instrument_mem_region_access (src0.start, src0_len,
-                                             iter, loc, /*is_store=*/false);
-             if (src1.start != NULL_TREE)
-               instrument_mem_region_access (src1.start, src1_len,
-                                             iter, loc, /*is_store=*/false);
-             if (dest.start != NULL_TREE)
-               instrument_mem_region_access (dest.start, dest_len,
-                                             iter, loc, /*is_store=*/true);
-             *iter = gsi_for_stmt (call);
-             gsi_next (iter);
-             iter_advanced_p = true;
-           }
+         instrument_derefs (iter, dest.start, loc, dest_is_store);
+         gsi_next (iter);
+         iter_advanced_p = true;
+       }
+      else if (!intercepted_p
+              && (src0_len || src1_len || dest_len))
+       {
+         if (src0.start != NULL_TREE)
+           instrument_mem_region_access (src0.start, src0_len,
+                                         iter, loc, /*is_store=*/false);
+         if (src1.start != NULL_TREE)
+           instrument_mem_region_access (src1.start, src1_len,
+                                         iter, loc, /*is_store=*/false);
+         if (dest.start != NULL_TREE)
+           instrument_mem_region_access (dest.start, dest_len,
+                                         iter, loc, /*is_store=*/true);
+
+         *iter = gsi_for_stmt (call);
+         gsi_next (iter);
+         iter_advanced_p = true;
+       }
+      else
+       {
+         if (src0.start != NULL_TREE)
+           maybe_update_mem_ref_hash_table (src0.start, src0_len);
+         if (src1.start != NULL_TREE)
+           maybe_update_mem_ref_hash_table (src1.start, src1_len);
+         if (dest.start != NULL_TREE)
+           maybe_update_mem_ref_hash_table (dest.start, dest_len);
        }
     }
   return iter_advanced_p;
@@ -2133,7 +2058,7 @@ instrument_builtin_call (gimple_stmt_iterator *iter)
 static bool
 maybe_instrument_assignment (gimple_stmt_iterator *iter)
 {
-  gimple s = gsi_stmt (*iter);
+  gimple *s = gsi_stmt (*iter);
 
   gcc_assert (gimple_assign_single_p (s));
 
@@ -2149,7 +2074,7 @@ maybe_instrument_assignment (gimple_stmt_iterator *iter)
                         is_store);
       is_instrumented = true;
     }
+
   if (gimple_assign_load_p (s))
     {
       ref_expr = gimple_assign_rhs1 (s);
@@ -2177,7 +2102,7 @@ maybe_instrument_assignment (gimple_stmt_iterator *iter)
 static bool
 maybe_instrument_call (gimple_stmt_iterator *iter)
 {
-  gimple stmt = gsi_stmt (*iter);
+  gimple *stmt = gsi_stmt (*iter);
   bool is_builtin = gimple_call_builtin_p (stmt, BUILT_IN_NORMAL);
 
   if (is_builtin && instrument_builtin_call (iter))
@@ -2194,14 +2119,48 @@ maybe_instrument_call (gimple_stmt_iterator *iter)
            case BUILT_IN_TRAP:
              /* Don't instrument these.  */
              return false;
+           default:
+             break;
            }
        }
       tree decl = builtin_decl_implicit (BUILT_IN_ASAN_HANDLE_NO_RETURN);
-      gimple g = gimple_build_call (decl, 0);
+      gimple *g = gimple_build_call (decl, 0);
       gimple_set_location (g, gimple_location (stmt));
       gsi_insert_before (iter, g, GSI_SAME_STMT);
     }
-  return false;
+
+  bool instrumented = false;
+  if (gimple_store_p (stmt))
+    {
+      tree ref_expr = gimple_call_lhs (stmt);
+      instrument_derefs (iter, ref_expr,
+                        gimple_location (stmt),
+                        /*is_store=*/true);
+
+      instrumented = true;
+    }
+
+  /* Walk through gimple_call arguments and check them id needed.  */
+  unsigned args_num = gimple_call_num_args (stmt);
+  for (unsigned i = 0; i < args_num; ++i)
+    {
+      tree arg = gimple_call_arg (stmt, i);
+      /* If ARG is not a non-aggregate register variable, compiler in general
+        creates temporary for it and pass it as argument to gimple call.
+        But in some cases, e.g. when we pass by value a small structure that
+        fits to register, compiler can avoid extra overhead by pulling out
+        these temporaries.  In this case, we should check the argument.  */
+      if (!is_gimple_reg (arg) && !is_gimple_min_invariant (arg))
+       {
+         instrument_derefs (iter, arg,
+                            gimple_location (stmt),
+                            /*is_store=*/false);
+         instrumented = true;
+       }
+    }
+  if (instrumented)
+    gsi_next (iter);
+  return instrumented;
 }
 
 /* Walk each instruction of all basic block and instrument those that
@@ -2239,11 +2198,12 @@ transform_statements (void)
 
       for (i = gsi_start_bb (bb); !gsi_end_p (i);)
        {
-         gimple s = gsi_stmt (i);
+         gimple *s = gsi_stmt (i);
 
          if (has_stmt_been_instrumented_p (s))
            gsi_next (&i);
          else if (gimple_assign_single_p (s)
+                  && !gimple_clobber_p (s)
                   && maybe_instrument_assignment (&i))
            /*  Nothing to do as maybe_instrument_assignment advanced
                the iterator I.  */;
@@ -2257,8 +2217,11 @@ transform_statements (void)
                 If the current instruction is a function call that
                 might free something, let's forget about the memory
                 references that got instrumented.  Otherwise we might
-                miss some instrumentation opportunities.  */
-             if (is_gimple_call (s) && !nonfreeing_call_p (s))
+                miss some instrumentation opportunities.  Do the same
+                for a ASAN_MARK poisoning internal function.  */
+             if (is_gimple_call (s)
+                 && (!nonfreeing_call_p (s)
+                     || asan_mark_p (s, ASAN_MARK_POISON)))
                empty_mem_ref_hash_table ();
 
              gsi_next (&i);
@@ -2277,6 +2240,9 @@ transform_statements (void)
 tree
 asan_dynamic_init_call (bool after_p)
 {
+  if (shadow_ptr_types[0] == NULL_TREE)
+    asan_init_shadow_ptr_types ();
+
   tree fn = builtin_decl_implicit (after_p
                                   ? BUILT_IN_ASAN_AFTER_DYNAMIC_INIT
                                   : BUILT_IN_ASAN_BEFORE_DYNAMIC_INIT);
@@ -2286,8 +2252,6 @@ asan_dynamic_init_call (bool after_p)
       pretty_printer module_name_pp;
       pp_string (&module_name_pp, main_input_filename);
 
-      if (shadow_ptr_types[0] == NULL_TREE)
-       asan_init_shadow_ptr_types ();
       module_name_cst = asan_pp_string (&module_name_pp);
       module_name_cst = fold_convert (const_ptr_type_node,
                                      module_name_cst);
@@ -2305,19 +2269,22 @@ asan_dynamic_init_call (bool after_p)
      const void *__name;
      const void *__module_name;
      uptr __has_dynamic_init;
+     __asan_global_source_location *__location;
+     char *__odr_indicator;
    } type.  */
 
 static tree
 asan_global_struct (void)
 {
-  static const char *field_names[6]
+  static const char *field_names[]
     = { "__beg", "__size", "__size_with_redzone",
-       "__name", "__module_name", "__has_dynamic_init" };
-  tree fields[6], ret;
-  int i;
+       "__name", "__module_name", "__has_dynamic_init", "__location",
+       "__odr_indicator" };
+  tree fields[ARRAY_SIZE (field_names)], ret;
+  unsigned i;
 
   ret = make_node (RECORD_TYPE);
-  for (i = 0; i < 6; i++)
+  for (i = 0; i < ARRAY_SIZE (field_names); i++)
     {
       fields[i]
        = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
@@ -2328,12 +2295,74 @@ asan_global_struct (void)
       if (i)
        DECL_CHAIN (fields[i - 1]) = fields[i];
     }
+  tree type_decl = build_decl (input_location, TYPE_DECL,
+                              get_identifier ("__asan_global"), ret);
+  DECL_IGNORED_P (type_decl) = 1;
+  DECL_ARTIFICIAL (type_decl) = 1;
   TYPE_FIELDS (ret) = fields[0];
-  TYPE_NAME (ret) = get_identifier ("__asan_global");
+  TYPE_NAME (ret) = type_decl;
+  TYPE_STUB_DECL (ret) = type_decl;
   layout_type (ret);
   return ret;
 }
 
+/* Create and return odr indicator symbol for DECL.
+   TYPE is __asan_global struct type as returned by asan_global_struct.  */
+
+static tree
+create_odr_indicator (tree decl, tree type)
+{
+  char *name;
+  tree uptr = TREE_TYPE (DECL_CHAIN (TYPE_FIELDS (type)));
+  tree decl_name
+    = (HAS_DECL_ASSEMBLER_NAME_P (decl) ? DECL_ASSEMBLER_NAME (decl)
+                                       : DECL_NAME (decl));
+  /* DECL_NAME theoretically might be NULL.  Bail out with 0 in this case.  */
+  if (decl_name == NULL_TREE)
+    return build_int_cst (uptr, 0);
+  size_t len = strlen (IDENTIFIER_POINTER (decl_name)) + sizeof ("__odr_asan_");
+  name = XALLOCAVEC (char, len);
+  snprintf (name, len, "__odr_asan_%s", IDENTIFIER_POINTER (decl_name));
+#ifndef NO_DOT_IN_LABEL
+  name[sizeof ("__odr_asan") - 1] = '.';
+#elif !defined(NO_DOLLAR_IN_LABEL)
+  name[sizeof ("__odr_asan") - 1] = '$';
+#endif
+  tree var = build_decl (UNKNOWN_LOCATION, VAR_DECL, get_identifier (name),
+                        char_type_node);
+  TREE_ADDRESSABLE (var) = 1;
+  TREE_READONLY (var) = 0;
+  TREE_THIS_VOLATILE (var) = 1;
+  DECL_GIMPLE_REG_P (var) = 0;
+  DECL_ARTIFICIAL (var) = 1;
+  DECL_IGNORED_P (var) = 1;
+  TREE_STATIC (var) = 1;
+  TREE_PUBLIC (var) = 1;
+  DECL_VISIBILITY (var) = DECL_VISIBILITY (decl);
+  DECL_VISIBILITY_SPECIFIED (var) = DECL_VISIBILITY_SPECIFIED (decl);
+
+  TREE_USED (var) = 1;
+  tree ctor = build_constructor_va (TREE_TYPE (var), 1, NULL_TREE,
+                                   build_int_cst (unsigned_type_node, 0));
+  TREE_CONSTANT (ctor) = 1;
+  TREE_STATIC (ctor) = 1;
+  DECL_INITIAL (var) = ctor;
+  DECL_ATTRIBUTES (var) = tree_cons (get_identifier ("asan odr indicator"),
+                                    NULL, DECL_ATTRIBUTES (var));
+  make_decl_rtl (var);
+  varpool_node::finalize_decl (var);
+  return fold_convert (uptr, build_fold_addr_expr (var));
+}
+
+/* Return true if DECL, a global var, might be overridden and needs
+   an additional odr indicator symbol.  */
+
+static bool
+asan_needs_odr_indicator_p (tree decl)
+{
+  return !DECL_ARTIFICIAL (decl) && !DECL_WEAK (decl) && TREE_PUBLIC (decl);
+}
+
 /* Append description of a single global DECL into vector V.
    TYPE is __asan_global struct type as returned by asan_global_struct.  */
 
@@ -2374,6 +2403,9 @@ asan_add_global (tree decl, tree type, vec<constructor_elt, va_gc> *v)
       assemble_alias (refdecl, DECL_ASSEMBLER_NAME (decl));
     }
 
+  tree odr_indicator_ptr
+    = (asan_needs_odr_indicator_p (decl) ? create_odr_indicator (decl, type)
+                                        : build_int_cst (uptr, 0));
   CONSTRUCTOR_APPEND_ELT (vinner, NULL_TREE,
                          fold_convert (const_ptr_type_node,
                                        build_fold_addr_expr (refdecl)));
@@ -2389,6 +2421,39 @@ asan_add_global (tree decl, tree type, vec<constructor_elt, va_gc> *v)
   int has_dynamic_init = vnode ? vnode->dynamically_initialized : 0;
   CONSTRUCTOR_APPEND_ELT (vinner, NULL_TREE,
                          build_int_cst (uptr, has_dynamic_init));
+  tree locptr = NULL_TREE;
+  location_t loc = DECL_SOURCE_LOCATION (decl);
+  expanded_location xloc = expand_location (loc);
+  if (xloc.file != NULL)
+    {
+      static int lasanloccnt = 0;
+      char buf[25];
+      ASM_GENERATE_INTERNAL_LABEL (buf, "LASANLOC", ++lasanloccnt);
+      tree var = build_decl (UNKNOWN_LOCATION, VAR_DECL, get_identifier (buf),
+                            ubsan_get_source_location_type ());
+      TREE_STATIC (var) = 1;
+      TREE_PUBLIC (var) = 0;
+      DECL_ARTIFICIAL (var) = 1;
+      DECL_IGNORED_P (var) = 1;
+      pretty_printer filename_pp;
+      pp_string (&filename_pp, xloc.file);
+      tree str = asan_pp_string (&filename_pp);
+      tree ctor = build_constructor_va (TREE_TYPE (var), 3,
+                                       NULL_TREE, str, NULL_TREE,
+                                       build_int_cst (unsigned_type_node,
+                                                      xloc.line), NULL_TREE,
+                                       build_int_cst (unsigned_type_node,
+                                                      xloc.column));
+      TREE_CONSTANT (ctor) = 1;
+      TREE_STATIC (ctor) = 1;
+      DECL_INITIAL (var) = ctor;
+      varpool_node::finalize_decl (var);
+      locptr = fold_convert (uptr, build_fold_addr_expr (var));
+    }
+  else
+    locptr = build_int_cst (uptr, 0);
+  CONSTRUCTOR_APPEND_ELT (vinner, NULL_TREE, locptr);
+  CONSTRUCTOR_APPEND_ELT (vinner, NULL_TREE, odr_indicator_ptr);
   init = build_constructor (type, vinner);
   CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, init);
 }
@@ -2418,6 +2483,9 @@ initialize_sanitizer_builtins (void)
                                pointer_sized_int_node, NULL_TREE);
   tree BT_FN_VOID_INT
     = build_function_type_list (void_type_node, integer_type_node, NULL_TREE);
+  tree BT_FN_SIZE_CONST_PTR_INT
+    = build_function_type_list (size_type_node, const_ptr_type_node,
+                               integer_type_node, NULL_TREE);
   tree BT_FN_BOOL_VPTR_PTR_IX_INT_INT[5];
   tree BT_FN_IX_CONST_VPTR_INT[5];
   tree BT_FN_IX_VPTR_IX_INT[5];
@@ -2474,6 +2542,9 @@ initialize_sanitizer_builtins (void)
 #define ATTR_TMPURE_NOTHROW_LEAF_LIST ECF_TM_PURE | ATTR_NOTHROW_LEAF_LIST
 #undef ATTR_NORETURN_NOTHROW_LEAF_LIST
 #define ATTR_NORETURN_NOTHROW_LEAF_LIST ECF_NORETURN | ATTR_NOTHROW_LEAF_LIST
+#undef ATTR_CONST_NORETURN_NOTHROW_LEAF_LIST
+#define ATTR_CONST_NORETURN_NOTHROW_LEAF_LIST \
+  ECF_CONST | ATTR_NORETURN_NOTHROW_LEAF_LIST
 #undef ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST
 #define ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST \
   ECF_TM_PURE | ATTR_NORETURN_NOTHROW_LEAF_LIST
@@ -2483,6 +2554,13 @@ initialize_sanitizer_builtins (void)
 #undef ATTR_COLD_NORETURN_NOTHROW_LEAF_LIST
 #define ATTR_COLD_NORETURN_NOTHROW_LEAF_LIST \
   /* ECF_COLD missing */ ATTR_NORETURN_NOTHROW_LEAF_LIST
+#undef ATTR_COLD_CONST_NORETURN_NOTHROW_LEAF_LIST
+#define ATTR_COLD_CONST_NORETURN_NOTHROW_LEAF_LIST \
+  /* ECF_COLD missing */ ATTR_CONST_NORETURN_NOTHROW_LEAF_LIST
+#undef ATTR_PURE_NOTHROW_LEAF_LIST
+#define ATTR_PURE_NOTHROW_LEAF_LIST ECF_PURE | ATTR_NOTHROW_LEAF_LIST
+#undef DEF_BUILTIN_STUB
+#define DEF_BUILTIN_STUB(ENUM, NAME)
 #undef DEF_SANITIZER_BUILTIN
 #define DEF_SANITIZER_BUILTIN(ENUM, NAME, TYPE, ATTRS) \
   decl = add_builtin_function ("__builtin_" NAME, TYPE, ENUM,          \
@@ -2492,21 +2570,31 @@ initialize_sanitizer_builtins (void)
 
 #include "sanitizer.def"
 
+  /* -fsanitize=object-size uses __builtin_object_size, but that might
+     not be available for e.g. Fortran at this point.  We use
+     DEF_SANITIZER_BUILTIN here only as a convenience macro.  */
+  if ((flag_sanitize & SANITIZE_OBJECT_SIZE)
+      && !builtin_decl_implicit_p (BUILT_IN_OBJECT_SIZE))
+    DEF_SANITIZER_BUILTIN (BUILT_IN_OBJECT_SIZE, "object_size",
+                          BT_FN_SIZE_CONST_PTR_INT,
+                          ATTR_PURE_NOTHROW_LEAF_LIST)
+
 #undef DEF_SANITIZER_BUILTIN
+#undef DEF_BUILTIN_STUB
 }
 
 /* Called via htab_traverse.  Count number of emitted
    STRING_CSTs in the constant hash table.  */
 
-static int
-count_string_csts (void **slot, void *data)
+int
+count_string_csts (constant_descriptor_tree **slot,
+                  unsigned HOST_WIDE_INT *data)
 {
-  struct constant_descriptor_tree *desc
-    = (struct constant_descriptor_tree *) *slot;
+  struct constant_descriptor_tree *desc = *slot;
   if (TREE_CODE (desc->value) == STRING_CST
       && TREE_ASM_WRITTEN (desc->value)
       && asan_protect_global (desc->value))
-    ++*((unsigned HOST_WIDE_INT *) data);
+    ++*data;
   return 1;
 }
 
@@ -2519,20 +2607,18 @@ struct asan_add_string_csts_data
   vec<constructor_elt, va_gc> *v;
 };
 
-/* Called via htab_traverse.  Call asan_add_global
+/* Called via hash_table::traverse.  Call asan_add_global
    on emitted STRING_CSTs from the constant hash table.  */
 
-static int
-add_string_csts (void **slot, void *data)
+int
+add_string_csts (constant_descriptor_tree **slot,
+                asan_add_string_csts_data *aascd)
 {
-  struct constant_descriptor_tree *desc
-    = (struct constant_descriptor_tree *) *slot;
+  struct constant_descriptor_tree *desc = *slot;
   if (TREE_CODE (desc->value) == STRING_CST
       && TREE_ASM_WRITTEN (desc->value)
       && asan_protect_global (desc->value))
     {
-      struct asan_add_string_csts_data *aascd
-       = (struct asan_add_string_csts_data *) data;
       asan_add_global (SYMBOL_REF_DECL (XEXP (desc->rtl, 0)),
                       aascd->type, aascd->v);
     }
@@ -2561,14 +2647,27 @@ asan_finish_file (void)
      nor after .LASAN* array.  */
   flag_sanitize &= ~SANITIZE_ADDRESS;
 
-  tree fn = builtin_decl_implicit (BUILT_IN_ASAN_INIT);
-  append_to_statement_list (build_call_expr (fn, 0), &asan_ctor_statements);
+  /* For user-space we want asan constructors to run first.
+     Linux kernel does not support priorities other than default, and the only
+     other user of constructors is coverage. So we run with the default
+     priority.  */
+  int priority = flag_sanitize & SANITIZE_USER_ADDRESS
+                 ? MAX_RESERVED_INIT_PRIORITY - 1 : DEFAULT_INIT_PRIORITY;
+
+  if (flag_sanitize & SANITIZE_USER_ADDRESS)
+    {
+      tree fn = builtin_decl_implicit (BUILT_IN_ASAN_INIT);
+      append_to_statement_list (build_call_expr (fn, 0), &asan_ctor_statements);
+      fn = builtin_decl_implicit (BUILT_IN_ASAN_VERSION_MISMATCH_CHECK);
+      append_to_statement_list (build_call_expr (fn, 0), &asan_ctor_statements);
+    }
   FOR_EACH_DEFINED_VARIABLE (vnode)
     if (TREE_ASM_WRITTEN (vnode->decl)
        && asan_protect_global (vnode->decl))
       ++gcount;
-  htab_t const_desc_htab = constant_pool_htab ();
-  htab_traverse (const_desc_htab, count_string_csts, &gcount);
+  hash_table<tree_descriptor_hasher> *const_desc_htab = constant_pool_htab ();
+  const_desc_htab->traverse<unsigned HOST_WIDE_INT *, count_string_csts>
+    (&gcount);
   if (gcount)
     {
       tree type = asan_global_struct (), var, ctor;
@@ -2592,14 +2691,15 @@ asan_finish_file (void)
       struct asan_add_string_csts_data aascd;
       aascd.type = TREE_TYPE (type);
       aascd.v = v;
-      htab_traverse (const_desc_htab, add_string_csts, &aascd);
+      const_desc_htab->traverse<asan_add_string_csts_data *, add_string_csts>
+               (&aascd);
       ctor = build_constructor (type, v);
       TREE_CONSTANT (ctor) = 1;
       TREE_STATIC (ctor) = 1;
       DECL_INITIAL (var) = ctor;
       varpool_node::finalize_decl (var);
 
-      fn = builtin_decl_implicit (BUILT_IN_ASAN_REGISTER_GLOBALS);
+      tree fn = builtin_decl_implicit (BUILT_IN_ASAN_REGISTER_GLOBALS);
       tree gcount_tree = build_int_cst (pointer_sized_int_node, gcount);
       append_to_statement_list (build_call_expr (fn, 2,
                                                 build_fold_addr_expr (var),
@@ -2611,14 +2711,350 @@ asan_finish_file (void)
                                                 build_fold_addr_expr (var),
                                                 gcount_tree),
                                &dtor_statements);
-      cgraph_build_static_cdtor ('D', dtor_statements,
-                                MAX_RESERVED_INIT_PRIORITY - 1);
+      cgraph_build_static_cdtor ('D', dtor_statements, priority);
     }
-  cgraph_build_static_cdtor ('I', asan_ctor_statements,
-                            MAX_RESERVED_INIT_PRIORITY - 1);
+  if (asan_ctor_statements)
+    cgraph_build_static_cdtor ('I', asan_ctor_statements, priority);
   flag_sanitize |= SANITIZE_ADDRESS;
 }
 
+/* Poison or unpoison (depending on IS_CLOBBER variable) shadow memory based
+   on SHADOW address.  Newly added statements will be added to ITER with
+   given location LOC.  We mark SIZE bytes in shadow memory, where
+   LAST_CHUNK_SIZE is greater than zero in situation where we are at the
+   end of a variable.  */
+
+static void
+asan_store_shadow_bytes (gimple_stmt_iterator *iter, location_t loc,
+                        tree shadow,
+                        unsigned HOST_WIDE_INT base_addr_offset,
+                        bool is_clobber, unsigned size,
+                        unsigned last_chunk_size)
+{
+  tree shadow_ptr_type;
+
+  switch (size)
+    {
+    case 1:
+      shadow_ptr_type = shadow_ptr_types[0];
+      break;
+    case 2:
+      shadow_ptr_type = shadow_ptr_types[1];
+      break;
+    case 4:
+      shadow_ptr_type = shadow_ptr_types[2];
+      break;
+    default:
+      gcc_unreachable ();
+    }
+
+  unsigned char c = (char) is_clobber ? ASAN_STACK_MAGIC_USE_AFTER_SCOPE : 0;
+  unsigned HOST_WIDE_INT val = 0;
+  for (unsigned i = 0; i < size; ++i)
+    {
+      unsigned char shadow_c = c;
+      if (i == size - 1 && last_chunk_size && !is_clobber)
+       shadow_c = last_chunk_size;
+      val |= (unsigned HOST_WIDE_INT) shadow_c << (BITS_PER_UNIT * i);
+    }
+
+  /* Handle last chunk in unpoisoning.  */
+  tree magic = build_int_cst (TREE_TYPE (shadow_ptr_type), val);
+
+  tree dest = build2 (MEM_REF, TREE_TYPE (shadow_ptr_type), shadow,
+                     build_int_cst (shadow_ptr_type, base_addr_offset));
+
+  gimple *g = gimple_build_assign (dest, magic);
+  gimple_set_location (g, loc);
+  gsi_insert_after (iter, g, GSI_NEW_STMT);
+}
+
+/* Expand the ASAN_MARK builtins.  */
+
+bool
+asan_expand_mark_ifn (gimple_stmt_iterator *iter)
+{
+  gimple *g = gsi_stmt (*iter);
+  location_t loc = gimple_location (g);
+  HOST_WIDE_INT flag = tree_to_shwi (gimple_call_arg (g, 0));
+  bool is_poison = ((asan_mark_flags)flag) == ASAN_MARK_POISON;
+
+  tree base = gimple_call_arg (g, 1);
+  gcc_checking_assert (TREE_CODE (base) == ADDR_EXPR);
+  tree decl = TREE_OPERAND (base, 0);
+
+  /* For a nested function, we can have: ASAN_MARK (2, &FRAME.2.fp_input, 4) */
+  if (TREE_CODE (decl) == COMPONENT_REF
+      && DECL_NONLOCAL_FRAME (TREE_OPERAND (decl, 0)))
+    decl = TREE_OPERAND (decl, 0);
+
+  gcc_checking_assert (TREE_CODE (decl) == VAR_DECL);
+  if (asan_handled_variables == NULL)
+    asan_handled_variables = new hash_set<tree> (16);
+  asan_handled_variables->add (decl);
+  tree len = gimple_call_arg (g, 2);
+
+  gcc_assert (tree_fits_shwi_p (len));
+  unsigned HOST_WIDE_INT size_in_bytes = tree_to_shwi (len);
+  gcc_assert (size_in_bytes);
+
+  g = gimple_build_assign (make_ssa_name (pointer_sized_int_node),
+                          NOP_EXPR, base);
+  gimple_set_location (g, loc);
+  gsi_replace (iter, g, false);
+  tree base_addr = gimple_assign_lhs (g);
+
+  /* Generate direct emission if size_in_bytes is small.  */
+  if (size_in_bytes <= ASAN_PARAM_USE_AFTER_SCOPE_DIRECT_EMISSION_THRESHOLD)
+    {
+      unsigned HOST_WIDE_INT shadow_size = shadow_mem_size (size_in_bytes);
+
+      tree shadow = build_shadow_mem_access (iter, loc, base_addr,
+                                            shadow_ptr_types[0], true);
+
+      for (unsigned HOST_WIDE_INT offset = 0; offset < shadow_size;)
+       {
+         unsigned size = 1;
+         if (shadow_size - offset >= 4)
+           size = 4;
+         else if (shadow_size - offset >= 2)
+           size = 2;
+
+         unsigned HOST_WIDE_INT last_chunk_size = 0;
+         unsigned HOST_WIDE_INT s = (offset + size) * ASAN_SHADOW_GRANULARITY;
+         if (s > size_in_bytes)
+           last_chunk_size = ASAN_SHADOW_GRANULARITY - (s - size_in_bytes);
+
+         asan_store_shadow_bytes (iter, loc, shadow, offset, is_poison,
+                                  size, last_chunk_size);
+         offset += size;
+       }
+    }
+  else
+    {
+      g = gimple_build_assign (make_ssa_name (pointer_sized_int_node),
+                              NOP_EXPR, len);
+      gimple_set_location (g, loc);
+      gsi_insert_before (iter, g, GSI_SAME_STMT);
+      tree sz_arg = gimple_assign_lhs (g);
+
+      tree fun
+       = builtin_decl_implicit (is_poison ? BUILT_IN_ASAN_POISON_STACK_MEMORY
+                                : BUILT_IN_ASAN_UNPOISON_STACK_MEMORY);
+      g = gimple_build_call (fun, 2, base_addr, sz_arg);
+      gimple_set_location (g, loc);
+      gsi_insert_after (iter, g, GSI_NEW_STMT);
+    }
+
+  return false;
+}
+
+/* Expand the ASAN_{LOAD,STORE} builtins.  */
+
+bool
+asan_expand_check_ifn (gimple_stmt_iterator *iter, bool use_calls)
+{
+  gimple *g = gsi_stmt (*iter);
+  location_t loc = gimple_location (g);
+  bool recover_p;
+  if (flag_sanitize & SANITIZE_USER_ADDRESS)
+    recover_p = (flag_sanitize_recover & SANITIZE_USER_ADDRESS) != 0;
+  else
+    recover_p = (flag_sanitize_recover & SANITIZE_KERNEL_ADDRESS) != 0;
+
+  HOST_WIDE_INT flags = tree_to_shwi (gimple_call_arg (g, 0));
+  gcc_assert (flags < ASAN_CHECK_LAST);
+  bool is_scalar_access = (flags & ASAN_CHECK_SCALAR_ACCESS) != 0;
+  bool is_store = (flags & ASAN_CHECK_STORE) != 0;
+  bool is_non_zero_len = (flags & ASAN_CHECK_NON_ZERO_LEN) != 0;
+
+  tree base = gimple_call_arg (g, 1);
+  tree len = gimple_call_arg (g, 2);
+  HOST_WIDE_INT align = tree_to_shwi (gimple_call_arg (g, 3));
+
+  HOST_WIDE_INT size_in_bytes
+    = is_scalar_access && tree_fits_shwi_p (len) ? tree_to_shwi (len) : -1;
+
+  if (use_calls)
+    {
+      /* Instrument using callbacks.  */
+      gimple *g = gimple_build_assign (make_ssa_name (pointer_sized_int_node),
+                                     NOP_EXPR, base);
+      gimple_set_location (g, loc);
+      gsi_insert_before (iter, g, GSI_SAME_STMT);
+      tree base_addr = gimple_assign_lhs (g);
+
+      int nargs;
+      tree fun = check_func (is_store, recover_p, size_in_bytes, &nargs);
+      if (nargs == 1)
+       g = gimple_build_call (fun, 1, base_addr);
+      else
+       {
+         gcc_assert (nargs == 2);
+         g = gimple_build_assign (make_ssa_name (pointer_sized_int_node),
+                                  NOP_EXPR, len);
+         gimple_set_location (g, loc);
+         gsi_insert_before (iter, g, GSI_SAME_STMT);
+         tree sz_arg = gimple_assign_lhs (g);
+         g = gimple_build_call (fun, nargs, base_addr, sz_arg);
+       }
+      gimple_set_location (g, loc);
+      gsi_replace (iter, g, false);
+      return false;
+    }
+
+  HOST_WIDE_INT real_size_in_bytes = size_in_bytes == -1 ? 1 : size_in_bytes;
+
+  tree shadow_ptr_type = shadow_ptr_types[real_size_in_bytes == 16 ? 1 : 0];
+  tree shadow_type = TREE_TYPE (shadow_ptr_type);
+
+  gimple_stmt_iterator gsi = *iter;
+
+  if (!is_non_zero_len)
+    {
+      /* So, the length of the memory area to asan-protect is
+        non-constant.  Let's guard the generated instrumentation code
+        like:
+
+        if (len != 0)
+          {
+            //asan instrumentation code goes here.
+          }
+        // falltrough instructions, starting with *ITER.  */
+
+      g = gimple_build_cond (NE_EXPR,
+                           len,
+                           build_int_cst (TREE_TYPE (len), 0),
+                           NULL_TREE, NULL_TREE);
+      gimple_set_location (g, loc);
+
+      basic_block then_bb, fallthrough_bb;
+      insert_if_then_before_iter (as_a <gcond *> (g), iter,
+                                 /*then_more_likely_p=*/true,
+                                 &then_bb, &fallthrough_bb);
+      /* Note that fallthrough_bb starts with the statement that was
+       pointed to by ITER.  */
+
+      /* The 'then block' of the 'if (len != 0) condition is where
+       we'll generate the asan instrumentation code now.  */
+      gsi = gsi_last_bb (then_bb);
+    }
+
+  /* Get an iterator on the point where we can add the condition
+     statement for the instrumentation.  */
+  basic_block then_bb, else_bb;
+  gsi = create_cond_insert_point (&gsi, /*before_p*/false,
+                                 /*then_more_likely_p=*/false,
+                                 /*create_then_fallthru_edge*/recover_p,
+                                 &then_bb,
+                                 &else_bb);
+
+  g = gimple_build_assign (make_ssa_name (pointer_sized_int_node),
+                          NOP_EXPR, base);
+  gimple_set_location (g, loc);
+  gsi_insert_before (&gsi, g, GSI_NEW_STMT);
+  tree base_addr = gimple_assign_lhs (g);
+
+  tree t = NULL_TREE;
+  if (real_size_in_bytes >= 8)
+    {
+      tree shadow = build_shadow_mem_access (&gsi, loc, base_addr,
+                                            shadow_ptr_type);
+      t = shadow;
+    }
+  else
+    {
+      /* Slow path for 1, 2 and 4 byte accesses.  */
+      /* Test (shadow != 0)
+        & ((base_addr & 7) + (real_size_in_bytes - 1)) >= shadow).  */
+      tree shadow = build_shadow_mem_access (&gsi, loc, base_addr,
+                                            shadow_ptr_type);
+      gimple *shadow_test = build_assign (NE_EXPR, shadow, 0);
+      gimple_seq seq = NULL;
+      gimple_seq_add_stmt (&seq, shadow_test);
+      /* Aligned (>= 8 bytes) can test just
+        (real_size_in_bytes - 1 >= shadow), as base_addr & 7 is known
+        to be 0.  */
+      if (align < 8)
+       {
+         gimple_seq_add_stmt (&seq, build_assign (BIT_AND_EXPR,
+                                                  base_addr, 7));
+         gimple_seq_add_stmt (&seq,
+                              build_type_cast (shadow_type,
+                                               gimple_seq_last (seq)));
+         if (real_size_in_bytes > 1)
+           gimple_seq_add_stmt (&seq,
+                                build_assign (PLUS_EXPR,
+                                              gimple_seq_last (seq),
+                                              real_size_in_bytes - 1));
+         t = gimple_assign_lhs (gimple_seq_last_stmt (seq));
+       }
+      else
+       t = build_int_cst (shadow_type, real_size_in_bytes - 1);
+      gimple_seq_add_stmt (&seq, build_assign (GE_EXPR, t, shadow));
+      gimple_seq_add_stmt (&seq, build_assign (BIT_AND_EXPR, shadow_test,
+                                              gimple_seq_last (seq)));
+      t = gimple_assign_lhs (gimple_seq_last (seq));
+      gimple_seq_set_location (seq, loc);
+      gsi_insert_seq_after (&gsi, seq, GSI_CONTINUE_LINKING);
+
+      /* For non-constant, misaligned or otherwise weird access sizes,
+       check first and last byte.  */
+      if (size_in_bytes == -1)
+       {
+         g = gimple_build_assign (make_ssa_name (pointer_sized_int_node),
+                                  MINUS_EXPR, len,
+                                  build_int_cst (pointer_sized_int_node, 1));
+         gimple_set_location (g, loc);
+         gsi_insert_after (&gsi, g, GSI_NEW_STMT);
+         tree last = gimple_assign_lhs (g);
+         g = gimple_build_assign (make_ssa_name (pointer_sized_int_node),
+                                  PLUS_EXPR, base_addr, last);
+         gimple_set_location (g, loc);
+         gsi_insert_after (&gsi, g, GSI_NEW_STMT);
+         tree base_end_addr = gimple_assign_lhs (g);
+
+         tree shadow = build_shadow_mem_access (&gsi, loc, base_end_addr,
+                                                shadow_ptr_type);
+         gimple *shadow_test = build_assign (NE_EXPR, shadow, 0);
+         gimple_seq seq = NULL;
+         gimple_seq_add_stmt (&seq, shadow_test);
+         gimple_seq_add_stmt (&seq, build_assign (BIT_AND_EXPR,
+                                                  base_end_addr, 7));
+         gimple_seq_add_stmt (&seq, build_type_cast (shadow_type,
+                                                     gimple_seq_last (seq)));
+         gimple_seq_add_stmt (&seq, build_assign (GE_EXPR,
+                                                  gimple_seq_last (seq),
+                                                  shadow));
+         gimple_seq_add_stmt (&seq, build_assign (BIT_AND_EXPR, shadow_test,
+                                                  gimple_seq_last (seq)));
+         gimple_seq_add_stmt (&seq, build_assign (BIT_IOR_EXPR, t,
+                                                  gimple_seq_last (seq)));
+         t = gimple_assign_lhs (gimple_seq_last (seq));
+         gimple_seq_set_location (seq, loc);
+         gsi_insert_seq_after (&gsi, seq, GSI_CONTINUE_LINKING);
+       }
+    }
+
+  g = gimple_build_cond (NE_EXPR, t, build_int_cst (TREE_TYPE (t), 0),
+                        NULL_TREE, NULL_TREE);
+  gimple_set_location (g, loc);
+  gsi_insert_after (&gsi, g, GSI_NEW_STMT);
+
+  /* Generate call to the run-time library (e.g. __asan_report_load8).  */
+  gsi = gsi_start_bb (then_bb);
+  int nargs;
+  tree fun = report_error_func (is_store, recover_p, size_in_bytes, &nargs);
+  g = gimple_build_call (fun, nargs, base_addr, len);
+  gimple_set_location (g, loc);
+  gsi_insert_after (&gsi, g, GSI_NEW_STMT);
+
+  gsi_remove (iter, true);
+  *iter = gsi_start_bb (else_bb);
+
+  return true;
+}
+
 /* Instrument the current function.  */
 
 static unsigned int
@@ -2626,7 +3062,6 @@ asan_instrument (void)
 {
   if (shadow_ptr_types[0] == NULL_TREE)
     asan_init_shadow_ptr_types ();
-  asan_num_accesses = 0;
   transform_statements ();
   return 0;
 }
@@ -2712,88 +3147,4 @@ make_pass_asan_O0 (gcc::context *ctxt)
   return new pass_asan_O0 (ctxt);
 }
 
-/* Perform optimization of sanitize functions.  */
-
-namespace {
-
-const pass_data pass_data_sanopt =
-{
-  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 */
-};
-
-class pass_sanopt : public gimple_opt_pass
-{
-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
-
-unsigned int
-pass_sanopt::execute (function *fun)
-{
-  basic_block bb;
-
-  FOR_EACH_BB_FN (bb, fun)
-    {
-      gimple_stmt_iterator gsi;
-      for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); )
-       {
-         gimple stmt = gsi_stmt (gsi);
-         bool no_next = false;
-
-         if (!is_gimple_call (stmt))
-           {
-             gsi_next (&gsi);
-             continue;
-           }
-
-         if (gimple_call_internal_p (stmt))
-           switch (gimple_call_internal_fn (stmt))
-             {
-             case IFN_UBSAN_NULL:
-               no_next = ubsan_expand_null_ifn (&gsi);
-               break;
-             case IFN_UBSAN_BOUNDS:
-               no_next = ubsan_expand_bounds_ifn (&gsi);
-               break;
-             default:
-               break;
-             }
-
-         if (dump_file && (dump_flags & TDF_DETAILS))
-           {
-             fprintf (dump_file, "Optimized\n  ");
-             print_gimple_stmt (dump_file, stmt, 0, dump_flags);
-             fprintf (dump_file, "\n");
-           }
-
-         if (!no_next)
-           gsi_next (&gsi);
-       }
-    }
-  return 0;
-}
-
-} // anon namespace
-
-gimple_opt_pass *
-make_pass_sanopt (gcc::context *ctxt)
-{
-  return new pass_sanopt (ctxt);
-}
-
 #include "gt-asan.h"