On 8/19/23 19:57, Bruno Haible wrote:
bit <<= 1;
- if (bit > exp)
+ if (bit > uexp)
break;
This loops forever if exp == INT_MIN, which I reproduced with
'./configure gl_cv_func_ldexp_works=no' on Fedora 38 x86-64. I fixed it
by installing the attached.From 9c7ca2ba1020fadba5939b3792f1021843c1c808 Mon Sep 17 00:00:00 2001
From: Paul Eggert <[email protected]>
Date: Sun, 20 Aug 2023 13:23:11 -0700
Subject: [PATCH] ldexp: fix INT_MIN infloop
* lib/ldexp.c (FUNC): Instead of converting EXP to unsigned,
work on it directly. This simplifies the code and avoids
an infinite loop when EXP == INT_MIN.
* modules/ldexp, modules/ldexpl: Depend on stdbool.
* tests/test-ldexp.h: Include <limits.h> for INT_MIN.
(test_function): Test for infloop.
---
ChangeLog | 10 ++++++++++
lib/ldexp.c | 39 ++++++++++-----------------------------
modules/ldexp | 1 +
modules/ldexpl | 1 +
tests/test-ldexp.h | 3 +++
5 files changed, 25 insertions(+), 29 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index bad59ebcf6..764176466f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2023-08-20 Paul Eggert <[email protected]>
+
+ ldexp: fix INT_MIN infloop
+ * lib/ldexp.c (FUNC): Instead of converting EXP to unsigned,
+ work on it directly. This simplifies the code and avoids
+ an infinite loop when EXP == INT_MIN.
+ * modules/ldexp, modules/ldexpl: Depend on stdbool.
+ * tests/test-ldexp.h: Include <limits.h> for INT_MIN.
+ (test_function): Test for infloop.
+
2023-08-20 Bruno Haible <[email protected]>
ldexp: Fix compilation error in C++ mode.
diff --git a/lib/ldexp.c b/lib/ldexp.c
index dd09ca3814..844fd11f53 100644
--- a/lib/ldexp.c
+++ b/lib/ldexp.c
@@ -57,38 +57,19 @@ FUNC (DOUBLE x, int exp)
BEGIN_ROUNDING ();
/* Check for zero, nan and infinity. */
- if (!(ISNAN (x) || x + x == x))
+ if (!(ISNAN (x) || x + x == x || exp == 0))
{
- unsigned int uexp;
- DOUBLE factor;
+ bool negexp = exp < 0;
+ DOUBLE factor = negexp ? L_(0.5) : L_(2.0);
- if (exp < 0)
+ while (true)
{
- /* Avoid signed integer overflow when exp == INT_MIN. */
- uexp = (unsigned int) (-1 - exp) + 1;
- factor = L_(0.5);
- }
- else
- {
- uexp = exp;
- factor = L_(2.0);
- }
-
- if (uexp > 0)
- {
- unsigned int bit;
-
- for (bit = 1;;)
- {
- /* Invariant: Here bit = 2^i, factor = 2^-2^i or = 2^2^i,
- and bit <= uexp. */
- if (uexp & bit)
- x *= factor;
- bit <<= 1;
- if (bit > uexp)
- break;
- factor = factor * factor;
- }
+ if (exp & 1)
+ x *= factor;
+ exp = (exp + negexp) >> 1;
+ if (exp == 0)
+ break;
+ factor = factor * factor;
}
}
diff --git a/modules/ldexp b/modules/ldexp
index 2f55db6416..528efaad77 100644
--- a/modules/ldexp
+++ b/modules/ldexp
@@ -8,6 +8,7 @@ m4/ldexp.m4
Depends-on:
math
isnand [test $REPLACE_LDEXP = 1]
+stdbool [test $REPLACE_LDEXP = 1]
configure.ac:
gl_FUNC_LDEXP
diff --git a/modules/ldexpl b/modules/ldexpl
index 515ce713cd..622cad6ef5 100644
--- a/modules/ldexpl
+++ b/modules/ldexpl
@@ -12,6 +12,7 @@ extensions
ldexp [{ test $HAVE_DECL_LDEXPL = 0 || test $gl_func_ldexpl = no; } && test $HAVE_SAME_LONG_DOUBLE_AS_DOUBLE = 1]
isnanl [{ test $HAVE_DECL_LDEXPL = 0 || test $gl_func_ldexpl = no; } && test $HAVE_SAME_LONG_DOUBLE_AS_DOUBLE = 0]
fpucw [{ test $HAVE_DECL_LDEXPL = 0 || test $gl_func_ldexpl = no; } && test $HAVE_SAME_LONG_DOUBLE_AS_DOUBLE = 0]
+stdbool [{ test $HAVE_DECL_LDEXPL = 0 || test $gl_func_ldexpl = no; } && test $HAVE_SAME_LONG_DOUBLE_AS_DOUBLE = 0]
configure.ac:
gl_FUNC_LDEXPL
diff --git a/tests/test-ldexp.h b/tests/test-ldexp.h
index b1aac4f325..5252b1424c 100644
--- a/tests/test-ldexp.h
+++ b/tests/test-ldexp.h
@@ -16,6 +16,8 @@
/* Written by Bruno Haible <[email protected]>, 2007, 2010. */
+#include <limits.h>
+
static void
test_function (void)
{
@@ -99,6 +101,7 @@ test_function (void)
ASSERT (y == expected);
}
y = LDEXP (x, -5); ASSERT (y == x * 0.03125L);
+ y = LDEXP (x, INT_MIN); ASSERT (y == 0);
}
for (i = 1, x = L_(1.73205); i >= MIN_EXP; i--, x *= L_(0.5))
{
--
2.41.0