Mail Archives: cygwin-developers/1999/06/22/17:56:30
While trying to build libstdc++-v3, I ran into an odd problem with
handling FPE in b20.1. If this is fixed in dev snapshots, please
ignore this message.
The problem is this: let's say you have a handler for FPE and it
gets triggered by a an integer divide by zero; handler gets called
and everybody's happy. Let's say you get another of these div_by_0
and now the handler never gets called and the process goes to sleep
waiting for SIGFPE to be unblocked according to strace.
I believe that the solution is to reset the FPU after handling (which
includes the rather dangerous act of ignoring FPE) *each* FP exception
in exceptions.cc:handle_exceptions(). That's what I do in Mingw runtime
which runs the attached test code ok.
Where's the patch you say? I have no patch is because I have no clue
what it takes to reset the damn thing, but I assume it's a few-liner
x86 assembly code for those in the know.
Here's a test code (adapted from libstdc++-v3 src/gen-num-limits.cc):
To test:
$ c++ -g -o fpe-bug fpe-bug.cc
$ ./fpe-bug
If the bug is there, it'll get stuck in the <bool> test after getting
through <double>, <float>, ... <char> trap tests. <char> is the one
that gets the FPU all messed up, and <bool> gets stuck.
=== fpe-bug.cc: cut from here to end
#include <iostream>
#include <cfloat>
#include <csignal>
#include <csetjmp>
#include <cmath>
using namespace std;
jmp_buf env;
void
signal_handler (int sig)
{
cerr << "In signal handler: " << sig << endl;
longjmp(env, sig);
}
template<typename Operation>
bool
trapping (const Operation& op)
{
if (setjmp(env) == 0)
op();
else
{
cerr << "trapping: Returning from longjmp. " << endl;
return true;
}
return false;
}
template<typename T> struct
division_by_zero {
void operator() () const
{
volatile T zero = T();
volatile T one = T(1);
volatile T infinity = one / zero;
}
};
template<typename T> struct
overflow
{
void operator() () const
{
T i = T (1);
T j = T ();
while (i > j)
{
j = i;
i = i * 2 + 1;
}
}
};
template<typename T> struct
underflow {};
template<typename T> void
traps()
{
cerr << __PRETTY_FUNCTION__ << ": Enter" << endl;
#ifndef NO_SIGHANDLER
signal (SIGFPE, signal_handler);
#endif
bool trap_flag = trapping (division_by_zero<T> ());
cerr << "After trapping division_by_zero<T>" << endl;
#ifndef NO_SIGHANDLER
signal (SIGFPE, signal_handler);
#endif
trap_flag = trap_flag && trapping (overflow<T> ());
cerr << "After trapping overflow<T>" << endl;
cerr << __PRETTY_FUNCTION__ << ": Leave" << endl;
}
// type traits
template<typename T> struct
type_trait {
type_trait()
{
traps<T>();
}
};
int
main ()
{
cerr << "Testing <double> ..." << endl;
type_trait<double> ();
cerr << "Testing <float> ..." << endl;
type_trait<float> ();
#ifndef HIDE_BUG
cerr << "Testing <char> ..." << endl;
type_trait<char> ();
cerr << "Testing <bool> ..." << endl;
type_trait<bool> ();
#endif /* HIDE_BUG */
return 0;
}
- Raw text -