Skip to content
Advertisement

sigaction’s signal handler not called in child process

I’ve a program, which installs a signal handler for SIGSEGV. In signal handler ( I try to catch crash ) I restart my application.

But when my application is resurrected it doesn’t handle SIGSEGV anymore.

Here’s an example:

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

const char * app = 0;

void sig_handler(int signo)
{
    puts("sig_handler");

    const pid_t p = fork();

    if (p == 0)
    {
        printf("Running app %sn", app);
        execl(app, 0);
    }

    exit(1);
}


int main(int argc, char** argv)
{
    app = argv[0];

    struct sigaction act;
    sigemptyset(&act.sa_mask);

    act.sa_handler = sig_handler;
    act.sa_flags = 0;

    const int status = sigaction(SIGSEGV, &act, 0) == 0;     
    printf("signaction = %dn", status);

    sleep(5);

    int* a = 0;
    int b = *a;

    return 0;
}

what I get in output is:

./signals 
signaction = 1
sig_handler
Running app ./signals
signaction = 1

So I can see sighandler was set in right way, but resurrected app simply crashed silently.

What am I missing?

Advertisement

Answer

What you’re missing is that, by default, when you handle a signal, any additional delivery of that signal is blocked until the handling function returns. Since you never return from your signal handler (you call execl() instead) then your second SIGSEGV isn’t being delivered. It’s waiting until your signal handler function returns, which it never will.

To get the results you seem to want, you have to change this default behavior. The easiest way to do that is to set the appropriate flag when you register the signal handler:

act.sa_flags = SA_NODEFER;

and you’ll get the recursive behavior you seem to be looking for. Your other option is to unblock it with sigprocmask() before your execl() call.

Couple of other ancillary points:

  1. puts(), printf(), execl() and exit() are not async-safe, and shouldn’t be called from a signal handler. execle() and _exit() would be OK.

  2. You’re not calling execl() properly. The first argument should be the application name, so execl(app, app, (char *)0); would be correct. The cast to char *, which you omit, is required.

User contributions licensed under: CC BY-SA
6 People found this is helpful
Advertisement