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