[Ada] Add centralized capacity check in Generic_Bignums

Message ID 20200716092051.GA146384@adacore.com
State New
Headers show
Series
  • [Ada] Add centralized capacity check in Generic_Bignums
Related show

Commit Message

Pierre-Marie de Rodat July 16, 2020, 9:20 a.m.
This replaces the special case done in "**" so far.

Tested on x86_64-pc-linux-gnu, committed on trunk

gcc/ada/

	* libgnat/s-genbig.adb ("**"): Remove capacity limit check.
	Improve code by using an extended return.
	(Normalize): Perform capacity limit check here instead which is
	the centralized place where (potentially large) big integers are
	allocated.

Patch

diff --git a/gcc/ada/libgnat/s-genbig.adb b/gcc/ada/libgnat/s-genbig.adb
--- a/gcc/ada/libgnat/s-genbig.adb
+++ b/gcc/ada/libgnat/s-genbig.adb
@@ -98,6 +98,7 @@  package body System.Generic_Bignums is
    --  Given a digit vector and sign, allocate and construct a big integer
    --  value. Note that X may have leading zeroes which must be removed, and if
    --  the result is zero, the sign is forced positive.
+   --  If X is too big, Storage_Error is raised.
 
    function "**" (X : Bignum; Y : SD) return Big_Integer;
    --  Exponentiation routine where we know right operand is one word
@@ -274,32 +275,18 @@  package body System.Generic_Bignums is
                XY2  : aliased Big_Integer := X ** (Y / 2);
                XY2S : aliased Big_Integer :=
                  Big_Mul (To_Bignum (XY2), To_Bignum (XY2));
-               Res  : Big_Integer;
 
             begin
                Free_Big_Integer (XY2);
 
-               --  Raise storage error if intermediate value is getting too
-               --  large, which we arbitrarily define as 200 words for now.
-               --  ??? Consider putting a limit instead in a wrapper of
-               --  Allocate_Big_Integer and update all calls to
-               --  Allocate_Big_Integer to call this wrapper, to catch all such
-               --  cases.
-
-               if To_Bignum (XY2S).Len > 200 then
-                  Free_Big_Integer (XY2S);
-                  raise Storage_Error with
-                    "exponentiation result is too large";
-               end if;
-
-               --  Otherwise take care of even/odd cases
-
                if (Y and 1) = 0 then
                   return XY2S;
                else
-                  Res := Big_Mul (To_Bignum (XY2S), X);
-                  Free_Big_Integer (XY2S);
-                  return Res;
+                  return Res : constant Big_Integer :=
+                    Big_Mul (To_Bignum (XY2S), X)
+                  do
+                     Free_Big_Integer (XY2S);
+                  end return;
                end if;
             end;
       end case;
@@ -1108,6 +1095,8 @@  package body System.Generic_Bignums is
    -- Normalize --
    ---------------
 
+   Bignum_Limit : constant := 200;
+
    function Normalize
      (X   : Digit_Vector;
       Neg : Boolean := False) return Big_Integer
@@ -1120,6 +1109,10 @@  package body System.Generic_Bignums is
          J := J + 1;
       end loop;
 
+      if X'Last - J > Bignum_Limit then
+         raise Storage_Error with "big integer limit exceeded";
+      end if;
+
       return Allocate_Big_Integer (X (J .. X'Last), J <= X'Last and then Neg);
    end Normalize;