Patchwork PR libstdc++/59392: Fix ARM EABI uncaught throw from unexpected exception handler

login
register
mail settings
Submitter Roland McGrath
Date Dec. 6, 2013, 11:24 p.m.
Message ID <CAB=4xhqXcMgpObWY6k2eAeY1D=nfWneni5pyY9wOEsWkdcMO5w@mail.gmail.com>
Download mbox | patch
Permalink /patch/298515/
State New
Headers show

Comments

Roland McGrath - Dec. 6, 2013, 11:24 p.m.
[This patch is on the git-only branch roland/pr59392.]

As described in http://gcc.gnu.org/bugzilla/show_bug.cgi?id=59392, this
bug looks to have been present since 4.2 originally introduced support
for ARM EABI-based C++ exception handling.  I'd like to put this fix on
trunk and 4.8, and don't personally care about older versions but the
same fix should apply to all versions still being maintained.

The nature of the bug is quite straightforward: it's an unconditional
null pointer dereference in the code path for an unexpected throw done
inside a user-supplied handler for unexpected exceptions.  I'm not
really sure if there are other ways to make it manifest.

Mark Seaborn is responsible for identifying the fix, which mimics the
similar code for the non-EABI implementation (and copies its comment).
I filled it out with a regression test.  (We're both covered by Google's
blanket copyright assignment.)

No regressions in 'make check-c++' on arm-linux-gnueabihf.

Ok for trunk and 4.8?


Thanks,
Roland


libstdc++-v3/
2013-12-06  Roland McGrath  <mcgrathr@google.com>
	    Mark Seaborn  <mseaborn@google.com>

	PR libstdc++/59392
	* libsupc++/eh_call.cc (__cxa_call_unexpected): Call __do_catch with
	the address of a null pointer, not with a null pointer to pointer.
	Copy comment for this case from eh_personality.cc:__cxa_call_unexpected.
	* testsuite/18_support/bad_exception/59392.cc: New file.
Roland McGrath - March 12, 2014, 10:46 p.m.
Committed (r208519 on trunk and r208520 on 4.8) after approval posted
in http://gcc.gnu.org/bugzilla/show_bug.cgi?id=59392.
Only the dates are changed from what I posted originally.


Thanks,
Roland

On Fri, Dec 6, 2013 at 3:24 PM, Roland McGrath <mcgrathr@google.com> wrote:
> [This patch is on the git-only branch roland/pr59392.]
>
> As described in http://gcc.gnu.org/bugzilla/show_bug.cgi?id=59392, this
> bug looks to have been present since 4.2 originally introduced support
> for ARM EABI-based C++ exception handling.  I'd like to put this fix on
> trunk and 4.8, and don't personally care about older versions but the
> same fix should apply to all versions still being maintained.
>
> The nature of the bug is quite straightforward: it's an unconditional
> null pointer dereference in the code path for an unexpected throw done
> inside a user-supplied handler for unexpected exceptions.  I'm not
> really sure if there are other ways to make it manifest.
>
> Mark Seaborn is responsible for identifying the fix, which mimics the
> similar code for the non-EABI implementation (and copies its comment).
> I filled it out with a regression test.  (We're both covered by Google's
> blanket copyright assignment.)
>
> No regressions in 'make check-c++' on arm-linux-gnueabihf.
>
> Ok for trunk and 4.8?
>
>
> Thanks,
> Roland
>
>
> libstdc++-v3/
> 2013-12-06  Roland McGrath  <mcgrathr@google.com>
>             Mark Seaborn  <mseaborn@google.com>
>
>         PR libstdc++/59392
>         * libsupc++/eh_call.cc (__cxa_call_unexpected): Call __do_catch with
>         the address of a null pointer, not with a null pointer to pointer.
>         Copy comment for this case from eh_personality.cc:__cxa_call_unexpected.
>         * testsuite/18_support/bad_exception/59392.cc: New file.
>
> --- a/libstdc++-v3/libsupc++/eh_call.cc
> +++ b/libstdc++-v3/libsupc++/eh_call.cc
> @@ -140,7 +140,11 @@ __cxa_call_unexpected(void* exc_obj_in)
>                                &new_ptr) != ctm_failed)
>             __throw_exception_again;
>
> -         if (catch_type->__do_catch(&bad_exc, 0, 1))
> +         // If the exception spec allows std::bad_exception, throw that.
> +         // We don't have a thrown object to compare against, but since
> +         // bad_exception doesn't have virtual bases, that's OK; just pass NULL.
> +         void* obj = NULL;
> +         if (catch_type->__do_catch(&bad_exc, &obj, 1))
>             bad_exception_allowed = true;
>         }
>
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/18_support/bad_exception/59392.cc
> @@ -0,0 +1,51 @@
> +// Copyright (C) 2013 Free Software Foundation, Inc.
> +//
> +// This file is part of the GNU ISO C++ Library.  This library is free
> +// software; you can redistribute it and/or modify it under the
> +// terms of the GNU General Public License as published by the
> +// Free Software Foundation; either version 3, or (at your option)
> +// any later version.
> +
> +// This library is distributed in the hope that it will be useful,
> +// but WITHOUT ANY WARRANTY; without even the implied warranty of
> +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +// GNU General Public License for more details.
> +
> +// You should have received a copy of the GNU General Public License along
> +// with this library; see the file COPYING3.  If not see
> +// <http://www.gnu.org/licenses/>.
> +
> +#include <exception>
> +#include <cstdlib>
> +
> +class expected {};
> +class unexpected {};
> +class from_handler {};
> +
> +static void func_with_exception_spec() throw(expected)
> +{
> +  throw unexpected();
> +}
> +
> +static void unexpected_handler()
> +{
> +  throw from_handler();
> +}
> +
> +static void terminate_handler()
> +{
> +  exit(0);
> +}
> +
> +// libstdc++/59392
> +int main()
> +{
> +  std::set_unexpected(unexpected_handler);
> +  std::set_terminate(terminate_handler);
> +  try {
> +    func_with_exception_spec();
> +  } catch (expected&) {
> +    abort();
> +  }
> +  abort();
> +}

Patch

--- a/libstdc++-v3/libsupc++/eh_call.cc
+++ b/libstdc++-v3/libsupc++/eh_call.cc
@@ -140,7 +140,11 @@  __cxa_call_unexpected(void* exc_obj_in)
 			       &new_ptr) != ctm_failed)
 	    __throw_exception_again;

-	  if (catch_type->__do_catch(&bad_exc, 0, 1))
+	  // If the exception spec allows std::bad_exception, throw that.
+	  // We don't have a thrown object to compare against, but since
+	  // bad_exception doesn't have virtual bases, that's OK; just pass NULL.
+	  void* obj = NULL;
+	  if (catch_type->__do_catch(&bad_exc, &obj, 1))
 	    bad_exception_allowed = true;
 	}

--- /dev/null
+++ b/libstdc++-v3/testsuite/18_support/bad_exception/59392.cc
@@ -0,0 +1,51 @@ 
+// Copyright (C) 2013 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <exception>
+#include <cstdlib>
+
+class expected {};
+class unexpected {};
+class from_handler {};
+
+static void func_with_exception_spec() throw(expected)
+{
+  throw unexpected();
+}
+
+static void unexpected_handler()
+{
+  throw from_handler();
+}
+
+static void terminate_handler()
+{
+  exit(0);
+}
+
+// libstdc++/59392
+int main()
+{
+  std::set_unexpected(unexpected_handler);
+  std::set_terminate(terminate_handler);
+  try {
+    func_with_exception_spec();
+  } catch (expected&) {
+    abort();
+  }
+  abort();
+}