-1

I am trying to learn Signals. I know invalid memory access will cause segfault. So, I register a signal handler for SIGSEGV signal.

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


void sighandler(int signum)
{
    printf("%s\n", __func__);
}

int main()
{
    int *a = NULL;
    signal(SIGSEGV, sighandler);
    *a = 5;
    return 0;
}

Running this code, I am continuously getting SIGSEGV Signals. I thought i should only get the signal once. Can you guys explain why I am getting signals continuously

md.jamal
  • 4,067
  • 8
  • 45
  • 108
  • 1
    Also see [Formatted I/O inside signal handler](https://stackoverflow.com/q/17138158/608639), [`signal-safety(7)` man page](http://man7.org/linux/man-pages/man7/signal-safety.7.html) and friends. You must use async-safe functions in signal handlers. – jww Jul 07 '19 at 05:20

2 Answers2

4

After the SEGV handler finishes, the instruction that triggered re-executes. Since you didn't do anything to prevent the next execution from faulting, you get SEGV again, ad infinitum.

See more in this answer.

root
  • 5,528
  • 1
  • 7
  • 15
2

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;
}
Ahmed Masud
  • 21,655
  • 3
  • 33
  • 58