分段故障处理

use*_*606 33 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);

}
Run Code Online (Sandbox Code Playgroud)

和处理程序是这样的.

void mysighandler()
{
MyfreeBuffers(); /*related to my applciation*/
}
Run Code Online (Sandbox Code Playgroud)

这里对于Segmentation故障信号,处理程序被多次调用,很明显,MyfreeBuffers()给了我释放已经释放的内存的错误.我只想释放一次,但仍然不想退出应用程序.

请帮忙.

Pav*_*ath 34

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

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

此外,POSIX标准说,

在正常从[XSI] SIGBUS,SIGFPE,SIGILL或SIGSEGV信号的信号捕获函数返回之后,进程的行为是未定义的,该函数不是由kill(),[RTS] sigqueue()或raise( ).

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

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

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

Cha*_*nac 10

我完全不同意"不要抓住SIGSEGV"的说法.

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

但是请注意,如果你用'的sigaction'上SEGV,你一定不要忘了说SA_NODEFERsa_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;
}
Run Code Online (Sandbox Code Playgroud)


caf*_*caf 9

如果SIGSEGV再次闪光,明显的结论是,调用MyfreeBuffers();已经没有固定的根本问题(如果该功能确实只有free()一些分配的内存,我不知道为什么你会认为它会).

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


Jer*_*myP 6

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

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

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