This is the mail archive of the gcc-help@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

catching floating-point exceptions on GNU/Linux



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.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]