From 8f7f76d6a2272bc88d76898d2474bc27a2a5d0cf Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Tue, 21 May 2024 00:33:55 +0200 Subject: [PATCH] vasnprintf: Don't abort for pseudo-denormal arguments on macOS 12. MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Reported by Gaëtan Herfray via Erik Blake in . * lib/vasnprintf.c (safe_frexpl): New function. (decode_long_double, floorlog10l): Invoke it instead of frexpl. --- ChangeLog | 9 +++++++++ lib/vasnprintf.c | 40 +++++++++++++++++++++++++++++++++++++--- 2 files changed, 46 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8b9b73a218..dd5dd8c2a2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2024-05-20 Bruno Haible + + vasnprintf: Don't abort for pseudo-denormal arguments on macOS 12. + Reported by Gaëtan Herfray via Erik Blake in + + . + * lib/vasnprintf.c (safe_frexpl): New function. + (decode_long_double, floorlog10l): Invoke it instead of frexpl. + 2024-05-20 Paul Eggert getopt-posix: port better to Alpine 3.20.0_rc1 diff --git a/lib/vasnprintf.c b/lib/vasnprintf.c index 544ae62d9f..b7950a5612 100644 --- a/lib/vasnprintf.c +++ b/lib/vasnprintf.c @@ -86,7 +86,7 @@ #include /* mbstate_t, mbrtowc(), mbrlen(), wcrtomb(), mbszero() */ #include /* errno */ #include /* CHAR_BIT, INT_WIDTH, LONG_WIDTH */ -#include /* DBL_MAX_EXP, LDBL_MAX_EXP */ +#include /* DBL_MAX_EXP, LDBL_MAX_EXP, LDBL_MANT_DIG */ #if HAVE_NL_LANGINFO # include #endif @@ -406,6 +406,40 @@ is_infinite_or_zerol (long double x) #endif +#if NEED_PRINTF_LONG_DOUBLE + +/* Like frexpl, except that it supports even "unsupported" numbers. */ +# if (LDBL_MANT_DIG == 64 && (defined __ia64 || (defined __x86_64__ || defined __amd64__) || (defined __i386 || defined __i386__ || defined _I386 || defined _M_IX86 || defined _X86_))) && (defined __APPLE__ && defined __MACH__) +/* Don't assume that frexpl can handle pseudo-denormals; it does not on + macOS 12/x86_64. Therefore test for a pseudo-denormal explicitly. */ + +static +long double safe_frexpl (long double x, int *exp) +{ + union + { + long double value; + struct { unsigned int mant_word[2]; unsigned short sign_exp_word; } r; + } + u; + u.value = x; + if (u.r.sign_exp_word == 0 && (u.r.mant_word[1] & 0x80000000u) != 0) + { + /* Pseudo-Denormal. */ + *exp = LDBL_MIN_EXP; + u.r.sign_exp_word = 1 - LDBL_MIN_EXP; + return u.value; + } + else + return frexpl (x, exp); +} + +# else +# define safe_frexpl frexpl +# endif + +#endif + #if NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_DOUBLE /* Converting 'long double' to decimal without rare rounding bugs requires @@ -1015,7 +1049,7 @@ decode_long_double (long double x, int *ep, mpn_t *mp) if (m.limbs == NULL) return NULL; /* Split into exponential part and mantissa. */ - y = frexpl (x, &exp); + y = safe_frexpl (x, &exp); if (!(y >= 0.0L && y < 1.0L)) abort (); /* x = 2^exp * y = 2^(exp - LDBL_MANT_BIT) * (y * 2^LDBL_MANT_BIT), and the @@ -1442,7 +1476,7 @@ floorlog10l (long double x) double l; /* Split into exponential part and mantissa. */ - y = frexpl (x, &exp); + y = safe_frexpl (x, &exp); if (!(y >= 0.0L && y < 1.0L)) abort (); if (y == 0.0L) -- 2.39.5