diff mbox series

[PR,sanitizer/78651] Incorrect exception handling when catch clause uses local class and PIC and sanitizer are active

Message ID 1645801f-7dbe-65e8-a991-eee6a9c2f4fc@samsung.com
State New
Headers show
Series [PR,sanitizer/78651] Incorrect exception handling when catch clause uses local class and PIC and sanitizer are active | expand

Commit Message

Maxim Ostapenko March 19, 2018, 3:44 p.m. UTC
Hi,


as noted in bugzilla, ASan inserts redzones for  `.LDFCM*' variables and 
breaks internal ABI between GCC and libstdc++ because libstdc++ tries to 
obtain a pointer to `typeinfo for (anonymous namespace)::SomeRandomType' 
from a constant offset from `.LDFCM*' labels and hits these redzones. 
This can be trivially fixed by not sanitizing `.LDFCM*' variables (and 
other debug variables) at all.

Attached patch is tested/bootstrapped on x86_64-unknown-linux-gnu and 
ppc64le-redhat-linux targets.

Is it OK for trunk now, or should I wait for stage 1?


-Maxim

Comments

Jakub Jelinek March 19, 2018, 3:55 p.m. UTC | #1
On Mon, Mar 19, 2018 at 06:44:39PM +0300, Maxim Ostapenko wrote:
> as noted in bugzilla, ASan inserts redzones for  `.LDFCM*' variables and
> breaks internal ABI between GCC and libstdc++ because libstdc++ tries to
> obtain a pointer to `typeinfo for (anonymous namespace)::SomeRandomType'
> from a constant offset from `.LDFCM*' labels and hits these redzones. This
> can be trivially fixed by not sanitizing `.LDFCM*' variables (and other
> debug variables) at all.

I don't like very much adding an extra argument for such so frequently used
function to handle a corner case.
Wouldn't just:
  /* Don't instrument this decl with -fsanitize=*address.  */
  unsigned int save_flag_sanitize = flag_sanitize;
  flag_sanitize &= ~(SANITIZE_ADDRESS | SANITIZE_USER_ADDRESS
		     | SANITIZE_KERNEL_ADDRESS);
  assemble_variable (decl, 1, 1, 1);
  flag_sanitize = save_flag_sanitize;
DTRT?

	Jakub
Maxim Ostapenko March 19, 2018, 4:28 p.m. UTC | #2
On 03/19/2018 06:55 PM, Jakub Jelinek wrote:
> On Mon, Mar 19, 2018 at 06:44:39PM +0300, Maxim Ostapenko wrote:
>> as noted in bugzilla, ASan inserts redzones for  `.LDFCM*' variables and
>> breaks internal ABI between GCC and libstdc++ because libstdc++ tries to
>> obtain a pointer to `typeinfo for (anonymous namespace)::SomeRandomType'
>> from a constant offset from `.LDFCM*' labels and hits these redzones. This
>> can be trivially fixed by not sanitizing `.LDFCM*' variables (and other
>> debug variables) at all.
> I don't like very much adding an extra argument for such so frequently used
> function to handle a corner case.
> Wouldn't just:
>    /* Don't instrument this decl with -fsanitize=*address.  */
>    unsigned int save_flag_sanitize = flag_sanitize;
>    flag_sanitize &= ~(SANITIZE_ADDRESS | SANITIZE_USER_ADDRESS
> 		     | SANITIZE_KERNEL_ADDRESS);
>    assemble_variable (decl, 1, 1, 1);
>    flag_sanitize = save_flag_sanitize;
> DTRT?
>
>

Yes, it works, attaching the patch.

-Maxim
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index b5b5559..356e68c 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,9 @@
+2018-03-19  Maxim Ostapenko  <m.ostapenko@samsung.com>
+
+	PR sanitizer/78651
+	* dwarf2asm.c (dw2_output_indirect_constant_1): Disable ASan before
+	calling assemble_variable.
+
 2018-03-19  Richard Biener  <rguenther@suse.de>
 
 	PR tree-optimization/84929
diff --git a/gcc/dwarf2asm.c b/gcc/dwarf2asm.c
index e9b18b8..065406b 100644
--- a/gcc/dwarf2asm.c
+++ b/gcc/dwarf2asm.c
@@ -967,7 +967,11 @@ dw2_output_indirect_constant_1 (const char *sym, tree id)
     }
 
   sym_ref = gen_rtx_SYMBOL_REF (Pmode, sym);
+  unsigned int save_flag_sanitize = flag_sanitize;
+  flag_sanitize &= ~(SANITIZE_ADDRESS | SANITIZE_USER_ADDRESS
+		     | SANITIZE_KERNEL_ADDRESS);
   assemble_variable (decl, 1, 1, 1);
+  flag_sanitize = save_flag_sanitize;
   assemble_integer (sym_ref, POINTER_SIZE_UNITS, POINTER_SIZE, 1);
 
   return 0;
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 868d8e8..6ff9217 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2018-03-19  Maxim Ostapenko  <m.ostapenko@samsung.com>
+
+	PR sanitizer/78651
+	* g++.dg/asan/pr78651.C: New test.
+
 2018-03-19  Richard Biener  <rguenther@suse.de>
 
 	PR tree-optimization/84929
diff --git a/gcc/testsuite/g++.dg/asan/pr78651.C b/gcc/testsuite/g++.dg/asan/pr78651.C
new file mode 100644
index 0000000..3f14be7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/asan/pr78651.C
@@ -0,0 +1,24 @@
+// { dg-do run { target fpic } }
+
+struct A { };
+
+namespace {
+
+void thisThrows () {
+  throw A();
+}
+
+struct SomeRandomType {};
+}
+
+int main() {
+  try {
+    thisThrows();
+  }
+  catch (SomeRandomType) {
+    throw;
+  }
+  catch (A) {
+  }
+  return 0;
+}
Jakub Jelinek March 19, 2018, 4:35 p.m. UTC | #3
On Mon, Mar 19, 2018 at 07:28:11PM +0300, Maxim Ostapenko wrote:
> Yes, it works, attaching the patch.

Can you please add a short comment why we do this?  Also, the testcase
needs work, see below.  Ok for trunk with those changes and after a
while for affected release branches as well.

Thanks.

> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/asan/pr78651.C
> @@ -0,0 +1,24 @@
> +// { dg-do run { target fpic } }

Effective target fpic just means that -fpic or -fPIC is supported, nothing
else.  So, you want instead:
// PR sanitizer/78651
// { dg-do run }
// { dg-additional-options "-fpic" { target fpic } }

and verify make check-c++-all RUNTESTFLAGS=asan.exp=pr78651.C fails without
the dwarf2asm.c patch and succeeds with it.

	Jakub
Maxim Ostapenko March 19, 2018, 4:48 p.m. UTC | #4
On 03/19/2018 07:35 PM, Jakub Jelinek wrote:
> On Mon, Mar 19, 2018 at 07:28:11PM +0300, Maxim Ostapenko wrote:
>> Yes, it works, attaching the patch.
> Can you please add a short comment why we do this?  Also, the testcase
> needs work, see below.  Ok for trunk with those changes and after a
> while for affected release branches as well.

Ok, thanks, attaching the patch I'm going to apply.

-Maxim
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index b5b5559..356e68c 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,9 @@
+2018-03-19  Maxim Ostapenko  <m.ostapenko@samsung.com>
+
+	PR sanitizer/78651
+	* dwarf2asm.c (dw2_output_indirect_constant_1): Disable ASan before
+	calling assemble_variable.
+
 2018-03-19  Richard Biener  <rguenther@suse.de>
 
 	PR tree-optimization/84929
diff --git a/gcc/dwarf2asm.c b/gcc/dwarf2asm.c
index e9b18b8..2e108ac 100644
--- a/gcc/dwarf2asm.c
+++ b/gcc/dwarf2asm.c
@@ -967,7 +967,13 @@ dw2_output_indirect_constant_1 (const char *sym, tree id)
     }
 
   sym_ref = gen_rtx_SYMBOL_REF (Pmode, sym);
+  /* Disable ASan for decl because redzones cause ABI breakage between GCC and
+     libstdc++ for `.LDFCM*' variables.  See PR 78651 for details.  */
+  unsigned int save_flag_sanitize = flag_sanitize;
+  flag_sanitize &= ~(SANITIZE_ADDRESS | SANITIZE_USER_ADDRESS
+		     | SANITIZE_KERNEL_ADDRESS);
   assemble_variable (decl, 1, 1, 1);
+  flag_sanitize = save_flag_sanitize;
   assemble_integer (sym_ref, POINTER_SIZE_UNITS, POINTER_SIZE, 1);
 
   return 0;
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 868d8e8..6ff9217 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2018-03-19  Maxim Ostapenko  <m.ostapenko@samsung.com>
+
+	PR sanitizer/78651
+	* g++.dg/asan/pr78651.C: New test.
+
 2018-03-19  Richard Biener  <rguenther@suse.de>
 
 	PR tree-optimization/84929
diff --git a/gcc/testsuite/g++.dg/asan/pr78651.C b/gcc/testsuite/g++.dg/asan/pr78651.C
new file mode 100644
index 0000000..09f1be5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/asan/pr78651.C
@@ -0,0 +1,26 @@
+// PR sanitizer/78651
+// { dg-do run }
+// { dg-additional-options "-fpic" { target fpic } }
+
+struct A { };
+
+namespace {
+
+void thisThrows () {
+  throw A();
+}
+
+struct SomeRandomType {};
+}
+
+int main() {
+  try {
+    thisThrows();
+  }
+  catch (SomeRandomType) {
+    throw;
+  }
+  catch (A) {
+  }
+  return 0;
+}
diff mbox series

Patch

gcc/

	PR sanitizer/78651
	* dwarf2asm.c (dw2_output_indirect_constant_1): Call
	assemble_variable with new parameter.
	* output.h (assemble_variable): Add new parameter.
	* varasm.c (assemble_variable): Add new parameter. Do not
	protect variable with ASan if is_debug_var is true.

gcc/testsuite/ChangeLog:

	PR sanitizer/78651
	* g++.dg/asan/pr78651.C: New test.

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index b5b5559..a26f05e 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,12 @@ 
+2018-03-19  Maxim Ostapenko  <m.ostapenko@samsung.com>
+
+	PR sanitizer/78651
+	* dwarf2asm.c (dw2_output_indirect_constant_1): Call assemble_variable
+	with new parameter.
+	* output.h (assemble_variable): Add new parameter.
+	* varasm.c (assemble_variable): Add new parameter. Do not protect
+	variable with ASan if is_debug_var is true.
+
 2018-03-19  Richard Biener  <rguenther@suse.de>
 
 	PR tree-optimization/84929
diff --git a/gcc/dwarf2asm.c b/gcc/dwarf2asm.c
index e9b18b8..5c90994 100644
--- a/gcc/dwarf2asm.c
+++ b/gcc/dwarf2asm.c
@@ -967,7 +967,7 @@  dw2_output_indirect_constant_1 (const char *sym, tree id)
     }
 
   sym_ref = gen_rtx_SYMBOL_REF (Pmode, sym);
-  assemble_variable (decl, 1, 1, 1);
+  assemble_variable (decl, 1, 1, 1, 1);
   assemble_integer (sym_ref, POINTER_SIZE_UNITS, POINTER_SIZE, 1);
 
   return 0;
diff --git a/gcc/output.h b/gcc/output.h
index f708cc7..678c370 100644
--- a/gcc/output.h
+++ b/gcc/output.h
@@ -200,7 +200,7 @@  extern void assemble_end_function (tree, const char *);
    to define things that have had only tentative definitions.
    DONT_OUTPUT_DATA if nonzero means don't actually output the
    initial value (that will be done by the caller).  */
-extern void assemble_variable (tree, int, int, int);
+extern void assemble_variable (tree, int, int, int, int is_debug_var = 0);
 
 /* Put the vtable verification constructor initialization function
    into the preinit array.  */
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 868d8e8..6ff9217 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@ 
+2018-03-19  Maxim Ostapenko  <m.ostapenko@samsung.com>
+
+	PR sanitizer/78651
+	* g++.dg/asan/pr78651.C: New test.
+
 2018-03-19  Richard Biener  <rguenther@suse.de>
 
 	PR tree-optimization/84929
diff --git a/gcc/testsuite/g++.dg/asan/pr78651.C b/gcc/testsuite/g++.dg/asan/pr78651.C
new file mode 100644
index 0000000..3f14be7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/asan/pr78651.C
@@ -0,0 +1,24 @@ 
+// { dg-do run { target fpic } }
+
+struct A { };
+
+namespace {
+
+void thisThrows () {
+  throw A();
+}
+
+struct SomeRandomType {};
+}
+
+int main() {
+  try {
+    thisThrows();
+  }
+  catch (SomeRandomType) {
+    throw;
+  }
+  catch (A) {
+  }
+  return 0;
+}
diff --git a/gcc/varasm.c b/gcc/varasm.c
index 2b5c70c..b18d011 100644
--- a/gcc/varasm.c
+++ b/gcc/varasm.c
@@ -2158,11 +2158,14 @@  assemble_undefined_decl (tree decl)
    AT_END is nonzero if this is the special handling, at end of compilation,
    to define things that have had only tentative definitions.
    DONT_OUTPUT_DATA if nonzero means don't actually output the
-   initial value (that will be done by the caller).  */
+   initial value (that will be done by the caller).
+   IS_DEBUG_VAR if nonzero that we are assembling debug variable.
+   This information is useful for ASan, see pr78651.  */
 
 void
 assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
-		   int at_end ATTRIBUTE_UNUSED, int dont_output_data)
+		   int at_end ATTRIBUTE_UNUSED, int dont_output_data,
+		   int is_debug_var)
 {
   const char *name;
   rtx decl_rtl, symbol;
@@ -2258,6 +2261,7 @@  assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
   align_variable (decl, dont_output_data);
 
   if ((flag_sanitize & SANITIZE_ADDRESS)
+      && !is_debug_var
       && asan_protect_global (decl))
     {
       asan_protected = true;