从分段故障中恢复的最佳实践

Sam*_*Sam 10 c c++ segmentation-fault

我正在研究用C++编写的多线程进程,我正在考虑使用google-coredumper修改SIGSEGV处理,以便在发生分段错误时保持进程活跃.

然而,使用google-coredumper似乎已经成熟,有机会陷入无限循环的核心转储,除非我以某种方式重新初始化线程和可能导致核心转储的对象.

在尝试通过核心转储使进程保持活动时,我应该记住哪些最佳实践?我应该注意哪些"陷阱"?

谢谢!

use*_*527 21

它实际上可以用C.你可以用相当复杂的方式实现它:

1)覆盖信号处理程序

2)使用setjump()longjmp()设置跳回的位置,并实际跳回那里.

看看我写的这段代码(来自Peter Van Der Linden的"专家C编程:深度C秘密"的想法):

#include <signal.h>
#include <stdio.h>
#include <setjmp.h>

//Declaring global jmp_buf variable to be used by both main and signal handler
jmp_buf buf;


void magic_handler(int s)
{

    switch(s)
    {

        case SIGSEGV:
        printf("\nSegmentation fault signal caught! Attempting recovery..");
        longjmp(buf, 1);
        break;
    }

    printf("\nAfter switch. Won't be reached");

}



int main(void) 
{

    int *p = NULL;

    signal(SIGSEGV, magic_handler);

    if(!setjmp(buf))
    {

         //Trying to dereference a null pointer will cause a segmentation fault, 
         //which is handled by our magic_handler now.
         *p=0xdead;

    }
    else
    {
        printf("\nSuccessfully recovered! Welcome back in main!!\n\n"); 
    }



    return 0;
}
Run Code Online (Sandbox Code Playgroud)

  • 使用“longjmp”和朋友确实可以让您隔离发生段错误的代码行,但它不能让您隔离哪些内存可能已损坏。 (3认同)

par*_*mar 9

最佳做法是修复导致核心转储的原始问题并重新编译并重新启动应用程序.

要在野外部署之前捕获这些错误,请进行大量的同行评审并编写大量测试

  • 这是个好主意,但有时此应用程序会控制例如在不受控制的加热时可能损坏的科学相机。在这种情况下,回家并重新编译不是一种选择。我知道糟糕的硬件设计,但我在野外见过这种情况,在这种情况下从致命信号中恢复绝对至关重要。 (3认同)

小智 6

史蒂夫的回答实际上是一个非常有用的公式。我在一款复杂的嵌入式软件中使用了类似的东西,其中代码中至少有一个 SIGSEGV 错误,我们无法按发布时间追踪到该错误。只要您可以重置代码以消除不良影响(内存或资源泄漏),并且错误不会导致无限循环,它就可以成为救星(尽管最好修复错误)。仅供参考,在我们的例子中它是单线程。

但遗漏的是,一旦您从信号处理程序中恢复,除非您取消屏蔽信号,否则它将无法再次工作。这是执行此操作的一段代码:

sigset_t signal_set;
...
setjmp(buf);
sigemptyset(&signal_set);
sigaddset(&signal_set, SIGSEGV); 
sigprocmask(SIG_UNBLOCK, &signal_set, NULL); 
// Initialize all Variables...
Run Code Online (Sandbox Code Playgroud)

请务必释放内存、套接字和其他资源,否则发生这种情况时可能会泄漏内存。


thi*_*ton 5

我对分段错误的经验是,很难以可移植的方式捕获它们,并且在多线程上下文中以可移植的方式捕获它们几乎是不可能的。

这是有充分理由的:您真的希望内存(您的线程共享的)在 SIGSEGV 之后完好无损吗?毕竟,您刚刚证明了某些寻址已损坏,因此其余内存空间是干净的假设是相当乐观的。

考虑不同的并发模型,例如进程。进程不共享其内存或仅共享其中明确定义的部分(共享内存),并且当另一个进程死亡时,一个进程可以合理地继续工作。当您有程序的关键部分(例如核心温度控制)时,将其放入额外的进程中可以保护它免受其他进程分段错误的内存损坏。