SIGABRT on throwing and catching exceptions with GCC on Mac OS X

  c++, gcc, homebrew, macos

I’m currently working on proper error management in a C++ library I’m maintaining. When writing a unit test for some negative cases (i. e. testing the proper throwing of exceptions), the unit test suite simply aborted with SIGABRT. I went on a hunt and tried to boil down the error with simpler exceptions being thrown and experimenting with various catch statements. But even a catch-all block could not prevent the crash (for a MWE see below).

My setup is this: I’m working on a Mac with the most current OS X Big Sur 11.1 with the latest XCode Command Line Tools installed. I’m using GCC from Homebrew, currently v10.2.0.

$ g++-10 -v
Using built-in specs.
COLLECT_GCC=g++-10
COLLECT_LTO_WRAPPER=/usr/local/Cellar/gcc/10.2.0/libexec/gcc/x86_64-apple-darwin20/10.2.0/lto-wrapper
Target: x86_64-apple-darwin20
Configured with: ../configure --build=x86_64-apple-darwin20 --prefix=/usr/local/Cellar/gcc/10.2.0 --libdir=/usr/local/Cellar/gcc/10.2.0/lib/gcc/10 --disable-nls --enable-checking=release --enable-languages=c,c++,objc,obj-c++,fortran --program-suffix=-10 --with-gmp=/usr/local/opt/gmp --with-mpfr=/usr/local/opt/mpfr --with-mpc=/usr/local/opt/libmpc --with-isl=/usr/local/opt/isl --with-system-zlib --with-pkgversion='Homebrew GCC 10.2.0' --with-bugurl=https://github.com/Homebrew/homebrew-core/issues --disable-multilib --with-native-system-header-dir=/usr/include --with-sysroot=/Library/Developer/CommandLineTools/SDKs/MacOSX11.0.sdk SED=/usr/bin/sed
Thread model: posix
Supported LTO compression algorithms: zlib
gcc version 10.2.0 (Homebrew GCC 10.2.0)

I had to create a symbolic link from /Library/Developer/CommandLineTools/SDKs/MacOSX11.0.sdk -> /Library/Developer/CommandLineTools/SDKs/MacOSX11.1.sdk, because Homebrew’s GCC didn’t have a new release yet since the new XCode Command Line Tools were released.

My minimum working example is this:

#include <iostream>
#include <stdexcept>

int main()
{
    try {
        throw "this is an exception text";
    }
    catch(const char* e)
    {
        std::cerr << e << std::endl;
    }
    catch(...)
    {
        std::cerr << "Unknown error!" << std::endl;
    }

    return 0;
}

This compiles fine and produces the expected output on my Linux VM.

I’m using the following commands to compile it on my Mac:

$ g++-10 -o bin/main.o -c -std=c++11 main.cpp
$ g++-10 -o bin/main bin/main.o
$ ./bin/main
[1]    60310 abort      ./bin/main

Using LLDB yields:

(lldb) run
Process 61177 launched: './bin/main' (x86_64)
Process 61177 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGABRT
    frame #0: 0x00007fff202fa462 libsystem_kernel.dylib`__pthread_kill + 10
libsystem_kernel.dylib`__pthread_kill:
->  0x7fff202fa462 <+10>: jae    0x7fff202fa46c            ; <+20>
    0x7fff202fa464 <+12>: movq   %rax, %rdi
    0x7fff202fa467 <+15>: jmp    0x7fff202f46a1            ; cerror_nocancel
    0x7fff202fa46c <+20>: retq   
Target 0: (main) stopped.
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGABRT
  * frame #0: 0x00007fff202fa462 libsystem_kernel.dylib`__pthread_kill + 10
    frame #1: 0x00007fff20328610 libsystem_pthread.dylib`pthread_kill + 263
    frame #2: 0x00007fff2027b720 libsystem_c.dylib`abort + 120
    frame #3: 0x000000010048b00a libgcc_s.1.dylib`uw_init_context_1.cold + 5
    frame #4: 0x0000000100488475 libgcc_s.1.dylib`_Unwind_RaiseException + 69
    frame #5: 0x00000001001382f7 libstdc++.6.dylib`__cxa_throw + 55
    frame #6: 0x0000000100003d55 main`main + 52
    frame #7: 0x00007fff20343621 libdyld.dylib`start + 1

It seems to me as if another error happens during the unwind phase which then leads to the termination. Which would also explain, why no catch block is ever reached.

This is way out of my realm of expertise, so any ideas are welcome.

Source: Windows Questions C++

LEAVE A COMMENT