tests/kernel: Add floating-point exceptions test.
Tests #18624 and related issues.
This commit is contained in:
@@ -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++ ]
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
#define _DEFAULT_SOURCE
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <fenv.h>
|
||||
#include <setjmp.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
Reference in New Issue
Block a user