discuss-gnustep
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Crash occurs when catching std::exception in Objective-C++ code comp


From: David Chisnall
Subject: Re: Crash occurs when catching std::exception in Objective-C++ code compiled with clang on Linux and using libobjc2
Date: Wed, 1 Nov 2017 08:25:33 +0000

Hi,

I’m a bit surprised I missed your LLVM mailing list post, because I am the 
maintainer of the relevant clang code, as well as of libobjc2.  If you had 
asked me earlier, I could have saved you a lot of time:

This test case works perfectly for me on FreeBSD, where clang defaults to 
-fobjc-runtime=gnustep.  It segfaults if I add -fobjc-runtime=gcc.  This is 
entirely expected, because the GCC ABI for exceptions is makes it impossible to 
correctly interop with C++ (I spent a few weeks trying and it always fails for 
at least some of the corner cases).  If you specify -fobjc-runtime=gnustep-1.8, 
then it will work correctly.

When using the GNUstep ABI, Objective-C objects are thrown as Objective-C 
exceptions, C++ objects are thrown as C++ exceptions.  The GNUstep ObjC++ 
personality function is used for catch and @catch blocks in ObjC++ code, the 
ObjC personality function for @catch blocks in ObjC code, and the C++ 
personality function in C++ code.  The C++ and ObjC personality functions don’t 
let you catch foreign exceptions (except for cleanups or with catch(…) in C++). 
 The ObjC++ personality function checks whether the thrown exception is from 
C++ or ObjC.  If it’s thrown from C++, it simply forwards it to the C++ 
personality function.  If it’s thrown from ObjC, then it wraps it in a C++ 
exception first, and provides some special C++ type_info structures that allow 
the C++ personality function to deliver it to the correct block.  This allows 
us to use a slightly more efficient code path for pure-ObjC exceptions.

The Apple implementation simply implements the ObjC exceptions as thin wrappers 
around C++ exceptions, so ObjC exceptions are always thrown as C++ exceptions.  
This means that the Apple ObjC runtime has a hard dependency on their C++ 
runtime, even when not using ObjC++.  This doesn’t matter too much for them, 
because a bunch of their core frameworks are C++ or ObjC++, so there’s likely 
not to be any code on macOS / iOS that uses ObjC but not C++.

Note: We have tests for all of these cases in the libobjc2 test suite.  There’s 
also some logic to allow foreign exceptions to be automatically boxed as ObjC 
objects.

David

> On 31 Oct 2017, at 20:13, Lobron, David <dlobron@akamai.com> wrote:
> 
> Hello GNUstep,
> 
> I opened a bug with clang/llvm a few months ago when I found that 
> Objective-C++ programs compiled with clang on Linux were crashing with a 
> segmentation fault when the code attempted to catch a std::exception.  The 
> crash only occurred when the code was compiled as Objective-C++ (i.e., with a 
> suffix of .mm).  When compiled as C++, with a .cc suffix, the code works 
> correctly.  The code to reproduce the bug is very simple and pure C++:
> 
> #include <iostream>
> 
> using namespace std;
> 
> int main(int argc, char *argv[]) {
>  try {
>    throw exception();
>  } catch (exception &e) {
>  }
> 
>  return 0;
> }
> 
> I worked on this with an llvm developer, and he reported the following:
> 
> "I've investigated the issue further and discovered that the problem is with 
> personality routine. For C++ in my case it was 
> __cxxabiv1::__gxx_personality_v0. It returned _URC_HANDLER_FOUND and 
> correctly prepared everything to land in the catch block.
> 
> For ObjC++ it was __gnu_objc_personality_v0 () from 
> /usr/lib/x86_64-linux-gnu/libobjc.so.4. In my case it returned 
> _URC_CONTINUE_UNWIND, so the exception wasn't caught in `main` and it caused 
> SIGABRT as any uncaught exception does. Personality routine is also 
> responsible for setting exception object for the catch block so it might be 
> causing NULL exception object you are observing."
> 
> In my own tests, I'm using GNUStep libobjc2, version 1.8.1, which produces a 
> shared library called libobjc.so.4.6.  My C++ binary has a different 
> personality from the ObjC++ binary:
> 
> C++ (works): __gxx_personality_v0@@CXXABI_1.3
> ObjC++ (crashes): __gnu_objc_personality_v0
> 
> I checked for the string "personality" in libobjc2.so.4.6 using nm, and found 
> the following matching symbols:
> 
> 000000000022e590 d DW.ref.__gcc_personality_v0
> 000000000022ff08 d DW.ref.__gnustep_objc_personality_v0
>                 U __gcc_personality_v0@@GCC_3.3.1
> 00000000000126b0 T __gnu_objc_personality_v0
> 0000000000012d20 T __gnustep_objc_personality_v0
> 0000000000012d60 T __gnustep_objcxx_personality_v0
>                 w __gxx_personality_v0
> 00000000000126f0 t internal_objc_personality
> 
> I'm a bit suspicious of the "__gcc_personality_v0@@GCC_3.3.1" line, since I'm 
> compiling with clang rather than gcc.  But that might be a red herring.
> 
> The llvm/clang developers suggested I get in touch with GNUstep to see if 
> this is a known issue.  Has anyone seen this behavior before?
> 
> Thanks,
> 
> David
> 
> 
> 
> 
> 
> _______________________________________________
> Discuss-gnustep mailing list
> Discuss-gnustep@gnu.org
> https://lists.gnu.org/mailman/listinfo/discuss-gnustep




reply via email to

[Prev in Thread] Current Thread [Next in Thread]