* GNAT Allocation of a very large record
@ 2013-08-14 3:50 hyunghwan.chung
2013-08-14 19:32 ` Per Sandberg
` (2 more replies)
0 siblings, 3 replies; 7+ messages in thread
From: hyunghwan.chung @ 2013-08-14 3:50 UTC (permalink / 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;
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: GNAT Allocation of a very large record
2013-08-14 3:50 GNAT Allocation of a very large record hyunghwan.chung
@ 2013-08-14 19:32 ` Per Sandberg
2013-08-14 20:08 ` Anh Vo
2013-08-15 8:59 ` Georg Bauhaus
2013-08-15 14:27 ` Robert A Duff
2 siblings, 1 reply; 7+ messages in thread
From: Per Sandberg @ 2013-08-14 19:32 UTC (permalink / raw)
Tried 4 different GCC:s and one failed:
gcc 4.4.7 20120313 (Red Hat 4.4.7-3) (GCC) x86 ok
gcc 4.6.3 20120306 (Red Hat 4.6.3-2) (GCC) x86_64 ok
gcc 4.7.3 20130318 for GNAT Pro 7.2.0w (20130317) (GCC) x86_64 ok
gcc 4.4.5 (Debian 4.4.5-8) arm (raspberry-pi) fail
It seems as there is a bug in your particular instance of GCC as well
as the GCC for the pi.
/Per
On Tue, 13 Aug 2013 20:50:21 -0700 (PDT)
hyunghwan.chung@gmail.com wrote:
> 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_Obje
ct_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;
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: GNAT Allocation of a very large record
2013-08-14 19:32 ` Per Sandberg
@ 2013-08-14 20:08 ` Anh Vo
2013-08-15 1:06 ` Hyung-Hwan Chung
0 siblings, 1 reply; 7+ messages in thread
From: Anh Vo @ 2013-08-14 20:08 UTC (permalink / raw)
On Wednesday, August 14, 2013 12:32:10 PM UTC-7, Per Sandberg wrote:
> Tried 4 different GCC:s and one failed:
>
> gcc 4.4.7 20120313 (Red Hat 4.4.7-3) (GCC) x86 ok
> gcc 4.6.3 20120306 (Red Hat 4.6.3-2) (GCC) x86_64 ok
> gcc 4.7.3 20130318 for GNAT Pro 7.2.0w (20130317) (GCC) x86_64 ok
> gcc 4.4.5 (Debian 4.4.5-8) arm (raspberry-pi) fail
It works fine with GNAT-GPL-2013 on Windows and GNATPro 7.1.1 on Red Hat x86.
A. Vo
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: GNAT Allocation of a very large record
2013-08-14 20:08 ` Anh Vo
@ 2013-08-15 1:06 ` Hyung-Hwan Chung
0 siblings, 0 replies; 7+ messages in thread
From: Hyung-Hwan Chung @ 2013-08-15 1:06 UTC (permalink / raw)
On Thursday, August 15, 2013 5:08:32 AM UTC+9, Anh Vo wrote:
> On Wednesday, August 14, 2013 12:32:10 PM UTC-7, Per Sandberg wrote:
>
> > Tried 4 different GCC:s and one failed:
> >
> > gcc 4.4.7 20120313 (Red Hat 4.4.7-3) (GCC) x86 ok
> > gcc 4.6.3 20120306 (Red Hat 4.6.3-2) (GCC) x86_64 ok
> > gcc 4.7.3 20130318 for GNAT Pro 7.2.0w (20130317) (GCC) x86_64 ok
> > gcc 4.4.5 (Debian 4.4.5-8) arm (raspberry-pi) fail
>
> It works fine with GNAT-GPL-2013 on Windows and GNATPro 7.1.1 on Red Hat x86.
>
> A. Vo
I tried gcc 4.4.7 20120313 (Red Hat 4.4.7-2) (GCC) x86_64 and it seemed to work find originally. Soon later, I wanted to confirm this at a slightly lower-level and realized that it gave me the illusion that it worked.
It raised the STORAGE_ERROR exception. But the key here is that how it was raised.
Strace reveals that there was a segmentation fault. You can guess that the program catches SIGSEGV from rt_sigaction (SIGSEGV,...) at the beginning.
$ strace ./x1
--<snip>--
rt_sigaction(SIGSEGV, {0x41ac90, [], SA_RESTORER|SA_STACK|SA_RESTART|SA_NODEFER|SA_SIGINFO, 0x7fd6ba93a920}, NULL, 8) = 0
fstat(2, {st_mode=S_IFREG|0664, st_size=2182, ...}) = 0
fstat(0, {st_mode=S_IFCHR|0620, st_rdev=makedev(4, 2), ...}) = 0
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(4, 2), ...}) = 0
brk(0) = 0xd23000
brk(0xd44000) = 0xd44000
write(1, "1. Kind: POINTER_OBJECT Size: 1"..., 34) = 34
--- SIGSEGV (Segmentation fault) @ 0 (0) ---
brk(0xd65000) = 0xd65000
write(1, "2. Allocation Failed\n", 21) = 21
exit_group(0) = ?
Ltrace reveals that the second attempt to 'new' that translated to malloc eventually requested 16 bytes only. You can also print the Pointer_Object_Record'Max_Size_In_Storage_Elements from within the program. I used ltrace to see the real value passed to the malloc function. This comes down to the overflow/wrap-around issue.
$ ltrace ./x1
-- <snip> --
malloc(104) = 0x18cd010
memcpy(0x7fff0c80a6d0, "1. Kind: ", 9) = 0x7fff0c80a6d0
memcpy(0x7fff0c80a6d9, "POINTER_OBJECT", 14) = 0x7fff0c80a6d9
memcpy(0x7fff0c80a6e7, " Size: ", 7) = 0x7fff0c80a6e7
memcpy(0x7fff0c80a6ee, " 10", 3) = 0x7fff0c80a6ee
memcpy(0x6302a8, "1. Kind: POINTER_OBJECT Size: 1"..., 33) = 0x6302a8
memcpy(0x7fff0c80a790, "1. Kind: POINTER_OBJECT Size: 1"..., 33) = 0x7fff0c80a790
fwrite("1. Kind: POINTER_OBJECT Size: 1"..., 34, 1, 0x7f630f8ad780) = 1
malloc(16) = 0x18cd080
--- SIGSEGV (Segmentation fault) ---
malloc(64) = 0x18ee010
-- <snip> --
The assembly listing for the 'new' allocation part is shown here. It was produced with the command 'gcc -S x1.adb'. You can see that it initializes the record after memory allocation. I assume that __gnat_malloc contains the check for the actual malloc failure. For this case, malloc was given 16 so I'm sure it has reached the part after 'call __gnat_malloc'. The line 'movq $0, 16(%rax)' violates the memory access for the first time as it's accessing beyond the 16 byte block allocated. I believe that the line is for 'Class => Null'. If it carried on, it would execute the code after the label .L53 starting from a few lines above it in a loop for 'Pointer_Slot => (others => null)'. That would also violate the memory access.
--<snip>--
call __gnat_malloc
movb $0, (%rax)
movq -840(%rbp), %rdx
movq %rdx, 8(%rax)
movzbl 1(%rax), %edx
andl $-8, %edx
movb %dl, 1(%rax)
movzbl 1(%rax), %edx
andl $-9, %edx
movb %dl, 1(%rax)
movzbl 1(%rax), %edx
andl $15, %edx
movb %dl, 1(%rax)
movq $0, 16(%rax)
movq -840(%rbp), %rdx
movq %rdx, %rcx
testq %rcx, %rcx
jle .L52
movl $1, %edx
.L53:
movq %rdx, %rbx
addq $1, %rbx
movq $0, 8(%rax,%rbx,8)
cmpq %rdx, %rcx
je .L52
addq $1, %rdx
jmp .L53
--<snip>--
Valgrind fails more miserably with this program. Any comments?
Thanks again,
Hyung-Hwan
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: GNAT Allocation of a very large record
2013-08-14 3:50 GNAT Allocation of a very large record hyunghwan.chung
2013-08-14 19:32 ` Per Sandberg
@ 2013-08-15 8:59 ` Georg Bauhaus
2013-08-15 14:27 ` Robert A Duff
2 siblings, 0 replies; 7+ messages in thread
From: Georg Bauhaus @ 2013-08-15 8:59 UTC (permalink / raw)
On 14.08.13 05:50, hyunghwan.chung@gmail.com wrote:
> 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
>
For the record only, On Mac OS X, using both GNAT GPL 2012 and GCC 4.8.1
I get
$ ./x1
1. Kind: POINTER_OBJECT Size: 10
x1(3471) malloc: *** mmap(size=576460752303427584) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
2. Allocation Failed
Or, with some tracing statements inserted, some in a local copy
of s-memory.adb,
$ ./x1
Size: 10
Alloc: Size as S.CRTL.size_t 104, Size 104, Actual_Size 104
1. Kind: POINTER_OBJECT Size: 10
Size: 72057594037927935
Alloc: Size as S.CRTL.size_t 576460752303423504, Size 576460752303423504, Actual_Size 576460752303423504
x1(13497) malloc: *** mmap(size=576460752303427584) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
Alloc: Size as S.CRTL.size_t 656, Size 656, Actual_Size 656
Exception name: STORAGE_ERROR
Message: heap exhausted
2. Allocation Failed
Doing as the ***-lines suggest, in the debugger, the stack frames said
that System.Memory.Alloc had been called (line 92 of s-memory.adb),
Result := c_malloc (System.CRTL.size_t (Actual_Size));
After learning about libgmalloc, I tried
$ DYLD_INSERT_LIBRARIES=/usr/lib/libgmalloc.dylib ./x1
GuardMalloc[x1-6126]: Allocations will be placed on 16 byte boundaries.
GuardMalloc[x1-6126]: - Some buffer overruns may not be noticed.
GuardMalloc[x1-6126]: - Applications using vector instructions (e.g., SSE) should work.
GuardMalloc[x1-6126]: version 25
1. Kind: POINTER_OBJECT Size: 10
GuardMalloc[x1-6126]: Attempting excessively large memory allocation: 576460752303423504 bytes
GuardMalloc[x1-6126]: If you really wanted to allocate so much memory, launch your executable with the environment variable MALLOC_PERMIT_INSANE_REQUESTS set to any value to circumvent this check.
GuardMalloc[x1-6126]: If you run under the debugger, it will automatically break here.
^C
The following little C program triggers the same message from the
mallocs:
#include <stdio.h>
#include <stdlib.h>
int main()
{
size_t what = 576460752303423504; /* 0x800000000000010 */
void *bytes;
fprintf(stdout, "d %ld u %lu x %lx\n", what, what, what);
bytes = malloc(what);
return 0;
}
The C program starts working properly on this (4GB, OS X 10.7) machine at
what = 576460752303423504 /(1<<13).
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: GNAT Allocation of a very large record
2013-08-14 3:50 GNAT Allocation of a very large record hyunghwan.chung
2013-08-14 19:32 ` Per Sandberg
2013-08-15 8:59 ` Georg Bauhaus
@ 2013-08-15 14:27 ` Robert A Duff
2013-08-16 1:18 ` Hyung-Hwan Chung
2 siblings, 1 reply; 7+ messages in thread
From: Robert A Duff @ 2013-08-15 14:27 UTC (permalink / raw)
hyunghwan.chung@gmail.com writes:
> 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
Do you have overflow checks enabled (-gnato)?
- Bob
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: GNAT Allocation of a very large record
2013-08-15 14:27 ` Robert A Duff
@ 2013-08-16 1:18 ` Hyung-Hwan Chung
0 siblings, 0 replies; 7+ messages in thread
From: Hyung-Hwan Chung @ 2013-08-16 1:18 UTC (permalink / raw)
On Thursday, August 15, 2013 11:27:41 PM UTC+9, Robert A Duff wrote:
>
> > 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
>
> Do you have overflow checks enabled (-gnato)?
>
> - Bob
Yes, I did. That didn't make any difference.
GNAT, however, is able to detect it if a predictable size is in play.
The following raises the Storage_Error exception with the message "object too large". No compile time warning is given.
--<snip>--
begin
ObjPtr := new Object_Record'(
Kind => Pointer_Object,
Size => Pointer_Object_Size'Last,
Flags => 0,
Extra => 0,
Unit => 0,
Class => null,
Pointer_Slot => (others=>null)
);
--<snip>--
end X1;
The following raises the CONSTRAINT_ERROR exception. A compile-time warning is also issued - "warning: "Constraint_Error" will be raised at run time".
--<snip>--
subtype Dummy_Object_Record is Object_Record (Pointer_Object, Pointer_Object_Size'Last);
begin
Ada.Text_IO.Put_Line (Storage_Count'Image(Dummy_Object_Record'Max_Size_In_Storage_Elements));
--<snip>--
end X1;
In my case, the type definition is rather dynamic as it uses the Size parameter passed to the function.
I put this line in Alloc_Pointer_Object before 'Ptr := new Pointer_Object_Record'...'.
Ada.Text_IO.Put_Line (Pointer_Object_Record'Max_Size_In_Storage_Elements'Img);
and generated the assembly listing, of course with -gnato enabled.
--<snip>--
call system__img_lli__image_long_long_integer
movl %eax, %edx
testl %edx, %edx
movl %eax, %edx
testl %edx, %edx
movl %eax, %edx
testl %edx, %edx
leaq -160(%rbp), %rdx
movq %rdx, -112(%rbp)
movl $1, -96(%rbp)
movl %eax, -92(%rbp)
leaq -96(%rbp), %rax
movq %rax, -104(%rbp)
movq -112(%rbp), %rdx
movq -104(%rbp), %rax
movq %rdx, %rdi
movq %rax, %rsi
call ada__text_io__put_line__2
movq -808(%rbp), %rax
salq $3, %rax
addq $7, %rax
andq $-8, %rax
addq $7, %rax
andq $-8, %rax
addq $31, %rax
andq $-8, %rax
movq %rax, %rdi
call __gnat_malloc
--<snip>--
There is no call to the range check routines. GNAT seems to produce calls to __gnat_rcheck_XX when it performs the range check for normal cases.
call __gnat_rcheck_00
call __gnat_rcheck_02
and so on.
Cheers,
Hyung-Hwan
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2013-08-16 1:18 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-08-14 3:50 GNAT Allocation of a very large record hyunghwan.chung
2013-08-14 19:32 ` 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
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox