我正在玩信号,并对此感到惊讶。为什么程序无限循环?
#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不涵盖我的问题。
答案 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)。