C 抓住机遇,继续生活

C 抓住机遇,继续生活,c,memory,malloc,signals,C,Memory,Malloc,Signals,我正在写一个程序来检查它自己的地址空间 具体来说,我关心所有malloc-ed数据块。如果有一些系统调用来获取它们的列表,那就太棒了(对于我的应用程序,我不能使用LD_PRELOAD,-wrap,也不能使用任何额外的命令行选项)。如果有办法做到这一点,我更愿意听到它,而不是下面我所说问题的答案 与此相反,我目前的方法是取消对所有内容的引用并四处查看。显然,所有可能的指针集都是等待发生的segfaults雷区,因此我尝试注册一个信号处理程序并使用setjmp/longjmp(简单地通过让处理程序什

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

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

与此相反,我目前的方法是取消对所有内容的引用并四处查看。显然,所有可能的指针集都是等待发生的segfaults雷区,因此我尝试注册一个信号处理程序并使用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有什么问题?为什么需要重置信号?]

signal()
是一个遗留接口,并且根据操作系统的不同,在信号处理器被调用后可以重新注册,也可以不重新注册;您可能需要发出另一个
signal()
调用,将信号处理程序重置为处理程序中的最后一个操作。参见
man 2信号


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

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

  • 您可以在
    longjmp
    之前或之后调用
    sigprocmask
    ,自行解除对其的屏蔽
  • 您可以使用
    sigaction
    安装信号处理程序(无论如何,这是首选的安装方式),并使用
    SA_NODEFER
    标志防止其被屏蔽
  • 您可以使用
    sigsetjmp
    siglongjmp
    函数,这些函数本身负责保存和恢复信号掩码

谢谢。我曾尝试在循环中设置信号处理程序,但这并不能解决问题。我不关心可移植性;这个程序只是为了我的目的而写的,这里的重点不在于可移植性,而在于行为的明确定义(这是可移植性的一个副作用)<代码>信号的行为定义不明确;这就是为什么
sigaction
存在的原因。我选择sigaction是因为它使用起来更简单,但您完全正确:可移植性对于定义的行为很重要。不过,在本例中,问题最终是我没有用sigrelse清除信号,所以这不是问题所在。您不能在运行时使用LD_PRELOAD或类似的方法,但是由于您正在编译代码,您不能简单地定义自己的
malloc()
,这是有原因的吗,或者在链接时包含其中一个?使用glibc的“内存分配挂钩”,您可以非常轻松地完成所需的检测: