C 如果我捕捉到SIGSEGV并且信号处理程序导致另一个SIGSEGV,会发生什么?
这个问题是在考虑Linux的情况下提出的。使用GCC编译器 如果SIGSEGV(我指的是通常导致SIGSEGV的违反)发生在一个旨在捕获SIGSEGV的信号处理程序中,那么会出现什么行为?帮助讨论的代码示例:C 如果我捕捉到SIGSEGV并且信号处理程序导致另一个SIGSEGV,会发生什么?,c,linux,C,Linux,这个问题是在考虑Linux的情况下提出的。使用GCC编译器 如果SIGSEGV(我指的是通常导致SIGSEGV的违反)发生在一个旨在捕获SIGSEGV的信号处理程序中,那么会出现什么行为?帮助讨论的代码示例: /* In main or whatever */ { struct sigaction sa = {}; /* initialised to all zero (I vote for GCC style breach of standard here) */ sa.sa_hand
/* 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”中,有一条令人不快的机器指令
1) 没有SA|u RESETHAND | SA|u NODEFER
:这似乎将系统置于逻辑陷阱:在“Q”处,应生成SIGSEGV。但是SIGSEGV在信号处理程序中被阻塞(默认sigaction行为)。如何继续执行?会结冰吗?它会跳过令人不快的指令吗(我想不会)
2) 使用SA|u RESETHAND | SA|u NODEFER
:我猜在这种情况下,当SIGSEGV重复时,程序将以“正常”方式崩溃
3) 仅使用
SA_NODEFER
:我猜在这种情况下,当重复SIGSEGV时,会递归调用信号处理程序;如果SIGSEGV总是重复,我们会得到一个冻结,直到堆栈溢出,然后发生什么。默认情况下,在处理信号时,它被屏蔽,因此不能递归触发。如果屏蔽信号由程序执行触发(无效内存访问、segfault、除法0等),则行为未定义:
如果在运行时生成了SIGBUS、SIGFPE、SIGILL或SIGSEGV
阻塞,结果未定义,除非信号由
终止(2)、信号队列(3)或提升(3)
在我的系统上,它会导致进程崩溃
使用SA_NODEFER
时,没有掩蔽,因此可以递归处理信号,直到堆栈溢出。添加SA_RESETHAND
将恢复默认操作(SIGSEGV崩溃)
我将您的示例改编为简单的测试程序,因此您可以验证此行为:
#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;
}
#包括
#包括
#包括
#包括
挥发性炭*ptr;
静态无效解除信号(int信号)
{
/*我们无法挽救局面,捕捉信号的目的是
只是在我们开始之前做一些聪明的事情来帮助调试*/
写(1,“11\n”,3);
*ptr=1;
写(1,“13\n”,3);
abort();/*这将为我们提供预期的内核转储(如果我们能够生存到这一点)*/
}
结构sigaction sa={};/*初始化为零(我在这里投票赞成GCC风格违反标准)*/
int main()
{
sa.sa_handler=灾难信号;
sa.sa_flags=/*sa_RESETHAND |*/sa_NODEFER;/*是否有*/
sigaction(SIGSEGV,&sa,NULL);
写(1,“25\n”,3);
*ptr=1;
}
Quis custodiet ipsos custodes?您应该只调用信号处理程序中的可重入函数。我的结果显示:处理器中的1和2-segfault会立即使程序崩溃。3-信号处理程序递归约13k次(变化),然后崩溃。-逻辑陷阱的答案:“如果SIGBUS、SIGFPE、SIGILL或SIGSEGV在阻塞时生成,则结果未定义,除非信号是由kill(2)、sigqueue(3)或raise(3)生成的。”您不能将注释标记为已接受的答案,但可以标记答案。