public inbox for gcc-help@gcc.gnu.org
 help / color / mirror / Atom feed
* catching floating-point exceptions on GNU/Linux
@ 2002-04-01 20:54 kainz
  0 siblings, 0 replies; only message in thread
From: kainz @ 2002-04-01 20:54 UTC (permalink / raw)
  To: gcc-help


Summary:

    I would like to handle floating-point exceptions like regular
    C++ exceptions, using try/catch blocks.  I managed to make this
    work, but my method is an ugly hack.  Is there a better way?

Details:

    A large program that is currently being ported from Unix (Irix 6.5)
    to GNU/Linux (i686, gcc-3.0.4), requires that floating-point exceptions
    can be handled like regular C++ exceptions, using try/catch blocks.

    The following works reasonably well, as long as I don't call any of
    the functions defined in /usr/include/math.h:

    1. Make floating-point exceptions (division by zero, overflow,
       invalid operand) generate SIGFPE, and install a signal handler
       for SIGFPE:

	void initFpe()
	{
	    __asm__ ("fldcw %0" : : "m" (0x372));

	    struct sigaction sa;
	    sa.sa_flags = SA_SIGINFO | SA_NOMASK;
	    sa.sa_sigaction = fpeHandler;

	    sigaction (SIGFPE, &sa, 0);
	}

    2. In the signal handler, throw a C++ exception:

	void fpeHandler (int, siginfo_t*, void*)
	{
	    throw "Floating-point exception";
	}

    3. Use try/catch blocks to handle exceptions:

	double f (double x)
	{
	    return 1 / x;
	}

	int main ()
	{
	    initFpe();

	    try
	    {
		std::cout << f(0) << '\n';   // division by zero
	    }
	    catch (const char *except)
	    {
		std::cerr << except << '\n';
	    }
	}

    4. Compile the program with
    
	g++ -funwind-tables -fnon-call-exceptions ...

    Unfortunately, this scheme stops working when I call functions
    defined in math.h.  For example, when I try

	try
	{
	    std::cout << exp (1e10);   // overflow
	}
	catch (...)
	{
	    // print error message
	}

    my program aborts.  As far as I can tell, this happens because
    1) libm is not compiled with -funwind-tables, and 2) math.h adds
    throw() specifications to all math functions, telling the compiler
    that none of those functions will ever throw any exceptions.

    To get around this problem, without altering libm or /usr/include/math.h,
    I wrote my own math.h, which, needless to say, is a rather ugly hack.
    My math.h looks like this (only exp() is shown; sin(), cos(), sqrt()
    etc. work the same way):

	#define exp hidden_exp
	#define __NO_MATH_INLINES 1
	#include </usr/include/math.h>
	#undef exp

	extern "C++"
	{
	    double exp_fpe (double x);
	    inline double exp (double x) {return exp_fpe (x);}
	}

    The exp_fpe() function is implemented like this:

	#include </usr/include/math.h>

	double exp_fpe (double x)
	{
	    __asm__ ("fldcw %0" : : "m" (0x37f)); // disable fpes
	    double y = exp (x);
	    __asm__ ("fldcw %0" : : "m" (0x372)); // enable fpes
	    
	    if (!finite (y))
		throw "Floating-point exception";

	    return y;
	}


Question:

    Is there a better way to do what I described above?

    I am porting a large program; changing the it so
    that it does not rely on try/catch is not an option.

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2002-04-02  4:54 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2002-04-01 20:54 catching floating-point exceptions on GNU/Linux kainz

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).