From 1d810c307f9a988d67f1c205852895088b2e9572 Mon Sep 17 00:00:00 2001 From: Augustin Cavalier Date: Wed, 18 Jun 2025 16:22:21 -0400 Subject: [PATCH] tests/kernel: Add floating-point exceptions test. Tests #18624 and related issues. --- src/tests/system/kernel/Jamfile | 2 + src/tests/system/kernel/fp_excepts.c | 91 ++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+) create mode 100644 src/tests/system/kernel/fp_excepts.c diff --git a/src/tests/system/kernel/Jamfile b/src/tests/system/kernel/Jamfile index b71b1c5279..3555ce2b3d 100644 --- a/src/tests/system/kernel/Jamfile +++ b/src/tests/system/kernel/Jamfile @@ -16,6 +16,8 @@ local avxSource = [ FGristFiles hello_avx.c ] ; local avxObject = $(avxSource:S=$(SUFOBJ)) ; CCFLAGS on $(avxObject) = -mavx ; +SimpleTest fp_excepts_test : fp_excepts.c ; + SimpleTest live_query : live_query.cpp : be [ TargetLibsupc++ ] diff --git a/src/tests/system/kernel/fp_excepts.c b/src/tests/system/kernel/fp_excepts.c new file mode 100644 index 0000000000..f0587c4211 --- /dev/null +++ b/src/tests/system/kernel/fp_excepts.c @@ -0,0 +1,91 @@ +#define _DEFAULT_SOURCE +#include +#include +#include +#include +#include +#include +#include + + +static int sExceptions = 0; +static int sLastCode = -1; +static jmp_buf sJmpBuf; + + +static void +signal_handler(int signal, siginfo_t* siginfo, void*) +{ + sExceptions++; + sLastCode = siginfo->si_code; + + longjmp(sJmpBuf, 1); +} + + +int main() +{ + fenv_t exceptenv; + long double volatile nanl, resultl; + + struct sigaction action = {}; + sigemptyset(&action.sa_mask); + action.sa_flags = SA_SIGINFO | SA_NODEFER | SA_NOMASK; + action.sa_sigaction = signal_handler; + if (sigaction(SIGFPE, &action, NULL) == -1) { + fprintf(stderr, "failed to install signal handler: %s\n", + strerror(errno)); + return 1; + } + + assert(feclearexcept(FE_ALL_EXCEPT) == 0); + + // Test 1: switching to an fenv with an exception raised triggers SIGFPE + // (but not a kernel panic.) + if (feenableexcept(FE_INVALID) == -1) { + fputs("trapping floating-point exceptions are not supported on this machine.\n", stderr); + return -1; + } + + assert(fegetenv(&exceptenv) == 0); + assert(fesetenv(FE_DFL_ENV) == 0); + + assert(feraiseexcept(FE_INVALID) == 0); + + assert(sExceptions == 0); + if (setjmp(sJmpBuf) == 0) { + assert(feupdateenv(&exceptenv) == 0); + } else { + assert(feclearexcept(FE_INVALID) == 0); + assert(feupdateenv(&exceptenv) == 0); + } + assert(sExceptions == 1); + assert(sLastCode == FPE_FLTINV); + + // Test 2: long signaling NaNs also trigger SIGFPE + // (but again no kernel panic.) + nanl = __builtin_nansl(""); + assert(sExceptions == 1); + if (setjmp(sJmpBuf) == 0) { + resultl = nanl + 42.0L; + } else { + assert(feclearexcept(FE_ALL_EXCEPT) == 0); + } + assert(sExceptions == 2); + assert(sLastCode == FPE_FLTINV); + + // Test 3: Overflow triggers SIGFPE, with the right code. + if (feenableexcept(FE_OVERFLOW) == -1) { + fputs("FE_OVERFLOW is not supported on this machine.\n", stderr); + return 0; + } + + if (setjmp(sJmpBuf) == 0) { + float volatile top = FLT_MAX; + float volatile result = top * top; + } + assert(sExceptions == 3); + assert(sLastCode == FPE_FLTOVF); + + return 0; +}