Version 1.1 of acs/ac-00107.txt

Unformatted version of acs/ac-00107.txt version 1.1
Other versions for file acs/ac-00107.txt

!standard 13.11(16)          05-01-20 AC95-00107/01
!class confirmation 05-01-20
!status received no action 05-01-20
!status received 05-01-11
!subject Allocators and maximum object size
!summary
!appendix

!topic Allocators and maximum object size
!reference RM95-13.11(16)
!from Florian Weimer 2005-01-11
!discussion

13.11(16) should touch the subject of allocators for objects which are
larger than the supported object size (and whose size cannot be
represented in a Storage_Count object).  IMHO, an implementation
should raise Storage_Error in this case.

I think something like the code below could be used to create an ACATS
test.  The default storage pool might be affected by similar problems,
but a portable check might be impossible.

with Ada.Text_IO; use Ada.Text_IO;
with Pool; use Pool;
with System.Storage_Elements; use System.Storage_Elements;

procedure Main is

   P : Test_Pool;

   subtype String_16 is String (1 .. 16);
   type String_Array is array (Storage_Count range <>) of String_16;
   type String_Access is access String_Array;
   for String_Access'Storage_Pool use P;

   X : String_Access;

begin
   X := new String_Array
     (1 .. Storage_Count'Last / (String_16'Size
                                 / Storage_Element'Size) + 1);

exception
   when Storage_Error =>
      if not Failure then
         Put_Line ("PASSED");
      end if;
   when others =>
      Put_Line ("FAILED (unexpected exception)");
end Main;

with System; use System;
with System.Storage_Elements; use System.Storage_Elements;
with System.Storage_Pools; use System.Storage_Pools;

package Pool is

   type Test_Pool is new Root_Storage_Pool with null record;

   procedure Allocate
     (Pool : in out Test_Pool;
      Storage_Address : out Address;
      Size_In_Storage_Elements : in Storage_Count;
      Alignment : in Storage_Count);

   procedure Deallocate
     (Pool : in out Test_Pool;
      Storage_Address : in Address;
      Size_In_Storage_Elements : in Storage_Count;
      Alignment : in Storage_Count);

   function Storage_Size
     (Pool : Test_Pool)
     return Storage_Count;

   Failure : Boolean := False;

end Pool;

with Ada.Text_IO; use Ada.Text_IO;

package body Pool is

   --------------
   -- Allocate --
   --------------

   procedure Allocate
     (Pool : in out Test_Pool;
      Storage_Address : out Address;
      Size_In_Storage_Elements : in Storage_Count;
      Alignment : in Storage_Count)
   is
   begin
      Put_Line ("FAILURE");
      Failure := True;
      raise Storage_Error;
   end Allocate;

   ----------------
   -- Deallocate --
   ----------------

   procedure Deallocate
     (Pool : in out Test_Pool;
      Storage_Address : in Address;
      Size_In_Storage_Elements : in Storage_Count;
      Alignment : in Storage_Count)
   is
   begin
      null;
   end Deallocate;

   ------------------
   -- Storage_Size --
   ------------------

   function Storage_Size
     (Pool : Test_Pool)
      return Storage_Count
   is
   begin
      return 0;
   end Storage_Size;

end Pool;

****************************************************************

From: Pascal Leroy
Sent: Wednesday, January 12, 2005  3:12 AM

I disagree with this.

Overspecifying the behavior of implementations is generally a bad idea,
and trying to nail down precisely which predefined exception is raised in
what circumstances has bitten us in the past (remember Numeric_Error?).

Furthermore, it would force implementations to change for little benefits.

I agree that I would be surprised to get Tasking_Error in the situation
that you describe, but as far as I can tell, either Constraint_Error or
Program_Error is fine (the former because a computation overflowed, the
latter because this is surely a programming error).  RM95 1.1.3(2) seems
to give implementations much flexibility.

Actually, I think that Storage_Error is a bad choice if the problem is
detected during size (or dope) computation.  Storage_Error should be
reserved to cases where some actual attempt to allocate storage failed:
after a Storage_Error you are on thin ice, and you might not be able to do
much without raising Storage_Error again.  This is all going to depend
heavily on your compiler, and an application that handles Storage_Error
and expects to do anything useful is in a state of sin in my opinion.  On
the other hand, you can in practice expect to recover easily from
Constraint_Error or Program_Error.

At any rate, this is all informal discussion, and I don't think enshrining
it in the RM would be wise.

****************************************************************

From: Florian Weimer
Sent: Wednesday, January 12, 2005  4:58 AM

If the implementation raises any exception, this is fine.  However,
the standard does not permit this.  Only Allocate may raise
exceptions, and it's too late to detect the overflow at this point.

****************************************************************

From: Pascal Leroy
Sent: Wednesday, January 12, 2005  6:04 AM

RM95 1.1.3(3) requires that implementations "identify all programs or
program units that are so large as to exceed the capacity of the
implementation (or raise an appropriate exception at run time)".  In the
example you gave it's hard to see how the detection could happen at
compilation time, so it has to happen by raising an "appropriate
exception" at run time.

For a user-defined pool, if the Size_In_Storage_Elements is not in
Storage_Count, Constraint_Error will be raised anyway by the parameter
association in the (implicit) call to Allocate (assuming no exception was
raised in previous computations).

For an implementation-defined pool, there is no call to Allocate, and it
is conceivable that an implementation could do the right thing even if it
has to allocate more than Storage_Count'Last storage elements.  At any
rate, either it does the right thing, or it raises an exception.

****************************************************************

Questions? Ask the ACAA Technical Agent