SIGSEGV 处理程序中的段错误 [英] Segfault in SIGSEGV handler

查看:20
本文介绍了SIGSEGV 处理程序中的段错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有以下 C 代码:

static void handler(int sig, siginfo_t *si, void *unused){printf("BOOM!
");//这里的另一个段错误退出(-1);}int main(int argc, char *argv[]){结构 sigaction sa;sa.sa_flags = SA_SIGINFO;sigemptyset(&sa.sa_mask);sa.sa_sigaction = 处理程序;if (sigaction(SIGSEGV, &sa, NULL) == -1)perror("设置处理程序失败");//在这里调用其他东西,在调用堆栈的某个地方发生了段错误}

如果执行遇到第一个分段错误,则将触发处理程序.但是当处理程序本身由于某种原因发生分段错误时会发生什么?它会用新的 siginfo_t 再次调用处理程序还是会立即终止程序?

如果再次调用处理程序,类似这样的工作:

int in_handler = 0;静态无效处理程序(int sig,siginfo_t *si,无效*未使用){printf("BOOM!
");如果(!in_handler){in_handler = 1;//可能出现段错误的代码} 别的 {//完全安全的代码}退出(-1);}

我问的原因是我目前正在用 C 语言编写某种单元测试框架.如果测试用例由于某些非法内存访问而失败,我想将所有剩余的测试标记为失败.如果由于某种原因测试严重破坏了堆,则此操作可能会失败,因为我必须遍历数据结构并将该信息写入 xml 文件.但是,如果将所有剩余的测试都标记为失败,我仍然希望保留哪些测试是失败的信息.

解决方案

来自 sigaction(2):

<块引用>

#include <signal.h>int sigaction(int signum, const struct sigaction *act, struct sigaction*旧行为);……

sigaction 结构被定义为类似

 struct sigaction {无效 (*sa_handler)(int);无效 (*sa_sigaction)(int, siginfo_t *, 无效 *);sigset_t sa_mask;int sa_flags;无效(*sa_restorer)(无效);}

....

sa_mask 给出一个信号掩码,在信号处理程序的执行.此外,该信号触发处理程序将被阻止,除非 SA_NODEFER 标志是用过.

因为您在设置信号处理程序时没有设置 SA_NODEFER 标志,所以如果在信号处理程序中发生另一个段错误,则不会再次调用它仍在信号处理程序中.一旦退出,之前被阻塞的信号就会被传递出去.

Lets assume I have the following C code:

static void handler(int sig, siginfo_t *si, void *unused)
{
    printf("BOOM!
");

    //another segfault here

    exit(-1);
}

int main(int argc, char *argv[])
{
    struct sigaction sa;

    sa.sa_flags = SA_SIGINFO;
    sigemptyset(&sa.sa_mask);
    sa.sa_sigaction = handler;
    if (sigaction(SIGSEGV, &sa, NULL) == -1)
        perror("failed to set handler");

   // call other stuff here, somewhere in the callstack a segfault happens 

}

If the execution hits the first segmentation fault the handler will be triggered. But what happens when in the handler itself from some reason a segmentation fault happens? Will it call the handler again with the new siginfo_t or will the program be terminated immediately?

If the handler is called again would something like this work:

int in_handler = 0;
static void handler(int sig, siginfo_t *si, void *unused)
{
    printf("BOOM!
");
    if(!in_handler) 
    {
         in_handler = 1;
         //code that could possibly segfault
    } else {
         //totally safe code
    }
    exit(-1);
}

The reason why I'm asking is that I'm currently writing some sort of unit test framework in C. If a testcase failed due to some illegal memory access I would like to mark all remaining tests as failed. If for some reason the test hast screwed up the heap really badly this operation could fail because I have to iterate over a data structure and write that information to a xml file. But if marking all remaining tests as failed I would still like to preserver the information which test was the failing one.

解决方案

From the man page for sigaction(2):

#include <signal.h>

int sigaction(int signum, const struct sigaction *act, struct sigaction
    *oldact);  

....

The sigaction structure is defined as something like

          struct sigaction {
              void (*sa_handler)(int);
              void (*sa_sigaction)(int, siginfo_t *, void *);
              sigset_t sa_mask;
              int sa_flags;
              void (*sa_restorer)(void);
          }

....

sa_mask gives a mask of signals which should be blocked during execu- tion of the signal handler. In addition, the signal which triggered the handler will be blocked, unless the SA_NODEFER flag is used.

Because you didn't set the SA_NODEFER flag when setting up your signal handler, it won't get called again if another segfault occurs while still in the signal handler. Once you exit, the signal which was previously blocked will then be delivered.

这篇关于SIGSEGV 处理程序中的段错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆