Bug 30990 - fesetexceptflag raises floating-point exception traps on i386, x86_64
Summary: fesetexceptflag raises floating-point exception traps on i386, x86_64
Status: RESOLVED FIXED
Alias: None
Product: glibc
Classification: Unclassified
Component: libc (show other bugs)
Version: 2.35
: P2 normal
Target Milestone: 2.39
Assignee: Adhemerval Zanella
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2023-10-23 17:37 UTC by Bruno Haible
Modified: 2023-12-19 18:37 UTC (History)
2 users (show)

See Also:
Host: x86_64-linux-gnu, i386-linux-gnu
Target:
Build:
Last reconfirmed:


Attachments
test case foo.c (507 bytes, text/x-csrc)
2023-10-23 17:37 UTC, Bruno Haible
Details
proposed fix (1.24 KB, patch)
2023-10-23 18:49 UTC, Bruno Haible
Details | Diff
proposed fix v2 (1.24 KB, patch)
2023-10-23 19:25 UTC, Bruno Haible
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Bruno Haible 2023-10-23 17:37:46 UTC
Created attachment 15189 [details]
test case foo.c

According to ISO C 23 ยง 7.6.4.5, fesetexceptflag is supposed to set floating-point exception flags without raising a trap.
  "Like fesetexcept, this function does not raise floating-point exceptions, but only sets the state of the flags."

That's not how glibc's implementation does it on 32-bit x86, 64-bit x86_64, and powerpc/powerpc64/powerpc64le.

The powerpc/powerpc64/powerpc64le case is already being handled in https://sourceware.org/bugzilla/show_bug.cgi?id=30988 . Therefore here let me concentrate on x86 and x86_64.

How to reproduce:
1. Compile the attached program foo.c.
Compiling for 64-bit mode on x86_64 hosts, or for 32-bit mode on i386 hosts:
$ gcc -Wall foo.c -lm
Compiling for 32-bit mode on x86_64 hosts:
$ i686-linux-gnu-gcc -Wall foo.c -lm
or
$ gcc -m32 -Wall foo.c -lm

2. Run it.
$ ./a.out
Floating point exception


I think it is a hardware limitation that on i386 and x86_64 CPUs, setting
a floating-point exception flag in the 387 unit triggers a trap, when
traps are enabled for the particular exception. But setting a
floating-point exception flag in the SSE unit does not have this
problem, cf. glibc/sysdeps/x86_64/fpu/fesetexcept.c.

Therefore I would expect the fesetexceptflag() function to operate correctly
when the hardware has an SSE unit (determined e.g. like in
sysdeps/i386/fpu/ftestexcept.c).
And only in the case where the CPU has only the 387 unit, I would expect
the fesetexceptflag() function to return a non-zero value (as error indicator)
and not modify the 387 floating-point control register, when this is the
only way to avoid a trap.
Comment 1 Bruno Haible 2023-10-23 18:49:57 UTC
Created attachment 15190 [details]
proposed fix

Find attached a proposed fix.
Not tested within glibc, but I tested equivalent code in Gnulib.
Comment 2 Adhemerval Zanella 2023-10-23 19:20:20 UTC
(In reply to Bruno Haible from comment #1)
> Created attachment 15190 [details]
> proposed fix
> 
> Find attached a proposed fix.
> Not tested within glibc, but I tested equivalent code in Gnulib.

Thanks, it seems to a correct approach. I will send a patch upstream with some testing along with this proposed change.
Comment 3 Bruno Haible 2023-10-23 19:25:12 UTC
Created attachment 15191 [details]
proposed fix v2

proposed fix v2: fixes a mistake (I had forgotten that the __control_word has the trap bits inverted).
Comment 4 Adhemerval Zanella 2023-12-19 18:37:39 UTC
Fixed on 2.39 (787282dede7f134fdb22155cee0c35172e3e28f3).