prasun (prasun) wrote in cprogramming,
prasun
prasun
cprogramming

SIGFPE

What's the deal with SIGFPE?
I tried to install a signal handler to catch things like divide-by-zero, or sqrt(-1), but no SIGFPE is raised - on cygwin, sparc, ppc64. I tried to search this on google, but could not find anything useful.
What is the way to handle this? In C. Portably.
[pratn@ps00 ~]$ cat fpe.c
/*
 * Filename: fpe.c
 * Author:   prasun
 * Created:  Wed Feb 28 19:15:35 2007
 * $Id$
 */

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

void fpe (int x)
{
  fprintf (stderr"Error occurred %d\n"x);
  return ;
}

int main ()
{
  float xy;
  struct sigaction sa;
  memset (&sa0sizeof (struct sigaction));
  sa.sa_handler = fpe;
  sigaction (SIGFPE, &sa0);
  sa.sa_flags = SA_SIGINFO | SA_NODEFER;
  x = -1;
  y = 0;
  printf ("%f\n", (x/y));
  return 0;
}
/* vim: set tw=80 ts=2 sw=2 expandtab: */
[pratn@ps00 ~]$ uname -p
ppc64
[pratn@ps00 ~]$ gcc -Wall -g fpe.c
[pratn@ps00 ~]$ ./a.out
-inf
[pratn@ps00 ~]$
  • Post a new comment

    Error

    default userpic
  • 17 comments

Let's see your code, please. And what O/S's are you testing on?

I wouldn't necessarily expect it to work under cygwin since it's running on top of windows and may not be able to reliably trap exceptions.

I posted the code just now. I thought the same about cygwin - so tested it no solaris/sparc and linux/ppc64
Your platform presumably implements IEEE arithmetic, in which division of a nonzero floating point quantity yields an infinity with the same sign. You will probably find that integer division by zero will produce the SIGFPE you expect.
I changed that to int. But no exception is raised.

Division by 0 is after all undefined behavior.

Do you think you could fix the double-spacing in your source code paste?

Sorry about that. It somehow creeped in while pasting html.

Bookmark this, or grab a copy of the open source version. :)

http://www.lightning-rose.com/projects/txt2html.htm

You've posted that before, but I didn't have it bookmarked. I remembered though that you used the pre tag. I used it (without the code tag, which is also required I guess), but the html broke. So I had to use c2html (http://c2html.sourceforge.net/) -- it has syntax coloring too!

It's not just pre and code tags, one still has to deal with angle brackets, ampersands and horizontal tabs.

I didn't bother with color highlighting because,
1) I wanted something simple to use that would work with any ascii text
2) It's too much work. :)

I know of 4 other web based converters, and at least 2 of them do some syntax coloring, but mine is still the only one that correctly handles horizontal tabs.


Using the floating point code as posted, I recieved a runtime error of

-inf

I'm running FC5 on a 32 bit Athlon, gcc v4.1.0


I think the compiler is optimizing out the divide by zero because you're using constants. Try this code instead:


#include <stdio.h> #include <stdlib.h> #include <signal.h> #include <math.h> #include <string.h> void fpe ( int x ) { fprintf( stderr, "Error occurred %d\n", x ); exit( 1 ); } int main( int argc, char **argv ) { int q, d; struct sigaction sa; if ( argc < 3 ) { printf( "\nUsage is: %s QUOTIENT DIVIDEND \n\n", *argv ); exit( 1 ); } q = atoi( *++argv ); d = atoi( *++argv ); memset( &sa, 0, sizeof ( struct sigaction )); sa.sa_handler = fpe; sigaction( SIGFPE, &sa, 0 ); sa.sa_flags = SA_SIGINFO | SA_NODEFER; printf (" q = %d, d = %d \n", q, d ); printf ("\n q/d = %d\n", q/d ); return 0; } Lori> uname -p athlon Lori> gcc --version gcc (GCC) 4.1.0 20060304 (Red Hat 4.1.0-3) Copyright (C) 2006 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Lori> ./fpe -1 0 q = -1, d = 0 Error occurred 8
Ok, my bad. Both your and mine seem to work on all (linux-x86, solaris, cygwin) but one system (linux/ppc64).

Interesting. I know a bit about how the ppc itself handles math exceptions, but I have no idea what linux deals with it.

Ok, so what's the way to deal with float exceptions as this works for integers only. Funny that it's called SIGFPE (apparently for backward compatibility)

I just don't know. I haven't used fp professionally since 1983, and I've never had to handle integer math exceptions because I either knew everything would be in range when I wrote the code, or I'd range check user input before performing any math with it.

I've never used fp for real code before, and I added checks and asserts wherever I could, but was wondering if it was possible to install a handler to catch anything I might have missed. Guess I'm better off without it.

The short answer, as above, is that integer division is undefined behavior. An implementation is entitled to raise SIGFPE, to crash in some other way, to ignore the operation, anything it likes. The only portable way to handle it is to compare the divisor with 0 before attempting the division.

As for the specifics of the PPC case:

kakajou$ cat >t.c
int main() { return 1/0; }
kakajou$ gcc -S t.c
t.c: In function 'main':
t.c:1: warning: division by zero
kakajou$ cat t.s
        .section __TEXT,__text,regular,pure_instructions
        .section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32
        .machine ppc
        .text
        .align 2
        .globl _main
_main:
        stmw r30,-8(r1)
        stwu r1,-48(r1)
        mr r30,r1
        li r2,1
        li r0,0
        divw r0,r2,r0
        mr r3,r0
        lwz r1,0(r1)
        lmw r30,-8(r1)
        blr
        .subsections_via_symbols

All you actually need to spot in there is the divw instruction which you can then look up in an instruction set reference, in this case to find that division by 0 leaves the contents of the destination register undefined, with no mention of any trap being raise. C being C, you get what the underlying machine gives you, and no more - if you actually wanted guarantee semantics in this kind of area, you're using the wrong language.