2

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

具体来说,我关心所有 malloc-ed 数据块。如果有一些系统调用来获取它们的列表,那就太好了(对于我的应用程序,我不能使用 LD_PRELOAD、-wrap 或任何额外的命令行选项)。如果有办法做到这一点,我更愿意听到它,而不是我在下面陈述的问题的答案。

取而代之的是,我目前的方法是取消引用所有内容并环顾四周。显然,所有可能的指针的集合是等待发生的段错误的雷区,所以我尝试注册一个信号处理程序并使用 setjmp/longjmp(通过让处理程序不做任何事情来简单地忽略段错误是一个无限循环,因为处理程序将返回到错误指令)。一些示例代码如下所示:

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 怎么了?为什么我需要重置信号?]

4

2 回答 2

2

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

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

于 2012-04-25T00:19:07.647 回答
1

SIGSEGV调用信号处理程序时,SIGSEGV信号将被屏蔽,就像被sigprocmask. 这适用于任何信号。通常从信号处理程序返回会取消屏蔽它,但由于您没有返回,所以这永远不会发生。有几个可能的解决方案:

  • 您可以sigprocmask在 之前或之后调用longjmp以自己取消屏蔽。
  • sigaction您可以使用(无论如何都是首选方式)安装信号处理程序并使用该SA_NODEFER标志来防止它被屏蔽。
  • 您可以使用sigsetjmpsiglongjmp函数,它们自己负责保存和恢复信号掩码。
于 2012-04-25T01:09:59.660 回答