Can I ignore a SIGFPE resulting from division by zero?
Asked Answered
C

8

4

I have a program which deliberately performs a divide by zero (and stores the result in a volatile variable) in order to halt in certain circumstances. However, I'd like to be able to disable this halting, without changing the macro that performs the division by zero.

Is there any way to ignore it?

I've tried using

#include <signal.h>
...
int main(void) {
  signal(SIGFPE, SIG_IGN);
  ...
}

but it still dies with the message "Floating point exception (core dumped)".

I don't actually use the value, so I don't really care what's assigned to the variable; 0, random, undefined...

EDIT: I know this is not the most portable, but it's intended for an embedded device which runs on many different OSes. The default halt action is to divide by zero; other platforms require different tricks to force a watchdog induced reboot (such as an infinite loop with interrupts disabled). For a PC (linux) test environment, I wanted to disable the halt on division by zero without relying on things like assert.

Crease answered 7/1, 2009 at 8:5 Comment(1)
+1 good question. See comments of stackoverflow.com/questions/487737. 5 down, 10 to go (1 per day)Chivalric
B
4

Why would you deliberately perform a divide by zero to halt? Couldn't you exit(-1) or some equivalent?

Especially if you don't need the result of the divide by 0, this just doesn't make sense.

Bramlett answered 7/1, 2009 at 8:9 Comment(3)
Because it's for code generally used in an embedded device; I want to halt the device and have the watchdog reboot in most casesCrease
is there a reason you can't send a SIGQUIT instead of dividing by zero?Bramlett
For this particular test, I simply removed the divide by zero and used a different implementation. For the embedded application, I still use the divide by zero (most platforms are not POSIX), but there I don't have the requirement to disable it.Crease
T
6

Okay, first off, you ought to be using sigaction(2) instead of the deprecated signal().

Secondly, using SIGFPE for the purposes of terminating the program is patently absurd, as you should be raising a signal like SIGTERM or SIGUSR1 instead of jury-rigging some other signal for its side-effect and disregarding its semantic value. And more specifically, the man page for sigaction(2) has a NOTES section with a blurb about SIGFPE that indicates one or two ways your intended use of it is broken.

What you should do is raise(3) a signal when you want to terminate. Then, use the sa_handler field in the sigaction structure to change whether to ignore (SIG_IGN) or terminate (SIG_DFL) on that signal.

int main(void) {
  struct sigaction my_action;

  my_action.sa_handler = SIG_IGN;
  my_action.sa_flags = SA_RESTART;
  sigaction(SIGUSR1, &my_action, NULL);

  raise(SIGUSR1);  /* Ignored */

  my_action.sa_handler = SIG_DFL;
  sigaction(SIGUSR1, &my_action, NULL);

  raise(SIGUSR1); /* Terminates */

  return 0;
}

That said, I can't see why you'd use signals instead of a simple exit().

Tramp answered 7/1, 2009 at 9:0 Comment(0)
B
4

Why would you deliberately perform a divide by zero to halt? Couldn't you exit(-1) or some equivalent?

Especially if you don't need the result of the divide by 0, this just doesn't make sense.

Bramlett answered 7/1, 2009 at 8:9 Comment(3)
Because it's for code generally used in an embedded device; I want to halt the device and have the watchdog reboot in most casesCrease
is there a reason you can't send a SIGQUIT instead of dividing by zero?Bramlett
For this particular test, I simply removed the divide by zero and used a different implementation. For the embedded application, I still use the divide by zero (most platforms are not POSIX), but there I don't have the requirement to disable it.Crease
R
2

Check the return value of

signal(SIGFPE, SIG_IGN);

If you get SIG_ERR, check the value of errno to find out what went wrong. That's as much as you can do portably.

I know you don't want to change the divide by zero, but it's nonportable and counterintuitive. You want to coredump if some condition occurs, but be able to disable this behaviour without editing code? Use assert and NDEBUG.

Representation answered 7/1, 2009 at 9:6 Comment(1)
This will result in an infinite loop if it works, retrying the faulting instruction. Unless the kernel does something special.Dotty
D
1

This is not portable, but on x86 you can by controlling the FPU:

Using gcc on Linux (I'm sure other compilers have similar facilities):

#include <fpu_control.h>

_FPU_SETCW (_FPU_DEFAULT);

Since _FPU_DEFAULT defaults to _FPU_MASK_ZM set (ZM stands for Zero-Divide-Mask).

Declaim answered 7/1, 2009 at 8:22 Comment(1)
Presumably they meant from integer division by zero. FP exceptions are all masked by default.Dotty
C
1
void handler(int trapId)
{
   // Whatever
}

signal(SIGFPE, handler);
Carnelian answered 22/5, 2012 at 12:39 Comment(0)
P
0

Could you cause the program to exit through a less contrived expression? For instance:

#include <signal.h>

#ifdef DEBUG
#define DIE_HERE raise(SIGFPE)
#else
#define DIE_HERE
#endif

I'd be hesitant to override the default behavior, lest some other part of your program divide by zero unintentionally. Alternatively, if you're forcing it to exit this way in order to get a core dump, you may want to look into using breakpoints within a debugger. Or, if you're on a system with the gdb debugger, the gcore utility may be useful.

Pender answered 7/1, 2009 at 8:30 Comment(0)
A
0

If you have control over the crashing code, then I'd also recommend to change the code to die some other way. If you don't, you could try to install an empty signal handler instead (i.e. use signal(SIGFPE, &EmptyFunction)), but you're still relying on undefined behaviour, so there's no guarantee it will still work on other systems, or other kernel or C library versions.

Azerbaijani answered 7/1, 2009 at 9:55 Comment(0)
T
0

lnmiit l over the crashing code, then I'd also recommend to change the code to die some other way. If you don't, you could try to install an

Turro answered 16/2, 2012 at 9:54 Comment(1)
You might want to complete and clarify your answer. In it's current state parts seems to be missing and it's unclear at the very least.Rakeoff

© 2022 - 2024 — McMap. All rights reserved.