SIGABRT 在 Mac OS X 上使用 GCC 抛出和捕获异常
SIGABRT on throwing and catching exceptions with GCC on Mac OS X
我目前正在维护的 C++ 库中进行适当的错误管理。在为某些负面情况编写单元测试时(即测试正确抛出异常),单元测试套件会因 SIGABRT 而中止。我继续寻找并尝试通过抛出更简单的异常并尝试各种 catch 语句来归结错误。但即使是包罗万象的块也无法防止崩溃(对于 MWE,请参见下文)。
我的设置是这样的:我正在使用最新的 OS X Big Sur 11.1 和安装了最新的 XCode 命令行工具的 Mac。我正在使用来自 Homebrew 的 GCC,目前是 v10.2.0_1.
$ g++-10 -v
Using built-in specs.
COLLECT_GCC=g++-10
COLLECT_LTO_WRAPPER=/usr/local/Cellar/gcc/10.2.0_1/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_1 --libdir=/usr/local/Cellar/gcc/10.2.0_1/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_1' --with-bugurl=https://github.com/Homebrew/homebrew-core/issues --disable-multilib --with-native-system-header-dir=/usr/include --with-sysroot=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk SED=/usr/bin/sed
Thread model: posix
Supported LTO compression algorithms: zlib
gcc version 10.2.0 (Homebrew GCC 10.2.0_1)
我也用苹果的系统工具链自己编译了GCC。自己编译的GCC输出是这样的:
$ /opt/gcc/10.2.0/bin/g++-10 -v
Using built-in specs.
COLLECT_GCC=/opt/gcc/10.2.0/bin/g++-10
COLLECT_LTO_WRAPPER=/opt/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=/opt/gcc/10.2.0 --libdir=/opt/gcc/10.2.0/lib/gcc/10 --disable-nls --enable-checking=release --enable-languages=c,c++,objc,obj-c++,fortran --program-suffix=-10 --with-system-zlib --disable-multilib --with-native-system-header-dir=/usr/include --with-sysroot=/Library/Developer/CommandLineTools/SDKs/MacOSX11.1.sdk SED=/usr/bin/sed
Thread model: posix
Supported LTO compression algorithms: zlib
gcc version 10.2.0 (GCC)
结果还是一样:异常中止程序。
我的最小工作示例是这样的:
#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;
}
这可以很好地编译并在我的 Linux VM 上产生预期的输出。
我正在使用以下命令在我的 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
使用 LLDB 产生:
(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
在我看来,好像在展开阶段发生了另一个错误,然后导致终止。这也可以解释为什么没有到达任何 catch 块。
这超出了我的专业领域,所以欢迎任何想法。
编辑:在最新的 GCC Homebrew 版本之后更新了问题。
我确认了 Big Sur、Homebrew GCC 10.2 的意外行为。0_2 设置。将链接的 brew libstdc++ 更改为系统一(假设 macOS 安装了 /usr/lib
中的那个)解决了我的设置问题:
$ g++-10 main.cpp -o main -std=c++11
$ ./main
Abort trap: 6
$ otool -L main
main:
/usr/local/opt/gcc/lib/gcc/10/libstdc++.6.dylib (compatibility version 7.0.0, current version 7.28.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1292.60.1)
/usr/local/lib/gcc/10/libgcc_s.1.dylib (compatibility version 1.0.0, current version 1.0.0)
$ install_name_tool -change /usr/local/opt/gcc/lib/gcc/10/libstdc++.6.dylib /usr/lib/libstdc++.6.dylib main
$ ./main
this is an exception text
或者,在运行 main
之前设置export DYLD_LIBRARY_PATH=/usr/lib
也有同样的效果。
更新: 错误已经fixed 补丁包含在 brew 的 gcc-10.2.0_3.
我目前正在维护的 C++ 库中进行适当的错误管理。在为某些负面情况编写单元测试时(即测试正确抛出异常),单元测试套件会因 SIGABRT 而中止。我继续寻找并尝试通过抛出更简单的异常并尝试各种 catch 语句来归结错误。但即使是包罗万象的块也无法防止崩溃(对于 MWE,请参见下文)。
我的设置是这样的:我正在使用最新的 OS X Big Sur 11.1 和安装了最新的 XCode 命令行工具的 Mac。我正在使用来自 Homebrew 的 GCC,目前是 v10.2.0_1.
$ g++-10 -v
Using built-in specs.
COLLECT_GCC=g++-10
COLLECT_LTO_WRAPPER=/usr/local/Cellar/gcc/10.2.0_1/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_1 --libdir=/usr/local/Cellar/gcc/10.2.0_1/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_1' --with-bugurl=https://github.com/Homebrew/homebrew-core/issues --disable-multilib --with-native-system-header-dir=/usr/include --with-sysroot=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk SED=/usr/bin/sed
Thread model: posix
Supported LTO compression algorithms: zlib
gcc version 10.2.0 (Homebrew GCC 10.2.0_1)
我也用苹果的系统工具链自己编译了GCC。自己编译的GCC输出是这样的:
$ /opt/gcc/10.2.0/bin/g++-10 -v
Using built-in specs.
COLLECT_GCC=/opt/gcc/10.2.0/bin/g++-10
COLLECT_LTO_WRAPPER=/opt/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=/opt/gcc/10.2.0 --libdir=/opt/gcc/10.2.0/lib/gcc/10 --disable-nls --enable-checking=release --enable-languages=c,c++,objc,obj-c++,fortran --program-suffix=-10 --with-system-zlib --disable-multilib --with-native-system-header-dir=/usr/include --with-sysroot=/Library/Developer/CommandLineTools/SDKs/MacOSX11.1.sdk SED=/usr/bin/sed
Thread model: posix
Supported LTO compression algorithms: zlib
gcc version 10.2.0 (GCC)
结果还是一样:异常中止程序。
我的最小工作示例是这样的:
#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;
}
这可以很好地编译并在我的 Linux VM 上产生预期的输出。
我正在使用以下命令在我的 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
使用 LLDB 产生:
(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
在我看来,好像在展开阶段发生了另一个错误,然后导致终止。这也可以解释为什么没有到达任何 catch 块。
这超出了我的专业领域,所以欢迎任何想法。
编辑:在最新的 GCC Homebrew 版本之后更新了问题。
我确认了 Big Sur、Homebrew GCC 10.2 的意外行为。0_2 设置。将链接的 brew libstdc++ 更改为系统一(假设 macOS 安装了 /usr/lib
中的那个)解决了我的设置问题:
$ g++-10 main.cpp -o main -std=c++11
$ ./main
Abort trap: 6
$ otool -L main
main:
/usr/local/opt/gcc/lib/gcc/10/libstdc++.6.dylib (compatibility version 7.0.0, current version 7.28.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1292.60.1)
/usr/local/lib/gcc/10/libgcc_s.1.dylib (compatibility version 1.0.0, current version 1.0.0)
$ install_name_tool -change /usr/local/opt/gcc/lib/gcc/10/libstdc++.6.dylib /usr/lib/libstdc++.6.dylib main
$ ./main
this is an exception text
或者,在运行 main
之前设置export DYLD_LIBRARY_PATH=/usr/lib
也有同样的效果。
更新: 错误已经fixed 补丁包含在 brew 的 gcc-10.2.0_3.