This is the mail archive of the
gcc-help@gcc.gnu.org
mailing list for the GCC project.
catching floating-point exceptions on GNU/Linux
- From: kainz <kainz at ilm dot com>
- To: gcc-help at gcc dot gnu dot org
- Date: Mon, 1 Apr 2002 20:54:42 -0800 (PST)
- Subject: 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.