ASAN: Implement dynamic allocas/VLAs sanitization.
authorMaxim Ostapenko <m.ostapenko@samsung.com>
Thu, 6 Jul 2017 16:02:06 +0000 (16:02 +0000)
committerMaxim Ostapenko <chefmax@gcc.gnu.org>
Thu, 6 Jul 2017 16:02:06 +0000 (19:02 +0300)
gcc/
* asan.c: Include gimple-fold.h.
(get_last_alloca_addr): New function.
(handle_builtin_stackrestore): Likewise.
(handle_builtin_alloca): Likewise.
(asan_emit_allocas_unpoison): Likewise.
(get_mem_refs_of_builtin_call): Add new parameter, remove const
quallifier from first paramerer. Handle BUILT_IN_ALLOCA,
BUILT_IN_ALLOCA_WITH_ALIGN and BUILT_IN_STACK_RESTORE builtins.
(instrument_builtin_call): Pass gimple iterator to
get_mem_refs_of_builtin_call.
(last_alloca_addr): New global.
* asan.h (asan_emit_allocas_unpoison): Declare.
* builtins.c (expand_asan_emit_allocas_unpoison): New function.
(expand_builtin): Handle BUILT_IN_ASAN_ALLOCAS_UNPOISON.
* cfgexpand.c (expand_used_vars): Call asan_emit_allocas_unpoison
if function calls alloca.
* gimple-fold.c (replace_call_with_value): Remove static keyword.
* gimple-fold.h (replace_call_with_value): Declare.
* internal-fn.c: Include asan.h.
* sanitizer.def (BUILT_IN_ASAN_ALLOCA_POISON,
BUILT_IN_ASAN_ALLOCAS_UNPOISON): New builtins.

gcc/testsuite/
* c-c++-common/asan/alloca_big_alignment.c: New test.
* c-c++-common/asan/alloca_detect_custom_size.c: Likewise.
* c-c++-common/asan/alloca_instruments_all_paddings.c: Likewise.
* c-c++-common/asan/alloca_loop_unpoisoning.c: Likewise.
* c-c++-common/asan/alloca_overflow_partial.c: Likewise.
* c-c++-common/asan/alloca_overflow_right.c: Likewise.
* c-c++-common/asan/alloca_safe_access.c: Likewise.
* c-c++-common/asan/alloca_underflow_left.c: Likewise.

From-SVN: r250031

18 files changed:
gcc/ChangeLog
gcc/asan.c
gcc/asan.h
gcc/builtins.c
gcc/cfgexpand.c
gcc/gimple-fold.c
gcc/gimple-fold.h
gcc/internal-fn.c
gcc/sanitizer.def
gcc/testsuite/ChangeLog
gcc/testsuite/c-c++-common/asan/alloca_big_alignment.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/asan/alloca_detect_custom_size.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/asan/alloca_instruments_all_paddings.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/asan/alloca_loop_unpoisoning.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/asan/alloca_overflow_partial.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/asan/alloca_overflow_right.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/asan/alloca_safe_access.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/asan/alloca_underflow_left.c [new file with mode: 0644]

index 20fcd8213bb88e84718022052e7da4c014ca7a70..f5614b01dcd81e4a88e0057e39f72dcdbde3e948 100644 (file)
@@ -1,3 +1,27 @@
+2017-07-06  Maxim Ostapenko  <m.ostapenko@samsung.com>
+
+       * asan.c: Include gimple-fold.h.
+       (get_last_alloca_addr): New function.
+       (handle_builtin_stackrestore): Likewise.
+       (handle_builtin_alloca): Likewise.
+       (asan_emit_allocas_unpoison): Likewise.
+       (get_mem_refs_of_builtin_call): Add new parameter, remove const
+       quallifier from first paramerer. Handle BUILT_IN_ALLOCA,
+       BUILT_IN_ALLOCA_WITH_ALIGN and BUILT_IN_STACK_RESTORE builtins.
+       (instrument_builtin_call): Pass gimple iterator to
+       get_mem_refs_of_builtin_call.
+       (last_alloca_addr): New global.
+       * asan.h (asan_emit_allocas_unpoison): Declare.
+       * builtins.c (expand_asan_emit_allocas_unpoison): New function.
+       (expand_builtin): Handle BUILT_IN_ASAN_ALLOCAS_UNPOISON.
+       * cfgexpand.c (expand_used_vars): Call asan_emit_allocas_unpoison
+       if function calls alloca.
+       * gimple-fold.c (replace_call_with_value): Remove static keyword.
+       * gimple-fold.h (replace_call_with_value): Declare.
+       * internal-fn.c: Include asan.h.
+       * sanitizer.def (BUILT_IN_ASAN_ALLOCA_POISON,
+       BUILT_IN_ASAN_ALLOCAS_UNPOISON): New builtins.
+
 2017-07-06  David Malcolm  <dmalcolm@redhat.com>
 
        * Makefile.in (SELFTEST_FLAGS): Drop "-x c", moving it to...
index 533a7ec7bebee39aade2afa166ddbb4a8865d115..252e59fcd4d7c4d127304a08365857b21eec5140 100644 (file)
@@ -55,6 +55,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "langhooks.h"
 #include "cfgloop.h"
 #include "gimple-builder.h"
+#include "gimple-fold.h"
 #include "ubsan.h"
 #include "params.h"
 #include "builtins.h"
@@ -245,6 +246,7 @@ along with GCC; see the file COPYING3.  If not see
 static unsigned HOST_WIDE_INT asan_shadow_offset_value;
 static bool asan_shadow_offset_computed;
 static vec<char *> sanitized_sections;
+static tree last_alloca_addr;
 
 /* Set of variable declarations that are going to be guarded by
    use-after-scope sanitizer.  */
@@ -529,11 +531,186 @@ get_mem_ref_of_assignment (const gassign *assignment,
   return true;
 }
 
+/* Return address of last allocated dynamic alloca.  */
+
+static tree
+get_last_alloca_addr ()
+{
+  if (last_alloca_addr)
+    return last_alloca_addr;
+
+  last_alloca_addr = create_tmp_reg (ptr_type_node, "last_alloca_addr");
+  gassign *g = gimple_build_assign (last_alloca_addr, null_pointer_node);
+  edge e = single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun));
+  gsi_insert_on_edge_immediate (e, g);
+  return last_alloca_addr;
+}
+
+/* Insert __asan_allocas_unpoison (top, bottom) call after
+   __builtin_stack_restore (new_sp) call.
+   The pseudocode of this routine should look like this:
+     __builtin_stack_restore (new_sp);
+     top = last_alloca_addr;
+     bot = new_sp;
+     __asan_allocas_unpoison (top, bot);
+     last_alloca_addr = new_sp;
+   In general, we can't use new_sp as bot parameter because on some
+   architectures SP has non zero offset from dynamic stack area.  Moreover, on
+   some architectures this offset (STACK_DYNAMIC_OFFSET) becomes known for each
+   particular function only after all callees were expanded to rtl.
+   The most noticeable example is PowerPC{,64}, see
+   http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi.html#DYNAM-STACK.
+   To overcome the issue we use following trick: pass new_sp as a second
+   parameter to __asan_allocas_unpoison and rewrite it during expansion with
+   virtual_dynamic_stack_rtx later in expand_asan_emit_allocas_unpoison
+   function.
+*/
+
+static void
+handle_builtin_stack_restore (gcall *call, gimple_stmt_iterator *iter)
+{
+  if (!iter)
+    return;
+
+  tree last_alloca = get_last_alloca_addr ();
+  tree restored_stack = gimple_call_arg (call, 0);
+  tree fn = builtin_decl_implicit (BUILT_IN_ASAN_ALLOCAS_UNPOISON);
+  gimple *g = gimple_build_call (fn, 2, last_alloca, restored_stack);
+  gsi_insert_after (iter, g, GSI_NEW_STMT);
+  g = gimple_build_assign (last_alloca, restored_stack);
+  gsi_insert_after (iter, g, GSI_NEW_STMT);
+}
+
+/* Deploy and poison redzones around __builtin_alloca call.  To do this, we
+   should replace this call with another one with changed parameters and
+   replace all its uses with new address, so
+       addr = __builtin_alloca (old_size, align);
+   is replaced by
+       left_redzone_size = max (align, ASAN_RED_ZONE_SIZE);
+   Following two statements are optimized out if we know that
+   old_size & (ASAN_RED_ZONE_SIZE - 1) == 0, i.e. alloca doesn't need partial
+   redzone.
+       misalign = old_size & (ASAN_RED_ZONE_SIZE - 1);
+       partial_redzone_size = ASAN_RED_ZONE_SIZE - misalign;
+       right_redzone_size = ASAN_RED_ZONE_SIZE;
+       additional_size = left_redzone_size + partial_redzone_size +
+                         right_redzone_size;
+       new_size = old_size + additional_size;
+       new_alloca = __builtin_alloca (new_size, max (align, 32))
+       __asan_alloca_poison (new_alloca, old_size)
+       addr = new_alloca + max (align, ASAN_RED_ZONE_SIZE);
+       last_alloca_addr = new_alloca;
+   ADDITIONAL_SIZE is added to make new memory allocation contain not only
+   requested memory, but also left, partial and right redzones as well as some
+   additional space, required by alignment.  */
+
+static void
+handle_builtin_alloca (gcall *call, gimple_stmt_iterator *iter)
+{
+  if (!iter)
+    return;
+
+  gassign *g;
+  gcall *gg;
+  const HOST_WIDE_INT redzone_mask = ASAN_RED_ZONE_SIZE - 1;
+
+  tree last_alloca = get_last_alloca_addr ();
+  tree callee = gimple_call_fndecl (call);
+  tree old_size = gimple_call_arg (call, 0);
+  tree ptr_type = gimple_call_lhs (call) ? TREE_TYPE (gimple_call_lhs (call))
+                                        : ptr_type_node;
+  tree partial_size = NULL_TREE;
+  bool alloca_with_align
+    = DECL_FUNCTION_CODE (callee) == BUILT_IN_ALLOCA_WITH_ALIGN;
+  unsigned int align
+    = alloca_with_align ? tree_to_uhwi (gimple_call_arg (call, 1)) : 0;
+
+  /* If ALIGN > ASAN_RED_ZONE_SIZE, we embed left redzone into first ALIGN
+     bytes of allocated space.  Otherwise, align alloca to ASAN_RED_ZONE_SIZE
+     manually.  */
+  align = MAX (align, ASAN_RED_ZONE_SIZE * BITS_PER_UNIT);
+
+  tree alloca_rz_mask = build_int_cst (size_type_node, redzone_mask);
+  tree redzone_size = build_int_cst (size_type_node, ASAN_RED_ZONE_SIZE);
+
+  /* Extract lower bits from old_size.  */
+  wide_int size_nonzero_bits = get_nonzero_bits (old_size);
+  wide_int rz_mask
+    = wi::uhwi (redzone_mask, wi::get_precision (size_nonzero_bits));
+  wide_int old_size_lower_bits = wi::bit_and (size_nonzero_bits, rz_mask);
+
+  /* If alloca size is aligned to ASAN_RED_ZONE_SIZE, we don't need partial
+     redzone.  Otherwise, compute its size here.  */
+  if (wi::ne_p (old_size_lower_bits, 0))
+    {
+      /* misalign = size & (ASAN_RED_ZONE_SIZE - 1)
+         partial_size = ASAN_RED_ZONE_SIZE - misalign.  */
+      g = gimple_build_assign (make_ssa_name (size_type_node, NULL),
+                              BIT_AND_EXPR, old_size, alloca_rz_mask);
+      gsi_insert_before (iter, g, GSI_SAME_STMT);
+      tree misalign = gimple_assign_lhs (g);
+      g = gimple_build_assign (make_ssa_name (size_type_node, NULL), MINUS_EXPR,
+                              redzone_size, misalign);
+      gsi_insert_before (iter, g, GSI_SAME_STMT);
+      partial_size = gimple_assign_lhs (g);
+    }
+
+  /* additional_size = align + ASAN_RED_ZONE_SIZE.  */
+  tree additional_size = build_int_cst (size_type_node, align / BITS_PER_UNIT
+                                                       + ASAN_RED_ZONE_SIZE);
+  /* If alloca has partial redzone, include it to additional_size too.  */
+  if (partial_size)
+    {
+      /* additional_size += partial_size.  */
+      g = gimple_build_assign (make_ssa_name (size_type_node), PLUS_EXPR,
+                              partial_size, additional_size);
+      gsi_insert_before (iter, g, GSI_SAME_STMT);
+      additional_size = gimple_assign_lhs (g);
+    }
+
+  /* new_size = old_size + additional_size.  */
+  g = gimple_build_assign (make_ssa_name (size_type_node), PLUS_EXPR, old_size,
+                          additional_size);
+  gsi_insert_before (iter, g, GSI_SAME_STMT);
+  tree new_size = gimple_assign_lhs (g);
+
+  /* Build new __builtin_alloca call:
+       new_alloca_with_rz = __builtin_alloca (new_size, align).  */
+  tree fn = builtin_decl_implicit (BUILT_IN_ALLOCA_WITH_ALIGN);
+  gg = gimple_build_call (fn, 2, new_size,
+                         build_int_cst (size_type_node, align));
+  tree new_alloca_with_rz = make_ssa_name (ptr_type, gg);
+  gimple_call_set_lhs (gg, new_alloca_with_rz);
+  gsi_insert_before (iter, gg, GSI_SAME_STMT);
+
+  /* new_alloca = new_alloca_with_rz + align.  */
+  g = gimple_build_assign (make_ssa_name (ptr_type), POINTER_PLUS_EXPR,
+                          new_alloca_with_rz,
+                          build_int_cst (size_type_node,
+                                         align / BITS_PER_UNIT));
+  gsi_insert_before (iter, g, GSI_SAME_STMT);
+  tree new_alloca = gimple_assign_lhs (g);
+
+  /* Poison newly created alloca redzones:
+      __asan_alloca_poison (new_alloca, old_size).  */
+  fn = builtin_decl_implicit (BUILT_IN_ASAN_ALLOCA_POISON);
+  gg = gimple_build_call (fn, 2, new_alloca, old_size);
+  gsi_insert_before (iter, gg, GSI_SAME_STMT);
+
+  /* Save new_alloca_with_rz value into last_alloca to use it during
+     allocas unpoisoning.  */
+  g = gimple_build_assign (last_alloca, new_alloca_with_rz);
+  gsi_insert_before (iter, g, GSI_SAME_STMT);
+
+  /* Finally, replace old alloca ptr with NEW_ALLOCA.  */
+  replace_call_with_value (iter, new_alloca);
+}
+
 /* Return the memory references contained in a gimple statement
    representing a builtin call that has to do with memory access.  */
 
 static bool
-get_mem_refs_of_builtin_call (const gcall *call,
+get_mem_refs_of_builtin_call (gcall *call,
                              asan_mem_ref *src0,
                              tree *src0_len,
                              bool *src0_is_store,
@@ -544,7 +721,8 @@ get_mem_refs_of_builtin_call (const gcall *call,
                              tree *dst_len,
                              bool *dst_is_store,
                              bool *dest_is_deref,
-                             bool *intercepted_p)
+                             bool *intercepted_p,
+                             gimple_stmt_iterator *iter = NULL)
 {
   gcc_checking_assert (gimple_call_builtin_p (call, BUILT_IN_NORMAL));
 
@@ -603,6 +781,14 @@ get_mem_refs_of_builtin_call (const gcall *call,
       len = gimple_call_lhs (call);
       break;
 
+    case BUILT_IN_STACK_RESTORE:
+      handle_builtin_stack_restore (call, iter);
+      break;
+
+    case BUILT_IN_ALLOCA_WITH_ALIGN:
+    case BUILT_IN_ALLOCA:
+      handle_builtin_alloca (call, iter);
+      break;
     /* And now the __atomic* and __sync builtins.
        These are handled differently from the classical memory memory
        access builtins above.  */
@@ -1363,6 +1549,28 @@ asan_emit_stack_protection (rtx base, rtx pbase, unsigned int alignb,
   return insns;
 }
 
+/* Emit __asan_allocas_unpoison (top, bot) call.  The BASE parameter corresponds
+   to BOT argument, for TOP virtual_stack_dynamic_rtx is used.  NEW_SEQUENCE
+   indicates whether we're emitting new instructions sequence or not.  */
+
+rtx_insn *
+asan_emit_allocas_unpoison (rtx top, rtx bot, rtx_insn *before)
+{
+  if (before)
+    push_to_sequence (before);
+  else
+    start_sequence ();
+  rtx ret = init_one_libfunc ("__asan_allocas_unpoison");
+  ret = emit_library_call_value (ret, NULL_RTX, LCT_NORMAL, ptr_mode, 2, top,
+                                TYPE_MODE (pointer_sized_int_node), bot,
+                                TYPE_MODE (pointer_sized_int_node));
+
+  do_pending_stack_adjust ();
+  rtx_insn *insns = get_insns ();
+  end_sequence ();
+  return insns;
+}
+
 /* Return true if DECL, a global var, might be overridden and needs
    therefore a local alias.  */
 
@@ -2002,7 +2210,7 @@ instrument_builtin_call (gimple_stmt_iterator *iter)
                                    &src0, &src0_len, &src0_is_store,
                                    &src1, &src1_len, &src1_is_store,
                                    &dest, &dest_len, &dest_is_store,
-                                   &dest_is_deref, &intercepted_p))
+                                   &dest_is_deref, &intercepted_p, iter))
     {
       if (dest_is_deref)
        {
@@ -3192,6 +3400,7 @@ asan_instrument (void)
   if (shadow_ptr_types[0] == NULL_TREE)
     asan_init_shadow_ptr_types ();
   transform_statements ();
+  last_alloca_addr = NULL_TREE;
   return 0;
 }
 
index 95bb89e197c9b84a51d85975fa23fa437127341b..4e8120ef76164d8114645a68942d27815ba04e6d 100644 (file)
@@ -25,6 +25,7 @@ extern void asan_function_start (void);
 extern void asan_finish_file (void);
 extern rtx_insn *asan_emit_stack_protection (rtx, rtx, unsigned int,
                                             HOST_WIDE_INT *, tree *, int);
+extern rtx_insn *asan_emit_allocas_unpoison (rtx, rtx, rtx_insn *);
 extern bool asan_protect_global (tree);
 extern void initialize_sanitizer_builtins (void);
 extern tree asan_dynamic_init_call (bool);
index 034ec2e4cb03742ded872ac55bbdf44f0b6ed389..608993afc1b6caba92a22e03f51a637c0b08e05e 100644 (file)
@@ -4962,6 +4962,26 @@ expand_builtin_alloca (tree exp)
   return result;
 }
 
+/* Emit a call to __asan_allocas_unpoison call in EXP.  Replace second argument
+   of the call with virtual_stack_dynamic_rtx because in asan pass we emit a
+   dummy value into second parameter relying on this function to perform the
+   change.  See motivation for this in comment to handle_builtin_stack_restore
+   function.  */
+
+static rtx
+expand_asan_emit_allocas_unpoison (tree exp)
+{
+  tree arg0 = CALL_EXPR_ARG (exp, 0);
+  rtx top = expand_expr (arg0, NULL_RTX, GET_MODE (virtual_stack_dynamic_rtx),
+                        EXPAND_NORMAL);
+  rtx ret = init_one_libfunc ("__asan_allocas_unpoison");
+  ret = emit_library_call_value (ret, NULL_RTX, LCT_NORMAL, ptr_mode, 2, top,
+                                TYPE_MODE (pointer_sized_int_node),
+                                virtual_stack_dynamic_rtx,
+                                TYPE_MODE (pointer_sized_int_node));
+  return ret;
+}
+
 /* Expand a call to bswap builtin in EXP.
    Return NULL_RTX if a normal call should be emitted rather than expanding the
    function in-line.  If convenient, the result should be placed in TARGET.
@@ -6763,6 +6783,9 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode,
        return target;
       break;
 
+    case BUILT_IN_ASAN_ALLOCAS_UNPOISON:
+      return expand_asan_emit_allocas_unpoison (exp);
+
     case BUILT_IN_STACK_SAVE:
       return expand_stack_save ();
 
index 3b5f2fe270fda0214eb093c4defd92cd059ac1be..dd7277f4a73013ac9b3c25fb50b01c24febd95b4 100644 (file)
@@ -2241,6 +2241,11 @@ expand_used_vars (void)
       expand_stack_vars (NULL, &data);
     }
 
+  if ((flag_sanitize & SANITIZE_ADDRESS) && cfun->calls_alloca)
+    var_end_seq = asan_emit_allocas_unpoison (virtual_stack_dynamic_rtx,
+                                             virtual_stack_vars_rtx,
+                                             var_end_seq);
+
   fini_vars_expansion ();
 
   /* If there were any artificial non-ignored vars without rtl
index 8e315fe2e2ed7a7a3290356df76b55297141f119..d94dc9cd563ca1d4b7d56dd443ef04ba7fd367de 100644 (file)
@@ -571,7 +571,7 @@ gimplify_and_update_call_from_tree (gimple_stmt_iterator *si_p, tree expr)
 
 /* Replace the call at *GSI with the gimple value VAL.  */
 
-static void
+void
 replace_call_with_value (gimple_stmt_iterator *gsi, tree val)
 {
   gimple *stmt = gsi_stmt (*gsi);
index ad0b00dccadb8b1d13b71c256ba2aa00d9c82cb0..2cee38508fc23bab79e60fa3c7e41922f7a00489 100644 (file)
@@ -58,6 +58,7 @@ extern bool gimple_fold_builtin_sprintf (gimple_stmt_iterator *);
 extern bool gimple_fold_builtin_snprintf (gimple_stmt_iterator *);
 extern bool arith_code_with_undefined_signed_overflow (tree_code);
 extern gimple_seq rewrite_to_defined_overflow (gimple *);
+extern void replace_call_with_value (gimple_stmt_iterator *, tree);
 
 /* gimple_build, functionally matching fold_buildN, outputs stmts
    int the provided sequence, matching and simplifying them on-the-fly.
index d8dadcaa70adae704d2722c69e8abced32c1ec53..1dc754124843f044ee22a5e8a829d5a30fb520d4 100644 (file)
@@ -39,6 +39,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "stor-layout.h"
 #include "dojump.h"
 #include "expr.h"
+#include "asan.h"
 #include "ubsan.h"
 #include "recog.h"
 #include "builtins.h"
index 8b4acfcf45386b630e28880d424875b0b956dfeb..91759a8957ac25f92b97f790a0551c1a508430e8 100644 (file)
@@ -171,6 +171,10 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_POISON_STACK_MEMORY,
 DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_UNPOISON_STACK_MEMORY,
                      "__asan_unpoison_stack_memory",
                      BT_FN_VOID_PTR_PTRMODE, ATTR_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_ALLOCA_POISON, "__asan_alloca_poison",
+                     BT_FN_VOID_PTR_PTRMODE, ATTR_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_ALLOCAS_UNPOISON, "__asan_allocas_unpoison",
+                     BT_FN_VOID_PTR_PTRMODE, ATTR_NOTHROW_LEAF_LIST)
 
 /* Thread Sanitizer */
 DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_INIT, "__tsan_init", 
index 59ab5aaf446f8081204a45d3621f224e2cb5c196..886689f6c9c04b81cf4d37d3661d002d4a517b68 100644 (file)
@@ -1,3 +1,14 @@
+2017-07-06  Maxim Ostapenko  <m.ostapenko@samsung.com>
+
+       * c-c++-common/asan/alloca_big_alignment.c: New test.
+       * c-c++-common/asan/alloca_detect_custom_size.c: Likewise.
+       * c-c++-common/asan/alloca_instruments_all_paddings.c: Likewise.
+       * c-c++-common/asan/alloca_loop_unpoisoning.c: Likewise.
+       * c-c++-common/asan/alloca_overflow_partial.c: Likewise.
+       * c-c++-common/asan/alloca_overflow_right.c: Likewise.
+       * c-c++-common/asan/alloca_safe_access.c: Likewise.
+       * c-c++-common/asan/alloca_underflow_left.c: Likewise.
+
 2017-07-06  Georg-Johann Lay  <avr@gjlay.de>
 
        PR target/81305
diff --git a/gcc/testsuite/c-c++-common/asan/alloca_big_alignment.c b/gcc/testsuite/c-c++-common/asan/alloca_big_alignment.c
new file mode 100644 (file)
index 0000000..54f03b8
--- /dev/null
@@ -0,0 +1,22 @@
+/* { dg-do run } */
+/* { dg-shouldfail "asan" } */
+
+#include <assert.h>
+
+volatile int ten = 10;
+
+__attribute__((noinline)) void foo(int index, int len) {
+  volatile char str[len] __attribute__((aligned(128)));
+  assert(!((long) str & 127L));
+  str[index] = '1'; // BOOM
+}
+
+int main() {
+  foo(ten, ten);
+  return 0;
+}
+
+/* { dg-output "WRITE of size 1 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ +(in _*foo(\[^\n\r]*alloca_big_alignment.c:11|\[^\n\r]*:0)|\[(\]).*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*Address 0x\[0-9a-f\]+ is located in stack of thread T0.*(\n|\r\n|\r)" */
+/* { dg-output "\[^\n\r]*in foo.*alloca_big_alignment.c.*(\n|\r\n|\r)" */
diff --git a/gcc/testsuite/c-c++-common/asan/alloca_detect_custom_size.c b/gcc/testsuite/c-c++-common/asan/alloca_detect_custom_size.c
new file mode 100644 (file)
index 0000000..609dafe
--- /dev/null
@@ -0,0 +1,27 @@
+/* { dg-do run } */
+/* { dg-shouldfail "asan" } */
+
+#include <assert.h>
+
+struct A {
+  char a[3];
+  int b[3];
+};
+
+volatile int ten = 10;
+
+__attribute__((noinline)) void foo(int index, int len) {
+  volatile struct A str[len] __attribute__((aligned(32)));
+  assert(!((long) str & 31L));
+  str[index].a[0] = '1'; // BOOM
+}
+
+int main(int argc, char **argv) {
+  foo(ten, ten);
+  return 0;
+}
+
+/* { dg-output "WRITE of size 1 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ +(in _*foo(\[^\n\r]*alloca_detect_custom_size.c:16|\[^\n\r]*:0)|\[(\]).*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*Address 0x\[0-9a-f\]+ is located in stack of thread T0.*(\n|\r\n|\r)" */
+/* { dg-output "\[^\n\r]*in foo.*alloca_detect_custom_size.c.*(\n|\r\n|\r)" */
diff --git a/gcc/testsuite/c-c++-common/asan/alloca_instruments_all_paddings.c b/gcc/testsuite/c-c++-common/asan/alloca_instruments_all_paddings.c
new file mode 100644 (file)
index 0000000..6b08c0b
--- /dev/null
@@ -0,0 +1,21 @@
+/* { dg-do run } */
+
+#include "sanitizer/asan_interface.h"
+#include <assert.h>
+
+__attribute__((noinline)) void foo(int index, int len) {
+  volatile char str[len] __attribute__((aligned(32)));
+  assert(!((long) str & 31L));
+  char *q = (char *)__asan_region_is_poisoned((char *)str, 64);
+  assert(q && ((q - str) == index));
+}
+
+int main(int argc, char **argv) {
+  for (int i = 1; i < 33; ++i)
+    foo(i, i);
+
+  for (int i = 1; i < 33; ++i)
+    foo(i, i);
+
+  return 0;
+}
diff --git a/gcc/testsuite/c-c++-common/asan/alloca_loop_unpoisoning.c b/gcc/testsuite/c-c++-common/asan/alloca_loop_unpoisoning.c
new file mode 100644 (file)
index 0000000..0ddadb9
--- /dev/null
@@ -0,0 +1,34 @@
+/* { dg-do run } */
+
+/* This testcase checks that allocas and VLAs inside loop are correctly unpoisoned.  */
+
+#include <assert.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "sanitizer/asan_interface.h"
+
+void *top, *bot;
+volatile int thirty_two = 32;
+
+__attribute__((noinline)) void foo(int len) {
+  char x;
+  top = &x;
+  volatile char array[len];
+  assert(!((uintptr_t) array & 31L));
+  alloca(len);
+  for (int i = 0; i < thirty_two; ++i) {
+    char array[i];
+    bot = array;
+    /* Just to prevent optimization.  */
+    printf("%p\n", bot);
+    assert(!((uintptr_t) bot & 31L));
+  }
+}
+
+int main(int argc, char **argv) {
+  foo(thirty_two);
+  void *q = __asan_region_is_poisoned(bot, (char *)top - (char *)bot);
+  assert(!q);
+  return 0;
+}
diff --git a/gcc/testsuite/c-c++-common/asan/alloca_overflow_partial.c b/gcc/testsuite/c-c++-common/asan/alloca_overflow_partial.c
new file mode 100644 (file)
index 0000000..9f4d078
--- /dev/null
@@ -0,0 +1,22 @@
+/* { dg-do run } */
+/* { dg-shouldfail "asan" } */
+
+#include <assert.h>
+
+volatile const int ten = 10;
+
+__attribute__((noinline)) void foo(int index, int len) {
+  volatile char str[len] __attribute__((aligned(32)));
+  assert(!((long) str & 31L));
+  str[index] = '1'; // BOOM
+}
+
+int main(int argc, char **argv) {
+  foo(ten, ten);
+  return 0;
+}
+
+/* { dg-output "WRITE of size 1 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ +(in _*foo(\[^\n\r]*alloca_overflow_partial.c:11|\[^\n\r]*:0)|\[(\]).*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*Address 0x\[0-9a-f\]+ is located in stack of thread T0.*(\n|\r\n|\r)" */
+/* { dg-output "\[^\n\r]*in foo.*alloca_overflow_partial.c.*(\n|\r\n|\r)" */
diff --git a/gcc/testsuite/c-c++-common/asan/alloca_overflow_right.c b/gcc/testsuite/c-c++-common/asan/alloca_overflow_right.c
new file mode 100644 (file)
index 0000000..085fdae
--- /dev/null
@@ -0,0 +1,22 @@
+/* { dg-do run } */
+/* { dg-shouldfail "asan" } */
+
+#include <assert.h>
+
+volatile const int ten = 10;
+
+__attribute__((noinline)) void foo(int index, int len) {
+  volatile char str[len] __attribute__((aligned(32)));
+  assert(!((long) str & 31L));
+  str[index] = '1'; // BOOM
+}
+
+int main(int argc, char **argv) {
+  foo(33, ten);
+  return 0;
+}
+
+/* { dg-output "WRITE of size 1 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ +(in _*foo(\[^\n\r]*alloca_overflow_right.c:11|\[^\n\r]*:0)|\[(\]).*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*Address 0x\[0-9a-f\]+ is located in stack of thread T0.*(\n|\r\n|\r)" */
+/* { dg-output "\[^\n\r]*in foo.*alloca_overflow_right.c.*(\n|\r\n|\r)" */
diff --git a/gcc/testsuite/c-c++-common/asan/alloca_safe_access.c b/gcc/testsuite/c-c++-common/asan/alloca_safe_access.c
new file mode 100644 (file)
index 0000000..92da1b2
--- /dev/null
@@ -0,0 +1,15 @@
+/* { dg-do run } */
+
+#include <assert.h>
+
+__attribute__((noinline)) void foo(int index, int len) {
+  volatile char str[len] __attribute__((aligned(32)));
+  assert(!((long)str & 31L));
+  str[index] = '1';
+}
+
+int main(int argc, char **argv) {
+  foo(4, 5);
+  foo(39, 40);
+  return 0;
+}
diff --git a/gcc/testsuite/c-c++-common/asan/alloca_underflow_left.c b/gcc/testsuite/c-c++-common/asan/alloca_underflow_left.c
new file mode 100644 (file)
index 0000000..fe2abe1
--- /dev/null
@@ -0,0 +1,22 @@
+/* { dg-do run } */
+/* { dg-shouldfail "asan" } */
+
+#include <assert.h>
+
+volatile const int ten = 10;
+
+__attribute__((noinline)) void foo(int index, int len) {
+  volatile char str[len] __attribute__((aligned(32)));
+  assert(!((long) str & 31L));
+  str[index] = '1'; // BOOM
+}
+
+int main(int argc, char **argv) {
+  foo(-1, ten);
+  return 0;
+}
+
+/* { dg-output "WRITE of size 1 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ +(in _*foo(\[^\n\r]*alloca_underflow_left.c:11|\[^\n\r]*:0)|\[(\]).*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*Address 0x\[0-9a-f\]+ is located in stack of thread T0.*(\n|\r\n|\r)" */
+/* { dg-output "\[^\n\r]*in foo.*alloca_underflow_left.c.*(\n|\r\n|\r)" */