Steve Chaplin [stevech1097@yahoo.com.au] reported: Problem/error message #include <fenv.h> void feclearexcept(int ex) This function should clear the specified exception status bits in the FPU status register. For CPUs with SSE support it should also clear the MXCSR status register bits. The problem is that feclearexcept() clears the status control bits also, causing future floating-point errors to generate interrupts which will lead to a SIGFPE signal which terminates the program (unless caught by a SIGFPE handler). The program that follows illustrates the problem When compiled on a SSE processor, such as an athlon-xp, with 'gcc -march=athlon-xp file.c' It shows that: The status bits change - they are cleared - which is correct The control bits change - this is the bug Test program: /* start or file */ #include <stdio.h> #include <fenv.h> int main (void) { int exc_control, exc_status; __asm__ ("stmxcsr %0" : "=m" (*&exc_control)); exc_control = ~(exc_control >> 7) & FE_ALL_EXCEPT; // we cannot use: // exc_control = fegetexcept (); // since it does not return the SSE flags (that's another bug) /* raise all exceptions - set their status bit to on */ feraiseexcept(FE_ALL_EXCEPT); exc_status = fetestexcept(FE_ALL_EXCEPT); printf ("Before\n"); printf ("Exception control : %X\n", exc_control); printf ("Exception status : %X\n", exc_status); feclearexcept (FE_ALL_EXCEPT); __asm__ ("stmxcsr %0" : "=m" (*&exc_control)); exc_control = ~(exc_control >> 7) & FE_ALL_EXCEPT; exc_status = fetestexcept(FE_ALL_EXCEPT); printf ("After\n"); printf ("Exception control : %X\n", exc_control); // the bug - this should not change printf ("Exception status : %X\n", exc_status); // this is supposed to change to 0 } /* end of file */
This is the patch from Steve: Index: fclrexcpt.c =================================================================== RCS file: /cvs/glibc/libc/sysdeps/i386/fpu/fclrexcpt.c,v retrieving revision 1.8 diff -u -r1.8 fclrexcpt.c --- fclrexcpt.c 25 Sep 2003 05:57:16 -0000 1.8 +++ fclrexcpt.c 8 Jan 2004 13:28:26 -0000 @@ -50,7 +50,7 @@ __asm__ ("stmxcsr %0" : "=m" (*&xnew_exc)); /* Clear the relevant bits. */ - xnew_exc &= excepts ^ FE_ALL_EXCEPT; + xnew_exc &= ~excepts; /* Put the new data in effect. */ __asm__ ("ldmxcsr %0" : : "m" (*&xnew_exc));
The test program isn't really testing what it is supposed to (the SSE status is never touched) but the SSE control change is indeed wrong.