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

时间:2018-10-22 15:25:41

标签: c++ c exception signals posix

首先是上下文:

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

请注意,服务和应用程序在2个单独的进程中运行。该应用程序在其上下文中打开一个代理,以通过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信号还没有太多经验)

1 个答案:

答案 0 :(得分:0)

这是我(用伪代码)解决问题的方法。可能还有其他方法,我还是大开眼界:

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。