Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

When mixing C++, ObjC++, and ObjC, something goes wrong in stack unwinding and a crash (abort) ensues #320

Open
lcampbel opened this issue Dec 7, 2024 · 3 comments

Comments

@lcampbel
Copy link

lcampbel commented Dec 7, 2024

I boiled this down from a large codebase into the tiniest example I could manage, but it's still six files (including the GNUmakefile) so I'm attaching a tarball. The code executes normally on macOS:

2024-12-07 11:04:20.489861-0500 xtest[83830:4242596] finally
2024-12-07 11:04:20.490356-0500 xtest[83830:4242596] Got expected exception: yup
2024-12-07 11:04:20.490434-0500 xtest[83830:4242596] passed

but on gnustep/linux (Ubuntu 20.04, gnustep-base 1.27.0, libobjc2 2.0.1) it crashes with an abort in libobjc2/eh_personality.c:

2024-12-07 16:03:45.990 xtest[3003478:3003478] finally
2024-12-07 16:03:45.991 xtest[3003478:3003478] Got expected exception: yup
Aborted (core dumped)

with this stack:

#0  __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
#1  0x00007facc5d1c859 in __GI_abort () at abort.c:79
#2  0x00007facc607b35a in objc_begin_catch () from /home/lcampbel/dev/AkamaiKit-3.7-alsi11-lib64/common/lib/libobjc.so.4.6
#3  0x00000000004023a0 in -[UnitTest xidTest] (self=0x1335488, _cmd=0x408c00 <objc_selector_list+144>) at xtest.m:42
#4  0x000000000040250a in main (argc=<optimized out>, argv=<optimized out>) at xtest.m:75

Weirdly, any of the following tweaks to the code makes the crash go away:

Reversing the order of the tests, changing this:

        [u fooTest];
        [u xidTest];

to this:

        [u xidTest];
        [u fooTest];

Inlining the C++ ctor and dtor, by omitting utest.cc and changing the declarations in utest.h from this:

  xid();
  ~xid();

to this:

  xid() {}
  ~xid() {}

or eliminating the allocation of an xid object in -[Xid init] by removing this line:

    xid u;

There's only one call to abort() in objc_begin_catch:

        // If we have a foreign exception while we have stacked exceptions, we have                                                                                                                                                                                       
        // a problem.  We can't chain them, so we follow the example of C++ and                                                                                                                                                                                           
        // just abort.                                                                                                                                                                                                                                                    
        if (td->caughtExceptions != 0)
        {
                // FIXME: Actually, we can handle a C++ exception if only ObjC                                                                                                                                                                                            
                // exceptions are in-flight                                                                                                                                                                                                                               
                abort();
        }

so I suspect something is not cleaning out td->caughtExceptions properly, but I'm not familiar enough with libobjc2 internals to say any more than that.

@davidchisnall
Copy link
Member

Thanks for the report. Unfortunately, things that depend on GNUstep Make are not reproducible because they add a load of flags to the build that are set when you configure GNUstep Make. And, with dependencies on Foundation, things are not possible to integrate with our testing infrastructure. Is it possible for you to provide a minimal reproducible case? Something with no dependencies outside libobjc2 and with all of the command-line flags that you provide?

From the provided files, I can't tell which ABI you're using. The old GCC ABI had a lot of limitations and I'd expect a crash in this case, the GNUstep 2.0 ABI should have fixed them (but may still contain bugs) and I think the GNUstep 1.0 ABI mostly fixed them but had a few corner cases.

@lcampbel
Copy link
Author

lcampbel commented Dec 10, 2024 via email

@davidchisnall
Copy link
Member

I haven't used GNUstep Make for many years, but I think the ng thing means that it will pass --fobjc-runtime=gnustep-2.0. That's the important flag. I might be able to reduce your test case if I have that, but something that compiles without Foundation would be very helpful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

2 participants