我遇到过一个有趣的案例,当我试图捕获异常时,C++ 给了我一个总线错误。
我创建了一个最小的示例来重现该错误:
#include <iostream>
using Vertex = std::vector<double>;
struct TestStruct {
std::vector<Vertex> vertices;
};
void testFunction(TestStruct& set1, TestStruct& set2) {
if (set1.vertices.front().size() != set2.vertices.front().size()) {
throw std::invalid_argument("set1 has different dimensions (" +
std::to_string(set1.vertices.front().size()) + ") than set2 (" +
std::to_string(set2.vertices.front().size()) + ").");
}
}
int main() {
TestStruct set1;
TestStruct set2;
std::vector<Vertex> vertices1 = {{0.0, 0.0}};
std::vector<Vertex> vertices2 = {{0.0, 0.0, 0.0}};
set1.vertices = vertices1;
set2.vertices = vertices2;
try {
testFunction(set1, set2);
} catch (const std::invalid_argument& e) {
std::cerr << "Exception: " << e.what() << std::endl;
}
}
我在这里期望的是代码会消除 invalid_argument 错误并打印它。 然而,我得到的实际输出是:
Process finished with exit code 138 (interrupted by signal 10:SIGBUS)
堆栈跟踪是
Process 7078 launched: '/Users/roland/Development/cps/sonia/build-debug/examples/cpp/Debug/sonia_exe' (arm64)
Process 7078 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=261, address=0xdac11410)
frame #0: 0x000000018d12aa58 libunwind.dylib`_Unwind_GetIP + 224
libunwind.dylib`:
-> 0x18d12aa58 <+224>: autib x16, x0
0x18d12aa5c <+228>: mov x17, x16
0x18d12aa60 <+232>: xpaci x17
0x18d12aa64 <+236>: cmp x16, x17
Target 1: (sonia_exe) stopped.
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=261, address=0xdac11410)
* frame #0: 0x000000018d12aa58 libunwind.dylib`_Unwind_GetIP + 224
frame #1: 0x0000000180887c7c libc++abi.dylib`__gxx_personality_v0 + 588
frame #2: 0x0000000100494930 libunwind.1.dylib`unwind_phase2 + 388
frame #3: 0x0000000100494b68 libunwind.1.dylib`_Unwind_Resume + 100
frame #4: 0x0000000100005ad4 sonia_exe`testFunction(set1=0x000000016fdfef20, set2=0x000000016fdfef08) at sonia.cpp:21:9
frame #5: 0x00000001000061e8 sonia_exe`main at sonia.cpp:38:9
frame #6: 0x000000018054d0e0 dyld`start + 2360
(lldb)
有趣的是,当我不尝试捕获错误时,代码会按预期抛出错误。
我真的不知道这里发生了什么,希望得到任何帮助!
一般来说,您需要考虑代码中不同层的异常代码。在语言层,您可以抛出异常,编译器将在捕获异常时提供调用堆栈展开。
从操作系统的角度来看,这仍然是一个功能完美的程序(即使代码的逻辑不是)。
在操作系统层,还有一种方法可以处理“低级”异常,例如除以零或访问您未正确访问的内存。这些是阻止用户空间程序继续做错误事情的保护措施,并且它会被内核捕获。在这种情况下,POSIX 兼容内核将触发“信号”(异步)。
“信号”是存储在失败线程的当前调用堆栈上的函数的地址(您可以有时自定义)。
然后内核将恢复跳转到该处理程序/函数的线程。默认情况下,当从该函数返回时,内核将尝试重新执行相同的代码,如果再次失败,将中止程序。在某些处理程序中,您可以修复错误的代码,以便第二次尝试可以工作,但这非常困难,而且您可能不会费心这样做。
默认函数可以转储回溯或创建核心转储。请注意,这与您的代码 (*) 和 C++ 异常处理程序完全无关。
这就是您在问题中观察到的内容,这与 C++ 异常无关。除非使用 POSIX 特定方式,否则您无法捕获它们(并且很可能,您的代码将不如默认处理程序有用如果您可以安装自己的处理程序)。
一般来说,当程序尝试访问它尚未首先声明的内存时,您会得到一个
SIGSEGV
;当您尝试访问未对齐的内存时(例如,尝试访问 char ),您会得到一个 SIGBUS
在奇数指针地址上)。
您的示例代码无法重现您记录的错误,因为这可能是由于最小代码中不可见的对齐问题造成的。