[COMMITTED,12/31] ada: Add guard to System.Val_Real.Large_Powfive against pathological input

Message ID 20250107125350.619654-12-poulhies@adacore.com
State New
Headers
Series [COMMITTED,01/31] ada: Restrict previous change made to expansion of allocators |

Commit Message

Marc Poulhiès Jan. 7, 2025, 12:53 p.m. UTC
  From: Eric Botcazou <ebotcazou@adacore.com>

There is no need to keep multiplying the result once it saturates to +Inf.

gcc/ada/ChangeLog:

	* libgnat/s-powflt.ads (Maxpow_Exact): Minor comment fix.
	* libgnat/s-powlfl.ads (Maxpow_Exact): Likewise.
	* libgnat/s-powllf.ads (Maxpow_Exact): Likewise.
	* libgnat/s-valrea.adb (Large_Powfive) [1 parameter]: Exit the loop
	as soon as the result saturates to +Inf.
	(Large_Powfive) [2 parameters]: Likewise.

Tested on x86_64-pc-linux-gnu, committed on master.

---
 gcc/ada/libgnat/s-powflt.ads |  2 +-
 gcc/ada/libgnat/s-powlfl.ads |  2 +-
 gcc/ada/libgnat/s-powllf.ads |  4 ++--
 gcc/ada/libgnat/s-valrea.adb | 16 ++++++++++++++++
 4 files changed, 20 insertions(+), 4 deletions(-)
  

Patch

diff --git a/gcc/ada/libgnat/s-powflt.ads b/gcc/ada/libgnat/s-powflt.ads
index eadea7f914d..ae904f05617 100644
--- a/gcc/ada/libgnat/s-powflt.ads
+++ b/gcc/ada/libgnat/s-powflt.ads
@@ -36,7 +36,7 @@  package System.Powten_Flt is
 
    Maxpow_Exact : constant := 10;
    --  Largest power of five exactly representable with Float. It is equal to
-   --  floor (M * log 2 / log 5), when M is the size of the mantissa (24).
+   --  floor (M * log 2 / log 5), where M is the size of the mantissa (24).
    --  It also works for any number of the form 5*(2**N) and in particular 10.
 
    Maxpow : constant := Maxpow_Exact * 2;
diff --git a/gcc/ada/libgnat/s-powlfl.ads b/gcc/ada/libgnat/s-powlfl.ads
index 13630fcad40..2bf72d9c17d 100644
--- a/gcc/ada/libgnat/s-powlfl.ads
+++ b/gcc/ada/libgnat/s-powlfl.ads
@@ -36,7 +36,7 @@  package System.Powten_LFlt is
 
    Maxpow_Exact : constant := 22;
    --  Largest power of five exactly representable with Long_Float. It is equal
-   --  to floor (M * log 2 / log 5), when M is the size of the mantissa (53).
+   --  to floor (M * log 2 / log 5), where M is the size of the mantissa (53).
    --  It also works for any number of the form 5*(2**N) and in particular 10.
 
    Maxpow : constant := Maxpow_Exact * 2;
diff --git a/gcc/ada/libgnat/s-powllf.ads b/gcc/ada/libgnat/s-powllf.ads
index b470ae044de..b184b31ea9c 100644
--- a/gcc/ada/libgnat/s-powllf.ads
+++ b/gcc/ada/libgnat/s-powllf.ads
@@ -37,8 +37,8 @@  package System.Powten_LLF is
    Maxpow_Exact : constant :=
      (if Long_Long_Float'Machine_Mantissa = 64 then 27 else 22);
    --  Largest power of five exactly representable with Long_Long_Float. It is
-   --  equal to floor (M * log 2 / log 5), when M is the size of the mantissa
-   --  assumed to be either 64 for IEEE Extended or 53 for IEEE Double.
+   --  equal to floor (M * log 2 / log 5), where M is the size of the mantissa
+   --  (assumed to be either 64 for IEEE Extended or 53 for IEEE Double).
    --  It also works for any number of the form 5*(2**N) and in particular 10.
 
    Maxpow : constant := Maxpow_Exact * 2;
diff --git a/gcc/ada/libgnat/s-valrea.adb b/gcc/ada/libgnat/s-valrea.adb
index f554280c0ea..3b0f0a99a63 100644
--- a/gcc/ada/libgnat/s-valrea.adb
+++ b/gcc/ada/libgnat/s-valrea.adb
@@ -336,6 +336,7 @@  package body System.Val_Real is
       pragma Import (Ada, Powfive_300);
       for Powfive_300'Address use Powfive_300_Address;
 
+      H : Double_T;
       R : Double_T;
       E : Natural;
 
@@ -359,8 +360,15 @@  package body System.Val_Real is
          E := Exp - Maxpow;
       end if;
 
+      --  Accumulate 5**Maxpow into R until E <= Maxpow or R saturates to +Inf
+
       while E > Maxpow loop
+         H := R;
          R := R * Powfive (Maxpow);
+         if R = H then
+            E := Maxpow;
+            exit;
+         end if;
          E := E - Maxpow;
       end loop;
 
@@ -381,6 +389,7 @@  package body System.Val_Real is
       pragma Import (Ada, Powfive);
       for Powfive'Address use Powfive_Address;
 
+      H : Double_T;
       R : Double_T;
       E : Natural;
 
@@ -407,8 +416,15 @@  package body System.Val_Real is
          S := 0;
       end if;
 
+      --  Accumulate 5**Maxpow into R until E <= Maxpow or R saturates to +Inf
+
       while E > Maxpow loop
+         H := R;
          R := R * Powfive (Maxpow);
+         if R = H then
+            E := Maxpow;
+            exit;
+         end if;
          E := E - Maxpow;
       end loop;