1

I am trying to understand how signal handling works so I decided to handle division by zero another way. The program should request input until division by zero does not occur. However, my handler is ignored after the first jump and the division is handled by the system. Why does this happen?

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

jmp_buf env;

void handler(int sig) {
    printf("Invalid input , try again\n");
    longjmp(env , 1);
}

int main() {
    signal(SIGFPE , handler);
    int x , y;
    setjmp(env);
    scanf("%d%d" , &x , &y);
    printf("%d\n" , x / y);
}
Narek Margaryan
  • 334
  • 1
  • 4
  • 11
  • 6
    It seems like your system is using the old semantics of `signal` which resets the signal handler to `SIG_DFL` once the signal is invoked. This behavior would not have been a surprise if you just read the [`signal(2)`](http://man7.org/linux/man-pages/man2/signal.2.html) and [`signal(7)`](http://man7.org/linux/man-pages/man7/signal.7.html) manual pages, as would be the solution to use [`sigaction(2)`](http://man7.org/linux/man-pages/man2/sigaction.2.html) instead. – Some programmer dude Nov 30 '14 at 18:39
  • @JoachimPileborg - you should make that into an answer. TBF to OP, signal handling is non-obvious for newbies. – abligh Nov 30 '14 at 18:44
  • Read [signal(7)](http://man7.org/linux/man-pages/man7/signal.7.html) and [this answer](http://stackoverflow.com/a/20310127/841108) to a very similar question. – Basile Starynkevitch Nov 30 '14 at 20:24

1 Answers1

5

You need to use sigsetjmp and siglongjmp instead of the regular versions, because the regular versions do not properly restore your signal masks. Here is a working version of your code:

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

jmp_buf env;

void handler(int sig) {
    printf("Invalid input , try again\n");
    siglongjmp(env , 1);
}

int main() {
    int x , y;

    signal(SIGFPE , handler);
    sigsetjmp(env, 1);
    scanf("%d%d" , &x , &y);
    printf("%d %d\n" , x, y);
    printf("%d\n" , x / y);
}

By the way, I tried using sigaction as suggested by Joachim Pileborg in the comments, but it did not help for me. I think the key here is that if you just plain longjmp to exit a signal handler, the signal context is not restored (meaning SIGFPE might be left in a disabled state).

JS1
  • 4,745
  • 1
  • 14
  • 19
  • Right. Behavior of a machine generated SIGFPE while that signal is blocked [_is undefined_](http://stackoverflow.com/questions/6628947/signal-sigfpe-question), but Linux appears to treat it as if the signal were unblocked and the disposition were SIG_DFL. – pilcrow Nov 30 '14 at 22:14
  • ... which is to say, the first SIGFPE goes to the handler, and the second (even though blocked by accident of the longjmp) terminates with core. – pilcrow Dec 01 '14 at 02:54