Skip to content

Commit 912100f

Browse files
committed
Fix i686 FPU restore: do not treat fpregs as kernel _fpstate
On Linux i386, uc_mcontext.fpregs points at glibc struct _libc_fpstate, which does not match the kernel struct _fpstate layout at the mxcsr and magic offsets. Reinterpreting the pointer and loading mxcsr could pass arbitrary bits to LDMXCSR and corrupt SSE state, matching ASan SEGVs in std::ostream::sentry after a SIGFPE-driven MathExc. Read MXCSR from the live CPU on Linux i386 (with the same 0x1f80 fallback when needed) instead of through a struct _fpstate cast. Also append CMAKE_C_FLAGS and CMAKE_CXX_FLAGS to CMAKE_REQUIRED_FLAGS while probing ucontext/fpstate members so multilib -m32 configure tests see the same struct layout as the build. Made-with: Cursor
1 parent 283b3dc commit 912100f

2 files changed

Lines changed: 14 additions & 8 deletions

File tree

cmake/CMakeLists.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,13 +86,20 @@ check_include_files(ucontext.h IEX_HAVE_UCONTEXT_H)
8686
if(IEX_HAVE_UCONTEXT_H)
8787
# TODO: remove this once we cleanly have IEX_ prefix on all #defines
8888
set(HAVE_UCONTEXT_H ON)
89+
# Multilib (-m32) builds must run these try-compiles with the same arch
90+
# flags as the main target, or feature checks use the wrong ucontext layout.
91+
set(_openexr_iex_saved_cmake_required_flags "${CMAKE_REQUIRED_FLAGS}")
92+
set(CMAKE_REQUIRED_FLAGS
93+
"${CMAKE_REQUIRED_FLAGS} ${CMAKE_C_FLAGS} ${CMAKE_CXX_FLAGS}")
8994
check_struct_has_member("struct _libc_fpstate" mxcsr ucontext.h IEX_HAVE_CONTROL_REGISTER_SUPPORT)
9095
if(NOT IEX_HAVE_CONTROL_REGISTER_SUPPORT)
9196
check_include_files(asm/sigcontext.h IEX_HAVE_SIGCONTEXT_H)
9297
if(IEX_HAVE_SIGCONTEXT_H)
9398
check_struct_has_member("struct _fpstate" mxcsr asm/sigcontext.h IEX_HAVE_SIGCONTEXT_CONTROL_REGISTER_SUPPORT)
9499
endif()
95100
endif()
101+
set(CMAKE_REQUIRED_FLAGS "${_openexr_iex_saved_cmake_required_flags}")
102+
unset(_openexr_iex_saved_cmake_required_flags)
96103
endif()
97104

98105
###check_include_files(pthread.h ILMTHREAD_HAVE_PTHREAD)

src/lib/Iex/IexMathFpu.cpp

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -250,20 +250,19 @@ restoreControlRegs (const ucontext_t& ucon, bool clearExceptions)
250250
setCw ((ucon.uc_mcontext.fpregs->cwd & cwRestoreMask) | cwRestoreVal);
251251
# endif
252252

253-
_fpstate* kfp = reinterpret_cast<_fpstate*> (ucon.uc_mcontext.fpregs);
254253
# if defined(__linux__) && defined(__i386__)
255254
//
256-
// Choose MXCSR from the signal-frame _fpstate when magic == 0 (kernel
257-
// layout matches this struct); otherwise read it from the CPU because
258-
// the saved mxcsr offset may not apply. LDMXCSR must not be given 0,
259-
// which is not a valid control value on x86—substitute 0x1f80 (typical
260-
// default) before setMxcsr clears sticky exception bits per
261-
// clearExceptions.
255+
// uc_mcontext.fpregs points at glibc's struct _libc_fpstate, which is
256+
// not layout-compatible with the kernel's struct _fpstate where mxcsr
257+
// and the FXSR magic field live. Reinterpreting fpregs as struct _fpstate
258+
// reads unrelated memory as MXCSR and can pass garbage to LDMXCSR.
259+
// Use the processor's MXCSR instead, then clear sticky exception bits.
262260
//
263-
uint32_t mxcsr = (kfp->magic == 0) ? kfp->mxcsr : getMxcsr ();
261+
uint32_t mxcsr = getMxcsr ();
264262
if (mxcsr == 0) mxcsr = 0x1f80;
265263
setMxcsr (mxcsr, clearExceptions);
266264
# else
265+
_fpstate* kfp = reinterpret_cast<_fpstate*> (ucon.uc_mcontext.fpregs);
267266
setMxcsr (kfp->mxcsr, clearExceptions);
268267
# endif
269268
}

0 commit comments

Comments
 (0)