【问题标题】:When will Linux kernel reset the signal handler for SIGSEGV to SIG_DFL?Linux 内核何时将 SIGSEGV 的信号处理程序重置为 SIG_DFL?
【发布时间】:2018-11-13 11:22:47
【问题描述】:
如果我为SIGSEGV 设置了信号处理程序,而生成的分段错误如下:
int *a = NULL;
*a = 1;
处理程序将被调用,但这个信号处理程序只会被调用一次。所以,我猜Linux内核会将信号处理程序重置为SIG_DFL,但是什么时候呢?我想知道细节,所以我检查了Linux内核源代码,但还没有找到线索。如果您知道详细信息,请给我代码。
【问题讨论】:
标签:
c
linux-kernel
segmentation-fault
signal-handling
【解决方案1】:
这取决于您如何注册信号处理程序。
使用sigaction 和没有SA_RESETHAND 标志,将不会重置为SIG_DFL(尽管从响应SIGSEGV 的信号处理程序运行返回由于分段错误在技术上是UB)。
使用SA_RESETHAND,它将被重置,如果您使用signal 注册处理程序,则未指定处理程序是否将被重置(所以不要使用signal())。
例子:
#include <signal.h>
#include <unistd.h>
int volatile*a;
void h(int Sig) { write(1,"h\n", 2); }
int main()
{
//sigaction(SIGSEGV,&(struct sigaction){.sa_handler=h}, 0); //won't reset the handler, will likely loop
sigaction(SIGSEGV,&(struct sigaction){.sa_handler=h,.sa_flags=SA_RESETHAND}, 0); //will reset the handler
//signal(SIGSEGV,h); //may or may not reset the handler
*a=1;
return 0;
}
【解决方案2】:
正如@PSkocik 正确回答的那样,在正常情况下,除非用户在sigaction 中安装了带有SA_RESETHAND 标志的信号处理程序,否则内核不会费心将信号操作更改为默认值。
但是,在某些情况下,内核确实将SIGSEGV 的信号操作更改为默认值。假设用户安装了信号处理程序,然后在生成信号之前耗尽了整个内存。在这种情况下,内核将无法创建帧来执行信号处理程序,因为没有剩余内存。在感知到这种情况后,内核会执行以下操作:
- 检查用户是否为
SIGSEGV 安装了处理程序。如果是,则将操作更改为默认操作,如果用户已阻止它,也取消阻止 SIGSEGV。
- 向用户发送
SIGSEGV 信号以终止用户进程。