Changeset View
Changeset View
Standalone View
Standalone View
lib/msun/tests/fenv_test.c
Show First 20 Lines • Show All 57 Lines • ▼ Show 20 Lines | |||||
/* init_exceptsets() initializes this to the power set of std_excepts[] */ | /* init_exceptsets() initializes this to the power set of std_excepts[] */ | ||||
static int std_except_sets[1 << NEXCEPTS]; | static int std_except_sets[1 << NEXCEPTS]; | ||||
#pragma STDC FENV_ACCESS ON | #pragma STDC FENV_ACCESS ON | ||||
/* | /* | ||||
* Initialize std_except_sets[] to the power set of std_excepts[] | * Initialize std_except_sets[] to the power set of std_excepts[] | ||||
*/ | */ | ||||
static void | static __attribute__((constructor)) void | ||||
init_exceptsets(void) | do_setup(void) | ||||
{ | { | ||||
unsigned i, j, sr; | unsigned i, j, sr; | ||||
/* Avoid double output after fork() */ | |||||
setvbuf(stdout, NULL, _IONBF, 0); | |||||
for (i = 0; i < 1 << NEXCEPTS; i++) { | for (i = 0; i < 1 << NEXCEPTS; i++) { | ||||
for (sr = i, j = 0; sr != 0; sr >>= 1, j++) | for (sr = i, j = 0; sr != 0; sr >>= 1, j++) | ||||
std_except_sets[i] |= std_excepts[j] & ((~sr & 1) - 1); | std_except_sets[i] |= std_excepts[j] & ((~sr & 1) - 1); | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* Raise a floating-point exception without relying on the standard | * Raise a floating-point exception without relying on the standard | ||||
▲ Show 20 Lines • Show All 70 Lines • ▼ Show 20 Lines | getround(void) | ||||
return (FE_TONEAREST); | return (FE_TONEAREST); | ||||
} | } | ||||
static void | static void | ||||
trap_handler(int sig) | trap_handler(int sig) | ||||
{ | { | ||||
assert(sig == SIGFPE); | ATF_CHECK_EQ(SIGFPE, sig); | ||||
_exit(0); | _exit(0); | ||||
} | } | ||||
/* | /* | ||||
* This tests checks the default FP environment, so it must be first. | * This tests checks the default FP environment, so it must be first. | ||||
* The memcmp() test below may be too much to ask for, since there | * The memcmp() test below may be too much to ask for, since there | ||||
* could be multiple machine-specific default environments. | * could be multiple machine-specific default environments. | ||||
*/ | */ | ||||
static void | ATF_TC_WITHOUT_HEAD(dfl_env); | ||||
test_dfl_env(void) | ATF_TC_BODY(dfl_env, tc) | ||||
{ | { | ||||
#ifndef NO_STRICT_DFL_ENV | #ifndef NO_STRICT_DFL_ENV | ||||
fenv_t env; | fenv_t env; | ||||
fegetenv(&env); | fegetenv(&env); | ||||
#ifdef __amd64__ | #ifdef __amd64__ | ||||
/* | /* | ||||
* Compare the fields that the AMD [1] and Intel [2] specs say will be | * Compare the fields that the AMD [1] and Intel [2] specs say will be | ||||
* set once fnstenv returns. | * set once fnstenv returns. | ||||
* | * | ||||
* Not all amd64 capable processors implement the fnstenv instruction | * Not all amd64 capable processors implement the fnstenv instruction | ||||
* by zero'ing out the env.__x87.__other field (example: AMD Opteron | * by zero'ing out the env.__x87.__other field (example: AMD Opteron | ||||
* 6308). The AMD64/x64 specs aren't explicit on what the | * 6308). The AMD64/x64 specs aren't explicit on what the | ||||
* env.__x87.__other field will contain after fnstenv is executed, so | * env.__x87.__other field will contain after fnstenv is executed, so | ||||
* the values in env.__x87.__other could be filled with arbitrary | * the values in env.__x87.__other could be filled with arbitrary | ||||
* data depending on how the CPU implements fnstenv. | * data depending on how the CPU implements fnstenv. | ||||
* | * | ||||
* 1. http://support.amd.com/TechDocs/26569_APM_v5.pdf | * 1. http://support.amd.com/TechDocs/26569_APM_v5.pdf | ||||
* 2. http://www.intel.com/Assets/en_US/PDF/manual/253666.pdf | * 2. http://www.intel.com/Assets/en_US/PDF/manual/253666.pdf | ||||
*/ | */ | ||||
assert(memcmp(&env.__mxcsr, &FE_DFL_ENV->__mxcsr, | ATF_CHECK(memcmp(&env.__mxcsr, &FE_DFL_ENV->__mxcsr, | ||||
sizeof(env.__mxcsr)) == 0); | sizeof(env.__mxcsr)) == 0); | ||||
assert(memcmp(&env.__x87.__control, &FE_DFL_ENV->__x87.__control, | ATF_CHECK(memcmp(&env.__x87.__control, &FE_DFL_ENV->__x87.__control, | ||||
sizeof(env.__x87.__control)) == 0); | sizeof(env.__x87.__control)) == 0); | ||||
assert(memcmp(&env.__x87.__status, &FE_DFL_ENV->__x87.__status, | ATF_CHECK(memcmp(&env.__x87.__status, &FE_DFL_ENV->__x87.__status, | ||||
sizeof(env.__x87.__status)) == 0); | sizeof(env.__x87.__status)) == 0); | ||||
assert(memcmp(&env.__x87.__tag, &FE_DFL_ENV->__x87.__tag, | ATF_CHECK(memcmp(&env.__x87.__tag, &FE_DFL_ENV->__x87.__tag, | ||||
sizeof(env.__x87.__tag)) == 0); | sizeof(env.__x87.__tag)) == 0); | ||||
#else | #else | ||||
assert(memcmp(&env, FE_DFL_ENV, sizeof(env)) == 0); | ATF_CHECK_EQ(0, memcmp(&env, FE_DFL_ENV, sizeof(env))); | ||||
#endif | #endif | ||||
#endif | #endif | ||||
assert(fetestexcept(FE_ALL_EXCEPT) == 0); | ATF_CHECK_EQ(0, fetestexcept(FE_ALL_EXCEPT)); | ||||
} | } | ||||
/* | /* | ||||
* Test fetestexcept() and feclearexcept(). | * Test fetestexcept() and feclearexcept(). | ||||
*/ | */ | ||||
static void | ATF_TC_WITHOUT_HEAD(fetestclearexcept); | ||||
test_fetestclearexcept(void) | ATF_TC_BODY(fetestclearexcept, tc) | ||||
{ | { | ||||
int excepts, i; | int excepts, i; | ||||
for (i = 0; i < 1 << NEXCEPTS; i++) | for (i = 0; i < 1 << NEXCEPTS; i++) | ||||
assert(fetestexcept(std_except_sets[i]) == 0); | ATF_CHECK_EQ(0, fetestexcept(std_except_sets[i])); | ||||
for (i = 0; i < 1 << NEXCEPTS; i++) { | for (i = 0; i < 1 << NEXCEPTS; i++) { | ||||
excepts = std_except_sets[i]; | excepts = std_except_sets[i]; | ||||
/* FE_ALL_EXCEPT might be special-cased, as on i386. */ | /* FE_ALL_EXCEPT might be special-cased, as on i386. */ | ||||
raiseexcept(excepts); | raiseexcept(excepts); | ||||
assert(fetestexcept(excepts) == excepts); | ATF_CHECK_EQ(excepts, fetestexcept(excepts)); | ||||
assert(feclearexcept(FE_ALL_EXCEPT) == 0); | ATF_REQUIRE_EQ(0, feclearexcept(FE_ALL_EXCEPT)); | ||||
assert(fetestexcept(FE_ALL_EXCEPT) == 0); | ATF_CHECK_EQ(0, fetestexcept(FE_ALL_EXCEPT)); | ||||
raiseexcept(excepts); | raiseexcept(excepts); | ||||
assert(fetestexcept(excepts) == excepts); | ATF_CHECK_EQ(excepts, fetestexcept(excepts)); | ||||
if ((excepts & (FE_UNDERFLOW | FE_OVERFLOW)) != 0) { | if ((excepts & (FE_UNDERFLOW | FE_OVERFLOW)) != 0) { | ||||
excepts |= FE_INEXACT; | excepts |= FE_INEXACT; | ||||
assert((fetestexcept(ALL_STD_EXCEPT) | FE_INEXACT) == | ATF_CHECK_EQ(excepts, (fetestexcept(ALL_STD_EXCEPT) | FE_INEXACT)); | ||||
excepts); | |||||
} else { | } else { | ||||
assert(fetestexcept(ALL_STD_EXCEPT) == excepts); | ATF_CHECK_EQ(excepts, fetestexcept(ALL_STD_EXCEPT)); | ||||
} | } | ||||
assert(feclearexcept(excepts) == 0); | ATF_CHECK_EQ(0, feclearexcept(excepts)); | ||||
assert(fetestexcept(ALL_STD_EXCEPT) == 0); | ATF_CHECK_EQ(0, fetestexcept(ALL_STD_EXCEPT)); | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* Test fegetexceptflag() and fesetexceptflag(). | * Test fegetexceptflag() and fesetexceptflag(). | ||||
* | * | ||||
* Prerequisites: fetestexcept(), feclearexcept() | * Prerequisites: fetestexcept(), feclearexcept() | ||||
*/ | */ | ||||
static void | ATF_TC_WITHOUT_HEAD(fegsetexceptflag); | ||||
test_fegsetexceptflag(void) | ATF_TC_BODY(fegsetexceptflag, tc) | ||||
{ | { | ||||
fexcept_t flag; | fexcept_t flag; | ||||
int excepts, i; | int excepts, i; | ||||
assert(fetestexcept(FE_ALL_EXCEPT) == 0); | ATF_CHECK_EQ(0, fetestexcept(FE_ALL_EXCEPT)); | ||||
for (i = 0; i < 1 << NEXCEPTS; i++) { | for (i = 0; i < 1 << NEXCEPTS; i++) { | ||||
excepts = std_except_sets[i]; | excepts = std_except_sets[i]; | ||||
assert(fegetexceptflag(&flag, excepts) == 0); | ATF_CHECK_EQ(0, fegetexceptflag(&flag, excepts)); | ||||
raiseexcept(ALL_STD_EXCEPT); | raiseexcept(ALL_STD_EXCEPT); | ||||
assert(fesetexceptflag(&flag, excepts) == 0); | ATF_CHECK_EQ(0, fesetexceptflag(&flag, excepts)); | ||||
assert(fetestexcept(ALL_STD_EXCEPT) == | ATF_CHECK_EQ((ALL_STD_EXCEPT ^ excepts), fetestexcept(ALL_STD_EXCEPT)); | ||||
(ALL_STD_EXCEPT ^ excepts)); | |||||
assert(fegetexceptflag(&flag, FE_ALL_EXCEPT) == 0); | ATF_CHECK_EQ(0, fegetexceptflag(&flag, FE_ALL_EXCEPT)); | ||||
assert(feclearexcept(FE_ALL_EXCEPT) == 0); | ATF_REQUIRE_EQ(0, feclearexcept(FE_ALL_EXCEPT)); | ||||
assert(fesetexceptflag(&flag, excepts) == 0); | ATF_CHECK_EQ(0, fesetexceptflag(&flag, excepts)); | ||||
assert(fetestexcept(ALL_STD_EXCEPT) == 0); | ATF_CHECK_EQ(0, fetestexcept(ALL_STD_EXCEPT)); | ||||
assert(fesetexceptflag(&flag, ALL_STD_EXCEPT ^ excepts) == 0); | ATF_CHECK_EQ(0, fesetexceptflag(&flag, ALL_STD_EXCEPT ^ excepts)); | ||||
assert(fetestexcept(ALL_STD_EXCEPT) == | ATF_CHECK_EQ((ALL_STD_EXCEPT ^ excepts), fetestexcept(ALL_STD_EXCEPT)); | ||||
(ALL_STD_EXCEPT ^ excepts)); | |||||
assert(feclearexcept(FE_ALL_EXCEPT) == 0); | ATF_REQUIRE_EQ(0, feclearexcept(FE_ALL_EXCEPT)); | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* Test feraiseexcept(). | * Test feraiseexcept(). | ||||
* | * | ||||
* Prerequisites: fetestexcept(), feclearexcept() | * Prerequisites: fetestexcept(), feclearexcept() | ||||
*/ | */ | ||||
static void | ATF_TC_WITHOUT_HEAD(feraiseexcept); | ||||
test_feraiseexcept(void) | ATF_TC_BODY(feraiseexcept, tc) | ||||
{ | { | ||||
int excepts, i; | int excepts, i; | ||||
for (i = 0; i < 1 << NEXCEPTS; i++) { | for (i = 0; i < 1 << NEXCEPTS; i++) { | ||||
excepts = std_except_sets[i]; | excepts = std_except_sets[i]; | ||||
assert(fetestexcept(FE_ALL_EXCEPT) == 0); | ATF_CHECK_EQ(0, fetestexcept(FE_ALL_EXCEPT)); | ||||
assert(feraiseexcept(excepts) == 0); | ATF_CHECK_EQ(0, feraiseexcept(excepts)); | ||||
if ((excepts & (FE_UNDERFLOW | FE_OVERFLOW)) != 0) { | if ((excepts & (FE_UNDERFLOW | FE_OVERFLOW)) != 0) { | ||||
excepts |= FE_INEXACT; | excepts |= FE_INEXACT; | ||||
assert((fetestexcept(ALL_STD_EXCEPT) | FE_INEXACT) == | ATF_CHECK_EQ(excepts, (fetestexcept(ALL_STD_EXCEPT) | FE_INEXACT)); | ||||
excepts); | |||||
} else { | } else { | ||||
assert(fetestexcept(ALL_STD_EXCEPT) == excepts); | ATF_CHECK_EQ(excepts, fetestexcept(ALL_STD_EXCEPT)); | ||||
} | } | ||||
assert(feclearexcept(FE_ALL_EXCEPT) == 0); | ATF_REQUIRE_EQ(0, feclearexcept(FE_ALL_EXCEPT)); | ||||
} | } | ||||
assert(feraiseexcept(FE_INVALID | FE_DIVBYZERO) == 0); | ATF_CHECK_EQ(0, feraiseexcept(FE_INVALID | FE_DIVBYZERO)); | ||||
assert(fetestexcept(ALL_STD_EXCEPT) == (FE_INVALID | FE_DIVBYZERO)); | ATF_CHECK_EQ((FE_INVALID | FE_DIVBYZERO), fetestexcept(ALL_STD_EXCEPT)); | ||||
assert(feraiseexcept(FE_OVERFLOW | FE_UNDERFLOW | FE_INEXACT) == 0); | ATF_CHECK_EQ(0, feraiseexcept(FE_OVERFLOW | FE_UNDERFLOW | FE_INEXACT)); | ||||
assert(fetestexcept(ALL_STD_EXCEPT) == ALL_STD_EXCEPT); | ATF_CHECK_EQ(ALL_STD_EXCEPT, fetestexcept(ALL_STD_EXCEPT)); | ||||
assert(feclearexcept(FE_ALL_EXCEPT) == 0); | ATF_REQUIRE_EQ(0, feclearexcept(FE_ALL_EXCEPT)); | ||||
} | } | ||||
/* | /* | ||||
* Test fegetround() and fesetround(). | * Test fegetround() and fesetround(). | ||||
*/ | */ | ||||
static void | ATF_TC_WITHOUT_HEAD(fegsetround); | ||||
test_fegsetround(void) | ATF_TC_BODY(fegsetround, tc) | ||||
{ | { | ||||
assert(fegetround() == FE_TONEAREST); | ATF_CHECK_EQ(FE_TONEAREST, fegetround()); | ||||
assert(getround() == FE_TONEAREST); | ATF_CHECK_EQ(FE_TONEAREST, getround()); | ||||
assert(FLT_ROUNDS == 1); | ATF_CHECK_EQ(1, FLT_ROUNDS); | ||||
assert(fesetround(FE_DOWNWARD) == 0); | ATF_CHECK_EQ(0, fesetround(FE_DOWNWARD)); | ||||
assert(fegetround() == FE_DOWNWARD); | ATF_CHECK_EQ(FE_DOWNWARD, fegetround()); | ||||
assert(getround() == FE_DOWNWARD); | ATF_CHECK_EQ(FE_DOWNWARD, getround()); | ||||
assert(FLT_ROUNDS == 3); | ATF_CHECK_EQ(3, FLT_ROUNDS); | ||||
assert(fesetround(FE_UPWARD) == 0); | ATF_CHECK_EQ(0, fesetround(FE_UPWARD)); | ||||
assert(getround() == FE_UPWARD); | ATF_CHECK_EQ(FE_UPWARD, getround()); | ||||
assert(fegetround() == FE_UPWARD); | ATF_CHECK_EQ(FE_UPWARD, fegetround()); | ||||
assert(FLT_ROUNDS == 2); | ATF_CHECK_EQ(2, FLT_ROUNDS); | ||||
assert(fesetround(FE_TOWARDZERO) == 0); | ATF_CHECK_EQ(0, fesetround(FE_TOWARDZERO)); | ||||
assert(getround() == FE_TOWARDZERO); | ATF_CHECK_EQ(FE_TOWARDZERO, getround()); | ||||
assert(fegetround() == FE_TOWARDZERO); | ATF_CHECK_EQ(FE_TOWARDZERO, fegetround()); | ||||
assert(FLT_ROUNDS == 0); | ATF_CHECK_EQ(0, FLT_ROUNDS); | ||||
assert(fesetround(FE_TONEAREST) == 0); | ATF_CHECK_EQ(0, fesetround(FE_TONEAREST)); | ||||
assert(getround() == FE_TONEAREST); | ATF_CHECK_EQ(FE_TONEAREST, getround()); | ||||
assert(FLT_ROUNDS == 1); | ATF_CHECK_EQ(1, FLT_ROUNDS); | ||||
assert(feclearexcept(FE_ALL_EXCEPT) == 0); | ATF_REQUIRE_EQ(0, feclearexcept(FE_ALL_EXCEPT)); | ||||
} | } | ||||
/* | /* | ||||
* Test fegetenv() and fesetenv(). | * Test fegetenv() and fesetenv(). | ||||
* | * | ||||
* Prerequisites: fetestexcept(), feclearexcept(), fegetround(), fesetround() | * Prerequisites: fetestexcept(), feclearexcept(), fegetround(), fesetround() | ||||
*/ | */ | ||||
static void | ATF_TC_WITHOUT_HEAD(fegsetenv); | ||||
test_fegsetenv(void) | ATF_TC_BODY(fegsetenv, tc) | ||||
{ | { | ||||
fenv_t env1, env2; | fenv_t env1, env2; | ||||
int excepts, i; | int excepts, i; | ||||
for (i = 0; i < 1 << NEXCEPTS; i++) { | for (i = 0; i < 1 << NEXCEPTS; i++) { | ||||
excepts = std_except_sets[i]; | excepts = std_except_sets[i]; | ||||
assert(fetestexcept(FE_ALL_EXCEPT) == 0); | ATF_CHECK_EQ(0, fetestexcept(FE_ALL_EXCEPT)); | ||||
assert(fegetround() == FE_TONEAREST); | ATF_CHECK_EQ(FE_TONEAREST, fegetround()); | ||||
assert(fegetenv(&env1) == 0); | ATF_CHECK_EQ(0, fegetenv(&env1)); | ||||
/* | /* | ||||
* fe[gs]etenv() should be able to save and restore | * fe[gs]etenv() should be able to save and restore | ||||
* exception flags without the spurious inexact | * exception flags without the spurious inexact | ||||
* exceptions that afflict raiseexcept(). | * exceptions that afflict raiseexcept(). | ||||
*/ | */ | ||||
raiseexcept(excepts); | raiseexcept(excepts); | ||||
if ((excepts & (FE_UNDERFLOW | FE_OVERFLOW)) != 0 && | if ((excepts & (FE_UNDERFLOW | FE_OVERFLOW)) != 0 && | ||||
(excepts & FE_INEXACT) == 0) | (excepts & FE_INEXACT) == 0) | ||||
assert(feclearexcept(FE_INEXACT) == 0); | ATF_CHECK_EQ(0, feclearexcept(FE_INEXACT)); | ||||
fesetround(FE_DOWNWARD); | fesetround(FE_DOWNWARD); | ||||
assert(fegetenv(&env2) == 0); | ATF_CHECK_EQ(0, fegetenv(&env2)); | ||||
assert(fesetenv(&env1) == 0); | ATF_CHECK_EQ(0, fesetenv(&env1)); | ||||
assert(fetestexcept(FE_ALL_EXCEPT) == 0); | ATF_CHECK_EQ(0, fetestexcept(FE_ALL_EXCEPT)); | ||||
assert(fegetround() == FE_TONEAREST); | ATF_CHECK_EQ(FE_TONEAREST, fegetround()); | ||||
assert(fesetenv(&env2) == 0); | ATF_CHECK_EQ(0, fesetenv(&env2)); | ||||
/* | /* | ||||
* Some platforms like powerpc may set extra exception bits. Since | * Some platforms like powerpc may set extra exception bits. Since | ||||
* only standard exceptions are tested, mask against ALL_STD_EXCEPT | * only standard exceptions are tested, mask against ALL_STD_EXCEPT | ||||
*/ | */ | ||||
assert((fetestexcept(FE_ALL_EXCEPT) & ALL_STD_EXCEPT) == excepts); | ATF_CHECK_EQ(excepts, (fetestexcept(FE_ALL_EXCEPT) & ALL_STD_EXCEPT)); | ||||
assert(fegetround() == FE_DOWNWARD); | ATF_CHECK_EQ(FE_DOWNWARD, fegetround()); | ||||
assert(fesetenv(&env1) == 0); | ATF_CHECK_EQ(0, fesetenv(&env1)); | ||||
assert(fetestexcept(FE_ALL_EXCEPT) == 0); | ATF_CHECK_EQ(0, fetestexcept(FE_ALL_EXCEPT)); | ||||
assert(fegetround() == FE_TONEAREST); | ATF_CHECK_EQ(FE_TONEAREST, fegetround()); | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* Test fegetexcept(), fedisableexcept(), and feenableexcept(). | * Test fegetexcept(), fedisableexcept(), and feenableexcept(). | ||||
* | * | ||||
* Prerequisites: fetestexcept(), feraiseexcept() | * Prerequisites: fetestexcept(), feraiseexcept() | ||||
*/ | */ | ||||
static void | ATF_TC_WITHOUT_HEAD(masking); | ||||
test_masking(void) | ATF_TC_BODY(masking, tc) | ||||
{ | { | ||||
struct sigaction act; | struct sigaction act; | ||||
int except, pass, raise, status; | int except, pass, raise, status; | ||||
unsigned i; | unsigned i; | ||||
assert((fegetexcept() & ALL_STD_EXCEPT) == 0); | ATF_CHECK_EQ(0, (fegetexcept() & ALL_STD_EXCEPT)); | ||||
assert((feenableexcept(FE_INVALID|FE_OVERFLOW) & ALL_STD_EXCEPT) == 0); | ATF_CHECK_EQ(0, (feenableexcept(FE_INVALID|FE_OVERFLOW) & ALL_STD_EXCEPT)); | ||||
assert((feenableexcept(FE_UNDERFLOW) & ALL_STD_EXCEPT) == | ATF_CHECK_EQ((FE_INVALID | FE_OVERFLOW), (feenableexcept(FE_UNDERFLOW) & ALL_STD_EXCEPT)); | ||||
(FE_INVALID | FE_OVERFLOW)); | ATF_CHECK_EQ((FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW), (fedisableexcept(FE_OVERFLOW) & ALL_STD_EXCEPT)); | ||||
assert((fedisableexcept(FE_OVERFLOW) & ALL_STD_EXCEPT) == | ATF_CHECK_EQ((FE_INVALID | FE_UNDERFLOW), (fegetexcept() & ALL_STD_EXCEPT)); | ||||
(FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW)); | ATF_CHECK_EQ((FE_INVALID | FE_UNDERFLOW), (fedisableexcept(FE_ALL_EXCEPT) & ALL_STD_EXCEPT)); | ||||
assert((fegetexcept() & ALL_STD_EXCEPT) == (FE_INVALID | FE_UNDERFLOW)); | ATF_CHECK_EQ(0, (fegetexcept() & ALL_STD_EXCEPT)); | ||||
assert((fedisableexcept(FE_ALL_EXCEPT) & ALL_STD_EXCEPT) == | |||||
(FE_INVALID | FE_UNDERFLOW)); | |||||
assert((fegetexcept() & ALL_STD_EXCEPT) == 0); | |||||
sigemptyset(&act.sa_mask); | sigemptyset(&act.sa_mask); | ||||
act.sa_flags = 0; | act.sa_flags = 0; | ||||
act.sa_handler = trap_handler; | act.sa_handler = trap_handler; | ||||
for (pass = 0; pass < 2; pass++) { | for (pass = 0; pass < 2; pass++) { | ||||
for (i = 0; i < NEXCEPTS; i++) { | for (i = 0; i < NEXCEPTS; i++) { | ||||
except = std_excepts[i]; | except = std_excepts[i]; | ||||
/* over/underflow may also raise inexact */ | /* over/underflow may also raise inexact */ | ||||
if (except == FE_INEXACT) | if (except == FE_INEXACT) | ||||
raise = FE_DIVBYZERO | FE_INVALID; | raise = FE_DIVBYZERO | FE_INVALID; | ||||
else | else | ||||
raise = ALL_STD_EXCEPT ^ except; | raise = ALL_STD_EXCEPT ^ except; | ||||
/* | /* | ||||
* We need to fork a child process because | * We need to fork a child process because | ||||
* there isn't a portable way to recover from | * there isn't a portable way to recover from | ||||
* a floating-point exception. | * a floating-point exception. | ||||
*/ | */ | ||||
switch(fork()) { | switch(fork()) { | ||||
case 0: /* child */ | case 0: /* child */ | ||||
assert((fegetexcept() & ALL_STD_EXCEPT) == 0); | ATF_CHECK_EQ(0, (fegetexcept() & ALL_STD_EXCEPT)); | ||||
assert((feenableexcept(except) | ATF_REQUIRE_EQ(0, (feenableexcept(except) & ALL_STD_EXCEPT)); | ||||
& ALL_STD_EXCEPT) == 0); | ATF_CHECK_EQ(except, fegetexcept()); | ||||
assert(fegetexcept() == except); | |||||
raiseexcept(raise); | raiseexcept(raise); | ||||
assert(feraiseexcept(raise) == 0); | ATF_CHECK_EQ(0, feraiseexcept(raise)); | ||||
assert(fetestexcept(ALL_STD_EXCEPT) == raise); | ATF_CHECK_EQ(raise, fetestexcept(ALL_STD_EXCEPT)); | ||||
assert(sigaction(SIGFPE, &act, NULL) == 0); | ATF_CHECK_EQ(0, sigaction(SIGFPE, &act, NULL)); | ||||
switch (pass) { | switch (pass) { | ||||
case 0: | case 0: | ||||
raiseexcept(except); | raiseexcept(except); | ||||
case 1: | case 1: | ||||
feraiseexcept(except); | feraiseexcept(except); | ||||
default: | default: | ||||
assert(0); | ATF_REQUIRE(0); | ||||
} | } | ||||
assert(0); | ATF_REQUIRE(0); | ||||
default: /* parent */ | default: /* parent */ | ||||
assert(wait(&status) > 0); | ATF_REQUIRE(wait(&status) > 0); | ||||
/* | /* | ||||
* Avoid assert() here so that it's possible | * Avoid assert() here so that it's possible | ||||
* to examine a failed child's core dump. | * to examine a failed child's core dump. | ||||
*/ | */ | ||||
if (!WIFEXITED(status)) | if (!WIFEXITED(status)) | ||||
errx(1, "child aborted\n"); | errx(1, "child aborted\n"); | ||||
assert(WEXITSTATUS(status) == 0); | ATF_CHECK_EQ(0, WEXITSTATUS(status)); | ||||
break; | break; | ||||
case -1: /* error */ | case -1: /* error */ | ||||
assert(0); | ATF_REQUIRE(0); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
assert(fetestexcept(FE_ALL_EXCEPT) == 0); | ATF_CHECK_EQ(0, fetestexcept(FE_ALL_EXCEPT)); | ||||
} | } | ||||
/* | /* | ||||
* Test feholdexcept() and feupdateenv(). | * Test feholdexcept() and feupdateenv(). | ||||
* | * | ||||
* Prerequisites: fetestexcept(), fegetround(), fesetround(), | * Prerequisites: fetestexcept(), fegetround(), fesetround(), | ||||
* fedisableexcept(), feenableexcept() | * fedisableexcept(), feenableexcept() | ||||
*/ | */ | ||||
static void | ATF_TC_WITHOUT_HEAD(feholdupdate); | ||||
test_feholdupdate(void) | ATF_TC_BODY(feholdupdate, tc) | ||||
{ | { | ||||
fenv_t env; | fenv_t env; | ||||
struct sigaction act; | struct sigaction act; | ||||
int except, pass, status, raise; | int except, pass, status, raise; | ||||
unsigned i; | unsigned i; | ||||
sigemptyset(&act.sa_mask); | sigemptyset(&act.sa_mask); | ||||
Show All 16 Lines | for (i = 0; i < NEXCEPTS; i++) { | ||||
switch(fork()) { | switch(fork()) { | ||||
case 0: /* child */ | case 0: /* child */ | ||||
/* | /* | ||||
* We don't want to cause a fatal exception in | * We don't want to cause a fatal exception in | ||||
* the child until the second pass, so we can | * the child until the second pass, so we can | ||||
* check other properties of feupdateenv(). | * check other properties of feupdateenv(). | ||||
*/ | */ | ||||
if (pass == 1) | if (pass == 1) | ||||
assert((feenableexcept(except) & | ATF_REQUIRE_EQ(0, feenableexcept(except) & ALL_STD_EXCEPT); | ||||
ALL_STD_EXCEPT) == 0); | |||||
raiseexcept(raise); | raiseexcept(raise); | ||||
assert(fesetround(FE_DOWNWARD) == 0); | ATF_CHECK_EQ(0, fesetround(FE_DOWNWARD)); | ||||
assert(feholdexcept(&env) == 0); | ATF_CHECK_EQ(0, feholdexcept(&env)); | ||||
assert(fetestexcept(FE_ALL_EXCEPT) == 0); | ATF_CHECK_EQ(0, fetestexcept(FE_ALL_EXCEPT)); | ||||
raiseexcept(except); | raiseexcept(except); | ||||
assert(fesetround(FE_UPWARD) == 0); | ATF_CHECK_EQ(0, fesetround(FE_UPWARD)); | ||||
if (pass == 1) | if (pass == 1) | ||||
assert(sigaction(SIGFPE, &act, NULL) == | ATF_CHECK_EQ(0, sigaction(SIGFPE, &act, NULL)); | ||||
0); | ATF_CHECK_EQ(0, feupdateenv(&env)); | ||||
assert(feupdateenv(&env) == 0); | ATF_CHECK_EQ(FE_DOWNWARD, fegetround()); | ||||
assert(fegetround() == FE_DOWNWARD); | ATF_CHECK_EQ((except | raise), fetestexcept(ALL_STD_EXCEPT)); | ||||
assert(fetestexcept(ALL_STD_EXCEPT) == | |||||
(except | raise)); | |||||
assert(pass == 0); | ATF_CHECK_EQ(0, pass); | ||||
_exit(0); | _exit(0); | ||||
default: /* parent */ | default: /* parent */ | ||||
assert(wait(&status) > 0); | ATF_REQUIRE(wait(&status) > 0); | ||||
/* | /* | ||||
* Avoid assert() here so that it's possible | * Avoid assert() here so that it's possible | ||||
* to examine a failed child's core dump. | * to examine a failed child's core dump. | ||||
*/ | */ | ||||
if (!WIFEXITED(status)) | if (!WIFEXITED(status)) | ||||
errx(1, "child aborted\n"); | errx(1, "child aborted\n"); | ||||
assert(WEXITSTATUS(status) == 0); | ATF_CHECK_EQ(0, WEXITSTATUS(status)); | ||||
break; | break; | ||||
case -1: /* error */ | case -1: /* error */ | ||||
assert(0); | ATF_REQUIRE(0); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
assert(fetestexcept(FE_ALL_EXCEPT) == 0); | ATF_CHECK_EQ(0, fetestexcept(FE_ALL_EXCEPT)); | ||||
} | } | ||||
int | ATF_TP_ADD_TCS(tp) | ||||
main(void) | |||||
{ | { | ||||
/* Avoid double output after fork() */ | ATF_TP_ADD_TC(tp, dfl_env); | ||||
setvbuf(stdout, NULL, _IONBF, 0); | ATF_TP_ADD_TC(tp, fetestclearexcept); | ||||
ATF_TP_ADD_TC(tp, fegsetexceptflag); | |||||
ATF_TP_ADD_TC(tp, feraiseexcept); | |||||
ATF_TP_ADD_TC(tp, fegsetround); | |||||
ATF_TP_ADD_TC(tp, fegsetenv); | |||||
ATF_TP_ADD_TC(tp, masking); | |||||
ATF_TP_ADD_TC(tp, feholdupdate); | |||||
printf("1..8\n"); | return (atf_no_error()); | ||||
init_exceptsets(); | |||||
test_dfl_env(); | |||||
printf("ok 1 - fenv\n"); | |||||
test_fetestclearexcept(); | |||||
printf("ok 2 - fenv\n"); | |||||
test_fegsetexceptflag(); | |||||
printf("ok 3 - fenv\n"); | |||||
test_feraiseexcept(); | |||||
printf("ok 4 - fenv\n"); | |||||
test_fegsetround(); | |||||
printf("ok 5 - fenv\n"); | |||||
test_fegsetenv(); | |||||
printf("ok 6 - fenv\n"); | |||||
test_masking(); | |||||
printf("ok 7 - fenv\n"); | |||||
test_feholdupdate(); | |||||
printf("ok 8 - fenv\n"); | |||||
return (0); | |||||
} | } |