This is the mail archive of the cygwin-developers@sourceware.cygnus.com mailing list for the Cygwin project.


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

handling SIGFPE and resetting the FPU


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;
  }



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