-/* Copyright (C) 1997, 1998 Free Software Foundation, Inc.
+/* Copyright (C) 1997-2019 Free Software Foundation, Inc.
This file is part of the GNU C Library.
- Contributed by Andreas Jaeger <aj@arthur.rhein-neckar.de> and
+ Contributed by Andreas Jaeger <aj@suse.de> and
Ulrich Drepper <drepper@cygnus.com>, 1997.
The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public License as
- published by the Free Software Foundation; either version 2 of the
- License, or (at your option) any later version.
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
+ Lesser General Public License for more details.
- You should have received a copy of the GNU Library General Public
- License along with the GNU C Library; see the file COPYING.LIB. If not,
- write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
/* Tests for ISO C99 7.6: Floating-point environment */
#include <unistd.h>
#include <sys/wait.h>
#include <sys/resource.h>
+#include <math-tests.h>
/*
Since not all architectures might define all exceptions, we define
#define OVERFLOW_EXC 0x08
#define INVALID_EXC 0x10
#define ALL_EXC \
- (INEXACT_EXC | DIVBYZERO_EXC | UNDERFLOW_EXC | OVERFLOW_EXC | \
- INVALID_EXC)
+ (INEXACT_EXC | DIVBYZERO_EXC | UNDERFLOW_EXC | OVERFLOW_EXC \
+ | INVALID_EXC)
static int count_errors;
+#if FE_ALL_EXCEPT
/* Test whether a given exception was raised. */
static void
test_single_exception (short int exception,
}
}
}
+#endif
static void
test_exceptions (const char *test_name, short int exception,
}
+#if FE_ALL_EXCEPT
static void
set_single_exc (const char *test_name, int fe_exc, fexcept_t exception)
{
feclearexcept (exception);
test_exceptions (str, ALL_EXC ^ fe_exc, 0);
}
+#endif
static void
fe_tests (void)
test_exceptions ("feclearexcept (FE_ALL_EXCEPT) clears all exceptions",
NO_EXC, 0);
+ /* Skip further tests here if exceptions not supported. */
+ if (!EXCEPTION_TESTS (float) && FE_ALL_EXCEPT != 0)
+ return;
/* raise all exceptions and test if all are raised */
feraiseexcept (FE_ALL_EXCEPT);
test_exceptions ("feraiseexcept (FE_ALL_EXCEPT) raises all exceptions",
#endif
}
+#if FE_ALL_EXCEPT
/* Test that program aborts with no masked interrupts */
static void
feenv_nomask_test (const char *flag_name, int fe_exc)
{
-#if defined FE_NOMASK_ENV
+# if defined FE_NOMASK_ENV
int status;
pid_t pid;
- fenv_t saved;
- fegetenv (&saved);
- errno = 0;
- fesetenv (FE_NOMASK_ENV);
- status = errno;
- fesetenv (&saved);
- if (status == ENOSYS)
+ if (!EXCEPTION_ENABLE_SUPPORTED (FE_ALL_EXCEPT)
+ && fesetenv (FE_NOMASK_ENV) != 0)
{
printf ("Test: not testing FE_NOMASK_ENV, it isn't implemented.\n");
return;
pid = fork ();
if (pid == 0)
{
-#ifdef RLIMIT_CORE
+# ifdef RLIMIT_CORE
/* Try to avoid dumping core. */
struct rlimit core_limit;
core_limit.rlim_cur = 0;
core_limit.rlim_max = 0;
setrlimit (RLIMIT_CORE, &core_limit);
-#endif
+# endif
fesetenv (FE_NOMASK_ENV);
feraiseexcept (fe_exc);
++count_errors;
}
}
-#endif
+# endif
}
/* Test that program doesn't abort with default environment */
}
}
+/* Test that program aborts with no masked interrupts */
+static void
+feexcp_nomask_test (const char *flag_name, int fe_exc)
+{
+ int status;
+ pid_t pid;
+
+ if (!EXCEPTION_ENABLE_SUPPORTED (fe_exc) && feenableexcept (fe_exc) == -1)
+ {
+ printf ("Test: not testing feenableexcept, it isn't implemented.\n");
+ return;
+ }
+
+ printf ("Test: after feenableexcept (%s) processes will abort\n",
+ flag_name);
+ printf (" when feraiseexcept (%s) is called.\n", flag_name);
+ pid = fork ();
+ if (pid == 0)
+ {
+#ifdef RLIMIT_CORE
+ /* Try to avoid dumping core. */
+ struct rlimit core_limit;
+ core_limit.rlim_cur = 0;
+ core_limit.rlim_max = 0;
+ setrlimit (RLIMIT_CORE, &core_limit);
+#endif
+
+ fedisableexcept (FE_ALL_EXCEPT);
+ feenableexcept (fe_exc);
+ feraiseexcept (fe_exc);
+ exit (2);
+ }
+ else if (pid < 0)
+ {
+ if (errno != ENOSYS)
+ {
+ printf (" Fail: Could not fork.\n");
+ ++count_errors;
+ }
+ else
+ printf (" `fork' not implemented, test ignored.\n");
+ }
+ else {
+ if (waitpid (pid, &status, 0) != pid)
+ {
+ printf (" Fail: waitpid call failed.\n");
+ ++count_errors;
+ }
+ else if (WIFSIGNALED (status) && WTERMSIG (status) == SIGFPE)
+ printf (" Pass: Process received SIGFPE.\n");
+ else
+ {
+ printf (" Fail: Process didn't receive signal and exited with status %d.\n",
+ status);
+ ++count_errors;
+ }
+ }
+}
+
+/* Test that program doesn't abort with exception. */
+static void
+feexcp_mask_test (const char *flag_name, int fe_exc)
+{
+ int status;
+ int exception;
+ pid_t pid;
+
+ printf ("Test: after fedisableexcept (%s) processes will not abort\n",
+ flag_name);
+ printf (" when feraiseexcept (%s) is called.\n", flag_name);
+ pid = fork ();
+ if (pid == 0)
+ {
+#ifdef RLIMIT_CORE
+ /* Try to avoid dumping core. */
+ struct rlimit core_limit;
+ core_limit.rlim_cur = 0;
+ core_limit.rlim_max = 0;
+ setrlimit (RLIMIT_CORE, &core_limit);
+#endif
+ feenableexcept (FE_ALL_EXCEPT);
+ exception = fe_exc;
+#ifdef FE_INEXACT
+ /* The standard allows the inexact exception to be set together with the
+ underflow and overflow exceptions. So add FE_INEXACT to the set of
+ exceptions to be disabled if we will be raising underflow or
+ overflow. */
+# ifdef FE_OVERFLOW
+ if (fe_exc & FE_OVERFLOW)
+ exception |= FE_INEXACT;
+# endif
+# ifdef FE_UNDERFLOW
+ if (fe_exc & FE_UNDERFLOW)
+ exception |= FE_INEXACT;
+# endif
+#endif
+ fedisableexcept (exception);
+ feraiseexcept (fe_exc);
+ exit (2);
+ }
+ else if (pid < 0)
+ {
+ if (errno != ENOSYS)
+ {
+ printf (" Fail: Could not fork.\n");
+ ++count_errors;
+ }
+ else
+ printf (" `fork' not implemented, test ignored.\n");
+ }
+ else {
+ if (waitpid (pid, &status, 0) != pid)
+ {
+ printf (" Fail: waitpid call failed.\n");
+ ++count_errors;
+ }
+ else if (WIFEXITED (status) && WEXITSTATUS (status) == 2)
+ printf (" Pass: Process exited normally.\n");
+ else
+ {
+ printf (" Fail: Process exited abnormally with status %d.\n",
+ status);
+ ++count_errors;
+ }
+ }
+}
+
+
+/* Tests for feenableexcept/fedisableexcept/fegetexcept. */
+static void
+feenable_test (const char *flag_name, int fe_exc)
+{
+ int excepts;
+
+ printf ("Tests for feenableexcepts etc. with flag %s\n", flag_name);
+
+ /* First disable all exceptions. */
+ if (fedisableexcept (FE_ALL_EXCEPT) == -1)
+ {
+ printf ("Test: fedisableexcept (FE_ALL_EXCEPT) failed\n");
+ ++count_errors;
+ /* If this fails, the other tests don't make sense. */
+ return;
+ }
+ excepts = fegetexcept ();
+ if (excepts != 0)
+ {
+ printf ("Test: fegetexcept (%s) failed, return should be 0, is %d\n",
+ flag_name, excepts);
+ ++count_errors;
+ }
+ excepts = feenableexcept (fe_exc);
+ if (!EXCEPTION_ENABLE_SUPPORTED (fe_exc) && excepts == -1)
+ {
+ printf ("Test: not testing feenableexcept, it isn't implemented.\n");
+ return;
+ }
+ if (excepts == -1)
+ {
+ printf ("Test: feenableexcept (%s) failed\n", flag_name);
+ ++count_errors;
+ return;
+ }
+ if (excepts != 0)
+ {
+ printf ("Test: feenableexcept (%s) failed, return should be 0, is %x\n",
+ flag_name, excepts);
+ ++count_errors;
+ }
+
+ excepts = fegetexcept ();
+ if (excepts != fe_exc)
+ {
+ printf ("Test: fegetexcept (%s) failed, return should be 0x%x, is 0x%x\n",
+ flag_name, fe_exc, excepts);
+ ++count_errors;
+ }
+
+ /* And now disable the exception again. */
+ excepts = fedisableexcept (fe_exc);
+ if (excepts == -1)
+ {
+ printf ("Test: fedisableexcept (%s) failed\n", flag_name);
+ ++count_errors;
+ return;
+ }
+ if (excepts != fe_exc)
+ {
+ printf ("Test: fedisableexcept (%s) failed, return should be 0x%x, is 0x%x\n",
+ flag_name, fe_exc, excepts);
+ ++count_errors;
+ }
+
+ excepts = fegetexcept ();
+ if (excepts != 0)
+ {
+ printf ("Test: fegetexcept (%s) failed, return should be 0, is 0x%x\n",
+ flag_name, excepts);
+ ++count_errors;
+ }
+
+ /* Now the other way round: Enable all exceptions and disable just this one. */
+ if (feenableexcept (FE_ALL_EXCEPT) == -1)
+ {
+ printf ("Test: feenableexcept (FE_ALL_EXCEPT) failed\n");
+ ++count_errors;
+ /* If this fails, the other tests don't make sense. */
+ return;
+ }
+
+ excepts = fegetexcept ();
+ if (excepts != FE_ALL_EXCEPT)
+ {
+ printf ("Test: fegetexcept (%s) failed, return should be 0x%x, is 0x%x\n",
+ flag_name, FE_ALL_EXCEPT, excepts);
+ ++count_errors;
+ }
+
+ excepts = fedisableexcept (fe_exc);
+ if (excepts == -1)
+ {
+ printf ("Test: fedisableexcept (%s) failed\n", flag_name);
+ ++count_errors;
+ return;
+ }
+ if (excepts != FE_ALL_EXCEPT)
+ {
+ printf ("Test: fedisableexcept (%s) failed, return should be 0, is 0x%x\n",
+ flag_name, excepts);
+ ++count_errors;
+ }
+
+ excepts = fegetexcept ();
+ if (excepts != (FE_ALL_EXCEPT & ~fe_exc))
+ {
+ printf ("Test: fegetexcept (%s) failed, return should be 0x%x, is 0x%x\n",
+ flag_name, (FE_ALL_EXCEPT & ~fe_exc), excepts);
+ ++count_errors;
+ }
+
+ /* And now enable the exception again. */
+ excepts = feenableexcept (fe_exc);
+ if (excepts == -1)
+ {
+ printf ("Test: feenableexcept (%s) failed\n", flag_name);
+ ++count_errors;
+ return;
+ }
+ if (excepts != (FE_ALL_EXCEPT & ~fe_exc))
+ {
+ printf ("Test: feenableexcept (%s) failed, return should be 0, is 0x%x\n",
+ flag_name, excepts);
+ ++count_errors;
+ }
+
+ excepts = fegetexcept ();
+ if (excepts != FE_ALL_EXCEPT)
+ {
+ printf ("Test: fegetexcept (%s) failed, return should be 0x%x, is 0x%x\n",
+ flag_name, FE_ALL_EXCEPT, excepts);
+ ++count_errors;
+ }
+ feexcp_nomask_test (flag_name, fe_exc);
+ feexcp_mask_test (flag_name, fe_exc);
+
+}
+
+
+static void
+fe_single_test (const char *flag_name, int fe_exc)
+{
+ feenv_nomask_test (flag_name, fe_exc);
+ feenv_mask_test (flag_name, fe_exc);
+ feenable_test (flag_name, fe_exc);
+}
+#endif
static void
feenv_tests (void)
{
+ /* We might have some exceptions still set. */
+ feclearexcept (FE_ALL_EXCEPT);
#ifdef FE_DIVBYZERO
- feenv_nomask_test ("FE_DIVBYZERO", FE_DIVBYZERO);
- feenv_mask_test ("FE_DIVBYZERO", FE_DIVBYZERO);
+ fe_single_test ("FE_DIVBYZERO", FE_DIVBYZERO);
#endif
#ifdef FE_INVALID
- feenv_nomask_test ("FE_INVALID", FE_INVALID);
- feenv_mask_test ("FE_INVALID", FE_INVALID);
+ fe_single_test ("FE_INVALID", FE_INVALID);
#endif
#ifdef FE_INEXACT
- feenv_nomask_test ("FE_INEXACT", FE_INEXACT);
- feenv_mask_test ("FE_INEXACT", FE_INEXACT);
+ fe_single_test ("FE_INEXACT", FE_INEXACT);
#endif
#ifdef FE_UNDERFLOW
- feenv_nomask_test ("FE_UNDERFLOW", FE_UNDERFLOW);
- feenv_mask_test ("FE_UNDERFLOW", FE_UNDERFLOW);
+ fe_single_test ("FE_UNDERFLOW", FE_UNDERFLOW);
#endif
#ifdef FE_OVERFLOW
- feenv_nomask_test ("FE_OVERFLOW", FE_OVERFLOW);
- feenv_mask_test ("FE_OVERFLOW", FE_OVERFLOW);
+ fe_single_test ("FE_OVERFLOW", FE_OVERFLOW);
#endif
fesetenv (FE_DFL_ENV);
}
+static void
+feholdexcept_tests (void)
+{
+ fenv_t saved, saved2;
+ int res;
+
+ feclearexcept (FE_ALL_EXCEPT);
+ fedisableexcept (FE_ALL_EXCEPT);
+#ifdef FE_DIVBYZERO
+ feraiseexcept (FE_DIVBYZERO);
+#endif
+ if (EXCEPTION_TESTS (float))
+ test_exceptions ("feholdexcept_tests FE_DIVBYZERO test",
+ DIVBYZERO_EXC, 0);
+ res = feholdexcept (&saved);
+ if (res != 0)
+ {
+ printf ("feholdexcept failed: %d\n", res);
+ ++count_errors;
+ }
+#if defined FE_TONEAREST && defined FE_TOWARDZERO
+ res = fesetround (FE_TOWARDZERO);
+ if (res != 0 && ROUNDING_TESTS (float, FE_TOWARDZERO))
+ {
+ printf ("fesetround failed: %d\n", res);
+ ++count_errors;
+ }
+#endif
+ test_exceptions ("feholdexcept_tests 0 test", NO_EXC, 0);
+#ifdef FE_INVALID
+ feraiseexcept (FE_INVALID);
+ if (EXCEPTION_TESTS (float))
+ test_exceptions ("feholdexcept_tests FE_INVALID test",
+ INVALID_EXC, 0);
+#endif
+ res = feupdateenv (&saved);
+ if (res != 0)
+ {
+ printf ("feupdateenv failed: %d\n", res);
+ ++count_errors;
+ }
+#if defined FE_TONEAREST && defined FE_TOWARDZERO
+ res = fegetround ();
+ if (res != FE_TONEAREST)
+ {
+ printf ("feupdateenv didn't restore rounding mode: %d\n", res);
+ ++count_errors;
+ }
+#endif
+ if (EXCEPTION_TESTS (float))
+ test_exceptions ("feholdexcept_tests FE_DIVBYZERO|FE_INVALID test",
+ DIVBYZERO_EXC | INVALID_EXC, 0);
+ feclearexcept (FE_ALL_EXCEPT);
+#ifdef FE_INVALID
+ feraiseexcept (FE_INVALID);
+#endif
+#if defined FE_TONEAREST && defined FE_UPWARD
+ res = fesetround (FE_UPWARD);
+ if (res != 0 && ROUNDING_TESTS (float, FE_UPWARD))
+ {
+ printf ("fesetround failed: %d\n", res);
+ ++count_errors;
+ }
+#endif
+ res = feholdexcept (&saved2);
+ if (res != 0)
+ {
+ printf ("feholdexcept failed: %d\n", res);
+ ++count_errors;
+ }
+#if defined FE_TONEAREST && defined FE_UPWARD
+ res = fesetround (FE_TONEAREST);
+ if (res != 0)
+ {
+ printf ("fesetround failed: %d\n", res);
+ ++count_errors;
+ }
+#endif
+ test_exceptions ("feholdexcept_tests 0 2nd test", NO_EXC, 0);
+#ifdef FE_INEXACT
+ feraiseexcept (FE_INEXACT);
+ if (EXCEPTION_TESTS (float))
+ test_exceptions ("feholdexcept_tests FE_INEXACT test",
+ INEXACT_EXC, 0);
+#endif
+ res = feupdateenv (&saved2);
+ if (res != 0)
+ {
+ printf ("feupdateenv failed: %d\n", res);
+ ++count_errors;
+ }
+#if defined FE_TONEAREST && defined FE_UPWARD
+ res = fegetround ();
+ if (res != FE_UPWARD && ROUNDING_TESTS (float, FE_UPWARD))
+ {
+ printf ("feupdateenv didn't restore rounding mode: %d\n", res);
+ ++count_errors;
+ }
+ fesetround (FE_TONEAREST);
+#endif
+ if (EXCEPTION_TESTS (float))
+ test_exceptions ("feholdexcept_tests FE_INEXACT|FE_INVALID test",
+ INVALID_EXC | INEXACT_EXC, 0);
+ feclearexcept (FE_ALL_EXCEPT);
+}
+
+
/* IEC 559 and ISO C99 define a default startup environment */
static void
initial_tests (void)
{
test_exceptions ("Initially all exceptions should be cleared",
NO_EXC, 0);
+#ifdef FE_TONEAREST
test_rounding ("Rounding direction should be initalized to nearest",
FE_TONEAREST);
+#endif
}
int
initial_tests ();
fe_tests ();
feenv_tests ();
+ feholdexcept_tests ();
if (count_errors)
{
- printf ("\n%d errors occured.\n", count_errors);
+ printf ("\n%d errors occurred.\n", count_errors);
exit (1);
}
printf ("\n All tests passed successfully.\n");
- exit (0);
+ return 0;
}