#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; }