如果我捕捉到SIGSEGV,并且信号处理程序导致了另一个SIGSEGV,会发生什么? [英] What happens if I catch SIGSEGV and the signal handler causes another SIGSEGV?

查看:65
本文介绍了如果我捕捉到SIGSEGV,并且信号处理程序导致了另一个SIGSEGV,会发生什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这个问题是在考虑Linux的情况下提出的.使用了GCC编译器.

This question is asked with Linux in mind. GCC compiler is used.

如果在旨在捕获SIGSEGV的信号处理程序中发生SIGSEGV(通常是导致SIGSEGV的违规),将会发生什么行为?有助于讨论的代码示例:

What behaviour can be expected if SIGSEGV (I mean a violation that normally causes SIGSEGV) occurs within a signal handler whose purpose was to catch SIGSEGV? Code example to aid the discussion:

/* In main or whatever */
{
  struct sigaction sa = {}; /* initialised to all zero (I vote for GCC style breach of standard here) */
  sa.sa_handler = DisasterSignals;
  sa.sa_flags = SA_RESETHAND | SA_NODEFER;  /* To have or have not */
  sigaction(SIGSEGV, &sa, NULL);
}

static void DisasterSignals(int signal)
{
  /* We cannot save the situation, the purpose of catching the signal is
     only to do something clever to aid debugging before we go. */

  /* Q: What if we segfault in here?? */

  abort(); /* This should give us the expected core dump (if we survive to this point) */
}

想象一下,在点Q"处,有一条违规的机器指令.

Imagine, in the point "Q", There is an offending machine instruction.

1)没有 SA_RESETHAND |SA_NODEFER :这似乎使系统陷入逻辑陷阱:在"Q"处,应生成SIGSEGV.但是SIGSEGV在信号处理程序中被阻止(默认sigaction行为).如何继续执行?会冻结吗?它会跳过违规指令(我想不是)吗?

1) Without the SA_RESETHAND | SA_NODEFER: This appears to put the system in a logical trap: At "Q", SIGSEGV should be generated. But SIGSEGV is blocked in the signal handler (default sigaction behaviour). How can the execution continue? Will it freeze? Will it jump past the offending instruction (I guess not)?

2)使用 SA_RESETHAND |SA_NODEFER :我想在这种情况下,当重复SIGSEGV时,程序将以正常"方式崩溃.

2) With the SA_RESETHAND | SA_NODEFER: I guess in this case the program will crash in a "normal" fashion when SIGSEGV is repeated.

3)仅使用 SA_NODEFER :我想在这种情况下,当重复SIGSEGV时,将递归调用信号处理程序.如果始终重复执行SIGSEGV,我们将冻结直到堆栈溢出为止.

3) With only SA_NODEFER: I guess in this case the signal handler is recursively called when SIGSEGV is repeated; if the SIGSEGV is always repeated, we get a freeze until the stack overflows, and then what.

推荐答案

默认情况下,正在处理信号时将其屏蔽,因此无法递归触发它.如果屏蔽信号是由程序执行触发的(无效的内存访问,segfault,除以0等),则该行为是不确定的:

By default, while signal is being handled it is masked, so it can't be triggered recursively. If masked signal is triggered by program execution (invalid memory access, segfault, division by 0 etc.), the behavior is undefined:

如果在生成SIGBUS,SIGFPE,SIGILL或SIGSEGV的同时阻止,结果是不确定的,除非信号是由kill(2),sigqueue(3)或raise(3).

If SIGBUS, SIGFPE, SIGILL, or SIGSEGV are generated while they are blocked, the result is undefined, unless the signal was generated by kill(2), sigqueue(3), or raise(3).

在我的系统上,它导致进程崩溃.

On my system, it causes process to crash.

使用 SA_NODEFER 没有屏蔽,因此可以递归处理信号,直到堆栈溢出为止.添加 SA_RESETHAND 将恢复默认操作(SIGSEGV崩溃).

With SA_NODEFER there is no masking, so signal can be handled recursively until stack overflows. And adding SA_RESETHAND would restore default action (crash for SIGSEGV).

我将您的示例改编为简单的测试程序,因此您可以验证此行为:

I adapted your example to simple testing program, so you can verify this behavior:

#include<signal.h>
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>

volatile char *ptr;

static void DisasterSignals(int signal)
{
  /* We cannot save the situation, the purpose of catching the signal is
     only to do something clever to aid debugging before we go. */
  write(1, "11\n", 3);
  *ptr = 1;
  write(1, "13\n", 3);
  abort(); /* This should give us the expected core dump (if we survive to this point) */
}

struct sigaction sa = {}; /* initialised to all zero (I vote for GCC style breach of standard here) */

int main()
{
  sa.sa_handler = DisasterSignals;
  sa.sa_flags = /*SA_RESETHAND | */SA_NODEFER;  /* To have or have not */
  sigaction(SIGSEGV, &sa, NULL);

  write(1, "25\n", 3);
  *ptr = 1;
}

这篇关于如果我捕捉到SIGSEGV,并且信号处理程序导致了另一个SIGSEGV,会发生什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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