1238384Sjkim/* $OpenBSD: fenv_test.c,v 1.7 2021/12/13 18:04:28 deraadt Exp $ */ 2280297Sjkim/*- 3280297Sjkim * Copyright (c) 2004 David Schultz <das@FreeBSD.org> 4238384Sjkim * All rights reserved. 5238384Sjkim * 6238384Sjkim * Redistribution and use in source and binary forms, with or without 7238384Sjkim * modification, are permitted provided that the following conditions 8238384Sjkim * are met: 9238384Sjkim * 1. Redistributions of source code must retain the above copyright 10238384Sjkim * notice, this list of conditions and the following disclaimer. 11238384Sjkim * 2. Redistributions in binary form must reproduce the above copyright 12238384Sjkim * notice, this list of conditions and the following disclaimer in the 13280297Sjkim * documentation and/or other materials provided with the distribution. 14238384Sjkim * 15238384Sjkim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16238384Sjkim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17238384Sjkim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18238384Sjkim * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19238384Sjkim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20238384Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21238384Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22238384Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23238384Sjkim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24238384Sjkim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25238384Sjkim * SUCH DAMAGE. 26238384Sjkim */ 27238384Sjkim 28238384Sjkim#include "macros.h" 29238384Sjkim 30238384Sjkim/* 31238384Sjkim * Test the correctness and C99-compliance of various fenv.h features. 32238384Sjkim */ 33238384Sjkim 34238384Sjkim#include <sys/types.h> 35238384Sjkim#include <sys/wait.h> 36238384Sjkim#include <assert.h> 37238384Sjkim#include <err.h> 38238384Sjkim#include <fenv.h> 39238384Sjkim#include <float.h> 40238384Sjkim#ifndef __OpenBSD__ 41238384Sjkim#include <libutil.h> 42238384Sjkim#endif 43238384Sjkim#include <math.h> 44238384Sjkim#include <signal.h> 45238384Sjkim#include <stdio.h> 46238384Sjkim#include <string.h> 47238384Sjkim#include <unistd.h> 48238384Sjkim 49238384Sjkim#include "test-utils.h" 50238384Sjkim 51238384Sjkim#define NEXCEPTS (sizeof(std_excepts) / sizeof(std_excepts[0])) 52238384Sjkim 53238384Sjkimstatic const int std_excepts[] = { 54238384Sjkim FE_INVALID, 55238384Sjkim FE_DIVBYZERO, 56238384Sjkim FE_OVERFLOW, 57238384Sjkim FE_UNDERFLOW, 58238384Sjkim FE_INEXACT, 59238384Sjkim}; 60238384Sjkim 61238384Sjkim/* init_exceptsets() initializes this to the power set of std_excepts[] */ 62238384Sjkimstatic int std_except_sets[1 << NEXCEPTS]; 63238384Sjkim 64280297Sjkim#pragma STDC FENV_ACCESS ON 65280297Sjkim 66238384Sjkim/* 67238384Sjkim * Initialize std_except_sets[] to the power set of std_excepts[] 68238384Sjkim */ 69238384Sjkimstatic __attribute__((constructor)) void 70238384Sjkimdo_setup(void) 71238384Sjkim{ 72280297Sjkim unsigned i, j, sr; 73280297Sjkim 74280297Sjkim /* Avoid double output after fork() */ 75280297Sjkim setvbuf(stdout, NULL, _IONBF, 0); 76238384Sjkim 77238384Sjkim for (i = 0; i < 1 << NEXCEPTS; i++) { 78238384Sjkim for (sr = i, j = 0; sr != 0; sr >>= 1, j++) 79280297Sjkim std_except_sets[i] |= std_excepts[j] & ((~sr & 1) - 1); 80238384Sjkim } 81238384Sjkim} 82238384Sjkim 83238384Sjkim/* 84280297Sjkim * Raise a floating-point exception without relying on the standard 85280297Sjkim * library routines, which we are trying to test. 86280297Sjkim * 87280297Sjkim * XXX We can't raise an {over,under}flow without also raising an 88238384Sjkim * inexact exception. 89238384Sjkim */ 90280297Sjkimstatic void 91280297Sjkimraiseexcept(int excepts) 92280297Sjkim{ 93238384Sjkim volatile double d; 94238384Sjkim 95238384Sjkim /* 96280297Sjkim * With a compiler that supports the FENV_ACCESS pragma 97280297Sjkim * properly, simple expressions like '0.0 / 0.0' should 98280297Sjkim * be sufficient to generate traps. Unfortunately, we 99280297Sjkim * need to bring a volatile variable into the equation 100280297Sjkim * to prevent incorrect optimizations. 101280297Sjkim */ 102238384Sjkim if (excepts & FE_INVALID) { 103238384Sjkim d = 0.0; 104238384Sjkim d = 0.0 / d; 105238384Sjkim } 106238384Sjkim if (excepts & FE_DIVBYZERO) { 107238384Sjkim d = 0.0; 108280297Sjkim d = 1.0 / d; 109280297Sjkim } 110280297Sjkim if (excepts & FE_OVERFLOW) { 111238384Sjkim d = DBL_MAX; 112238384Sjkim d *= 2.0; 113280297Sjkim } 114280297Sjkim if (excepts & FE_UNDERFLOW) { 115280297Sjkim d = DBL_MIN; 116238384Sjkim d /= DBL_MAX; 117238384Sjkim } 118238384Sjkim if (excepts & FE_INEXACT) { 119280297Sjkim d = DBL_MIN; 120280297Sjkim d += 1.0; 121280297Sjkim } 122238384Sjkim 123238384Sjkim /* 124280297Sjkim * On the x86 (and some other architectures?) the FPU and 125280297Sjkim * integer units are decoupled. We need to execute an FWAIT 126280297Sjkim * or a floating-point instruction to get synchronous exceptions. 127238384Sjkim */ 128238384Sjkim d = 1.0; 129238384Sjkim d += 1.0; 130280297Sjkim} 131280297Sjkim 132280297Sjkim/* 133238384Sjkim * Determine the current rounding mode without relying on the fenv 134238384Sjkim * routines. This function may raise an inexact exception. 135238384Sjkim */ 136238384Sjkimstatic int 137238384Sjkimgetround(void) 138238384Sjkim{ 139280297Sjkim volatile double d, e; 140280297Sjkim 141280297Sjkim /* 142280297Sjkim * This test works just as well with 0.0 - 0.0, except on ia64 143280297Sjkim * where 0.0 - 0.0 gives the wrong sign when rounding downwards. 144280297Sjkim * For ia32 use a volatile double to force 64 bit rounding. 145280297Sjkim * Otherwise the i387 would use its internal 80 bit stack. 146280297Sjkim */ 147280297Sjkim d = 1.0; 148280297Sjkim d -= 1.0; 149238384Sjkim if (copysign(1.0, d) < 0.0) 150238384Sjkim return (FE_DOWNWARD); 151238384Sjkim 152238384Sjkim d = 1.0; 153238384Sjkim e = d + (DBL_EPSILON * 3.0 / 4.0); 154238384Sjkim if (e == 1.0) 155280297Sjkim return (FE_TOWARDZERO); 156280297Sjkim e = d + (DBL_EPSILON * 1.0 / 4.0); 157280297Sjkim if (e > 1.0) 158280297Sjkim return (FE_UPWARD); 159238384Sjkim 160238384Sjkim return (FE_TONEAREST); 161280297Sjkim} 162280297Sjkim 163280297Sjkimstatic void 164238384Sjkimtrap_handler(int sig) 165238384Sjkim{ 166238384Sjkim 167280297Sjkim ATF_CHECK_EQ(SIGFPE, sig); 168280297Sjkim _exit(0); 169280297Sjkim} 170280297Sjkim 171238384Sjkim/* 172238384Sjkim * This tests checks the default FP environment, so it must be first. 173280297Sjkim * The memcmp() test below may be too much to ask for, since there 174280297Sjkim * could be multiple machine-specific default environments. 175280297Sjkim */ 176238384SjkimATF_TC_WITHOUT_HEAD(dfl_env); 177238384SjkimATF_TC_BODY(dfl_env, tc) 178238384Sjkim{ 179280297Sjkim#ifndef NO_STRICT_DFL_ENV 180280297Sjkim fenv_t env; 181280297Sjkim 182238384Sjkim fegetenv(&env); 183238384Sjkim /* Print the default environment for debugging purposes. */ 184238384Sjkim hexdump(&env, sizeof(env), "current fenv ", HD_OMIT_CHARS); 185238384Sjkim hexdump(FE_DFL_ENV, sizeof(env), "default fenv ", HD_OMIT_CHARS); 186238384Sjkim CHECK_FP_EXCEPTIONS(0, FE_ALL_EXCEPT); 187238384Sjkim#ifdef __amd64__ 188238384Sjkim /* 189280297Sjkim * Compare the fields that the AMD [1] and Intel [2] specs say will be 190238384Sjkim * set once fnstenv returns. 191280297Sjkim * 192238384Sjkim * Not all amd64 capable processors implement the fnstenv instruction 193280297Sjkim * by zero'ing out the env.__x87.__other field (example: AMD Opteron 194280297Sjkim * 6308). The AMD64/x64 specs aren't explicit on what the 195280297Sjkim * env.__x87.__other field will contain after fnstenv is executed, so 196280297Sjkim * the values in env.__x87.__other could be filled with arbitrary 197280297Sjkim * data depending on how the CPU implements fnstenv. 198280297Sjkim * 199280297Sjkim * 1. http://support.amd.com/TechDocs/26569_APM_v5.pdf 200280297Sjkim * 2. http://www.intel.com/Assets/en_US/PDF/manual/253666.pdf 201280297Sjkim */ 202280297Sjkim ATF_CHECK(memcmp(&env.__mxcsr, &FE_DFL_ENV->__mxcsr, 203280297Sjkim sizeof(env.__mxcsr)) == 0); 204280297Sjkim ATF_CHECK(memcmp(&env.__x87.__control, &FE_DFL_ENV->__x87.__control, 205280297Sjkim sizeof(env.__x87.__control)) == 0); 206280297Sjkim ATF_CHECK(memcmp(&env.__x87.__status, &FE_DFL_ENV->__x87.__status, 207280297Sjkim sizeof(env.__x87.__status)) == 0); 208280297Sjkim ATF_CHECK(memcmp(&env.__x87.__tag, &FE_DFL_ENV->__x87.__tag, 209280297Sjkim sizeof(env.__x87.__tag)) == 0); 210238384Sjkim#else 211280297Sjkim ATF_CHECK_EQ(0, memcmp(&env, FE_DFL_ENV, sizeof(env))); 212238384Sjkim#endif 213238384Sjkim 214238384Sjkim#endif 215280297Sjkim CHECK_FP_EXCEPTIONS(0, FE_ALL_EXCEPT); 216238384Sjkim} 217280297Sjkim 218280297Sjkim/* 219280297Sjkim * Test fetestexcept() and feclearexcept(). 220280297Sjkim */ 221280297SjkimATF_TC_WITHOUT_HEAD(fetestclearexcept); 222280297SjkimATF_TC_BODY(fetestclearexcept, tc) 223280297Sjkim{ 224280297Sjkim int excepts, i; 225280297Sjkim 226280297Sjkim for (i = 0; i < 1 << NEXCEPTS; i++) 227280297Sjkim ATF_CHECK_EQ(0, fetestexcept(std_except_sets[i])); 228238384Sjkim for (i = 0; i < 1 << NEXCEPTS; i++) { 229238384Sjkim excepts = std_except_sets[i]; 230238384Sjkim 231280297Sjkim /* FE_ALL_EXCEPT might be special-cased, as on i386. */ 232280297Sjkim raiseexcept(excepts); 233238384Sjkim ATF_CHECK_EQ(excepts, fetestexcept(excepts)); 234238384Sjkim ATF_REQUIRE_EQ(0, feclearexcept(FE_ALL_EXCEPT)); 235238384Sjkim ATF_CHECK_EQ(0, fetestexcept(FE_ALL_EXCEPT)); 236280297Sjkim 237238384Sjkim raiseexcept(excepts); 238280297Sjkim ATF_CHECK_EQ(excepts, fetestexcept(excepts)); 239238384Sjkim if ((excepts & (FE_UNDERFLOW | FE_OVERFLOW)) != 0) { 240238384Sjkim excepts |= FE_INEXACT; 241280297Sjkim ATF_CHECK_EQ(excepts, (fetestexcept(ALL_STD_EXCEPT) | FE_INEXACT)); 242280297Sjkim } else { 243280297Sjkim ATF_CHECK_EQ(excepts, fetestexcept(ALL_STD_EXCEPT)); 244238384Sjkim } 245238384Sjkim ATF_CHECK_EQ(0, feclearexcept(excepts)); 246280297Sjkim ATF_CHECK_EQ(0, fetestexcept(ALL_STD_EXCEPT)); 247280297Sjkim } 248280297Sjkim} 249238384Sjkim 250238384Sjkim/* 251238384Sjkim * Test fegetexceptflag() and fesetexceptflag(). 252280297Sjkim * 253280297Sjkim * Prerequisites: fetestexcept(), feclearexcept() 254280297Sjkim */ 255238384SjkimATF_TC_WITHOUT_HEAD(fegsetexceptflag); 256238384SjkimATF_TC_BODY(fegsetexceptflag, tc) 257280297Sjkim{ 258280297Sjkim fexcept_t flag; 259280297Sjkim int excepts, i; 260238384Sjkim 261238384Sjkim CHECK_FP_EXCEPTIONS(0, FE_ALL_EXCEPT); 262238384Sjkim for (i = 0; i < 1 << NEXCEPTS; i++) { 263280297Sjkim excepts = std_except_sets[i]; 264280297Sjkim 265238384Sjkim ATF_CHECK_EQ(0, fegetexceptflag(&flag, excepts)); 266238384Sjkim raiseexcept(ALL_STD_EXCEPT); 267238384Sjkim ATF_CHECK_EQ(0, fesetexceptflag(&flag, excepts)); 268238384Sjkim ATF_CHECK_EQ((ALL_STD_EXCEPT ^ excepts), fetestexcept(ALL_STD_EXCEPT)); 269238384Sjkim 270238384Sjkim ATF_CHECK_EQ(0, fegetexceptflag(&flag, FE_ALL_EXCEPT)); 271280297Sjkim ATF_REQUIRE_EQ(0, feclearexcept(FE_ALL_EXCEPT)); 272280297Sjkim ATF_CHECK_EQ(0, fesetexceptflag(&flag, excepts)); 273238384Sjkim ATF_CHECK_EQ(0, fetestexcept(ALL_STD_EXCEPT)); 274238384Sjkim ATF_CHECK_EQ(0, fesetexceptflag(&flag, ALL_STD_EXCEPT ^ excepts)); 275238384Sjkim ATF_CHECK_EQ((ALL_STD_EXCEPT ^ excepts), fetestexcept(ALL_STD_EXCEPT)); 276238384Sjkim 277238384Sjkim ATF_REQUIRE_EQ(0, feclearexcept(FE_ALL_EXCEPT)); 278238384Sjkim } 279280297Sjkim} 280280297Sjkim 281238384Sjkim/* 282238384Sjkim * Test feraiseexcept(). 283238384Sjkim * 284238384Sjkim * Prerequisites: fetestexcept(), feclearexcept() 285238384Sjkim */ 286238384SjkimATF_TC_WITHOUT_HEAD(feraiseexcept); 287238384SjkimATF_TC_BODY(feraiseexcept, tc) 288238384Sjkim{ 289280297Sjkim int excepts, i; 290280297Sjkim 291280297Sjkim for (i = 0; i < 1 << NEXCEPTS; i++) { 292280297Sjkim excepts = std_except_sets[i]; 293280297Sjkim 294238384Sjkim ATF_CHECK_EQ(0, fetestexcept(FE_ALL_EXCEPT)); 295280297Sjkim ATF_CHECK_EQ(0, feraiseexcept(excepts)); 296280297Sjkim if ((excepts & (FE_UNDERFLOW | FE_OVERFLOW)) != 0) { 297280297Sjkim excepts |= FE_INEXACT; 298280297Sjkim ATF_CHECK_EQ(excepts, (fetestexcept(ALL_STD_EXCEPT) | FE_INEXACT)); 299238384Sjkim } else { 300280297Sjkim ATF_CHECK_EQ(excepts, fetestexcept(ALL_STD_EXCEPT)); 301280297Sjkim } 302280297Sjkim ATF_REQUIRE_EQ(0, feclearexcept(FE_ALL_EXCEPT)); 303280297Sjkim } 304280297Sjkim ATF_CHECK_EQ(0, feraiseexcept(FE_INVALID | FE_DIVBYZERO)); 305238384Sjkim ATF_CHECK_EQ((FE_INVALID | FE_DIVBYZERO), fetestexcept(ALL_STD_EXCEPT)); 306280297Sjkim ATF_CHECK_EQ(0, feraiseexcept(FE_OVERFLOW | FE_UNDERFLOW | FE_INEXACT)); 307280297Sjkim ATF_CHECK_EQ(ALL_STD_EXCEPT, fetestexcept(ALL_STD_EXCEPT)); 308280297Sjkim ATF_REQUIRE_EQ(0, feclearexcept(FE_ALL_EXCEPT)); 309280297Sjkim} 310280297Sjkim 311280297Sjkim/* 312280297Sjkim * Test fegetround() and fesetround(). 313238384Sjkim */ 314280297SjkimATF_TC_WITHOUT_HEAD(fegsetround); 315280297SjkimATF_TC_BODY(fegsetround, tc) 316280297Sjkim{ 317280297Sjkim 318280297Sjkim ATF_CHECK_EQ(FE_TONEAREST, fegetround()); 319280297Sjkim ATF_CHECK_EQ(FE_TONEAREST, getround()); 320238384Sjkim ATF_CHECK_EQ(1, FLT_ROUNDS); 321280297Sjkim 322280297Sjkim ATF_CHECK_EQ(0, fesetround(FE_DOWNWARD)); 323280297Sjkim ATF_CHECK_EQ(FE_DOWNWARD, fegetround()); 324280297Sjkim ATF_CHECK_EQ(FE_DOWNWARD, getround()); 325280297Sjkim ATF_CHECK_EQ(3, FLT_ROUNDS); 326238384Sjkim 327 ATF_CHECK_EQ(0, fesetround(FE_UPWARD)); 328 ATF_CHECK_EQ(FE_UPWARD, getround()); 329 ATF_CHECK_EQ(FE_UPWARD, fegetround()); 330 ATF_CHECK_EQ(2, FLT_ROUNDS); 331 332 ATF_CHECK_EQ(0, fesetround(FE_TOWARDZERO)); 333 ATF_CHECK_EQ(FE_TOWARDZERO, getround()); 334 ATF_CHECK_EQ(FE_TOWARDZERO, fegetround()); 335 ATF_CHECK_EQ(0, FLT_ROUNDS); 336 337 ATF_CHECK_EQ(0, fesetround(FE_TONEAREST)); 338 ATF_CHECK_EQ(FE_TONEAREST, getround()); 339 ATF_CHECK_EQ(1, FLT_ROUNDS); 340 341 ATF_REQUIRE_EQ(0, feclearexcept(FE_ALL_EXCEPT)); 342} 343 344/* 345 * Test fegetenv() and fesetenv(). 346 * 347 * Prerequisites: fetestexcept(), feclearexcept(), fegetround(), fesetround() 348 */ 349ATF_TC_WITHOUT_HEAD(fegsetenv); 350ATF_TC_BODY(fegsetenv, tc) 351{ 352 fenv_t env1, env2; 353 int excepts, i; 354 355 for (i = 0; i < 1 << NEXCEPTS; i++) { 356 excepts = std_except_sets[i]; 357 358 ATF_CHECK_EQ(0, fetestexcept(FE_ALL_EXCEPT)); 359 ATF_CHECK_EQ(FE_TONEAREST, fegetround()); 360 ATF_CHECK_EQ(0, fegetenv(&env1)); 361 362 /* 363 * fe[gs]etenv() should be able to save and restore 364 * exception flags without the spurious inexact 365 * exceptions that afflict raiseexcept(). 366 */ 367 raiseexcept(excepts); 368 if ((excepts & (FE_UNDERFLOW | FE_OVERFLOW)) != 0 && 369 (excepts & FE_INEXACT) == 0) 370 ATF_CHECK_EQ(0, feclearexcept(FE_INEXACT)); 371 372 fesetround(FE_DOWNWARD); 373 ATF_CHECK_EQ(0, fegetenv(&env2)); 374 ATF_CHECK_EQ(0, fesetenv(&env1)); 375 ATF_CHECK_EQ(0, fetestexcept(FE_ALL_EXCEPT)); 376 ATF_CHECK_EQ(FE_TONEAREST, fegetround()); 377 378 ATF_CHECK_EQ(0, fesetenv(&env2)); 379 380 /* 381 * Some platforms like powerpc may set extra exception bits. Since 382 * only standard exceptions are tested, mask against ALL_STD_EXCEPT 383 */ 384 ATF_CHECK_EQ(excepts, (fetestexcept(FE_ALL_EXCEPT) & ALL_STD_EXCEPT)); 385 386 ATF_CHECK_EQ(FE_DOWNWARD, fegetround()); 387 ATF_CHECK_EQ(0, fesetenv(&env1)); 388 ATF_CHECK_EQ(0, fetestexcept(FE_ALL_EXCEPT)); 389 ATF_CHECK_EQ(FE_TONEAREST, fegetround()); 390 } 391} 392 393/* 394 * Test fegetexcept(), fedisableexcept(), and feenableexcept(). 395 * 396 * Prerequisites: fetestexcept(), feraiseexcept() 397 */ 398ATF_TC_WITHOUT_HEAD(masking); 399ATF_TC_BODY(masking, tc) 400{ 401#if !defined(__arm__) && !defined(__aarch64__) && !defined(__riscv) 402 struct sigaction act; 403 int except, pass, raise, status; 404 unsigned i; 405 406 ATF_REQUIRE_EQ(0, (fegetexcept() & ALL_STD_EXCEPT)); 407 408 /* 409 * Some CPUs, e.g. AArch64 QEMU does not support trapping on FP 410 * exceptions. In that case the trap enable bits are all RAZ/WI, so 411 * writing to those bits will be ignored and the the next read will 412 * return all zeroes for those bits. Skip the test if no floating 413 * point exceptions are supported and mark it XFAIL if some are missing. 414 */ 415 ATF_REQUIRE_EQ(0, (feenableexcept(FE_ALL_EXCEPT))); 416 except = fegetexcept(); 417 if (except == 0) { 418 atf_tc_skip("CPU does not support trapping on floating point " 419 "exceptions."); 420 } else if ((except & ALL_STD_EXCEPT) != ALL_STD_EXCEPT) { 421 atf_tc_expect_fail("Not all floating point exceptions can be " 422 "set to trap: %#x vs %#x", except, ALL_STD_EXCEPT); 423 } 424 fedisableexcept(FE_ALL_EXCEPT); 425 426 427 ATF_CHECK_EQ(0, (feenableexcept(FE_INVALID|FE_OVERFLOW) & ALL_STD_EXCEPT)); 428 ATF_CHECK_EQ((FE_INVALID | FE_OVERFLOW), (feenableexcept(FE_UNDERFLOW) & ALL_STD_EXCEPT)); 429 ATF_CHECK_EQ((FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW), (fedisableexcept(FE_OVERFLOW) & ALL_STD_EXCEPT)); 430 ATF_CHECK_EQ((FE_INVALID | FE_UNDERFLOW), (fegetexcept() & ALL_STD_EXCEPT)); 431 ATF_CHECK_EQ((FE_INVALID | FE_UNDERFLOW), (fedisableexcept(FE_ALL_EXCEPT) & ALL_STD_EXCEPT)); 432 ATF_CHECK_EQ(0, (fegetexcept() & ALL_STD_EXCEPT)); 433 434 sigemptyset(&act.sa_mask); 435 act.sa_flags = 0; 436 act.sa_handler = trap_handler; 437 for (pass = 0; pass < 2; pass++) { 438 for (i = 0; i < NEXCEPTS; i++) { 439 except = std_excepts[i]; 440 /* over/underflow may also raise inexact */ 441 if (except == FE_INEXACT) 442 raise = FE_DIVBYZERO | FE_INVALID; 443 else 444 raise = ALL_STD_EXCEPT ^ except; 445 446 /* 447 * We need to fork a child process because 448 * there isn't a portable way to recover from 449 * a floating-point exception. 450 */ 451 switch(fork()) { 452 case 0: /* child */ 453 ATF_CHECK_EQ(0, (fegetexcept() & ALL_STD_EXCEPT)); 454 ATF_REQUIRE_EQ(0, (feenableexcept(except) & ALL_STD_EXCEPT)); 455 ATF_CHECK_EQ(except, fegetexcept()); 456 raiseexcept(raise); 457 ATF_CHECK_EQ(0, feraiseexcept(raise)); 458 ATF_CHECK_EQ(raise, fetestexcept(ALL_STD_EXCEPT)); 459 460 ATF_CHECK_EQ(0, sigaction(SIGFPE, &act, NULL)); 461 switch (pass) { 462 case 0: 463 raiseexcept(except); 464 case 1: 465 feraiseexcept(except); 466 default: 467 ATF_REQUIRE(0); 468 } 469 ATF_REQUIRE(0); 470 default: /* parent */ 471 ATF_REQUIRE(wait(&status) > 0); 472 /* 473 * Avoid assert() here so that it's possible 474 * to examine a failed child's core dump. 475 */ 476 if (!WIFEXITED(status)) 477 errx(1, "child aborted\n"); 478 ATF_CHECK_EQ(0, WEXITSTATUS(status)); 479 break; 480 case -1: /* error */ 481 ATF_REQUIRE(0); 482 } 483 } 484 } 485 ATF_CHECK_EQ(0, fetestexcept(FE_ALL_EXCEPT)); 486#endif 487} 488 489/* 490 * Test feholdexcept() and feupdateenv(). 491 * 492 * Prerequisites: fetestexcept(), fegetround(), fesetround(), 493 * fedisableexcept(), feenableexcept() 494 */ 495ATF_TC_WITHOUT_HEAD(feholdupdate); 496ATF_TC_BODY(feholdupdate, tc) 497{ 498 fenv_t env; 499 500 struct sigaction act; 501 int except, pass, status, raise; 502 unsigned i; 503 504 sigemptyset(&act.sa_mask); 505 act.sa_flags = 0; 506 act.sa_handler = trap_handler; 507 for (pass = 0; pass < 2; pass++) { 508 for (i = 0; i < NEXCEPTS; i++) { 509 except = std_excepts[i]; 510 /* over/underflow may also raise inexact */ 511 if (except == FE_INEXACT) 512 raise = FE_DIVBYZERO | FE_INVALID; 513 else 514 raise = ALL_STD_EXCEPT ^ except; 515 516 /* 517 * We need to fork a child process because 518 * there isn't a portable way to recover from 519 * a floating-point exception. 520 */ 521 switch(fork()) { 522 case 0: /* child */ 523 /* 524 * We don't want to cause a fatal exception in 525 * the child until the second pass, so we can 526 * check other properties of feupdateenv(). 527 */ 528 if (pass == 1) 529 ATF_REQUIRE_EQ(0, 530 feenableexcept(except) & 531 ALL_STD_EXCEPT); 532 raiseexcept(raise); 533 ATF_CHECK_EQ(0, fesetround(FE_DOWNWARD)); 534 ATF_CHECK_EQ(0, feholdexcept(&env)); 535 ATF_CHECK_EQ(0, fetestexcept(FE_ALL_EXCEPT)); 536 raiseexcept(except); 537 ATF_CHECK_EQ(0, fesetround(FE_UPWARD)); 538 539 if (pass == 1) 540 ATF_CHECK_EQ(0, sigaction(SIGFPE, &act, NULL)); 541 ATF_CHECK_EQ(0, feupdateenv(&env)); 542 ATF_CHECK_EQ(FE_DOWNWARD, fegetround()); 543 ATF_CHECK_EQ((except | raise), fetestexcept(ALL_STD_EXCEPT)); 544 545 ATF_CHECK_EQ(0, pass); 546 _exit(0); 547 default: /* parent */ 548 ATF_REQUIRE(wait(&status) > 0); 549 /* 550 * Avoid assert() here so that it's possible 551 * to examine a failed child's core dump. 552 */ 553 if (!WIFEXITED(status)) 554 errx(1, "child aborted\n"); 555 ATF_CHECK_EQ(0, WEXITSTATUS(status)); 556 break; 557 case -1: /* error */ 558 ATF_REQUIRE(0); 559 } 560 } 561#if defined(__arm__) || defined(__aarch64__) || defined(__riscv) 562 break; 563#endif 564 } 565 ATF_CHECK_EQ(0, fetestexcept(FE_ALL_EXCEPT)); 566} 567 568ATF_TP_ADD_TCS(tp) 569{ 570 ATF_TP_ADD_TC(tp, dfl_env); 571 ATF_TP_ADD_TC(tp, fetestclearexcept); 572 ATF_TP_ADD_TC(tp, fegsetexceptflag); 573 ATF_TP_ADD_TC(tp, feraiseexcept); 574 ATF_TP_ADD_TC(tp, fegsetround); 575 ATF_TP_ADD_TC(tp, fegsetenv); 576 ATF_TP_ADD_TC(tp, masking); 577 ATF_TP_ADD_TC(tp, feholdupdate); 578 579 return (atf_no_error()); 580} 581