捕获分段违规并继续生活

时间:2012-04-25 00:13:38

标签: c memory malloc signals

我正在编写一个正在检查自己地址空间的程序。

具体来说,我关心所有malloc-ed数据块。如果有一些系统调用来获取它们的列表,那将是太棒了(对于我的应用程序,我不能使用LD_PRELOAD,-wrap,也没有任何额外的命令行选项)。如果有办法做到这一点,我很乐意听到它,而不仅仅是对我所陈述的问题的回答。

代替这一点,我目前的方法是取消引用一切并环顾四周。显然,所有可能指针的集合都是等待发生的段错误的雷区,因此我尝试注册信号处理程序并使用setjmp / longjmp(通过使处理程序不执行任何操作而忽略segfault是一个无限循环,因为处理程序将返回到错误指令)。一些示例代码如下:

static jmp_buf buf;
void handler(int i) {
    printf("    Segfaulted!\n");
    longjmp(buf,-1);
}
void segfault(void) {
    int* x = 0x0;
    int y = *x;
}
void test_function(void) {
    signal(11,handler);
    while (1) {
        if (setjmp(buf)==0) {
            printf("Segfaulting:\n");
            segfault();
        }
        else {
            printf("Recovered and not segfaulting!\n");
        }
        printf("\n");
    }
}

输出结果为:

    Segfaulting:
        Segfaulted!
    Recovered and not segfaulting!

    Segfaulting:
    Segmentation fault

所以,处理程序第二次没有工作。我不知道为什么会这样,但我推测它与不清除原始信号有关。我不知道该怎么做。

顺便说一下,我首先尝试了sigsetjmp / siglongjmp,但是在setjmp.h中由于某种原因没有定义它们。我得到了模糊的共鸣,需要传递一些额外的编译标志,但是,和以前一样,这个应用程序不允许这样做。

正在使用的系统是Ubuntu Linux 10.04 x86-64,任何的解决方案都需要是可移植的。

谢谢!
伊恩[

编辑:处理程序中的sigrelse清除信号,并有效地修复问题。问题现在涉及提出的其他问题 - 是否有更好的方法(即获得malloc块)?怎么了sigsetjmp / siglongjmp?为什么我需要重置信号?]

2 个答案:

答案 0 :(得分:2)

signal()是一个遗留接口,在调用信号处理程序后可能会也可能不会重新注册它,具体取决于操作系统;您可能需要发出另一个signal()调用来重置信号处理程序作为处理程序中的最后一个操作。请参阅man 2 signal

sigaction()是设置信号处理程序的首选机制,因为它具有良好定义和可移植的行为。

答案 1 :(得分:1)

当调用SIGSEGV的信号处理程序时,SIGSEGV信号将被屏蔽,就像sigprocmask一样。任何信号都是如此。通常从信号处理程序返回将取消屏蔽它,但由于您没有返回,因此永远不会发生。有几种可能的解决方案:

  • 您可以在sigprocmask之前或之后拨打longjmp以自行取消屏蔽。
  • 您可以使用sigaction安装信号处理程序(无论如何都是首选方法)并使用SA_NODEFER标志来防止它被屏蔽。
  • 您可以使用sigsetjmpsiglongjmp函数,这些函数本身负责保存和恢复信号掩码。