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

时间:2011-12-06 14:40:35

标签: c++ c segmentation-fault

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

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

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

谢谢!

6 个答案:

答案 0 :(得分:20)

在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;
}

答案 1 :(得分:8)

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

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

答案 2 :(得分:4)

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

这是有充分理由的:你真的期望在SIGSEGV之后内存(你的线程共享的内存)是完整的吗?毕竟,你刚刚证明某些寻址被破坏了,所以假设剩余的内存空间是干净的,这是非常乐观的。

考虑一个不同的并发模型,例如与流程。进程不共享其内存或仅共享其明确定义的部分(共享内存),并且一个进程可以合理地处理另一个进程何时死亡。当您拥有该程序的关键部分(例如核心温度控制)时,将其置于额外的进程中可以防止其他进程分段错误导致内存损坏。

答案 3 :(得分:3)

如果发生分段错误,最好放弃进程。你怎么知道你的进程的任何内存在此之后都可用?如果程序中的某些东西弄乱了内存它不应该,为什么你认为它没有弄乱你的进程实际上可以访问而没有segfaulting的内存的其他部分呢?

我认为这样做最有利于攻击者。

答案 4 :(得分:3)

史蒂夫的回答实际上是一个非常有用的公式。我在一个复杂的嵌入式软件中使用了类似的东西,其中代码中至少有一个SIGSEGV错误,我们无法按发货时间追踪。只要你可以重置你的代码没有不良影响(内存或资源泄漏),并且错误不是导致无限循环的东西,它可以是一个救星(即使它更好地修复bug)。在我们的案例中,仅供参考,它是单线程。

但遗漏的是,一旦你从信号处理程序恢复,它将无法再次工作,除非你取消屏蔽信号。以下是一大堆代码:

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

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

答案 5 :(得分:0)

从coredumper的描述来看,它的目的不是你想要的,而只是允许制作过程记忆的快照。

就个人而言,我不会在触发核心转储之后继续保持流程 - 它可以通过很多方式来解决 - 并且会在重新启动流程后使用一些持久性来允许数据恢复。

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