c++ - 在信号处理程序中捕获 C++ 未处理的异常并恢复应用程序

标签 c++ c exception signals posix

首先一些背景:

我正在测试一些在嵌入式 Linux 中运行的 C 编写的服务的稳健性。我的所有测试都是用 C++ 编写的,并调用服务的 C API。

请注意,服务和应用程序在两个单独的进程中运行。应用程序在其上下文中打开代理以通过 tcp/ip 与服务进行通信。

为了检查编码错误的回调是否会中断服务,我给它提供了一个仅抛出 C++ 异常的函数。正如预期的那样,在此 C 回调中引发异常会导致应用程序崩溃。

到目前为止,该服务似乎对此很稳健:回调是从在客户端应用程序上下文中运行的线程调用的。这意味着,只有客户端应用程序崩溃,服务仍保持事件状态。

当我说应用程序崩溃时,我的意思是它收到了 SIGABRT 信号,这是来自 gdb 的调用堆栈:

(gdb) info stack
0  0x4c22cb94 in raise () from /lib/libc.so.6
1  0x4c230670 in abort () from /lib/libc.so.6
2  0xb6e9e6c4 in __gnu_cxx::__verbose_terminate_handler() () from /usr/lib/libstdc++.so.6
3  0xb6e9c214 in ?? () from /usr/lib/libstdc++.so.6
4  0xb6e9c288 in std::terminate() () from /usr/lib/libstdc++.so.6
5  0xb6e9c5ac in __cxa_throw () from /usr/lib/libstdc++.so.6
6  0x0011824c in LocationTest::crashingLocCb (location=<optimized out>)
at ../../../TestLibrary/200-Location/src/locationtest.cpp:427
7  0x00144f64 in locationCb (location=<optimized out>)
at ../../PAL/src/tms/pallocationprovider.cpp:109
8  0xb6fbdb50 in locationcallback_thread (thread_info=0x1a82b8)
at ../lib_c/src-gen/location_proxy.c:273
9  0x4c33defc in ?? () from /lib/libpthread.so.0

我现在想做的事情:

我想捕获信号 SIGABRT 并恢复测试应用程序,以进一步进行(检查服务是否有某些内部状态损坏;检查它是否导致了一些泄漏等。)

让东西尽可能干净的最佳方法是什么?

这是通过信号处理程序完成的,但是其他正在运行的线程会受到损害吗?那么将信号处理程序中捕获的信息发送回相关线程的最佳方法是什么?

(我对这些 posix 信号还没有太多经验)

最佳答案

这是我解决问题的方法(用伪代码)。可能还有其他方法,我仍然竖起耳朵:

void malfunction()
{

    terminate_handler previousTerminateHandler = set_terminate(callbackUnhandledExceptionTerminateHandler);

    registerCallback(throwingCb);
    launchTheTest();
    waitForErrorEvent();
    saveTheResult();
    doSomeCleanUp();

    set_terminate(previousTerminateHandler);

    return;
}

static void callbackUnhandledExceptionTerminateHandler()
{
    try{ throw; }
    catch(const exception& e) { 
        cout << e.what() << endl;
        notifyTheErrorEvent();
    }catch(...){
        cout << "callbackUnhandledExceptionTerminateHandler : else ???" << endl;
        abort();
    }

    //Log whatever information, you need such as pid, stack or whatever
    cout << "processId = " << getpid() << endl;

    //Here if you return from this handler, it will call abort();
    //You could let it ends, if you already logged what you needed.
    //You could also trap the thread, if this is something you already do elsewhere before stopping the application.

}

就我而言,我可以检查服务是否能够适应客户应用程序的崩溃,并且仍然能够让其他人(甚至相同!)打开另一个代理并执行更多工作。现在剩下要做的就是确保这里不会造成内存泄漏。 (只是为了回答那些会质疑为什么这一切的人)。

在更一般的情况下,可以使用相同的处理在未处理的异常时打印堆栈,而不需要 gdb。

关于c++ - 在信号处理程序中捕获 C++ 未处理的异常并恢复应用程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52932817/

相关文章:

python - 如何最好地过滤其 __cause__ (或 __context__)的异常?

c++ - 在 C 语言中,除了使用 #define val 外不能改变结构属性

c++ - 在 C++ 中推断函数或仿函数的返回类型

c++ - 在 C++ API 中支持 Z3 的浮点理论

c - 另一个函数中的函数声明有用吗?

c - 使用 malloc() 函数设置全局数组大小获取转储核心

c++ - 我需要帮助开发多态引擎 - 指令依赖树

c - ATtiny2313 上的初始化堆栈指针

python - 为什么这个上下文管理器的行为与字典理解不同?

matlab - 如何将数据传递给 MATLAB oncleanup 函数?