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