From c7799a8108e2e53e80d41281e5625b78236d039a Mon Sep 17 00:00:00 2001 From: Eric Botcazou <ebotcazou@adacore.com> Date: Tue, 17 Dec 2024 20:00:38 +0100 Subject: [PATCH] ada: Add guard to System.Val_Real.Large_Powfive against pathological input 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. --- 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(-) diff --git a/gcc/ada/libgnat/s-powflt.ads b/gcc/ada/libgnat/s-powflt.ads index eadea7f914db..ae904f056173 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 13630fcad40a..2bf72d9c17d3 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 b470ae044de8..b184b31ea9c0 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 f554280c0ead..3b0f0a99a638 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; -- GitLab