]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
Fix spurious "inexact" exceptions from __kernel_standard_l (bug 18245, bug 18583).
authorJoseph Myers <joseph@codesourcery.com>
Tue, 23 Jun 2015 17:26:46 +0000 (17:26 +0000)
committerJoseph Myers <joseph@codesourcery.com>
Tue, 23 Jun 2015 17:26:46 +0000 (17:26 +0000)
__kernel_standard_l converts long double arguments to double for use
in SVID "struct exception".  This has special-case handling for when
that conversion would overflow or underflow but the original long
double function wouldn't.  However, it turns out that "inexact"
exceptions can be spurious here as well, when the function is exactly
determined and __kernel_standard_l is being called for a domain error.
This patch fixes this by using feholdexcept / fesetenv to avoid
exceptions from the conversion, replacing the previous special-case
logic for overflow and underflow (this covers all functions using
__kernel_standard_l, not just those that actually need a change, since
there doesn't seem to be much point in restricting things just to the
functions that mustn't get "inexact" here).

Tested for x86_64 and x86.

[BZ #18245]
[BZ #18583]
* sysdeps/ieee754/k_standardl.c: Include <fenv.h>.
(__kernel_standard_l): Use feholdexcept and fesetenv around
conversion to double instead of special-casing overflow and
underflow.
* math/libm-test.inc (fmod_test_data): Add more tests.
(remainder_test_data): Likewise.
(sqrt_test_data): Likewise.

ChangeLog
NEWS
math/libm-test.inc
sysdeps/ieee754/k_standardl.c

index 6c18edd5c5a4de21f30da99247f5679a73d3ddbb..2f07bc101b8e1299795e36a66c5a4acc4a6234d2 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2015-06-23  Joseph Myers  <joseph@codesourcery.com>
+
+       [BZ #18245]
+       [BZ #18583]
+       * sysdeps/ieee754/k_standardl.c: Include <fenv.h>.
+       (__kernel_standard_l): Use feholdexcept and fesetenv around
+       conversion to double instead of special-casing overflow and
+       underflow.
+       * math/libm-test.inc (fmod_test_data): Add more tests.
+       (remainder_test_data): Likewise.
+       (sqrt_test_data): Likewise.
+
 2015-06-23  Torvald Riegel  <triegel@redhat.com>
 
        [BZ #17403]
diff --git a/NEWS b/NEWS
index a46efd69bc5eeec3b9052cb0863db66d5e92b615..da4ed7e1fc92eda2891900ac8ec4fe9ba79b7866 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -19,12 +19,12 @@ Version 2.22
   18032, 18034, 18036, 18038, 18039, 18042, 18043, 18046, 18047, 18049,
   18068, 18080, 18093, 18100, 18104, 18110, 18111, 18116, 18125, 18128,
   18138, 18185, 18196, 18197, 18206, 18210, 18211, 18217, 18219, 18220,
-  18221, 18234, 18244, 18247, 18287, 18319, 18324, 18333, 18346, 18371,
-  18397, 18409, 18410, 18412, 18418, 18422, 18434, 18444, 18468, 18469,
-  18470, 18479, 18483, 18495, 18496, 18497, 18498, 18507, 18512, 18513,
-  18519, 18520, 18522, 18527, 18528, 18529, 18530, 18532, 18533, 18534,
-  18536, 18539, 18540, 18542, 18544, 18545, 18546, 18547, 18553, 18558,
-  18569.
+  18221, 18234, 18244, 18245, 18247, 18287, 18319, 18324, 18333, 18346,
+  18371, 18397, 18409, 18410, 18412, 18418, 18422, 18434, 18444, 18468,
+  18469, 18470, 18479, 18483, 18495, 18496, 18497, 18498, 18507, 18512,
+  18513, 18519, 18520, 18522, 18527, 18528, 18529, 18530, 18532, 18533,
+  18534, 18536, 18539, 18540, 18542, 18544, 18545, 18546, 18547, 18553,
+  18558, 18569, 18583.
 
 * Cache information can be queried via sysconf() function on s390 e.g. with
   _SC_LEVEL1_ICACHE_SIZE as argument.
index 85a1746876fefdb4d8757cadf24f324ba9cd2ded..03c3831389a72e883b1526095e3d4338ee737004 100644 (file)
@@ -7115,12 +7115,16 @@ static const struct test_ff_f_data fmod_test_data[] =
 
     /* fmod (+inf, y) == qNaN plus invalid exception.  */
     TEST_ff_f (fmod, plus_infty, 3, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM),
+    TEST_ff_f (fmod, plus_infty, -1.1L, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM),
     /* fmod (-inf, y) == qNaN plus invalid exception.  */
     TEST_ff_f (fmod, minus_infty, 3, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM),
+    TEST_ff_f (fmod, minus_infty, -1.1L, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM),
     /* fmod (x, +0) == qNaN plus invalid exception.  */
     TEST_ff_f (fmod, 3, 0, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM),
+    TEST_ff_f (fmod, -1.1L, 0, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM),
     /* fmod (x, -0) == qNaN plus invalid exception.  */
     TEST_ff_f (fmod, 3, minus_zero, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM),
+    TEST_ff_f (fmod, -1.1L, minus_zero, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM),
 
     /* fmod (x, +inf) == x for x not infinite.  */
     TEST_ff_f (fmod, 3.0, plus_infty, 3.0, NO_INEXACT_EXCEPTION),
@@ -8719,6 +8723,8 @@ static const struct test_ff_f_data remainder_test_data[] =
   {
     TEST_ff_f (remainder, 1, 0, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM),
     TEST_ff_f (remainder, 1, minus_zero, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM),
+    TEST_ff_f (remainder, -1.1L, 0, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM),
+    TEST_ff_f (remainder, -1.1L, minus_zero, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM),
     TEST_ff_f (remainder, plus_zero, plus_zero, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM),
     TEST_ff_f (remainder, plus_zero, minus_zero, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM),
     TEST_ff_f (remainder, minus_zero, plus_zero, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM),
@@ -8726,12 +8732,14 @@ static const struct test_ff_f_data remainder_test_data[] =
     TEST_ff_f (remainder, plus_infty, minus_zero, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM),
     TEST_ff_f (remainder, plus_infty, 0, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM),
     TEST_ff_f (remainder, plus_infty, 1, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM),
+    TEST_ff_f (remainder, plus_infty, 1.1L, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM),
     TEST_ff_f (remainder, plus_infty, 2, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM),
     TEST_ff_f (remainder, plus_infty, plus_infty, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM),
     TEST_ff_f (remainder, plus_infty, minus_infty, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM),
     TEST_ff_f (remainder, minus_infty, minus_zero, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM),
     TEST_ff_f (remainder, minus_infty, 0, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM),
     TEST_ff_f (remainder, minus_infty, 1, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM),
+    TEST_ff_f (remainder, minus_infty, 1.1L, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM),
     TEST_ff_f (remainder, minus_infty, 2, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM),
     TEST_ff_f (remainder, minus_infty, plus_infty, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM),
     TEST_ff_f (remainder, minus_infty, minus_infty, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM),
@@ -9507,6 +9515,7 @@ static const struct test_f_f_data sqrt_test_data[] =
 
     /* sqrt (x) == qNaN plus invalid exception for x < 0.  */
     TEST_f_f (sqrt, -1, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM),
+    TEST_f_f (sqrt, -1.1L, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM),
     TEST_f_f (sqrt, -max_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM),
     TEST_f_f (sqrt, minus_infty, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM),
 
index eaa2f661f13e595e8e1c07eba1a28194512c953f..aa95748825122955d11ecf9d513d043fe71bab31 100644 (file)
@@ -32,6 +32,7 @@
 
 #include <math.h>
 #include <math_private.h>
+#include <fenv.h>
 #include <float.h>
 #include <errno.h>
 
@@ -47,31 +48,14 @@ __kernel_standard_l (long double x, long double y, int type)
 {
   double dx, dy;
   struct exception exc;
+  fenv_t env;
 
-  if (isfinite (x))
-    {
-      long double ax = fabsl (x);
-      if (ax > DBL_MAX)
-       dx = __copysignl (DBL_MAX, x);
-      else if (ax > 0 && ax < DBL_MIN)
-       dx = __copysignl (DBL_MIN, x);
-      else
-       dx = x;
-    }
-  else
-    dx = x;
-  if (isfinite (y))
-    {
-      long double ay = fabsl (y);
-      if (ay > DBL_MAX)
-       dy = __copysignl (DBL_MAX, y);
-      else if (ay > 0 && ay < DBL_MIN)
-       dy = __copysignl (DBL_MIN, y);
-      else
-       dy = y;
-    }
-  else
-    dy = y;
+  feholdexcept (&env);
+  dx = x;
+  dy = y;
+  math_force_eval (dx);
+  math_force_eval (dy);
+  fesetenv (&env);
 
   switch (type)
     {