3

I have encountered in a problem where segmentation fault is being raised within segmentation fault handler. Although I have already fixed the actual issue, but still I am confused that why below program is not going in infinite loop:

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

void C() 
{
    int *p = NULL;
    *p = 3;
}

void B() 
{
    C();
}

void segfault_sigaction(int signal, siginfo_t *si, void *arg)
{
    printf("Came in sigaction.\n");
    //if(si)
        //printf("Caught segfault at address %p\n", si->si_addr);
    B();
}
int main(void)
{
    struct sigaction sa; 

    memset(&sa, 0, sizeof(struct sigaction));
    sigemptyset(&sa.sa_mask);
    sa.sa_sigaction = segfault_sigaction;
    sa.sa_flags   = SA_SIGINFO;

    sigaction(SIGSEGV, &sa, NULL);

    segfault_sigaction(0, NULL, NULL);

    return 0;
}

Output of the above code is as below:

Came in sigaction.
Came in sigaction.
Segmentation fault (core dumped)

In the comments of this similar post: Segmentation fault within segmentation fault handler some folks have commented that it should go in infinite loop but it's not the current behavior. Can someone explain to me what's happening ??

Pushpendra
  • 459
  • 1
  • 4
  • 18
  • Also see [How to avoid using printf in a signal handler?](https://stackoverflow.com/q/16891019/608639) and [Print int from signal handler using write or async-safe functions](https://stackoverflow.com/q/14573000/608639). – jww Jun 08 '18 at 07:40
  • 1
    See [What happens if I catch SIGSEGV and the signal handler causes another SIGSEGV](https://stackoverflow.com/questions/33265851/what-happens-if-i-catch-sigsegv-and-the-signal-handler-causes-another-sigsegv) and [Segfault in SIGSEGV handler](https://stackoverflow.com/questions/33743599/segfault-in-sigsegv-handler). The short answer is that you have to set SA_NODEFER to get the behavior you want. – Mark Plotnick Jun 08 '18 at 16:05
  • @MarkPlotnick thanks Mark your answer completely clarified what’s happening with my program. – Pushpendra Jun 29 '18 at 05:11

1 Answers1

3

You are raising a signal while in a signal handler. The POSIX standard says:

[table of safe functions]

All functions not in the above table are considered to be unsafe with respect to signals. In the presence of signals, all functions defined by this volume of IEEE Std 1003.1-2001 shall behave as defined when called from or interrupted by a signal-catching function, with a single exception: when a signal interrupts an unsafe function and the signal-catching function calls an unsafe function, the behavior is undefined.

void C() is an unsafe function because it is not in the list of safe functions, therefore having it raise a signal causes undefined behaviour. (I think it is also intended to mean that raising a signal from the signal handler function causes UB too, although the wording is unclear).

Being undefined behaviour, you cannot rely on an infinite loop or any other such behaviour.

Other points:

  • Dereferencing null is undefined behaviour and is not guaranteed to generate a SIGSEGV in the first place.
  • Calling printf in the signal handler is undefined behaviour because that is not one of the safe functions from the table either.
  • It is also UB to return from a signal handler for SIGSEGV. The only portable way to get out of the signal handler is to abort the process with a call such as exit.
M.M
  • 138,810
  • 21
  • 208
  • 365
  • Why ‘void C()’ is unsafe ? Is every user defined function comes to unsafe list by default or is there something wrong in the declaration/definition of this function? – Pushpendra Jun 10 '18 at 08:17
  • Every function is unsafe except those in the safe list – M.M Jun 10 '18 at 20:50
  • But I am not getting any undefined behaviour. As Mark pointed out in comments I got my program working infinitely until stack overflows. – Pushpendra Jun 29 '18 at 05:14
  • @Pushpendra you misunderstand what "undefined behaviour" means. It is not possible to say that you are not getting any. – M.M Jun 29 '18 at 05:52
  • 1
    Ok understood you mean even if we get desired output for instance still it’s behaviour could be undefined. – Pushpendra Jun 29 '18 at 07:52
  • -1 for "Every function is unsafe except those in the safe list" — this is misleading, and perhaps outright wrong. If you have a function that calls, and only calls, only functions on the list of functions required to be async-signal-safe, then your function certainly should be async-signal-safe. If your function is itself reentrant w.r.t any global state, then it should be async-signal-safe. – angelsl Oct 13 '21 at 22:05