* 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