1 /*- 2 * Copyright (c) 2004 David Schultz <das@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 /* 28 * Test the correctness and C99-compliance of various fenv.h features. 29 */ 30 31 #include <sys/types.h> 32 #include <sys/wait.h> 33 #include <assert.h> 34 #include <err.h> 35 #include <fenv.h> 36 #include <float.h> 37 #include <libutil.h> 38 #include <math.h> 39 #include <signal.h> 40 #include <stdio.h> 41 #include <string.h> 42 #include <unistd.h> 43 44 #include "test-utils.h" 45 46 #define NEXCEPTS (sizeof(std_excepts) / sizeof(std_excepts[0])) 47 48 static const int std_excepts[] = { 49 FE_INVALID, 50 FE_DIVBYZERO, 51 FE_OVERFLOW, 52 FE_UNDERFLOW, 53 FE_INEXACT, 54 }; 55 56 /* init_exceptsets() initializes this to the power set of std_excepts[] */ 57 static int std_except_sets[1 << NEXCEPTS]; 58 59 #pragma STDC FENV_ACCESS ON 60 61 /* 62 * Initialize std_except_sets[] to the power set of std_excepts[] 63 */ 64 static __attribute__((constructor)) void 65 do_setup(void) 66 { 67 unsigned i, j, sr; 68 69 /* Avoid double output after fork() */ 70 setvbuf(stdout, NULL, _IONBF, 0); 71 72 for (i = 0; i < 1 << NEXCEPTS; i++) { 73 for (sr = i, j = 0; sr != 0; sr >>= 1, j++) 74 std_except_sets[i] |= std_excepts[j] & ((~sr & 1) - 1); 75 } 76 } 77 78 /* 79 * Raise a floating-point exception without relying on the standard 80 * library routines, which we are trying to test. 81 * 82 * XXX We can't raise an {over,under}flow without also raising an 83 * inexact exception. 84 */ 85 static void 86 raiseexcept(int excepts) 87 { 88 volatile double d; 89 90 /* 91 * With a compiler that supports the FENV_ACCESS pragma 92 * properly, simple expressions like '0.0 / 0.0' should 93 * be sufficient to generate traps. Unfortunately, we 94 * need to bring a volatile variable into the equation 95 * to prevent incorrect optimizations. 96 */ 97 if (excepts & FE_INVALID) { 98 d = 0.0; 99 d = 0.0 / d; 100 } 101 if (excepts & FE_DIVBYZERO) { 102 d = 0.0; 103 d = 1.0 / d; 104 } 105 if (excepts & FE_OVERFLOW) { 106 d = DBL_MAX; 107 d *= 2.0; 108 } 109 if (excepts & FE_UNDERFLOW) { 110 d = DBL_MIN; 111 d /= DBL_MAX; 112 } 113 if (excepts & FE_INEXACT) { 114 d = DBL_MIN; 115 d += 1.0; 116 } 117 118 /* 119 * On the x86 (and some other architectures?) the FPU and 120 * integer units are decoupled. We need to execute an FWAIT 121 * or a floating-point instruction to get synchronous exceptions. 122 */ 123 d = 1.0; 124 d += 1.0; 125 } 126 127 /* 128 * Determine the current rounding mode without relying on the fenv 129 * routines. This function may raise an inexact exception. 130 */ 131 static int 132 getround(void) 133 { 134 volatile double d; 135 136 /* 137 * This test works just as well with 0.0 - 0.0, except on ia64 138 * where 0.0 - 0.0 gives the wrong sign when rounding downwards. 139 */ 140 d = 1.0; 141 d -= 1.0; 142 if (copysign(1.0, d) < 0.0) 143 return (FE_DOWNWARD); 144 145 d = 1.0; 146 if (d + (DBL_EPSILON * 3.0 / 4.0) == 1.0) 147 return (FE_TOWARDZERO); 148 if (d + (DBL_EPSILON * 1.0 / 4.0) > 1.0) 149 return (FE_UPWARD); 150 151 return (FE_TONEAREST); 152 } 153 154 static void 155 trap_handler(int sig) 156 { 157 158 ATF_CHECK_EQ(SIGFPE, sig); 159 _exit(0); 160 } 161 162 /* 163 * This tests checks the default FP environment, so it must be first. 164 * The memcmp() test below may be too much to ask for, since there 165 * could be multiple machine-specific default environments. 166 */ 167 ATF_TC_WITHOUT_HEAD(dfl_env); 168 ATF_TC_BODY(dfl_env, tc) 169 { 170 #ifndef NO_STRICT_DFL_ENV 171 fenv_t env; 172 173 fegetenv(&env); 174 /* Print the default environment for debugging purposes. */ 175 hexdump(&env, sizeof(env), "current fenv ", HD_OMIT_CHARS); 176 hexdump(FE_DFL_ENV, sizeof(env), "default fenv ", HD_OMIT_CHARS); 177 CHECK_FP_EXCEPTIONS(0, FE_ALL_EXCEPT); 178 #ifdef __amd64__ 179 /* 180 * Compare the fields that the AMD [1] and Intel [2] specs say will be 181 * set once fnstenv returns. 182 * 183 * Not all amd64 capable processors implement the fnstenv instruction 184 * by zero'ing out the env.__x87.__other field (example: AMD Opteron 185 * 6308). The AMD64/x64 specs aren't explicit on what the 186 * env.__x87.__other field will contain after fnstenv is executed, so 187 * the values in env.__x87.__other could be filled with arbitrary 188 * data depending on how the CPU implements fnstenv. 189 * 190 * 1. http://support.amd.com/TechDocs/26569_APM_v5.pdf 191 * 2. http://www.intel.com/Assets/en_US/PDF/manual/253666.pdf 192 */ 193 ATF_CHECK(memcmp(&env.__mxcsr, &FE_DFL_ENV->__mxcsr, 194 sizeof(env.__mxcsr)) == 0); 195 ATF_CHECK(memcmp(&env.__x87.__control, &FE_DFL_ENV->__x87.__control, 196 sizeof(env.__x87.__control)) == 0); 197 ATF_CHECK(memcmp(&env.__x87.__status, &FE_DFL_ENV->__x87.__status, 198 sizeof(env.__x87.__status)) == 0); 199 ATF_CHECK(memcmp(&env.__x87.__tag, &FE_DFL_ENV->__x87.__tag, 200 sizeof(env.__x87.__tag)) == 0); 201 #else 202 ATF_CHECK_EQ(0, memcmp(&env, FE_DFL_ENV, sizeof(env))); 203 #endif 204 205 #endif 206 CHECK_FP_EXCEPTIONS(0, FE_ALL_EXCEPT); 207 } 208 209 /* 210 * Test fetestexcept() and feclearexcept(). 211 */ 212 ATF_TC_WITHOUT_HEAD(fetestclearexcept); 213 ATF_TC_BODY(fetestclearexcept, tc) 214 { 215 int excepts, i; 216 217 for (i = 0; i < 1 << NEXCEPTS; i++) 218 ATF_CHECK_EQ(0, fetestexcept(std_except_sets[i])); 219 for (i = 0; i < 1 << NEXCEPTS; i++) { 220 excepts = std_except_sets[i]; 221 222 /* FE_ALL_EXCEPT might be special-cased, as on i386. */ 223 raiseexcept(excepts); 224 ATF_CHECK_EQ(excepts, fetestexcept(excepts)); 225 ATF_REQUIRE_EQ(0, feclearexcept(FE_ALL_EXCEPT)); 226 ATF_CHECK_EQ(0, fetestexcept(FE_ALL_EXCEPT)); 227 228 raiseexcept(excepts); 229 ATF_CHECK_EQ(excepts, fetestexcept(excepts)); 230 if ((excepts & (FE_UNDERFLOW | FE_OVERFLOW)) != 0) { 231 excepts |= FE_INEXACT; 232 ATF_CHECK_EQ(excepts, (fetestexcept(ALL_STD_EXCEPT) | FE_INEXACT)); 233 } else { 234 ATF_CHECK_EQ(excepts, fetestexcept(ALL_STD_EXCEPT)); 235 } 236 ATF_CHECK_EQ(0, feclearexcept(excepts)); 237 ATF_CHECK_EQ(0, fetestexcept(ALL_STD_EXCEPT)); 238 } 239 } 240 241 /* 242 * Test fegetexceptflag() and fesetexceptflag(). 243 * 244 * Prerequisites: fetestexcept(), feclearexcept() 245 */ 246 ATF_TC_WITHOUT_HEAD(fegsetexceptflag); 247 ATF_TC_BODY(fegsetexceptflag, tc) 248 { 249 fexcept_t flag; 250 int excepts, i; 251 252 CHECK_FP_EXCEPTIONS(0, FE_ALL_EXCEPT); 253 for (i = 0; i < 1 << NEXCEPTS; i++) { 254 excepts = std_except_sets[i]; 255 256 ATF_CHECK_EQ(0, fegetexceptflag(&flag, excepts)); 257 raiseexcept(ALL_STD_EXCEPT); 258 ATF_CHECK_EQ(0, fesetexceptflag(&flag, excepts)); 259 ATF_CHECK_EQ((ALL_STD_EXCEPT ^ excepts), fetestexcept(ALL_STD_EXCEPT)); 260 261 ATF_CHECK_EQ(0, fegetexceptflag(&flag, FE_ALL_EXCEPT)); 262 ATF_REQUIRE_EQ(0, feclearexcept(FE_ALL_EXCEPT)); 263 ATF_CHECK_EQ(0, fesetexceptflag(&flag, excepts)); 264 ATF_CHECK_EQ(0, fetestexcept(ALL_STD_EXCEPT)); 265 ATF_CHECK_EQ(0, fesetexceptflag(&flag, ALL_STD_EXCEPT ^ excepts)); 266 ATF_CHECK_EQ((ALL_STD_EXCEPT ^ excepts), fetestexcept(ALL_STD_EXCEPT)); 267 268 ATF_REQUIRE_EQ(0, feclearexcept(FE_ALL_EXCEPT)); 269 } 270 } 271 272 /* 273 * Test feraiseexcept(). 274 * 275 * Prerequisites: fetestexcept(), feclearexcept() 276 */ 277 ATF_TC_WITHOUT_HEAD(feraiseexcept); 278 ATF_TC_BODY(feraiseexcept, tc) 279 { 280 int excepts, i; 281 282 for (i = 0; i < 1 << NEXCEPTS; i++) { 283 excepts = std_except_sets[i]; 284 285 ATF_CHECK_EQ(0, fetestexcept(FE_ALL_EXCEPT)); 286 ATF_CHECK_EQ(0, feraiseexcept(excepts)); 287 if ((excepts & (FE_UNDERFLOW | FE_OVERFLOW)) != 0) { 288 excepts |= FE_INEXACT; 289 ATF_CHECK_EQ(excepts, (fetestexcept(ALL_STD_EXCEPT) | FE_INEXACT)); 290 } else { 291 ATF_CHECK_EQ(excepts, fetestexcept(ALL_STD_EXCEPT)); 292 } 293 ATF_REQUIRE_EQ(0, feclearexcept(FE_ALL_EXCEPT)); 294 } 295 ATF_CHECK_EQ(0, feraiseexcept(FE_INVALID | FE_DIVBYZERO)); 296 ATF_CHECK_EQ((FE_INVALID | FE_DIVBYZERO), fetestexcept(ALL_STD_EXCEPT)); 297 ATF_CHECK_EQ(0, feraiseexcept(FE_OVERFLOW | FE_UNDERFLOW | FE_INEXACT)); 298 ATF_CHECK_EQ(ALL_STD_EXCEPT, fetestexcept(ALL_STD_EXCEPT)); 299 ATF_REQUIRE_EQ(0, feclearexcept(FE_ALL_EXCEPT)); 300 } 301 302 /* 303 * Test fegetround() and fesetround(). 304 */ 305 ATF_TC_WITHOUT_HEAD(fegsetround); 306 ATF_TC_BODY(fegsetround, tc) 307 { 308 309 ATF_CHECK_EQ(FE_TONEAREST, fegetround()); 310 ATF_CHECK_EQ(FE_TONEAREST, getround()); 311 ATF_CHECK_EQ(1, FLT_ROUNDS); 312 313 ATF_CHECK_EQ(0, fesetround(FE_DOWNWARD)); 314 ATF_CHECK_EQ(FE_DOWNWARD, fegetround()); 315 ATF_CHECK_EQ(FE_DOWNWARD, getround()); 316 ATF_CHECK_EQ(3, FLT_ROUNDS); 317 318 ATF_CHECK_EQ(0, fesetround(FE_UPWARD)); 319 ATF_CHECK_EQ(FE_UPWARD, getround()); 320 ATF_CHECK_EQ(FE_UPWARD, fegetround()); 321 ATF_CHECK_EQ(2, FLT_ROUNDS); 322 323 ATF_CHECK_EQ(0, fesetround(FE_TOWARDZERO)); 324 ATF_CHECK_EQ(FE_TOWARDZERO, getround()); 325 ATF_CHECK_EQ(FE_TOWARDZERO, fegetround()); 326 ATF_CHECK_EQ(0, FLT_ROUNDS); 327 328 ATF_CHECK_EQ(0, fesetround(FE_TONEAREST)); 329 ATF_CHECK_EQ(FE_TONEAREST, getround()); 330 ATF_CHECK_EQ(1, FLT_ROUNDS); 331 332 ATF_REQUIRE_EQ(0, feclearexcept(FE_ALL_EXCEPT)); 333 } 334 335 /* 336 * Test fegetmode() and fesetmode(). 337 * 338 * Prerequisites: fetestexcept(), feclearexcept(), fegetround(), fesetround() 339 */ 340 ATF_TC_WITHOUT_HEAD(fegsetmode); 341 ATF_TC_BODY(fegsetmode, tc) 342 { 343 femode_t mode_dfl, mode_down, mode_nomask, mode_mask; 344 int excepts; 345 346 ATF_CHECK(FE_DFL_MODE != NULL); 347 ATF_CHECK_EQ(0, fegetmode(&mode_dfl)); 348 ATF_CHECK_EQ(FE_TONEAREST, fegetround()); 349 350 ATF_REQUIRE_EQ(0, feclearexcept(FE_ALL_EXCEPT)); 351 raiseexcept(FE_INVALID | FE_DIVBYZERO); 352 excepts = fetestexcept(ALL_STD_EXCEPT); 353 ATF_CHECK(excepts != 0); 354 355 ATF_CHECK_EQ(0, fesetround(FE_DOWNWARD)); 356 ATF_CHECK_EQ(0, fegetmode(&mode_down)); 357 358 ATF_CHECK_EQ(0, fesetmode(FE_DFL_MODE)); 359 ATF_CHECK_EQ(FE_TONEAREST, fegetround()); 360 ATF_CHECK_EQ(excepts, fetestexcept(ALL_STD_EXCEPT)); 361 362 ATF_CHECK_EQ(0, fesetmode(&mode_down)); 363 ATF_CHECK_EQ(FE_DOWNWARD, fegetround()); 364 ATF_CHECK_EQ(FE_DOWNWARD, getround()); 365 ATF_CHECK_EQ(excepts, fetestexcept(ALL_STD_EXCEPT)); 366 367 ATF_CHECK_EQ(0, fesetmode(&mode_dfl)); 368 ATF_CHECK_EQ(FE_TONEAREST, fegetround()); 369 ATF_CHECK_EQ(excepts, fetestexcept(ALL_STD_EXCEPT)); 370 371 ATF_REQUIRE_EQ(0, feclearexcept(FE_ALL_EXCEPT)); 372 ATF_CHECK_EQ(0, fesetround(FE_TONEAREST)); 373 374 /* 375 * Exception masks are control modes. Skip the restore check 376 * when the CPU ignores trap-enable bits, as on some AArch64 377 * implementations. 378 */ 379 ATF_CHECK_EQ(0, fedisableexcept(FE_ALL_EXCEPT) & ALL_STD_EXCEPT); 380 ATF_CHECK_EQ(0, fegetexcept() & ALL_STD_EXCEPT); 381 ATF_CHECK_EQ(0, fegetmode(&mode_nomask)); 382 (void)feenableexcept(FE_INVALID); 383 if ((fegetexcept() & FE_INVALID) != 0) { 384 ATF_CHECK_EQ(0, fegetmode(&mode_mask)); 385 ATF_CHECK_EQ(0, fesetmode(&mode_nomask)); 386 ATF_CHECK_EQ(0, fegetexcept() & ALL_STD_EXCEPT); 387 ATF_CHECK_EQ(0, fesetmode(&mode_mask)); 388 ATF_CHECK_EQ(FE_INVALID, fegetexcept() & ALL_STD_EXCEPT); 389 ATF_CHECK_EQ(0, fesetmode(FE_DFL_MODE)); 390 ATF_CHECK_EQ(0, fegetexcept() & ALL_STD_EXCEPT); 391 } 392 (void)fedisableexcept(FE_ALL_EXCEPT); 393 ATF_CHECK_EQ(0, fesetround(FE_TONEAREST)); 394 ATF_REQUIRE_EQ(0, feclearexcept(FE_ALL_EXCEPT)); 395 } 396 397 /* 398 * Test fegetenv() and fesetenv(). 399 * 400 * Prerequisites: fetestexcept(), feclearexcept(), fegetround(), fesetround() 401 */ 402 ATF_TC_WITHOUT_HEAD(fegsetenv); 403 ATF_TC_BODY(fegsetenv, tc) 404 { 405 fenv_t env1, env2; 406 int excepts, i; 407 408 for (i = 0; i < 1 << NEXCEPTS; i++) { 409 excepts = std_except_sets[i]; 410 411 ATF_CHECK_EQ(0, fetestexcept(FE_ALL_EXCEPT)); 412 ATF_CHECK_EQ(FE_TONEAREST, fegetround()); 413 ATF_CHECK_EQ(0, fegetenv(&env1)); 414 415 /* 416 * fe[gs]etenv() should be able to save and restore 417 * exception flags without the spurious inexact 418 * exceptions that afflict raiseexcept(). 419 */ 420 raiseexcept(excepts); 421 if ((excepts & (FE_UNDERFLOW | FE_OVERFLOW)) != 0 && 422 (excepts & FE_INEXACT) == 0) 423 ATF_CHECK_EQ(0, feclearexcept(FE_INEXACT)); 424 425 fesetround(FE_DOWNWARD); 426 ATF_CHECK_EQ(0, fegetenv(&env2)); 427 ATF_CHECK_EQ(0, fesetenv(&env1)); 428 ATF_CHECK_EQ(0, fetestexcept(FE_ALL_EXCEPT)); 429 ATF_CHECK_EQ(FE_TONEAREST, fegetround()); 430 431 ATF_CHECK_EQ(0, fesetenv(&env2)); 432 433 /* 434 * Some platforms like powerpc may set extra exception bits. Since 435 * only standard exceptions are tested, mask against ALL_STD_EXCEPT 436 */ 437 ATF_CHECK_EQ(excepts, (fetestexcept(FE_ALL_EXCEPT) & ALL_STD_EXCEPT)); 438 439 ATF_CHECK_EQ(FE_DOWNWARD, fegetround()); 440 ATF_CHECK_EQ(0, fesetenv(&env1)); 441 ATF_CHECK_EQ(0, fetestexcept(FE_ALL_EXCEPT)); 442 ATF_CHECK_EQ(FE_TONEAREST, fegetround()); 443 } 444 } 445 446 /* 447 * Test fegetexcept(), fedisableexcept(), and feenableexcept(). 448 * 449 * Prerequisites: fetestexcept(), feraiseexcept() 450 */ 451 ATF_TC_WITHOUT_HEAD(masking); 452 ATF_TC_BODY(masking, tc) 453 { 454 struct sigaction act; 455 int except, pass, raise, status; 456 unsigned i; 457 458 ATF_REQUIRE_EQ(0, (fegetexcept() & ALL_STD_EXCEPT)); 459 460 /* 461 * Some CPUs, e.g. AArch64 QEMU does not support trapping on FP 462 * exceptions. In that case the trap enable bits are all RAZ/WI, so 463 * writing to those bits will be ignored and the next read will 464 * return all zeroes for those bits. Skip the test if no floating 465 * point exceptions are supported and mark it XFAIL if some are missing. 466 */ 467 ATF_REQUIRE_EQ(0, (feenableexcept(FE_ALL_EXCEPT))); 468 except = fegetexcept(); 469 if (except == 0) { 470 atf_tc_skip("CPU does not support trapping on floating point " 471 "exceptions."); 472 } else if ((except & ALL_STD_EXCEPT) != ALL_STD_EXCEPT) { 473 atf_tc_expect_fail("Not all floating point exceptions can be " 474 "set to trap: %#x vs %#x", except, ALL_STD_EXCEPT); 475 } 476 fedisableexcept(FE_ALL_EXCEPT); 477 478 479 ATF_CHECK_EQ(0, (feenableexcept(FE_INVALID|FE_OVERFLOW) & ALL_STD_EXCEPT)); 480 ATF_CHECK_EQ((FE_INVALID | FE_OVERFLOW), (feenableexcept(FE_UNDERFLOW) & ALL_STD_EXCEPT)); 481 ATF_CHECK_EQ((FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW), (fedisableexcept(FE_OVERFLOW) & ALL_STD_EXCEPT)); 482 ATF_CHECK_EQ((FE_INVALID | FE_UNDERFLOW), (fegetexcept() & ALL_STD_EXCEPT)); 483 ATF_CHECK_EQ((FE_INVALID | FE_UNDERFLOW), (fedisableexcept(FE_ALL_EXCEPT) & ALL_STD_EXCEPT)); 484 ATF_CHECK_EQ(0, (fegetexcept() & ALL_STD_EXCEPT)); 485 486 sigemptyset(&act.sa_mask); 487 act.sa_flags = 0; 488 act.sa_handler = trap_handler; 489 for (pass = 0; pass < 2; pass++) { 490 for (i = 0; i < NEXCEPTS; i++) { 491 except = std_excepts[i]; 492 /* over/underflow may also raise inexact */ 493 if (except == FE_INEXACT) 494 raise = FE_DIVBYZERO | FE_INVALID; 495 else 496 raise = ALL_STD_EXCEPT ^ except; 497 498 /* 499 * We need to fork a child process because 500 * there isn't a portable way to recover from 501 * a floating-point exception. 502 */ 503 switch(fork()) { 504 case 0: /* child */ 505 ATF_CHECK_EQ(0, (fegetexcept() & ALL_STD_EXCEPT)); 506 ATF_REQUIRE_EQ(0, (feenableexcept(except) & ALL_STD_EXCEPT)); 507 ATF_CHECK_EQ(except, fegetexcept()); 508 raiseexcept(raise); 509 ATF_CHECK_EQ(0, feraiseexcept(raise)); 510 ATF_CHECK_EQ(raise, fetestexcept(ALL_STD_EXCEPT)); 511 512 ATF_CHECK_EQ(0, sigaction(SIGFPE, &act, NULL)); 513 switch (pass) { 514 case 0: 515 raiseexcept(except); 516 case 1: 517 feraiseexcept(except); 518 default: 519 ATF_REQUIRE(0); 520 } 521 ATF_REQUIRE(0); 522 default: /* parent */ 523 ATF_REQUIRE(wait(&status) > 0); 524 /* 525 * Avoid assert() here so that it's possible 526 * to examine a failed child's core dump. 527 */ 528 if (!WIFEXITED(status)) 529 errx(1, "child aborted\n"); 530 ATF_CHECK_EQ(0, WEXITSTATUS(status)); 531 break; 532 case -1: /* error */ 533 ATF_REQUIRE(0); 534 } 535 } 536 } 537 ATF_CHECK_EQ(0, fetestexcept(FE_ALL_EXCEPT)); 538 } 539 540 /* 541 * Test feholdexcept() and feupdateenv(). 542 * 543 * Prerequisites: fetestexcept(), fegetround(), fesetround(), 544 * fedisableexcept(), feenableexcept() 545 */ 546 ATF_TC_WITHOUT_HEAD(feholdupdate); 547 ATF_TC_BODY(feholdupdate, tc) 548 { 549 fenv_t env; 550 551 struct sigaction act; 552 int except, pass, status, raise; 553 unsigned i; 554 555 sigemptyset(&act.sa_mask); 556 act.sa_flags = 0; 557 act.sa_handler = trap_handler; 558 for (pass = 0; pass < 2; pass++) { 559 for (i = 0; i < NEXCEPTS; i++) { 560 except = std_excepts[i]; 561 /* over/underflow may also raise inexact */ 562 if (except == FE_INEXACT) 563 raise = FE_DIVBYZERO | FE_INVALID; 564 else 565 raise = ALL_STD_EXCEPT ^ except; 566 567 /* 568 * We need to fork a child process because 569 * there isn't a portable way to recover from 570 * a floating-point exception. 571 */ 572 switch(fork()) { 573 case 0: /* child */ 574 /* 575 * We don't want to cause a fatal exception in 576 * the child until the second pass, so we can 577 * check other properties of feupdateenv(). 578 */ 579 if (pass == 1) 580 ATF_REQUIRE_EQ(0, feenableexcept(except) & ALL_STD_EXCEPT); 581 raiseexcept(raise); 582 ATF_CHECK_EQ(0, fesetround(FE_DOWNWARD)); 583 ATF_CHECK_EQ(0, feholdexcept(&env)); 584 ATF_CHECK_EQ(0, fetestexcept(FE_ALL_EXCEPT)); 585 raiseexcept(except); 586 ATF_CHECK_EQ(0, fesetround(FE_UPWARD)); 587 588 if (pass == 1) 589 ATF_CHECK_EQ(0, sigaction(SIGFPE, &act, NULL)); 590 ATF_CHECK_EQ(0, feupdateenv(&env)); 591 ATF_CHECK_EQ(FE_DOWNWARD, fegetround()); 592 ATF_CHECK_EQ((except | raise), fetestexcept(ALL_STD_EXCEPT)); 593 594 ATF_CHECK_EQ(0, pass); 595 _exit(0); 596 default: /* parent */ 597 ATF_REQUIRE(wait(&status) > 0); 598 /* 599 * Avoid assert() here so that it's possible 600 * to examine a failed child's core dump. 601 */ 602 if (!WIFEXITED(status)) 603 errx(1, "child aborted\n"); 604 ATF_CHECK_EQ(0, WEXITSTATUS(status)); 605 break; 606 case -1: /* error */ 607 ATF_REQUIRE(0); 608 } 609 } 610 } 611 ATF_CHECK_EQ(0, fetestexcept(FE_ALL_EXCEPT)); 612 } 613 614 ATF_TP_ADD_TCS(tp) 615 { 616 ATF_TP_ADD_TC(tp, dfl_env); 617 ATF_TP_ADD_TC(tp, fetestclearexcept); 618 ATF_TP_ADD_TC(tp, fegsetexceptflag); 619 ATF_TP_ADD_TC(tp, feraiseexcept); 620 ATF_TP_ADD_TC(tp, fegsetround); 621 ATF_TP_ADD_TC(tp, fegsetmode); 622 ATF_TP_ADD_TC(tp, fegsetenv); 623 ATF_TP_ADD_TC(tp, masking); 624 ATF_TP_ADD_TC(tp, feholdupdate); 625 626 return (atf_no_error()); 627 } 628