]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
asan: Fix up address sanitizer instrumentation of __builtin_alloca* if it can throw...
authorJakub Jelinek <jakub@redhat.com>
Sat, 12 Feb 2022 18:17:44 +0000 (19:17 +0100)
committerJakub Jelinek <jakub@redhat.com>
Tue, 10 May 2022 08:14:32 +0000 (10:14 +0200)
With -fstack-check* __builtin_alloca* can throw and the asan
instrumentation of this builtin wasn't prepared for that case.
The following patch fixes that by replacing the builtin with the
replacement builtin and emitting any further insns on the fallthru
edge.

I haven't touched the hwasan code which most likely suffers from the
same problem.

2022-02-12  Jakub Jelinek  <jakub@redhat.com>

PR sanitizer/104449
* asan.c: Include tree-eh.h.
(handle_builtin_alloca): Handle the case when __builtin_alloca or
__builtin_alloca_with_align can throw.

* gcc.dg/asan/pr104449.c: New test.
* g++.dg/asan/pr104449.C: New test.

(cherry picked from commit f0c7367b8802c47efaad87b1f2126fe6350d8b47)

gcc/asan.c
gcc/testsuite/g++.dg/asan/pr104449.C [new file with mode: 0644]
gcc/testsuite/gcc.dg/asan/pr104449.c [new file with mode: 0644]

index 30baf414655cc013c43ea4ddf939c49044bef01b..3c033f23983991d2ae3a59286c30a90e943b5e51 100644 (file)
@@ -63,6 +63,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "fnmatch.h"
 #include "tree-inline.h"
 #include "tree-ssa.h"
+#include "tree-eh.h"
 
 /* AddressSanitizer finds out-of-bounds and use-after-free bugs
    with <2x slowdown on average.
@@ -630,14 +631,24 @@ handle_builtin_alloca (gcall *call, gimple_stmt_iterator *iter)
 
   tree last_alloca = get_last_alloca_addr ();
   tree callee = gimple_call_fndecl (call);
+  tree lhs = gimple_call_lhs (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 ptr_type = lhs ? TREE_TYPE (lhs) : ptr_type_node;
   tree partial_size = NULL_TREE;
   unsigned int align
     = DECL_FUNCTION_CODE (callee) == BUILT_IN_ALLOCA
       ? 0 : tree_to_uhwi (gimple_call_arg (call, 1));
 
+  bool throws = false;
+  edge e = NULL;
+  if (stmt_can_throw_internal (cfun, call))
+    {
+      if (!lhs)
+       return;
+      throws = true;
+      e = find_fallthru_edge (gsi_bb (*iter)->succs);
+    }
+
   /* 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.  */
@@ -694,29 +705,54 @@ handle_builtin_alloca (gcall *call, gimple_stmt_iterator *iter)
                          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);
+  if (throws)
+    {
+      gimple_call_set_lhs (call, NULL);
+      gsi_replace (iter, gg, true);
+    }
+  else
+    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);
+  gimple_stmt_iterator gsi = gsi_none ();
+  if (throws)
+    {
+      gsi_insert_on_edge_immediate (e, g);
+      gsi = gsi_for_stmt (g);
+    }
+  else
+    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);
+  if (throws)
+    gsi_insert_after (&gsi, gg, GSI_NEW_STMT);
+  else
+    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);
+  if (throws)
+    gsi_insert_after (&gsi, g, GSI_NEW_STMT);
+  else
+    gsi_insert_before (iter, g, GSI_SAME_STMT);
 
   /* Finally, replace old alloca ptr with NEW_ALLOCA.  */
-  replace_call_with_value (iter, new_alloca);
+  if (throws)
+    {
+      g = gimple_build_assign (lhs, new_alloca);
+      gsi_insert_after (&gsi, g, GSI_NEW_STMT);
+    }
+  else
+    replace_call_with_value (iter, new_alloca);
 }
 
 /* Return the memory references contained in a gimple statement
diff --git a/gcc/testsuite/g++.dg/asan/pr104449.C b/gcc/testsuite/g++.dg/asan/pr104449.C
new file mode 100644 (file)
index 0000000..166ed8d
--- /dev/null
@@ -0,0 +1,16 @@
+// PR sanitizer/104449
+// { dg-do compile }
+// { dg-options "-fexceptions -fsanitize=address -fstack-check=generic" }
+
+void bar (int *);
+struct A { A (); ~A (); };
+
+void
+foo (int n)
+{
+  A b;
+  {
+    int a[n];
+    bar (a);
+  }
+}
diff --git a/gcc/testsuite/gcc.dg/asan/pr104449.c b/gcc/testsuite/gcc.dg/asan/pr104449.c
new file mode 100644 (file)
index 0000000..5054027
--- /dev/null
@@ -0,0 +1,12 @@
+/* PR sanitizer/104449 */
+/* { dg-do compile } */
+/* { dg-options "-fexceptions -fsanitize=address -fstack-check=generic" } */
+
+void bar (int *);
+
+void
+foo (void)
+{
+  int a[16];
+  bar (a);
+}