分段故障处理

时间:2012-04-18 04:48:01

标签: c linux signals signal-handling

我有一个应用程序,我用它来捕获任何分段错误或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*/
}

这里为Segmentation故障信号,多次调用处理程序,显而易见MyfreeBuffers()给出了释放已释放内存的错误。我只想释放一次,但仍然不想退出应用程序。

请帮忙。

7 个答案:

答案 0 :(得分:33)

SIGSEGV这样的事情的默认操作是终止你的进程,但是当你为它安装了一个处理程序时,它会调用你的处理程序来覆盖默认行为。但问题是在您的处理程序完成后可能会重试segfaulting指令,如果您没有采取措施来修复第一个seg故障,重试的指令将再次出现故障并继续运行。

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

此外,POSIX标准说,

  

正常返回后,进程的行为是未定义的   信号捕捉功能[XSI] SIGBUS,SIGFPE,SIGILL或   不是由kill(),[RTS] sigqueue()生成的SIGSEGV信号,   或者提高()。

所以,理想的做法是首先修复你的段错误。 段错误的处理程序并不意味着绕过潜在的错误条件

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

答案 1 :(得分:10)

我完全不同意声明"不要抓住SIGSEGV"

处理意外条件是一个非常好的实践。使用与setjmp/longjmp相关联的信号机制处理 NULL 指针(由malloc失败给出)更清晰,而不是在整个代码中分配错误条件管理。 / p>

但请注意,如果您使用' sigaction''在SEGV上,您不要忘记在SA_NODEFER中说sa_flags - 或者找到另一种处理事实的方法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;
}

答案 2 :(得分:9)

如果SIGSEGV再次触发,那么明显的结论就是对MyfreeBuffers();的调用修复了潜在问题(如果该函数确实只有{{1}一些分配的内存,我不知道为什么你会认为它会。)

粗略地说,当尝试访问无法访问的内存地址时,free()会触发。如果您不打算退出应用程序,则需要使该内存地址可访问,或者使用SIGSEGV更改执行路径。

答案 3 :(得分:6)

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

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

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

答案 4 :(得分:0)

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

答案 5 :(得分:0)

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

答案 6 :(得分:0)

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