7c0489
commit 9333498794cde1d5cca518badf79533a24114b6f
7c0489
Author: Joseph Myers <joseph@codesourcery.com>
7c0489
Date:   Wed Feb 12 23:31:56 2020 +0000
7c0489
7c0489
    Avoid ldbl-96 stack corruption from range reduction of pseudo-zero (bug 25487).
7c0489
7c0489
    Bug 25487 reports stack corruption in ldbl-96 sinl on a pseudo-zero
7c0489
    argument (an representation where all the significand bits, including
7c0489
    the explicit high bit, are zero, but the exponent is not zero, which
7c0489
    is not a valid representation for the long double type).
7c0489
7c0489
    Although this is not a valid long double representation, existing
7c0489
    practice in this area (see bug 4586, originally marked invalid but
7c0489
    subsequently fixed) is that we still seek to avoid invalid memory
7c0489
    accesses as a result, in case of programs that treat arbitrary binary
7c0489
    data as long double representations, although the invalid
7c0489
    representations of the ldbl-96 format do not need to be consistently
7c0489
    handled the same as any particular valid representation.
7c0489
7c0489
    This patch makes the range reduction detect pseudo-zero and unnormal
7c0489
    representations that would otherwise go to __kernel_rem_pio2, and
7c0489
    returns a NaN for them instead of continuing with the range reduction
7c0489
    process.  (Pseudo-zero and unnormal representations whose unbiased
7c0489
    exponent is less than -1 have already been safely returned from the
7c0489
    function before this point without going through the rest of range
7c0489
    reduction.)  Pseudo-zero representations would previously result in
7c0489
    the value passed to __kernel_rem_pio2 being all-zero, which is
7c0489
    definitely unsafe; unnormal representations would previously result in
7c0489
    a value passed whose high bit is zero, which might well be unsafe
7c0489
    since that is not a form of input expected by __kernel_rem_pio2.
7c0489
7c0489
    Tested for x86_64.
7c0489
7c0489
Revised for RHEL 8.3.0.
7c0489
7c0489
diff -Nrup a/sysdeps/ieee754/ldbl-96/e_rem_pio2l.c b/sysdeps/ieee754/ldbl-96/e_rem_pio2l.c
7c0489
--- a/sysdeps/ieee754/ldbl-96/e_rem_pio2l.c	2018-08-01 01:10:47.000000000 -0400
7c0489
+++ b/sysdeps/ieee754/ldbl-96/e_rem_pio2l.c	2020-04-03 13:05:02.609844427 -0400
7c0489
@@ -209,6 +209,18 @@ __ieee754_rem_pio2l (long double x, long
7c0489
       y[1] = y[0];
7c0489
       return 0;
7c0489
     }
7c0489
+  
7c0489
+  if ((i0 & 0x80000000) == 0)
7c0489
+    {
7c0489
+      /* Pseudo-zero and unnormal representations are not valid
7c0489
+        representations of long double.  We need to avoid stack
7c0489
+        corruption in __kernel_rem_pio2, which expects input in a
7c0489
+        particular normal form, but those representations do not need
7c0489
+        to be consistently handled like any particular floating-point
7c0489
+        value.  */
7c0489
+      y[1] = y[0] = __builtin_nanl ("");
7c0489
+      return 0;
7c0489
+    }
7c0489
 
7c0489
   /* Split the 64 bits of the mantissa into three 24-bit integers
7c0489
      stored in a double array.  */
7c0489
diff -Nrup a/sysdeps/ieee754/ldbl-96/Makefile b/sysdeps/ieee754/ldbl-96/Makefile
7c0489
--- a/sysdeps/ieee754/ldbl-96/Makefile	2018-08-01 01:10:47.000000000 -0400
7c0489
+++ b/sysdeps/ieee754/ldbl-96/Makefile	2020-04-03 13:03:20.233546734 -0400
7c0489
@@ -17,5 +17,6 @@
7c0489
 # <http://www.gnu.org/licenses/>.
7c0489
 
7c0489
 ifeq ($(subdir),math)
7c0489
-tests += test-canonical-ldbl-96 test-totalorderl-ldbl-96
7c0489
+tests += test-canonical-ldbl-96 test-totalorderl-ldbl-96 test-sinl-pseudo
7c0489
+CFLAGS-test-sinl-pseudo.c += -fstack-protector-all
7c0489
 endif
7c0489
diff -Nrup a/sysdeps/ieee754/ldbl-96/test-sinl-pseudo.c b/sysdeps/ieee754/ldbl-96/test-sinl-pseudo.c
7c0489
--- a/sysdeps/ieee754/ldbl-96/test-sinl-pseudo.c	1969-12-31 19:00:00.000000000 -0500
7c0489
+++ b/sysdeps/ieee754/ldbl-96/test-sinl-pseudo.c	2020-04-03 13:05:37.857952212 -0400
7c0489
@@ -0,0 +1,41 @@
7c0489
+/* Test sinl for pseudo-zeros and unnormals for ldbl-96 (bug 25487).
7c0489
+   Copyright (C) 2020 Free Software Foundation, Inc.
7c0489
+   This file is part of the GNU C Library.
7c0489
+
7c0489
+   The GNU C Library is free software; you can redistribute it and/or
7c0489
+   modify it under the terms of the GNU Lesser General Public
7c0489
+   License as published by the Free Software Foundation; either
7c0489
+   version 2.1 of the License, or (at your option) any later version.
7c0489
+
7c0489
+   The GNU C Library is distributed in the hope that it will be useful,
7c0489
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
7c0489
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
7c0489
+   Lesser General Public License for more details.
7c0489
+
7c0489
+   You should have received a copy of the GNU Lesser General Public
7c0489
+   License along with the GNU C Library; if not, see
7c0489
+   <https://www.gnu.org/licenses/>.  */
7c0489
+
7c0489
+#include <math.h>
7c0489
+#include <math_ldbl.h>
7c0489
+#include <stdint.h>
7c0489
+
7c0489
+static int
7c0489
+do_test (void)
7c0489
+{
7c0489
+  for (int i = 0; i < 64; i++)
7c0489
+    {
7c0489
+      uint64_t sig = i == 63 ? 0 : 1ULL << i;
7c0489
+      long double ld;
7c0489
+      SET_LDOUBLE_WORDS (ld, 0x4141,
7c0489
+                        sig >> 32, sig & 0xffffffffULL);
7c0489
+      /* The requirement is that no stack overflow occurs when the
7c0489
+        pseudo-zero or unnormal goes through range reduction.  */
7c0489
+      volatile long double ldr;
7c0489
+      ldr = sinl (ld);
7c0489
+      (void) ldr;
7c0489
+    }
7c0489
+  return 0;
7c0489
+}
7c0489
+
7c0489
+#include <support/test-driver.c>