comp.lang.ada
 help / color / mirror / Atom feed
From: hyunghwan.chung@gmail.com
Subject: GNAT Allocation of a very large record
Date: Tue, 13 Aug 2013 20:50:21 -0700 (PDT)
Date: 2013-08-13T20:50:21-07:00	[thread overview]
Message-ID: <9de9c3bf-c4c5-466f-a8cd-fca992daecbe@googlegroups.com> (raw)

Hi, 

The program at the bottom of this message, when compiled with GNAT 4.6 on Ubuntu12/x86_64, seems to corrupt memory, ending up with a malloc error message.

$ ./x1
1. Kind: POINTER_OBJECT Size:  10
x1: malloc.c:2451: sYSMALLOc: Assertion `(old_top == (((mbinptr) (((char *) &((av)->bins[((1) - 1) * 2])) - __builtin_offsetof (struct malloc_chunk, fd)))) && old_size == 0) || ((unsigned long) (old_size) >= (unsigned long)((((__builtin_offsetof (struct malloc_chunk, fd_nextsize))+((2 * (sizeof(size_t))) - 1)) & ~((2 * (sizeof(size_t))) - 1))) && ((old_top)->size & 0x1) && ((unsigned long)old_end & pagemask) == 0)' failed.
^C

On some other platforms (i.e. debian/armv5tel, gcc/gnat 4.4.5), just segmentation fault.

I expect an output like this, meaning that the second call to 'new' should raise an exception like storage_error.

$ ./x1
1. Kind: POINTER_OBJECT Size:  10
2. Allocation Failed

You'd get the result like above if you changed the upper bound of the range of Pointer_Object_Size from Storage_Count'Last to  (OBJECT_DATA_BYTES / (Object_Pointer'Max_Size_In_Storage_Elements * System.Storage_Unit)).

The new upper bound has been defined so that Pointer_Object_Record'Size don't exceed 2 ** 63 - 1 (System.Max_Int). On an 32-bit platform, the upper bound seems to be able to reach OBJECT_DATA_BYTES / Object_Pointer'Max_Size_In_Storage_Elements. With this upper bound on the 32-bit platform, Pointer_Object_Record'Size may go beyond 2 ^ 31 - 1 but Pointer_Object_Record'Max_Size_In_Storage_Elements falls below 2 ^ 31 - 1. 

Anyway, when the upper bound is set to Storage_Count'Last, Pointer_Object_Record'Max_Size_In_Storage_Elements and Pointer_Object_Record'Size seem to wrap around to an undesired value

The problem is that neither Constraint_Error nor Storage_Error is raised when the size of a record is very large. I'd like to have a graceful way to catch a ridiculously large size given to the function and handle the exception properly without ending up with segmentation fault or something similar.

Is it a bug of the GNU Ada compiler or am i doing anything wrong?

Thanks,
Hyung-Hwan

------------------------------------------------------------------------------- 
with Ada.Text_IO; 
with System;
with Ada.Unchecked_Conversion;

procedure X1 is

	type Storage_Element is mod 2 ** System.Storage_Unit;
	for Storage_Element'Size use System.Storage_Unit;
	type Storage_Offset is range -(2 ** (System.Word_Size - 1)) ..  +(2 ** (System.Word_Size - 1)) - 1;
	subtype Storage_Count is Storage_Offset range 0 .. Storage_Offset'Last;

	subtype Object_Byte      is Storage_Element;
	subtype Object_Character is Wide_Character;
	subtype Object_String    is Wide_String;

	type Object_Kind is (Pointer_Object, Character_Object, Byte_Object);
	for Object_Kind use (Pointer_Object => 0, Character_Object => 1, Byte_Object => 2);

	type Object_Record;
	type Object_Pointer is access all Object_Record;

	type Byte_Array is array (Storage_Count range <>) of Object_Byte;
	type Character_Array is array (Storage_Count range <>) of Object_Character;
	type Pointer_Array is array (Storage_Count range <>) of Object_Pointer;

	type Object_Record (Kind: Object_Kind; Size: Storage_Count) is record
		Flags: Standard.Integer range 0 .. 3;-- := 0;
		Extra: Standard.Integer range 0 .. 1;-- := 0;
		Unit:  Standard.Integer range 0 .. 4;-- := 0;
		Class: Object_Pointer;-- := null;

		case Kind is
			when Pointer_Object =>
				Pointer_Slot: Pointer_Array (1 .. Size);-- := (Others => null);
			when Character_Object =>
				Character_Slot: Character_Array (0 .. Size);-- := (Others => Object_Character'Val(0));
			when Byte_Object =>
				Byte_Slot: Byte_Array (1 .. Size);-- := (Others => 0);
		end case;
	end record;
	for Object_Record use record
		Kind  at 0 range 0 .. 7;
		Flags at 1 range 0 .. 2;
		Extra at 1 range 3 .. 3;
		Unit  at 1 range 4 .. 7;
	end record;

	subtype Empty_Object_Record is Object_Record (Byte_Object, 0);
	-- the number of bytes in an object header. this is fixed in size
	OBJECT_HEADER_BYTES: constant Storage_Count := Empty_Object_Record'Max_Size_In_Storage_Elements;
	-- the largest number of bytes that an object can hold after the header
	OBJECT_DATA_BYTES: constant Storage_Count := Storage_Count'Last - OBJECT_HEADER_BYTES;

	subtype Pointer_Object_Size is Storage_Count range
		Storage_Count'First .. (OBJECT_DATA_BYTES / (Object_Pointer'Max_Size_In_Storage_Elements * System.Storage_Unit));
	--	Storage_Count'First .. Storage_Count'Last;

	procedure Alloc_Pointer_Object (Size: in Pointer_Object_Size; Result: out Object_Pointer) is
		subtype Pointer_Object_Record is Object_Record (Pointer_Object, Size);
		type Pointer_Object_Pointer is access Pointer_Object_Record;
		function To_Object_Pointer is new Ada.Unchecked_Conversion (Pointer_Object_Pointer, Object_Pointer);
		Ptr: Pointer_Object_Pointer;
	begin
   		--Ada.Text_IO.Put_Line (Pointer_Object_Record'Size'Img);
   		--Ada.Text_IO.Put_Line (Pointer_Object_Record'Max_Size_In_Storage_Elements'Img);
		Ptr := new Pointer_Object_Record'( 
			Kind => Pointer_Object, 
			Size => Size,
			Flags => 0,
			Extra => 0,
			Unit => 0,
			Class => null,
			Pointer_Slot => (others=>null)
		);

		Result := To_Object_Pointer (Ptr);
	exception
		when others =>
			Result := null;
	end Alloc_Pointer_Object;


	ObjPtr: Object_Pointer;
begin

	Alloc_Pointer_Object (10, ObjPtr);
	if ObjPtr = null then
		Ada.Text_IO.Put_Line ("1. Allocation Failed");
	else
		Ada.Text_IO.Put_Line ("1. Kind: " & Object_Kind'Image(ObjPtr.Kind)  & " Size: " & Storage_Count'Image(ObjPtr.Size));
	end if;

	Alloc_Pointer_Object (Pointer_Object_Size'Last, ObjPtr);
	if ObjPtr = null then
		Ada.Text_IO.Put_Line ("2. Allocation Failed");
	else
		Ada.Text_IO.Put_Line ("2. Kind: " & Object_Kind'Image(ObjPtr.Kind)  & " Size: " & Storage_Count'Image(ObjPtr.Size));
	end if;

end X1;


             reply	other threads:[~2013-08-14  3:50 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-08-14  3:50 hyunghwan.chung [this message]
2013-08-14 19:32 ` GNAT Allocation of a very large record Per Sandberg
2013-08-14 20:08   ` Anh Vo
2013-08-15  1:06     ` Hyung-Hwan Chung
2013-08-15  8:59 ` Georg Bauhaus
2013-08-15 14:27 ` Robert A Duff
2013-08-16  1:18   ` Hyung-Hwan Chung
replies disabled

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox