Bug 59392 - crash on throw from "unexpected exception" handler with ARM EABI unwinder
Summary: crash on throw from "unexpected exception" handler with ARM EABI unwinder
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: libstdc++ (show other bugs)
Version: 4.9.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: patch
Depends on:
Blocks:
 
Reported: 2013-12-05 00:10 UTC by Roland McGrath
Modified: 2014-03-12 22:47 UTC (History)
1 user (show)

See Also:
Host:
Target: arm-linux-gnueabihf
Build:
Known to work:
Known to fail:
Last reconfirmed: 2014-03-12 00:00:00


Attachments
test case (184 bytes, text/plain)
2013-12-05 00:10 UTC, Roland McGrath
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Roland McGrath 2013-12-05 00:10:16 UTC
Created attachment 31382 [details]
test case

I've observed this on trunk and on 4.6.3, but I think the bug has been there since the introduction of ARM EABI unwinding in 4.2.

The attached test case crashes with a null pointer dereference (producing no output) on ARM/EABI targets.  On other targets (I only tested x86_64-linux-gnu), it correctly crashes via abort after emitting a message (i.e. std::terminate runs).  The original case was more complex and used std::set_terminate to set a handler that used longjmp, avoiding the abort.  For the test suite, it's probably most convenient to do that (or just exit with an expected code in the terminate handler) rather than to detect that the default std::terminate crash happened correctly vs a different crash.

The bug comes about in an obvious and straightforward way.  But I don't know the libsupc++ internals well enough to suggest an appropriate fix off hand.  What happens is that libstdc++-v3/libsupc++/eh_call.cc:__cxa_call_unexpected does:
	  if (catch_type->__do_catch(&bad_exc, 0, 1))
i.e., passes a null pointer as the second argument to the __do_catch method.
libstdc++-v3/libsupc++/class_type_info.cc:__do_catch passes this argument on as the second argument to __do_upcast.
In libstdc++-v3/libsupc++/class_type_info.cc:__do_upcast there is:
  __do_upcast (dst_type, *obj_ptr, result);
i.e., unconditionally dereferencing OBJ_PTR (the second argument).

I'd like to see this get fixed on the trunk and 4.8 at least.
I'd be glad to pursue the fix myself if I had any idea what it should be.
Comment 1 Mark Seaborn 2013-12-05 00:35:20 UTC
Instead of:

  if (catch_type->__do_catch(&bad_exc, NULL, 1))

I think this should be:

  // We don't have a thrown object to compare against, but since
  // bad_exception doesn't have virtual bases, that's OK; just pass 0.
  void *obj = NULL;
  if (catch_type->__do_catch(&bad_exc, &obj, 1))

or to avoid the comment, just:

  std::bad_exception ex;
  void *obj = &ex;
  if (catch_type->__do_catch(&typeid(ex), &obj, 1))

The non-EABI equivalent is the second check_exception_spec() call in __cxa_call_unexpected() in eh_personality.cc.
Comment 2 Roland McGrath 2013-12-09 17:32:41 UTC
Fix posted: http://gcc.gnu.org/ml/gcc-patches/2013-12/msg00753.html
Comment 3 Jonathan Wakely 2014-03-12 20:56:20 UTC
The posted patch is OK, approved for trunk and 4.8
Comment 4 roland 2014-03-12 22:42:46 UTC
Author: roland
Date: Wed Mar 12 22:42:13 2014
New Revision: 208519

URL: http://gcc.gnu.org/viewcvs?rev=208519&root=gcc&view=rev
Log:
PR libstdc++/59392: Fix ARM EABI uncaught throw from unexpected exception handler

libstdc++-v3/
	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.

Added:
    trunk/libstdc++-v3/testsuite/18_support/bad_exception/59392.cc   (with props)
Modified:
    trunk/libstdc++-v3/ChangeLog
    trunk/libstdc++-v3/libsupc++/eh_call.cc

Propchange: trunk/libstdc++-v3/testsuite/18_support/bad_exception/59392.cc
            ('svn:eol-style' added)
Comment 5 roland 2014-03-12 22:44:40 UTC
Author: roland
Date: Wed Mar 12 22:44:09 2014
New Revision: 208520

URL: http://gcc.gnu.org/viewcvs?rev=208520&root=gcc&view=rev
Log:
PR libstdc++/59392: Fix ARM EABI uncaught throw from unexpected exception handler

libstdc++-v3/
	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.

Added:
    branches/gcc-4_8-branch/libstdc++-v3/testsuite/18_support/bad_exception/59392.cc   (with props)
Modified:
    branches/gcc-4_8-branch/libstdc++-v3/ChangeLog
    branches/gcc-4_8-branch/libstdc++-v3/libsupc++/eh_call.cc

Propchange: branches/gcc-4_8-branch/libstdc++-v3/testsuite/18_support/bad_exception/59392.cc
            ('svn:eol-style' added)
Comment 6 Roland McGrath 2014-03-12 22:47:43 UTC
Fixed on trunk and 4.8.