Re: printf("%La\n", 1e1000L) crashes with segv.

Takashi Yano <[email protected]>
Newsgroups gmane.comp.lib.newlib
Message-ID <[email protected]>
On Sun, 28 Nov 2021 16:49:53 +0900
Takashi Yano wrote:
> I noticed that printf("%La\n", 1e1000L) crashes with segv.
> I confirmed this in 32bit cygwin, however, I guess this is
> newlib issue.
> 
> Is this the known issue?

I found that the main cause of this issue is lack of frexpl()
function. This is not implemented yet in newlib.

I have made a patch which implements frexpl() to fix this issue.

Please see attachd patch.

-- 
Takashi Yano <[email protected]>
0001-stdio-Fix-issue-of-printing-La-format-with-large-exp.patch (application/octet-stream, 6 KB)
From 2929df82449dc65eb75350e5d038968698582330 Mon Sep 17 00:00:00 2001
From: Takashi Yano <[email protected]>
Date: Mon, 29 Nov 2021 19:50:47 +0900
Subject: [PATCH] stdio: Fix issue of printing "%La" format with large exp
 part.

- Currently, printf("%La\n", 1e1000L) crashes with segv due to lack
  of frexpl() function. With this patch, frexpl() function has been
  implemented in libm to solve this issue.

Addresses: https://sourceware.org/pipermail/newlib/2021/018718.html
---
 newlib/Makefile.am            |  2 +-
 newlib/Makefile.in            |  3 +-
 newlib/libc/include/math.h    |  1 +
 newlib/libc/stdio/vfprintf.c  |  5 +--
 newlib/libc/stdio/vfwprintf.c |  5 +--
 newlib/libm/common/frexpl.c   | 72 ++++++++++++++++++++++++++++++++++-
 6 files changed, 77 insertions(+), 11 deletions(-)

diff --git a/newlib/Makefile.am b/newlib/Makefile.am
index d3da43a4b..1235adb8b 100644
--- a/newlib/Makefile.am
+++ b/newlib/Makefile.am
@@ -105,7 +105,7 @@ MATHOBJS_IN_LIBC = \
 	$(lpfx)s_isnand.$(oext) $(lpfx)sf_isnanf.$(oext) \
 	$(lpfx)s_nan.$(oext) $(lpfx)sf_nan.$(oext) \
 	$(lpfx)s_ldexp.$(oext) $(lpfx)sf_ldexp.$(oext) \
-	$(lpfx)s_frexp.$(oext) $(lpfx)sf_frexp.$(oext) \
+	$(lpfx)s_frexp.$(oext) $(lpfx)sf_frexp.$(oext) $(lpfx)frexpl.$(oext) \
 	$(lpfx)s_modf.$(oext) \
 	$(lpfx)sf_modf.$(oext) $(lpfx)s_scalbn.$(oext) \
 	$(lpfx)sf_scalbn.$(oext) \
diff --git a/newlib/Makefile.in b/newlib/Makefile.in
index bf15dfea3..68417953d 100644
--- a/newlib/Makefile.in
+++ b/newlib/Makefile.in
@@ -312,6 +312,7 @@ pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
 psdir = @psdir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 shared_machine_dir = @shared_machine_dir@
 sharedstatedir = @sharedstatedir@
@@ -415,7 +416,7 @@ MATHOBJS_IN_LIBC = \
 	$(lpfx)s_isnand.$(oext) $(lpfx)sf_isnanf.$(oext) \
 	$(lpfx)s_nan.$(oext) $(lpfx)sf_nan.$(oext) \
 	$(lpfx)s_ldexp.$(oext) $(lpfx)sf_ldexp.$(oext) \
-	$(lpfx)s_frexp.$(oext) $(lpfx)sf_frexp.$(oext) \
+	$(lpfx)s_frexp.$(oext) $(lpfx)sf_frexp.$(oext) $(lpfx)frexpl.$(oext) \
 	$(lpfx)s_modf.$(oext) \
 	$(lpfx)sf_modf.$(oext) $(lpfx)s_scalbn.$(oext) \
 	$(lpfx)sf_scalbn.$(oext) \
diff --git a/newlib/libc/include/math.h b/newlib/libc/include/math.h
index 0b6494e6a..799ac494a 100644
--- a/newlib/libc/include/math.h
+++ b/newlib/libc/include/math.h
@@ -509,6 +509,7 @@ extern long double erfcl (long double);
 #else /* !_LDBL_EQ_DBL && !__CYGWIN__ */
 extern long double hypotl (long double, long double);
 extern long double sqrtl (long double);
+extern long double frexpl (long double, int *);
 #ifdef __i386__
 /* Other long double precision functions.  */
 extern _LONG_DOUBLE rintl (_LONG_DOUBLE);
diff --git a/newlib/libc/stdio/vfprintf.c b/newlib/libc/stdio/vfprintf.c
index 1aaf05aa4..c1483c0ac 100644
--- a/newlib/libc/stdio/vfprintf.c
+++ b/newlib/libc/stdio/vfprintf.c
@@ -517,10 +517,7 @@ extern int _ldcheck (_LONG_DOUBLE *);
 
 #  define _PRINTF_FLOAT_TYPE _LONG_DOUBLE
 #  define _DTOA_R _ldtoa_r
-/* FIXME - frexpl is not yet supported; and cvt infloops if (double)f
-   converts a finite value into infinity.  */
-/* #  define FREXP frexpl */
-#  define FREXP(f,e) ((_LONG_DOUBLE) frexp ((double)f, e))
+#  define FREXP frexpl
 # endif /* !_NO_LONGDBL */
 
 static char *cvt(struct _reent *, _PRINTF_FLOAT_TYPE, int, int, char *, int *,
diff --git a/newlib/libc/stdio/vfwprintf.c b/newlib/libc/stdio/vfwprintf.c
index 980b31e3b..7384b37d3 100644
--- a/newlib/libc/stdio/vfwprintf.c
+++ b/newlib/libc/stdio/vfwprintf.c
@@ -243,10 +243,7 @@ extern int _ldcheck (_LONG_DOUBLE *);
 
 #  define _PRINTF_FLOAT_TYPE _LONG_DOUBLE
 #  define _DTOA_R _ldtoa_r
-/* FIXME - frexpl is not yet supported; and cvt infloops if (double)f
-   converts a finite value into infinity.  */
-/* #  define FREXP frexpl */
-#  define FREXP(f,e) ((_LONG_DOUBLE) frexp ((double)f, e))
+#  define FREXP frexpl
 # endif /* !_NO_LONGDBL */
 
 static wchar_t *wcvt(struct _reent *, _PRINTF_FLOAT_TYPE, int, int, wchar_t *,
diff --git a/newlib/libm/common/frexpl.c b/newlib/libm/common/frexpl.c
index 79e41fd9e..42ea41062 100644
--- a/newlib/libm/common/frexpl.c
+++ b/newlib/libm/common/frexpl.c
@@ -29,10 +29,11 @@ POSSIBILITY OF SUCH DAMAGE.
 */
 
 #include <math.h>
+#include <float.h>
 #include "local.h"
 
 /* On platforms where long double is as wide as double.  */
-#ifdef _LDBL_EQ_DBL
+#if defined(_LDBL_EQ_DBL) || (LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024)
 long double
 frexpl (long double x, int *eptr)
 {
@@ -40,3 +41,72 @@ frexpl (long double x, int *eptr)
 }
 #endif
 
+#if (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384
+# if (LDBL_MANT_DIG == 64) /* 80-bit long double */
+union ldbl {
+  long double x;
+  struct {
+# ifdef __IEEE_LITTLE_ENDIAN /* for Intel CPU */
+    __uint32_t fracl;
+    __uint32_t frach;
+    __uint32_t sexp:16;
+    __uint32_t pad:16;
+# endif
+# ifdef __IEEE_BIG_ENDIAN /* for m86k */
+    __uint32_t sexp:16;
+    __uint32_t pad:16
+    __uint32_t frach;
+    __uint32_t fracl;
+# endif
+  } u32;
+};
+# else /* LDBL_MANT_DIG == 113, 128-bit long double */
+union ldbl {
+  long double x;
+  struct {
+# ifdef __IEEE_LITTLE_ENDIAN
+    __uint32_t fracl;
+    __uint32_t fraclm;
+    __uint32_t frachm;
+    __uint32_t frach:16;
+    __uint32_t sexp:16;
+# endif
+# ifdef __IEEE_BIG_ENDIAN
+#ifndef ___IEEE_BYTES_LITTLE_ENDIAN
+    __uint32_t sexp:16;
+    __uint32_t frach:16;
+#else /* ARMEL without __VFP_FP__ */
+    __uint32_t frach:16;
+    __uint32_t sexp:16;
+#endif
+    __uint32_t frachm;
+    __uint32_t fraclm;
+    __uint32_t fracl;
+# endif
+  } u32;
+};
+# endif
+
+static const double two114 = 0x1p114;
+
+long double
+frexpl (long double x, int *eptr)
+{
+  union ldbl u;
+  u.x = x;
+  int e = u.u32.sexp & 0x7fff;
+  *eptr = 0;
+  if (e == 0x7fff || x == 0)
+    return x; /* 0,inf,nan */
+  if (e == 0)
+    {
+      x *= two114;
+      u.x = x;
+      e = u.u32.sexp & 0x7fff;
+      *eptr -= 114;
+    }
+  *eptr += e - 16382;
+  u.u32.sexp = (u.u32.sexp & 0x8000) | 0x3ffe;
+  return u.x;
+}
+#endif /* End of 80-bit or 128-bit long double */
-- 
2.33.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.