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

Reply via email to