[Ada] Test for object too large

Arnaud Charlet charlet@adacore.com
Wed Apr 15 10:28:00 GMT 2009


Test on object too large on a 32-bit machine were not generating an exception.
This patch adds a special front end test that at least catches some common
cases for array types.

The following program:

procedure obj_too_large is
   function id (x : integer) return integer is
   begin return x; end;
   type m is array
     (integer'first .. id (integer'last)) of integer;
   type p is access m;
   pv : p;
begin
   pv := new m;
end;

executed on a 32-bit machine previously executed silently
(allocating some junk too small array), with the patch it
generates:

raised STORAGE_ERROR : obj_too_large.adb:9 object too large

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

2009-04-15  Robert Dewar  <dewar@adacore.com>

	* exp_ch4.adb (Expand_N_Allocator): Install test for object too large

-------------- next part --------------
Index: exp_ch4.adb
===================================================================
--- exp_ch4.adb	(revision 146089)
+++ exp_ch4.adb	(working copy)
@@ -2935,6 +2935,11 @@ package body Exp_Ch4 is
       --  constrain. Such occurrences can be rewritten as aliased objects
       --  and their unrestricted access used instead of the coextension.
 
+      function Size_In_Storage_Elements (E : Entity_Id) return Node_Id;
+      --  Given a type E, returns a node representing the code to compute the
+      --  size in storage elements for the given type. This is not as trivial
+      --  as one might expect, as explained in the body.
+
       ---------------------------------------
       -- Complete_Coextension_Finalization --
       ---------------------------------------
@@ -3031,8 +3036,10 @@ package body Exp_Ch4 is
 
                      --  Retrieve the declaration of the body
 
-                     Decl := Parent (Parent (
-                               Corresponding_Body (Parent (Parent (S)))));
+                     Decl :=
+                       Parent
+                         (Parent
+                            (Corresponding_Body (Parent (Parent (S)))));
                      exit;
                   end if;
 
@@ -3161,6 +3168,74 @@ package body Exp_Ch4 is
          Analyze_And_Resolve (N, PtrT);
       end Rewrite_Coextension;
 
+      ------------------------------
+      -- Size_In_Storage_Elements --
+      ------------------------------
+
+      function Size_In_Storage_Elements (E : Entity_Id) return Node_Id is
+      begin
+         --  Logically this just returns E'Max_Size_In_Storage_Elements.
+         --  However, the reason for the existence of this function is
+         --  to construct a test for sizes too large, which means near the
+         --  32-bit limit on a 32-bit machine, and precisely the trouble
+         --  is that we get overflows when sizes are greater than 2**31.
+
+         --  So what we end up doing is using this expression for non-array
+         --  types, where it is not quite right, but should be good enough
+         --  most of the time. But for non-packed arrays, instead we compute
+         --  the expression:
+
+         --    number-of-elements * component_type'Max_Size_In_Storage_Elements
+
+         --  which avoids this problem. All this is a big bogus, but it does
+         --  mean we catch common cases of trying to allocate arrays that
+         --  are too large, and which in the absence of a check results in
+         --  undetected chaos ???
+
+         if Is_Array_Type (E) and then Is_Constrained (E) then
+            declare
+               Len : Node_Id;
+               Res : Node_Id;
+
+            begin
+               for J in 1 .. Number_Dimensions (E) loop
+                  Len :=
+                    Make_Attribute_Reference (Loc,
+                      Prefix         => New_Occurrence_Of (E, Loc),
+                      Attribute_Name => Name_Length,
+                      Expressions    => New_List (
+                        Make_Integer_Literal (Loc, J)));
+
+                  if J = 1 then
+                     Res := Len;
+
+                  else
+                     Res :=
+                       Make_Op_Multiply (Loc,
+                         Left_Opnd  => Res,
+                         Right_Opnd => Len);
+                  end if;
+               end loop;
+
+               return
+                 Make_Op_Multiply (Loc,
+                   Left_Opnd  => Len,
+                   Right_Opnd =>
+                     Make_Attribute_Reference (Loc,
+                       Prefix => New_Occurrence_Of (Component_Type (E), Loc),
+                       Attribute_Name => Name_Max_Size_In_Storage_Elements));
+            end;
+
+            --  Here for other than non-bit-packed array
+
+         else
+            return
+              Make_Attribute_Reference (Loc,
+                Prefix         => New_Occurrence_Of (E, Loc),
+                Attribute_Name => Name_Max_Size_In_Storage_Elements);
+         end if;
+      end Size_In_Storage_Elements;
+
    --  Start of processing for Expand_N_Allocator
 
    begin
@@ -3272,6 +3347,36 @@ package body Exp_Ch4 is
          Complete_Coextension_Finalization;
       end if;
 
+      --  Check for size too large, we do this because the back end misses
+      --  proper checks here and can generate rubbish allocation calls when
+      --  we are near the limit. We only do this for the 32-bit address case
+      --  since that is from a practical point of view where we see a problem.
+
+      if System_Address_Size = 32
+        and then not Storage_Checks_Suppressed (PtrT)
+        and then not Storage_Checks_Suppressed (Dtyp)
+        and then not Storage_Checks_Suppressed (Etyp)
+      then
+         --  The check we want to generate should look like
+
+         --  if Etyp'Max_Size_In_Storage_Elements > 3.5 gigabytes then
+         --    raise Storage_Error;
+         --  end if;
+
+         --  where 3.5 gigabytes is a constant large enough to accomodate
+         --  any reasonable request for
+
+         Insert_Action (N,
+           Make_Raise_Storage_Error (Loc,
+             Condition =>
+               Make_Op_Gt (Loc,
+                 Left_Opnd => Size_In_Storage_Elements (Etyp),
+                 Right_Opnd =>
+                   Make_Integer_Literal (Loc,
+                     Intval => Uint_7 * (Uint_2 ** 29))),
+             Reason    => SE_Object_Too_Large));
+      end if;
+
       --  Handle case of qualified expression (other than optimization above)
 
       if Nkind (Expression (N)) = N_Qualified_Expression then


More information about the Gcc-patches mailing list