Linux 内核何时将 SIGSEGV 的信号处理程序重置为 SIG_DFL?

When will Linux kernel reset the signal handler for SIGSEGV to SIG_DFL?

如果我为 SIGSEGV 设置了信号处理程序,则会生成如下分段错误:

int *a = NULL;
*a = 1;

将调用处理程序,但此信号处理程序只会调用一次。所以,我猜 Linux 内核会将信号处理程序重置为 SIG_DFL,但是什么时候?我想知道细节,所以我查看了Linux内核源代码,但还没有找到线索。如果您知道详细信息,请告诉我代码。

这取决于您如何注册信号处理程序。 使用 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;
}

正如@PSkocik 正确回答的那样,在正常情况下,内核不会费心将信号操作更改为默认值,除非用户在 sigaction 中安装了带有 SA_RESETHAND 标志的信号处理程序。

但是,有一种情况是内核确实将 SIGSEGV 的信号操作更改为默认值。假设,用户已经安装了信号处理程序,然后在生成信号之前耗尽了整个内存。在这种情况下,内核将无法创建帧来执行信号处理程序,因为没有剩余内存。感知到这种情况后,内核会执行以下操作:

  1. 检查用户是否为 SIGSEGV 安装了处理程序。如果是,则将操作更改为默认也取消阻止 SIGSEGV 如果用户已阻止它。
  2. 向用户发送 SIGSEGV 信号以终止用户进程。