The signal handler is returning to instruction that triggered it namely *a = 5
which is causing it to loop.
You have several problems including the use of printf
inside a signal handler.
There are safe and not-safe ways of dealing with this
NOTES
Using signal(2)
is not recommended for signal handling in general.
Handling SIGSEGV
is even more complicated because of the way the signal semantics work. Quoting from the man page:
The only portable use of signal() is to set a signal's disposition to SIG_DFL or SIG_IGN. The semantics when using signal()
to establish a signal handler vary across
systems (and POSIX.1 explicitly permits this variation); do not use it for this purpose.
POSIX.1 solved the portability mess by specifying sigaction(2), which provides explicit control of the semantics when a
signal handler is invoked; use that interface instead of signal().
So the first thing you should do is use sigaction
.
Next, handling SIGSEGV is a weird beast:
How to write a signal handler to catch SIGSEGV?
and
Does linux allow any system call to be made from signal handlers?
have good answers and get into specific details. There are external links in some of the answers given there.
How to do this using signal(2)
Well :-) let's say you want to use signal(2) and you want to play with this in a weird way....
You can use sigjmpset
and siglongjmp
.
sigjmpset
marks a point where siglongjmp
should jump to. The first time sigjmpset
is called (to set the point) it returns 0. When siglongjmp
jumps to it, (which means it gets called again as a result of the long jump), it returns 1.
Which means we can do this:
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <setjmp.h>
sigjmp_buf env;
int sigsav;
void sighandler(int signum)
{
const char msg[] = "Skipping signal\n";
write(2, msg, sizeof(msg));
siglongjmp(env, sigsav);
}
int main()
{
int *a = NULL;
signal(SIGSEGV, sighandler);
if(!sigsetjmp(env, sigsav)) {
printf("setting value of a\n");
*a = 5;
}
else {
printf("returned to sigsetjmp, but now we skip it!\n");
}
return 0;
}