How does one enable floating point exceptions on MinGW GCC, where feenableexcept is missing? Even reasonably complete solutions don't actually catch this, though it would appear that they intend to. I would prefer minimal code that is close to whatever future standards will emerge. Preferably, the code should work with and without SSE. A complete solution that shows how to enable the hardware signal, catch it, and reset it is preferable. Compiling cleanly with high optimization levels and full pedantic errors and warnings is a must. The ability to catch multiple times in a unit-test scenario is important. There are several questions that provide partial answers.
Asked
Active
Viewed 1,394 times
1 Answers
1
This appears to work on my machine. Compile it in MinGW GCC with -fnon-call-exceptions
. It isn't fully minimized yet.
#include <xmmintrin.h>
#include <cerrno>
#include <cfenv>
#include <cfloat> //or #include <float.h> // defines _controlfp_s
#include <cmath>
#include <csignal>
#ifdef _WIN32
void feenableexcept(uint16_t fpflags){
/*edit 2015-12-17, my attempt at ASM code was giving me
*problems in more complicated scenarios, so I
*switched to using _controlfp_s. I finally posted it here
*because of the upvote to the ASM version.*/
/*{// http://stackoverflow.com/questions/247053/
uint16_t mask(FE_ALL_EXCEPT & ~fpflags);
asm("fldcw %0" : : "m" (mask) : "cc");
} //https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html */
unsigned int new_word(0);
if (fpflags & FE_INVALID) new_word |= _EM_INVALID;
if (fpflags & FE_DIVBYZERO) new_word |= _EM_ZERODIVIDE;
if (fpflags & FE_OVERFLOW) new_word |= _EM_OVERFLOW;
unsigned int cw(0);
_controlfp_s(&cw,~new_word,_MCW_EM);
}
#endif
void fe_reset_traps(){
std::feclearexcept(FE_ALL_EXCEPT); //clear x87 FE state
#ifdef __SSE__
_MM_SET_EXCEPTION_STATE(0); // clear SSE FE state
#endif
feenableexcept(FE_DIVBYZERO|FE_OVERFLOW|FE_INVALID); // set x87 FE mask
#ifdef __SSE__
//set SSE FE mask (orientation of this command is different than the above)
_MM_SET_EXCEPTION_MASK(_MM_MASK_DENORM |_MM_MASK_UNDERFLOW|_MM_MASK_INEXACT);
#endif
}
void sigfpe_handler(int sig){
std::signal(sig,SIG_DFL); // block signal, if needed
std::cerr<<"A floating point exception was encountered. Exiting.\n";
fe_reset_traps(); // in testing mode the throw may not exit, so reset traps
std::signal(sig,&sigfpe_handler); // reinstall handler
throw std::exception();
}
fe_reset_traps();
std::signal(SIGFPE,&sigfpe_handler); // install handler
std::cerr<<"before\n";
std::cerr<<1.0/0.0<<"\n";
std::cerr<<"should be unreachable\n";
I'm sure it's not perfect. Let's hear what everyone else has to contribute.

Chris Chiasson
- 547
- 8
- 17