【问题标题】:Segmentation fault handling分段故障处理
【发布时间】:2012-04-29 11:36:47
【问题描述】:

我有一个应用程序,用于捕获任何分段错误或 ctrl-c。 使用下面的代码,我能够捕获分段错误,但处理程序被一次又一次地调用。我怎么能阻止他们。 为了您的信息,我不想退出我的应用程序。我只需要注意释放所有损坏的缓冲区。

有可能吗?

void SignalInit(void )
{

struct sigaction sigIntHandler;

sigIntHandler.sa_handler = mysighandler;
sigemptyset(&sigIntHandler.sa_mask);
sigIntHandler.sa_flags = 0;
sigaction(SIGINT, &sigIntHandler, NULL);
sigaction(SIGSEGV, &sigIntHandler, NULL);

}

处理程序是这样的。

void mysighandler()
{
MyfreeBuffers(); /*related to my applciation*/
}

这里对于分段错误信号,处理程序被多次调用,显然 MyfreeBuffers() 给我释放已释放内存的错误。我只想释放一次,但仍然不想退出应用程序。

请帮忙。

【问题讨论】:

    标签: c linux signals signal-handling


    【解决方案1】:

    SIGSEGV 之类的默认操作是终止您的进程,但是当您为其安装了处理程序时,它将调用您的处理程序来覆盖默认行为。但问题是在处理程序完成后可能会重试 segfaulting 指令,如果您没有采取措施修复第一个 seg 错误,则重试的指令将再次出错,并继续下去。

    所以首先找出导致SIGSEGV 的指令并尝试修复它(您可以在处理程序中调用backtrace() 之类的东西,自己看看出了什么问题)

    另外,POSIX 标准是这样说的,

    进程正常返回后的行为是不确定的 [XSI] SIGBUS、SIGFPE、SIGILL 或 不是由 kill() 生成的 SIGSEGV 信号,[RTS] sigqueue(), 或 raise()。

    因此,理想的做法是首先修复您的段错误。 段错误处理程序并不意味着绕过底层错误条件

    所以最好的建议是- 不要抓住SIGSEGV。让它转储核心。分析核心。修复无效的内存引用,然后就可以了!

    【讨论】:

    • 捕获分段违规有时很有用,因为这样程序员就能够在程序崩溃之前报告错误发生在 stderr、日志文件或远程服务器的位置。我想像这样:程序员保留全局变量,存储当前处理函数的名称(多线程程序的不同内容)和当前行号(行号变量更新语句(以处理能力为代价)将是自动插入每一行)。当发生段错误时,程序员可以将“SIGSEGV in tois()@main.c:492”报告到日志。
    【解决方案2】:

    我完全不同意“不要赶上 SIGSEGV”的说法

    这是处理意外条件的一个很好的做法。使用与setjmp/longjmp 关联的信号机制来处理 NULL 指针(由 malloc 失败给出)比在整个代码中分发错误条件管理要干净得多。

    但是请注意,如果你在SEGV 上使用''sigaction'',你不能忘记在sa_flags 中说SA_NODEFER - 或者找到另一种方法来处理SEGV 将触发你的处理程序的事实一次。

    #include <setjmp.h>
    #include <signal.h>
    #include <stdio.h>
    #include <string.h>
    
    static void do_segv()
    {
      int *segv;
    
      segv = 0; /* malloc(a_huge_amount); */
    
      *segv = 1;
    }
    
    sigjmp_buf point;
    
    static void handler(int sig, siginfo_t *dont_care, void *dont_care_either)
    {
       longjmp(point, 1);
    }
    
    int main()
    {
      struct sigaction sa;
    
      memset(&sa, 0, sizeof(sigaction));
      sigemptyset(&sa.sa_mask);
    
      sa.sa_flags     = SA_NODEFER;
      sa.sa_sigaction = handler;
    
      sigaction(SIGSEGV, &sa, NULL); /* ignore whether it works or not */ 
    
      if (setjmp(point) == 0)
       do_segv();
    
      else
        fprintf(stderr, "rather unexpected error\n");
    
      return 0;
    }
    

    【讨论】:

    • 这是一个很好的解决方案。我不是特别喜欢“让它崩溃然后分析核心转储”。
    • 请注意,您确实仍然需要使用这种样式传播错误检查,但方式不同。在这里,调用代码必须知道如何清理它在发生错误时调用的所有代码的任何资源。在传统风格中,每段代码都会检查错误,然后只清理自己的资源。 IMO 后者更可取,因为每个部分对其他部分的了解较少。
    • 超级有用的答案,谢谢。另请参阅“标准信号”部分here...看起来如果我想捕获所有内容,我需要手动指定一堆信号...
    • 好的,如果你这样做,你可以使用strsignal 来获取信号的字符串表示,然后你可以打印/记录该字符串和sig int 本身一般.然后您可以将这段代码重用于一大堆信号,只需 1 个handler() 函数!
    【解决方案3】:

    如果SIGSEGV 再次触发,显而易见的结论是对MyfreeBuffers(); 的调用没有解决了根本问题(如果该函数确实只对free() 分配了一些内存,我不知道你为什么会这么认为)。

    大致上,SIGSEGV 会在尝试访问不可访问的内存地址时触发。如果您不打算退出应用程序,则需要使该内存地址可访问,或者使用longjmp() 更改执行路径。

    【讨论】:

      【解决方案4】:

      您不应该尝试在SIG_SEGV 之后继续。这基本上意味着您的应用程序环境以某种方式损坏。可能是您刚刚取消了对空指针的引用,或者可能是某些错误导致您的程序破坏了它的堆栈或堆或某些指针变量,您只是不知道。 唯一安全的做法是终止程序。

      处理 control-C 是完全合法的。很多应用程序都这样做,但你必须非常小心你在信号处理程序中所做的事情。您不能调用任何不可重入的函数。这意味着如果您的 MyFreeBuffers() 调用 stdlib free() 函数,您可能会被搞砸。如果用户在程序处于 malloc()free() 的中间时按下 control-C,从而在操作他们用来跟踪堆分配的数据结构的一半时,如果你调用 @987654326,你几乎肯定会破坏堆@ 或 free() 在信号处理程序中。

      关于信号处理程序中唯一安全的事情,您可以设置一个标志来表示您已捕获到信号。然后,您的应用可以定期轮询标志以确定是否需要执行某些操作。

      【讨论】:

        【解决方案5】:

        你可以设置一个状态变量,如果没有设置它就只释放内存。每次都会调用信号处理程序,您无法控制该 AFAIK。

        【讨论】:

          【解决方案6】:

          我可以看到从 SIG_SEGV 恢复的案例,如果您在循环中处理事件并且其中一个事件导致分段违规,那么您只想跳过此事件,继续处理剩余事件。在我看来,SIG_SEGV 类似于 Java 中的 NullPointerException。是的,在其中任何一个之后,状态都会不一致且未知,但是在某些情况下,您希望处理这种情况并继续。例如,在 Algo 交易中,您可以暂停订单的执行并允许交易者手动接管,而不会导致整个系统崩溃并破坏所有其他订单。

          【讨论】:

            【解决方案7】:

            看起来至少在 Linux 下使用带有 -fnon-call-exceptions 选项的技巧可以解决问题。它将提供将信号转换为通用 C++ 异常并以通用方式处理它的能力。 以linux3/gcc46: "-fnon-call-exceptions", which signals are trapping instructions? 为例。

            【讨论】:

              猜你喜欢
              • 2018-01-19
              • 1970-01-01
              • 2016-09-09
              相关资源
              最近更新 更多