Bug 50934 - Attribute Max_Size_In_Storage_Elements is wrong for controlled types
Summary: Attribute Max_Size_In_Storage_Elements is wrong for controlled types
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: ada (show other bugs)
Version: 4.7.0
: P3 normal
Target Milestone: 4.7.0
Assignee: Not yet assigned to anyone
URL: http://gcc.gnu.org/ml/gcc-cvs/2011-11...
Keywords:
Depends on:
Blocks:
 
Reported: 2011-10-31 15:23 UTC by simon
Modified: 2012-05-27 11:00 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments
Demonstrator (5.71 KB, application/zip)
2011-10-31 15:23 UTC, simon
Details
Simpler demonstrator (558 bytes, application/zip)
2011-11-03 08:14 UTC, simon
Details

Note You need to log in before you can comment on or make changes to this bug.
Description simon 2011-10-31 15:23:40 UTC
Created attachment 25674 [details]
Demonstrator

When I create a controlled type and an access type, the address returned by the 'new' is 16 bytes greater than the address determined within the allocator.

I've attached an example which shows this with limited controlled, but it also happens with non-limited.

I originally reported this to AdaCore as [K916-011 public] with regard to fixed-size storage pools on GNAT GPL 2011 on Mac OS X. Now, however,

* GCC 4.7.0 fails on Mac OS X with both fixed-size and global pools,
* GNAT GPL 2011 fails similarly on Debian 6 (32 bit),

so I've taken the liberty of marking the Severity as 'major'.

The attached code contains instrumented versions of the library allocators, and should be compiled "gnatmake -a allocation_test.adb".

Running with
$ gcc -v
Using built-in specs.
COLLECT_GCC=/opt/gcc-4.7-180524/bin/gcc
COLLECT_LTO_WRAPPER=/opt/gcc-4.7-180524/libexec/gcc/x86_64-apple-darwin11/4.7.0/lto-wrapper
Target: x86_64-apple-darwin11
Configured with: ../gcc-trunk-svn/configure CC='gcc -D_FORTIFY_SOURCE=0' --prefix=/opt/gcc-4.7-180524 --disable-multilib --enable-languages=c,ada --build=x86_64-apple-darwin11
Thread model: posix
gcc version 4.7.0 20111026 (experimental) [trunk revision 180524] (GCC) 

I get

$ ./allocation_test --------------------------------------------------
Allocation from fixed-size pool
First_Free = 0
Pool_Size allocated 88 at      16#7FDD68400928#, The_Pool at      16#7FDD68400928#
A ( 1) allocated at      16#7FDD68400938# or  140588913527096
First_Free = 0
Pool_Size allocated 88 at      16#7FDD68400970#, The_Pool at      16#7FDD68400928#
A ( 2) allocated at      16#7FDD68400980# or  140588913527168
First_Free = 0
Pool_Size allocated 88 at      16#7FDD684009B8#, The_Pool at      16#7FDD68400928#
A ( 3) allocated at      16#7FDD684009C8# or  140588913527240
First_Free = 0
Pool_Size allocated 88 at      16#7FDD68400A00#, The_Pool at      16#7FDD68400928#
A ( 4) allocated at      16#7FDD68400A10# or  140588913527312
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa?	@h?(	@h?
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
@h?p	@h?
cccccccccccccccccccccccccccccccccccccccccccccccc?#??	@h?
dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
--------------------------------------------------
Allocation from global pool
Pool_Global allocated 88 at  140588913527376
B ( 1) allocated at      16#7FDD68400A60# or  140588913527392
Pool_Global allocated 88 at  140588913527472
B ( 2) allocated at      16#7FDD68400AC0# or  140588913527488
Pool_Global allocated 88 at  140588913527568
B ( 3) allocated at      16#7FDD68400B20# or  140588913527584
Pool_Global allocated 88 at  140588913527664
B ( 4) allocated at      16#7FDD68400B80# or  140588913527680
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
--------------------------------------------------

The corruption in the first section, the fixed-size storage pool, is obvious; there should be 4 lines, each containing 64 'a's, 'b's etc. The reason is to be seen in the trace output; for example, in the fixed-size section,

Pool_Size allocated 88 at      16#7FDD68400928#, The_Pool at      16#7FDD68400928#
A ( 1) allocated at      16#7FDD68400928# or  140588913527096

the internally allocated address is 16#7FDD68400928# but the value seen by the calling routine is 16#7FDD68400928#, 16#10# greater.

In the default section, the corruption is less obvious, presumably because malloc() is allocating spare space anyway, but in the trace output

Pool_Global allocated 88 at  140588913527376
B ( 1) allocated at      16#7FDD68400A60# or  140588913527392

the internal and external addresses are again off by 16 (I had to use GNAT.IO internally to avoid elaboration circularity).
Comment 1 simon 2011-11-02 20:58:09 UTC
I've now traced the reason for this.

Controlled objects require some memory to be allocated to manage the chains of objects which are to be finalised when a scope is exited (this may not be strictly accurate, but is probably close enough for this PR).

It used to be the case that System.Finalization_Root.Root_Controlled contained the necessary 2 pointers.

At r177275 this was changed so that System.Finalization_Root.Root_Controlled is a null record; instead, System.Storage_Pools.Subpools.Allocate_Any_Controlled adds the necessary space to the allocated size and adjusts the returned pointer, to support  Ada.Finalization.Heap_Managenent:

	Ada.Finalization.Heap_Management provides key functionality
	associated with controlled objects on the heap, their creation,
	finalization and reclamation. Type Finalization_Collection is
	effectively a wrapper which sits ontop of a storage pool and performs
	all necessary bookkeeping for all the objects it contains. Each
	access-to-controlled or access-to-class-wide type receives a collection
	as part of its expansion. The compiler generates buffer code and
	invokes Allocate / Deallocate to create and destroy allocated
	controlled objects.

The trouble is that this means that the attribute Max_Size_In_Storage_Elements is now *wrong* for any controlled object.

It seems to me that this new approach is a remarkably non-Ada way of addressing the problem; the original design is precisely the way that it should be addressed. Of course I have absolutely no objection to delegating this management to Ada.Finalization.Heap_Management (I think this should now in fact be System.Finalization_Masters). But System.Finalization_Root.Root_Controlled should contain a System.Finalization_Masters.FM_Node.
Comment 2 simon 2011-11-03 08:14:36 UTC
Created attachment 25699 [details]
Simpler demonstrator
Comment 3 simon 2011-11-03 17:34:01 UTC
(In reply to comment #1)

> It seems to me that this new approach is a remarkably non-Ada way of addressing
> the problem; the original design is precisely the way that it should be
> addressed. Of course I have absolutely no objection to delegating this
> management to Ada.Finalization.Heap_Management (I think this should now in fact
> be System.Finalization_Masters). But System.Finalization_Root.Root_Controlled
> should contain a System.Finalization_Masters.FM_Node.

Apologies all round; this isn't correct, because a type with a component of a controlled type also needs finalization support; for example,

   type E is record
      Str : Ada.Strings.Unbounded.Unbounded_String;
   end record;
   type E_P is access E;
   for E_P'Storage_Size use E'Max_Size_In_Storage_Elements * 4;
Comment 4 simon 2012-05-27 10:22:42 UTC
This problem has been fixed in the released 4.7.0.
Comment 5 Eric Botcazou 2012-05-27 11:00:27 UTC
Indeed.