1130330Sdas/*- 2130330Sdas * Copyright (c) 2004 David Schultz <das@FreeBSD.org> 3130330Sdas * All rights reserved. 4130330Sdas * 5130330Sdas * Redistribution and use in source and binary forms, with or without 6130330Sdas * modification, are permitted provided that the following conditions 7130330Sdas * are met: 8130330Sdas * 1. Redistributions of source code must retain the above copyright 9130330Sdas * notice, this list of conditions and the following disclaimer. 10130330Sdas * 2. Redistributions in binary form must reproduce the above copyright 11130330Sdas * notice, this list of conditions and the following disclaimer in the 12130330Sdas * documentation and/or other materials provided with the distribution. 13130330Sdas * 14130330Sdas * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15130330Sdas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16130330Sdas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17130330Sdas * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18130330Sdas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19130330Sdas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20130330Sdas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21130330Sdas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22130330Sdas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23130330Sdas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24130330Sdas * SUCH DAMAGE. 25130330Sdas */ 26130330Sdas 27130330Sdas/* 28130330Sdas * Test the correctness and C99-compliance of various fenv.h features. 29130330Sdas */ 30130330Sdas 31130330Sdas#include <sys/cdefs.h> 32130330Sdas__FBSDID("$FreeBSD: stable/11/lib/msun/tests/fenv_test.c 315121 2017-03-12 04:52:09Z ngie $"); 33130330Sdas 34130330Sdas#include <sys/types.h> 35130330Sdas#include <sys/wait.h> 36130330Sdas#include <assert.h> 37130330Sdas#include <err.h> 38130330Sdas#include <fenv.h> 39130330Sdas#include <float.h> 40130330Sdas#include <math.h> 41130330Sdas#include <signal.h> 42130330Sdas#include <stdio.h> 43130330Sdas#include <string.h> 44130330Sdas#include <unistd.h> 45130330Sdas 46130330Sdas/* 47130330Sdas * Implementations are permitted to define additional exception flags 48130330Sdas * not specified in the standard, so it is not necessarily true that 49130330Sdas * FE_ALL_EXCEPT == ALL_STD_EXCEPT. 50130330Sdas */ 51130330Sdas#define ALL_STD_EXCEPT (FE_DIVBYZERO | FE_INEXACT | FE_INVALID | \ 52130330Sdas FE_OVERFLOW | FE_UNDERFLOW) 53130330Sdas 54130330Sdas#define NEXCEPTS (sizeof(std_excepts) / sizeof(std_excepts[0])) 55130330Sdas 56130330Sdasstatic const int std_excepts[] = { 57130330Sdas FE_INVALID, 58130330Sdas FE_DIVBYZERO, 59130330Sdas FE_OVERFLOW, 60130330Sdas FE_UNDERFLOW, 61130330Sdas FE_INEXACT, 62130330Sdas}; 63130330Sdas 64130330Sdas/* init_exceptsets() initializes this to the power set of std_excepts[] */ 65130330Sdasstatic int std_except_sets[1 << NEXCEPTS]; 66130330Sdas 67130330Sdas#pragma STDC FENV_ACCESS ON 68130330Sdas 69130330Sdas/* 70130330Sdas * Initialize std_except_sets[] to the power set of std_excepts[] 71130330Sdas */ 72315121Sngiestatic void 73130330Sdasinit_exceptsets(void) 74130330Sdas{ 75315121Sngie unsigned i, j, sr; 76130330Sdas 77130330Sdas for (i = 0; i < 1 << NEXCEPTS; i++) { 78130330Sdas for (sr = i, j = 0; sr != 0; sr >>= 1, j++) 79130330Sdas std_except_sets[i] |= std_excepts[j] & ((~sr & 1) - 1); 80130330Sdas } 81130330Sdas} 82130330Sdas 83130330Sdas/* 84315121Sngie * Raise a floating-point exception without relying on the standard 85315121Sngie * library routines, which we are trying to test. 86315121Sngie * 87315121Sngie * XXX We can't raise an {over,under}flow without also raising an 88315121Sngie * inexact exception. 89315121Sngie */ 90315121Sngiestatic void 91315121Sngieraiseexcept(int excepts) 92315121Sngie{ 93315121Sngie volatile double d; 94315121Sngie 95315121Sngie /* 96315121Sngie * With a compiler that supports the FENV_ACCESS pragma 97315121Sngie * properly, simple expressions like '0.0 / 0.0' should 98315121Sngie * be sufficient to generate traps. Unfortunately, we 99315121Sngie * need to bring a volatile variable into the equation 100315121Sngie * to prevent incorrect optimizations. 101315121Sngie */ 102315121Sngie if (excepts & FE_INVALID) { 103315121Sngie d = 0.0; 104315121Sngie d = 0.0 / d; 105315121Sngie } 106315121Sngie if (excepts & FE_DIVBYZERO) { 107315121Sngie d = 0.0; 108315121Sngie d = 1.0 / d; 109315121Sngie } 110315121Sngie if (excepts & FE_OVERFLOW) { 111315121Sngie d = DBL_MAX; 112315121Sngie d *= 2.0; 113315121Sngie } 114315121Sngie if (excepts & FE_UNDERFLOW) { 115315121Sngie d = DBL_MIN; 116315121Sngie d /= DBL_MAX; 117315121Sngie } 118315121Sngie if (excepts & FE_INEXACT) { 119315121Sngie d = DBL_MIN; 120315121Sngie d += 1.0; 121315121Sngie } 122315121Sngie 123315121Sngie /* 124315121Sngie * On the x86 (and some other architectures?) the FPU and 125315121Sngie * integer units are decoupled. We need to execute an FWAIT 126315121Sngie * or a floating-point instruction to get synchronous exceptions. 127315121Sngie */ 128315121Sngie d = 1.0; 129315121Sngie d += 1.0; 130315121Sngie} 131315121Sngie 132315121Sngie/* 133315121Sngie * Determine the current rounding mode without relying on the fenv 134315121Sngie * routines. This function may raise an inexact exception. 135315121Sngie */ 136315121Sngiestatic int 137315121Sngiegetround(void) 138315121Sngie{ 139315121Sngie volatile double d; 140315121Sngie 141315121Sngie /* 142315121Sngie * This test works just as well with 0.0 - 0.0, except on ia64 143315121Sngie * where 0.0 - 0.0 gives the wrong sign when rounding downwards. 144315121Sngie */ 145315121Sngie d = 1.0; 146315121Sngie d -= 1.0; 147315121Sngie if (copysign(1.0, d) < 0.0) 148315121Sngie return (FE_DOWNWARD); 149315121Sngie 150315121Sngie d = 1.0; 151315121Sngie if (d + (DBL_EPSILON * 3.0 / 4.0) == 1.0) 152315121Sngie return (FE_TOWARDZERO); 153315121Sngie if (d + (DBL_EPSILON * 1.0 / 4.0) > 1.0) 154315121Sngie return (FE_UPWARD); 155315121Sngie 156315121Sngie return (FE_TONEAREST); 157315121Sngie} 158315121Sngie 159315121Sngiestatic void 160315121Sngietrap_handler(int sig) 161315121Sngie{ 162315121Sngie 163315121Sngie assert(sig == SIGFPE); 164315121Sngie _exit(0); 165315121Sngie} 166315121Sngie 167315121Sngie/* 168130330Sdas * This tests checks the default FP environment, so it must be first. 169130330Sdas * The memcmp() test below may be too much to ask for, since there 170130330Sdas * could be multiple machine-specific default environments. 171130330Sdas */ 172130330Sdasstatic void 173130330Sdastest_dfl_env(void) 174130330Sdas{ 175130330Sdas#ifndef NO_STRICT_DFL_ENV 176130330Sdas fenv_t env; 177130330Sdas 178130330Sdas fegetenv(&env); 179289332Sngie 180289332Sngie#ifdef __amd64__ 181289332Sngie /* 182289332Sngie * Compare the fields that the AMD [1] and Intel [2] specs say will be 183289332Sngie * set once fnstenv returns. 184289332Sngie * 185289332Sngie * Not all amd64 capable processors implement the fnstenv instruction 186289332Sngie * by zero'ing out the env.__x87.__other field (example: AMD Opteron 187289332Sngie * 6308). The AMD64/x64 specs aren't explicit on what the 188289332Sngie * env.__x87.__other field will contain after fnstenv is executed, so 189289332Sngie * the values in env.__x87.__other could be filled with arbitrary 190289332Sngie * data depending on how the CPU implements fnstenv. 191289332Sngie * 192289332Sngie * 1. http://support.amd.com/TechDocs/26569_APM_v5.pdf 193289332Sngie * 2. http://www.intel.com/Assets/en_US/PDF/manual/253666.pdf 194289332Sngie */ 195289332Sngie assert(memcmp(&env.__mxcsr, &FE_DFL_ENV->__mxcsr, 196289332Sngie sizeof(env.__mxcsr)) == 0); 197289332Sngie assert(memcmp(&env.__x87.__control, &FE_DFL_ENV->__x87.__control, 198289332Sngie sizeof(env.__x87.__control)) == 0); 199289332Sngie assert(memcmp(&env.__x87.__status, &FE_DFL_ENV->__x87.__status, 200289332Sngie sizeof(env.__x87.__status)) == 0); 201289332Sngie assert(memcmp(&env.__x87.__tag, &FE_DFL_ENV->__x87.__tag, 202289332Sngie sizeof(env.__x87.__tag)) == 0); 203289332Sngie#else 204130330Sdas assert(memcmp(&env, FE_DFL_ENV, sizeof(env)) == 0); 205130330Sdas#endif 206289332Sngie 207289332Sngie#endif 208130330Sdas assert(fetestexcept(FE_ALL_EXCEPT) == 0); 209130330Sdas} 210130330Sdas 211130330Sdas/* 212130330Sdas * Test fetestexcept() and feclearexcept(). 213130330Sdas */ 214130330Sdasstatic void 215130330Sdastest_fetestclearexcept(void) 216130330Sdas{ 217130330Sdas int excepts, i; 218130330Sdas 219130330Sdas for (i = 0; i < 1 << NEXCEPTS; i++) 220130330Sdas assert(fetestexcept(std_except_sets[i]) == 0); 221130330Sdas for (i = 0; i < 1 << NEXCEPTS; i++) { 222130330Sdas excepts = std_except_sets[i]; 223130330Sdas 224130330Sdas /* FE_ALL_EXCEPT might be special-cased, as on i386. */ 225130330Sdas raiseexcept(excepts); 226130330Sdas assert(fetestexcept(excepts) == excepts); 227130330Sdas assert(feclearexcept(FE_ALL_EXCEPT) == 0); 228130330Sdas assert(fetestexcept(FE_ALL_EXCEPT) == 0); 229130330Sdas 230130330Sdas raiseexcept(excepts); 231130330Sdas assert(fetestexcept(excepts) == excepts); 232130330Sdas if ((excepts & (FE_UNDERFLOW | FE_OVERFLOW)) != 0) { 233130330Sdas excepts |= FE_INEXACT; 234130330Sdas assert((fetestexcept(ALL_STD_EXCEPT) | FE_INEXACT) == 235130330Sdas excepts); 236130330Sdas } else { 237130330Sdas assert(fetestexcept(ALL_STD_EXCEPT) == excepts); 238130330Sdas } 239130330Sdas assert(feclearexcept(excepts) == 0); 240130330Sdas assert(fetestexcept(ALL_STD_EXCEPT) == 0); 241130330Sdas } 242130330Sdas} 243130330Sdas 244130330Sdas/* 245130330Sdas * Test fegetexceptflag() and fesetexceptflag(). 246130330Sdas * 247130330Sdas * Prerequisites: fetestexcept(), feclearexcept() 248130330Sdas */ 249130330Sdasstatic void 250130330Sdastest_fegsetexceptflag(void) 251130330Sdas{ 252130330Sdas fexcept_t flag; 253130330Sdas int excepts, i; 254130330Sdas 255130330Sdas assert(fetestexcept(FE_ALL_EXCEPT) == 0); 256130330Sdas for (i = 0; i < 1 << NEXCEPTS; i++) { 257130330Sdas excepts = std_except_sets[i]; 258130330Sdas 259130330Sdas assert(fegetexceptflag(&flag, excepts) == 0); 260130330Sdas raiseexcept(ALL_STD_EXCEPT); 261130330Sdas assert(fesetexceptflag(&flag, excepts) == 0); 262130330Sdas assert(fetestexcept(ALL_STD_EXCEPT) == 263130330Sdas (ALL_STD_EXCEPT ^ excepts)); 264130330Sdas 265130330Sdas assert(fegetexceptflag(&flag, FE_ALL_EXCEPT) == 0); 266130330Sdas assert(feclearexcept(FE_ALL_EXCEPT) == 0); 267130330Sdas assert(fesetexceptflag(&flag, excepts) == 0); 268130330Sdas assert(fetestexcept(ALL_STD_EXCEPT) == 0); 269130330Sdas assert(fesetexceptflag(&flag, ALL_STD_EXCEPT ^ excepts) == 0); 270130330Sdas assert(fetestexcept(ALL_STD_EXCEPT) == 271130330Sdas (ALL_STD_EXCEPT ^ excepts)); 272130330Sdas 273130330Sdas assert(feclearexcept(FE_ALL_EXCEPT) == 0); 274130330Sdas } 275130330Sdas} 276130330Sdas 277130330Sdas/* 278130330Sdas * Test feraiseexcept(). 279130330Sdas * 280130330Sdas * Prerequisites: fetestexcept(), feclearexcept() 281130330Sdas */ 282130330Sdasstatic void 283130330Sdastest_feraiseexcept(void) 284130330Sdas{ 285130330Sdas int excepts, i; 286130330Sdas 287130330Sdas for (i = 0; i < 1 << NEXCEPTS; i++) { 288130330Sdas excepts = std_except_sets[i]; 289130330Sdas 290130330Sdas assert(fetestexcept(FE_ALL_EXCEPT) == 0); 291130330Sdas assert(feraiseexcept(excepts) == 0); 292130330Sdas if ((excepts & (FE_UNDERFLOW | FE_OVERFLOW)) != 0) { 293130330Sdas excepts |= FE_INEXACT; 294130330Sdas assert((fetestexcept(ALL_STD_EXCEPT) | FE_INEXACT) == 295130330Sdas excepts); 296130330Sdas } else { 297130330Sdas assert(fetestexcept(ALL_STD_EXCEPT) == excepts); 298130330Sdas } 299130330Sdas assert(feclearexcept(FE_ALL_EXCEPT) == 0); 300130330Sdas } 301130330Sdas assert(feraiseexcept(FE_INVALID | FE_DIVBYZERO) == 0); 302130330Sdas assert(fetestexcept(ALL_STD_EXCEPT) == (FE_INVALID | FE_DIVBYZERO)); 303130330Sdas assert(feraiseexcept(FE_OVERFLOW | FE_UNDERFLOW | FE_INEXACT) == 0); 304130330Sdas assert(fetestexcept(ALL_STD_EXCEPT) == ALL_STD_EXCEPT); 305130330Sdas assert(feclearexcept(FE_ALL_EXCEPT) == 0); 306130330Sdas} 307130330Sdas 308130330Sdas/* 309130330Sdas * Test fegetround() and fesetround(). 310130330Sdas */ 311130330Sdasstatic void 312130330Sdastest_fegsetround(void) 313130330Sdas{ 314130330Sdas 315130330Sdas assert(fegetround() == FE_TONEAREST); 316130330Sdas assert(getround() == FE_TONEAREST); 317132384Sdas assert(FLT_ROUNDS == 1); 318132384Sdas 319130330Sdas assert(fesetround(FE_DOWNWARD) == 0); 320130330Sdas assert(fegetround() == FE_DOWNWARD); 321130330Sdas assert(getround() == FE_DOWNWARD); 322132384Sdas assert(FLT_ROUNDS == 3); 323132384Sdas 324130330Sdas assert(fesetround(FE_UPWARD) == 0); 325130330Sdas assert(getround() == FE_UPWARD); 326130330Sdas assert(fegetround() == FE_UPWARD); 327132384Sdas assert(FLT_ROUNDS == 2); 328132384Sdas 329130330Sdas assert(fesetround(FE_TOWARDZERO) == 0); 330130330Sdas assert(getround() == FE_TOWARDZERO); 331130330Sdas assert(fegetround() == FE_TOWARDZERO); 332132384Sdas assert(FLT_ROUNDS == 0); 333132384Sdas 334130330Sdas assert(fesetround(FE_TONEAREST) == 0); 335130330Sdas assert(getround() == FE_TONEAREST); 336132384Sdas assert(FLT_ROUNDS == 1); 337132384Sdas 338130330Sdas assert(feclearexcept(FE_ALL_EXCEPT) == 0); 339130330Sdas} 340130330Sdas 341130330Sdas/* 342130330Sdas * Test fegetenv() and fesetenv(). 343130330Sdas * 344130330Sdas * Prerequisites: fetestexcept(), feclearexcept(), fegetround(), fesetround() 345130330Sdas */ 346130330Sdasstatic void 347130330Sdastest_fegsetenv(void) 348130330Sdas{ 349130330Sdas fenv_t env1, env2; 350130330Sdas int excepts, i; 351130330Sdas 352130330Sdas for (i = 0; i < 1 << NEXCEPTS; i++) { 353130330Sdas excepts = std_except_sets[i]; 354130330Sdas 355130330Sdas assert(fetestexcept(FE_ALL_EXCEPT) == 0); 356130330Sdas assert(fegetround() == FE_TONEAREST); 357130330Sdas assert(fegetenv(&env1) == 0); 358130330Sdas 359130330Sdas /* 360130330Sdas * fe[gs]etenv() should be able to save and restore 361130330Sdas * exception flags without the spurious inexact 362130330Sdas * exceptions that afflict raiseexcept(). 363130330Sdas */ 364130330Sdas raiseexcept(excepts); 365130330Sdas if ((excepts & (FE_UNDERFLOW | FE_OVERFLOW)) != 0 && 366130330Sdas (excepts & FE_INEXACT) == 0) 367130330Sdas assert(feclearexcept(FE_INEXACT) == 0); 368130330Sdas 369130330Sdas fesetround(FE_DOWNWARD); 370130330Sdas assert(fegetenv(&env2) == 0); 371130330Sdas assert(fesetenv(&env1) == 0); 372130330Sdas assert(fetestexcept(FE_ALL_EXCEPT) == 0); 373130330Sdas assert(fegetround() == FE_TONEAREST); 374130330Sdas 375130330Sdas assert(fesetenv(&env2) == 0); 376130330Sdas assert(fetestexcept(FE_ALL_EXCEPT) == excepts); 377130330Sdas assert(fegetround() == FE_DOWNWARD); 378130330Sdas assert(fesetenv(&env1) == 0); 379130330Sdas assert(fetestexcept(FE_ALL_EXCEPT) == 0); 380130330Sdas assert(fegetround() == FE_TONEAREST); 381130330Sdas } 382130330Sdas} 383130330Sdas 384130330Sdas/* 385143710Sdas * Test fegetexcept(), fedisableexcept(), and feenableexcept(). 386130330Sdas * 387130330Sdas * Prerequisites: fetestexcept(), feraiseexcept() 388130330Sdas */ 389130330Sdasstatic void 390143710Sdastest_masking(void) 391130330Sdas{ 392130330Sdas struct sigaction act; 393315121Sngie int except, pass, raise, status; 394315121Sngie unsigned i; 395130330Sdas 396143710Sdas assert((fegetexcept() & ALL_STD_EXCEPT) == 0); 397143710Sdas assert((feenableexcept(FE_INVALID|FE_OVERFLOW) & ALL_STD_EXCEPT) == 0); 398143710Sdas assert((feenableexcept(FE_UNDERFLOW) & ALL_STD_EXCEPT) == 399143710Sdas (FE_INVALID | FE_OVERFLOW)); 400143710Sdas assert((fedisableexcept(FE_OVERFLOW) & ALL_STD_EXCEPT) == 401143710Sdas (FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW)); 402143710Sdas assert((fegetexcept() & ALL_STD_EXCEPT) == (FE_INVALID | FE_UNDERFLOW)); 403143710Sdas assert((fedisableexcept(FE_ALL_EXCEPT) & ALL_STD_EXCEPT) == 404143710Sdas (FE_INVALID | FE_UNDERFLOW)); 405143710Sdas assert((fegetexcept() & ALL_STD_EXCEPT) == 0); 406143710Sdas 407130330Sdas sigemptyset(&act.sa_mask); 408130330Sdas act.sa_flags = 0; 409130330Sdas act.sa_handler = trap_handler; 410130330Sdas for (pass = 0; pass < 2; pass++) { 411130330Sdas for (i = 0; i < NEXCEPTS; i++) { 412130330Sdas except = std_excepts[i]; 413130330Sdas /* over/underflow may also raise inexact */ 414130330Sdas if (except == FE_INEXACT) 415130330Sdas raise = FE_DIVBYZERO | FE_INVALID; 416130330Sdas else 417130330Sdas raise = ALL_STD_EXCEPT ^ except; 418130330Sdas 419130330Sdas /* 420130330Sdas * We need to fork a child process because 421130330Sdas * there isn't a portable way to recover from 422130330Sdas * a floating-point exception. 423130330Sdas */ 424130330Sdas switch(fork()) { 425130330Sdas case 0: /* child */ 426143710Sdas assert((fegetexcept() & ALL_STD_EXCEPT) == 0); 427143710Sdas assert((feenableexcept(except) 428143710Sdas & ALL_STD_EXCEPT) == 0); 429143710Sdas assert(fegetexcept() == except); 430130330Sdas raiseexcept(raise); 431130330Sdas assert(feraiseexcept(raise) == 0); 432130330Sdas assert(fetestexcept(ALL_STD_EXCEPT) == raise); 433130330Sdas 434130330Sdas assert(sigaction(SIGFPE, &act, NULL) == 0); 435130330Sdas switch (pass) { 436130330Sdas case 0: 437130330Sdas raiseexcept(except); 438130330Sdas case 1: 439130330Sdas feraiseexcept(except); 440130330Sdas default: 441130330Sdas assert(0); 442130330Sdas } 443130330Sdas assert(0); 444130330Sdas default: /* parent */ 445130330Sdas assert(wait(&status) > 0); 446130330Sdas /* 447130330Sdas * Avoid assert() here so that it's possible 448130330Sdas * to examine a failed child's core dump. 449130330Sdas */ 450130330Sdas if (!WIFEXITED(status)) 451130330Sdas errx(1, "child aborted\n"); 452130330Sdas assert(WEXITSTATUS(status) == 0); 453130330Sdas break; 454130330Sdas case -1: /* error */ 455130330Sdas assert(0); 456130330Sdas } 457130330Sdas } 458130330Sdas } 459130330Sdas assert(fetestexcept(FE_ALL_EXCEPT) == 0); 460130330Sdas} 461130330Sdas 462130330Sdas/* 463130330Sdas * Test feholdexcept() and feupdateenv(). 464130330Sdas * 465143710Sdas * Prerequisites: fetestexcept(), fegetround(), fesetround(), 466143710Sdas * fedisableexcept(), feenableexcept() 467130330Sdas */ 468130330Sdasstatic void 469130330Sdastest_feholdupdate(void) 470130330Sdas{ 471130330Sdas fenv_t env; 472130330Sdas 473130330Sdas struct sigaction act; 474315121Sngie int except, pass, status, raise; 475315121Sngie unsigned i; 476130330Sdas 477130330Sdas sigemptyset(&act.sa_mask); 478130330Sdas act.sa_flags = 0; 479130330Sdas act.sa_handler = trap_handler; 480130330Sdas for (pass = 0; pass < 2; pass++) { 481130330Sdas for (i = 0; i < NEXCEPTS; i++) { 482130330Sdas except = std_excepts[i]; 483130330Sdas /* over/underflow may also raise inexact */ 484130330Sdas if (except == FE_INEXACT) 485130330Sdas raise = FE_DIVBYZERO | FE_INVALID; 486130330Sdas else 487130330Sdas raise = ALL_STD_EXCEPT ^ except; 488130330Sdas 489130330Sdas /* 490130330Sdas * We need to fork a child process because 491130330Sdas * there isn't a portable way to recover from 492130330Sdas * a floating-point exception. 493130330Sdas */ 494130330Sdas switch(fork()) { 495130330Sdas case 0: /* child */ 496130330Sdas /* 497130330Sdas * We don't want to cause a fatal exception in 498130330Sdas * the child until the second pass, so we can 499130330Sdas * check other properties of feupdateenv(). 500315121Sngie */ 501130330Sdas if (pass == 1) 502143710Sdas assert((feenableexcept(except) & 503130330Sdas ALL_STD_EXCEPT) == 0); 504130330Sdas raiseexcept(raise); 505130330Sdas assert(fesetround(FE_DOWNWARD) == 0); 506130330Sdas assert(feholdexcept(&env) == 0); 507130330Sdas assert(fetestexcept(FE_ALL_EXCEPT) == 0); 508130330Sdas raiseexcept(except); 509130330Sdas assert(fesetround(FE_UPWARD) == 0); 510130330Sdas 511130330Sdas if (pass == 1) 512130330Sdas assert(sigaction(SIGFPE, &act, NULL) == 513130330Sdas 0); 514130330Sdas assert(feupdateenv(&env) == 0); 515130330Sdas assert(fegetround() == FE_DOWNWARD); 516130330Sdas assert(fetestexcept(ALL_STD_EXCEPT) == 517130330Sdas (except | raise)); 518130330Sdas 519130330Sdas assert(pass == 0); 520130330Sdas _exit(0); 521130330Sdas default: /* parent */ 522130330Sdas assert(wait(&status) > 0); 523130330Sdas /* 524130330Sdas * Avoid assert() here so that it's possible 525130330Sdas * to examine a failed child's core dump. 526130330Sdas */ 527130330Sdas if (!WIFEXITED(status)) 528130330Sdas errx(1, "child aborted\n"); 529130330Sdas assert(WEXITSTATUS(status) == 0); 530130330Sdas break; 531130330Sdas case -1: /* error */ 532130330Sdas assert(0); 533130330Sdas } 534130330Sdas } 535130330Sdas } 536130330Sdas assert(fetestexcept(FE_ALL_EXCEPT) == 0); 537130330Sdas} 538130330Sdas 539315121Sngieint 540315121Sngiemain(void) 541130330Sdas{ 542130330Sdas 543315121Sngie printf("1..8\n"); 544315121Sngie init_exceptsets(); 545315121Sngie test_dfl_env(); 546315121Sngie printf("ok 1 - fenv\n"); 547315121Sngie test_fetestclearexcept(); 548315121Sngie printf("ok 2 - fenv\n"); 549315121Sngie test_fegsetexceptflag(); 550315121Sngie printf("ok 3 - fenv\n"); 551315121Sngie test_feraiseexcept(); 552315121Sngie printf("ok 4 - fenv\n"); 553315121Sngie test_fegsetround(); 554315121Sngie printf("ok 5 - fenv\n"); 555315121Sngie test_fegsetenv(); 556315121Sngie printf("ok 6 - fenv\n"); 557315121Sngie test_masking(); 558315121Sngie printf("ok 7 - fenv\n"); 559315121Sngie test_feholdupdate(); 560315121Sngie printf("ok 8 - fenv\n"); 561130330Sdas 562315121Sngie return (0); 563130330Sdas} 564