Bug 10

Summary: feclearexcept() error on CPUs with SSE
Product: glibc Reporter: H.J. Lu <hjl.tools>
Component: libcAssignee: Ulrich Drepper <drepper.fsp>
Severity: normal    
Priority: P2    
Version: 2.3.3   
Target Milestone: ---   
Host: Target: i386
Build: Last reconfirmed:

Description H.J. Lu 2004-02-06 21:43:26 UTC
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

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>

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 */
  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 */
Comment 1 H.J. Lu 2004-02-06 21:47:27 UTC
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));
Comment 2 Ulrich Drepper 2004-02-09 08:20:25 UTC
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.