42

我有一个应用程序,用于捕获任何分段错误或 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() 给了我释放已释放内存的错误。我只想释放一次,但仍然不想退出应用程序。

请帮忙。

4

7 回答 7

37

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

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

此外,POSIX 标准说,

一个进程的行为在它从一个信号捕获函数正常返回后,对于不是由 kill()、[RTS] sigqueue() 或 raise( )。

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

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

于 2012-04-18T05:00:19.987 回答
22

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

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

但是请注意,如果你在 ''sigaction'' 上使用,SEGV你一定不要忘记说- 或者找到另一种方式来处理这个事实,只会触发你的处理程序一次。SA_NODEFERsa_flagsSEGV

#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;
}
于 2015-09-26T17:08:27.433 回答
10

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

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

于 2012-04-18T05:28:34.403 回答
6

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

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

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

于 2012-04-18T10:54:52.877 回答
0

好吧,您可以设置一个状态变量,如果未设置,则仅释放内存。每次都会调用信号处理程序,您无法控制该 AFAIK。

于 2012-04-18T05:00:11.480 回答
0

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

于 2014-07-22T11:53:46.887 回答
0

看起来至少在 Linux 下使用带有 -fnon-call-exceptions 选项的技巧可以成为解决方案。它将提供将信号转换为通用 C++ 异常并以通用方式处理它的能力。查看linux3/gcc46: "-fnon-call-exceptions",哪些信号是捕获指令?例如。

于 2016-11-14T10:47:23.400 回答