尝试捕获异常时发生 C++ sigbus 错误

问题描述 投票:0回答:1

我遇到过一个有趣的案例,当我试图捕获异常时,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) 

有趣的是,当我不尝试捕获错误时,代码会按预期抛出错误。

我真的不知道这里发生了什么,希望得到任何帮助!

c++ try-catch exc-bad-access sigbus
1个回答
0
投票

一般来说,您需要考虑代码中不同层的异常代码。在语言层,您可以抛出异常,编译器将在捕获异常时提供调用堆栈展开。

从操作系统的角度来看,这仍然是一个功能完美的程序(即使代码的逻辑不是)。

在操作系统层,还有一种方法可以处理“低级”异常,例如除以零或访问您未正确访问的内存。这些是阻止用户空间程序继续做错误事情的保护措施,并且它会被内核捕获。在这种情况下,POSIX 兼容内核将触发“信号”(异步)。

“信号”是存储在失败线程的当前调用堆栈上的函数的地址(您可以有时自定义)。

然后内核将恢复跳转到该处理程序/函数的线程。默认情况下,当从该函数返回时,内核将尝试重新执行相同的代码,如果再次失败,将中止程序。在某些处理程序中,您可以修复错误的代码,以便第二次尝试可以工作,但这非常困难,而且您可能不会费心这样做。

默认函数可以转储回溯或创建核心转储。请注意,这与您的代码 (*) 和 C++ 异常处理程序完全无关。

这就是您在问题中观察到的内容,这与 C++ 异常无关。除非使用 POSIX 特定方式,否则您无法捕获它们(并且很可能,您的代码将不如默认处理程序有用如果您可以安装自己的处理程序)。

一般来说,当程序尝试访问它尚未首先声明的内存时,您会得到一个

SIGSEGV
;当您尝试访问未对齐的内存时(例如,尝试访问 char ),您会得到一个
SIGBUS
在奇数指针地址上)。

您的示例代码无法重现您记录的错误,因为这可能是由于最小代码中不可见的对齐问题造成的。

© www.soinside.com 2019 - 2024. All rights reserved.