从分段错误中恢复的最佳实践

Best practices for recovering from a segmentation fault

本文关键字:最佳 恢复 分段 错误      更新时间:2023-10-16

我正在研究一个用c++编写的多线程进程,并且正在考虑使用google- coreddump修改SIGSEGV处理,以便在发生分段错误时保持进程存活。

然而,google- coreddump的这种用法似乎很有可能陷入核心转储的无限循环,除非我以某种方式重新初始化可能导致核心转储的线程和对象。

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

谢谢!

这实际上在c中是可能的。你可以用一种相当复杂的方式实现它:

1)覆盖信号处理程序

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

看看我写的这段代码(灵感来自Peter Van Der Linden的"Expert C Programming: Deep C Secrets"):

#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!!nn"); 
    }

    return 0;
}

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

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

Steve的答案实际上是一个非常有用的公式。我在一个复杂的嵌入式软件中使用了类似的东西,其中至少有一个SIGSEGV错误,我们无法通过发货时间来追踪。只要您可以重置代码,使其不会产生不良影响(内存或资源泄漏),并且错误不会导致无休止的循环,它就可以拯救生命(即使修复错误更好)。仅供参考,在我们的情况下,它是单线程的。

但是忽略的是,一旦您从信号处理程序中恢复,它将无法再次工作,除非您揭开信号的掩码。下面是一段代码:

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

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

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

这是一个很好的理由:你真的希望在SIGSEGV之后内存(线程共享的)是完整的吗?毕竟,您刚刚证明了一些寻址被破坏了,所以假设其余的内存空间是干净的是相当乐观的。

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

如果出现分段错误,您最好放弃该过程。在此之后,您如何知道进程的任何内存都是可用的?如果你的程序中有什么东西扰乱了内存,它不应该,为什么你相信它没有扰乱内存的其他部分,你的进程实际上可以访问没有分段故障?

我认为这样做将主要有利于攻击者。

从coreddump的描述来看,它的目的似乎不是你想要的,而只是允许对进程内存进行快照。

就我个人而言,我不会在进程触发核心转储后保留它——它有很多可能被破坏的方式——并且会使用一些持久性来允许在进程重新启动后恢复数据。

是的,正如parapura所建议的,更好的是找出导致SIGSEGV的原因并修复它。