C信号(SIGSEGV)为什么会无限循环?

时间:2014-05-30 03:05:06

标签: c segmentation-fault signals

我正在玩信号,并对此感到惊讶。为什么程序无限循环?

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

//I'm told that volatile tells the compiler not to cache the address of the pointer.
volatile int *i;
void seg_fault_handler(int TrapID)
{
    i = malloc(sizeof(int));
    puts("seg fault avoided");
}

int main()
{
    signal(SIGSEGV, seg_fault_handler);
    *i += 1;
    return 0;
}

注意,我试图通过在处理程序中对i进行mallocing来纠正问题(我是NULL),因此this answer不涵盖我的问题。

1 个答案:

答案 0 :(得分:3)

首先,作为您链接的问题中的答案之一,捕获实际的段错误并正常返回会导致undefined behavior

  

正常返回后,进程的行为是未定义的   SIGBUS,SIGFPE,SIGILL或SIGSEGV的信号捕获功能   不是由kill(),sigqueue()或raise()生成的信号。

因此,一切皆有可能。

其次,volatile你在这里没有好处。这是gcc为*i += 1生成的内容:

movl    i, %eax            ; Copy the value (i.e., address) stored in i to eax
movl    i, %edx            ; Copy the value (i.e., address) stored in i to edx
movl    (%edx), %edx       ; Copy the value at the address in edx into edx <--- segfault here
addl    $1, %edx           ; Add 1 to edx
movl    %edx, (%eax)       ; Store the value in edx to the address in eax

即使你声明i volatile本身(volatile int * volatile i;),它也行不通。现在,编译器实际上只从i读取一次:

movl    i, %eax            ; Copy the value (i.e., address) stored in i to eax
movl    (%eax), %edx       ; Copy the value at the address in eax into edx <--- segfault here
addl    $1, %edx           ; Add 1 to edx
movl    %edx, (%eax)       ; Store the value in edx to the address in eax

从信号处理程序返回会导致重新执行segfaulting指令,但是对信号处理程序中的i的更改不会影响edx中的值,因此它仍然会陷入无限循环。操作系统不知道edx中的值是如何产生的,也不会为你重新计算它(在这种情况下,通过再次加载i)。