Thanks very much, David- this is extremely helpful! As you might expect, my code was running perfectly on the Mac, but crashing on Linux- this explains both.
Just to make sure I understand, can you tell me exactly where to specify -fobjc-runtime=gnustep-1.8? Would that be an argument when building llvm/clang, or libobjc2, or both? Thank you, David > On Nov 1, 2017, at 4:25 AM, David Chisnall <[email protected]> wrote: > > 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 <[email protected]> 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 >> [email protected] >> https://lists.gnu.org/mailman/listinfo/discuss-gnustep > _______________________________________________ Discuss-gnustep mailing list [email protected] https://lists.gnu.org/mailman/listinfo/discuss-gnustep
