Reputation: 1234
I was playing around with signals, and was surprised by this. Why does the program loop infinitely?
#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;
}
Note, I attempt to rectify the problem (i is NULL) by mallocing i in the handler, so my question isn't covered by this answer.
Upvotes: 4
Views: 811
Reputation: 137394
First, as one of the answers in the question you linked noted, catching an actual segfault and returning normally causes undefined behavior:
The behavior of a process is undefined after it returns normally from a signal-catching function for a SIGBUS, SIGFPE, SIGILL, or SIGSEGV signal that was not generated by kill(), sigqueue(), or raise().
Therefore, anything is possible.
Second, volatile
does you no good here. This is what gcc generates for *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
Even if you declare i
volatile itself (volatile int * volatile i;
), it wouldn't work. Now the compiler actually reads from i
only a single time:
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
Returning from the signal handler causes the segfaulting instruction to be re-executed, but your changes to i
in the signal handler will not affect the value in edx, so it still segfaults into an infinite loop. The OS doesn't know how the value in edx come about and will not recompute it (in this case, by loading i again) for you.
Upvotes: 4