|
Prev: Design help
Next: FYI - Lead Designer of Ada Dies
From: msimonides on 13 Mar 2007 11:25 I have experienced problems upon using an access to tagged type object converted to an access to ancestor type - Storage_Error is raised when calling its operations. After some investigation I found out that address of object (obtained like this: Object_Ptr.all'Address) is different after conversion. Using Unchecked_Deallocation for converting the access value solved the problem. The situation is analogous to that in program below: with System.Address_Image; use System; with Ada.Text_IO; use Ada.Text_IO; procedure IFace_Cast_Bug is type Root_Type is interface; type Root_Access is access all Root_Type'Class; type Additional_Operations_Type is interface and Root_Type; type Additional_Operations_Access is access all Additional_Operations_Type'Class; type Root_Implementation_Type is new Root_Type with null record; type Root_Implementation_Access is access all Root_Implementation_Type'Class; type Final_Implementation_Type is new Root_Implementation_Type and Additional_Operations_Type with null record; type Final_Implementation_Access is access all Final_Implementation_Type'Class; function To_Additional_Operations (Object_Ptr : Final_Implementation_Access) return Additional_Operations_Access is begin return Additional_Operations_Access (Object_Ptr); end To_Additional_Operations; Object_Ptr : constant Final_Implementation_Access := new Final_Implementation_Type; Iface_Ptr : constant Additional_Operations_Access := To_Additional_Operations (Object_Ptr); begin Put (Address_Image (Object_Ptr.all'Address)); Put (" /= "); Put_Line (Address_Image (IFace_Ptr.all'Address)); end IFace_Cast_Bug; The output of this program is two addresses, the first one 4 less than the second one (in my original program the difference is 12). Removing the Root_Implementation_Type tagged type from inheritance hierarchy results in identical addresses. The question is: Am I doing something wrong with the conversion? I believe that upcasting should be perfectly safe and operations defined for the target type should work on the access (and even incorrect downcast should raise Constraint_Error instead of a Storage_Error postponed to the first use). To me this looks like a compiler bug. I am using GNAT GPL 3.4.6 on Linux. -- Marcin Simonides
From: Robert A Duff on 13 Mar 2007 12:06 msimonides(a)power.com.pl writes: > The output of this program is two addresses, the first one 4 less than > the second one (in my original program the difference is 12). > Removing the Root_Implementation_Type tagged type from inheritance > hierarchy results in identical addresses. > > The question is: > Am I doing something wrong with the conversion? I don't know (I didn't read your code carefully), but it is normal for access values pointing at the same object to be represented by different addresses, depending on which interface you are viewing the object as. This is because C++ works that way, and GNAT mimics the C++ conventions in order to make interfacing Ada with C++ easier. C++ has a more powerful form of multiple inheritance than Ada does. If we didn't care about interfacing, we could implement Ada without this somewhat-strange offsetting of the addresses. > To me this looks like a compiler bug. Could be. - Bob
From: Adam Beneschan on 13 Mar 2007 12:54 On Mar 13, 9:06 am, Robert A Duff <bobd...(a)shell01.TheWorld.com> wrote: > msimoni...(a)power.com.pl writes: > > The output of this program is two addresses, the first one 4 less than > > the second one (in my original program the difference is 12). > > Removing the Root_Implementation_Type tagged type from inheritance > > hierarchy results in identical addresses. > > > The question is: > > Am I doing something wrong with the conversion? > > I don't know (I didn't read your code carefully), but it is normal for > access values pointing at the same object to be represented by different > addresses, depending on which interface you are viewing the object as. > This is because C++ works that way, and GNAT mimics the C++ conventions > in order to make interfacing Ada with C++ easier. I still think 'Address should be the same, though. The definition of X'Address for an object X is that it is "the address of the first of the storage elements allocated to X"; and here, after IFace_Ptr has been converted from Object_Ptr by a legal type conversion, IFace_Ptr.all and Object_Ptr.all are the same object, so their 'Address should be the same. It may be the case that IFace_Ptr and Object_Ptr are represented as different addresses in memory, and that if you used an Unchecked_Conversion on the access objects themselves, you might see different values. But Marcin's code didn't use Unchecked_Conversion; the 'Addresses should be the same, and if the addresses stored in memory are different, the compiler needs to adjust for this when computing 'Address. This definitely seems like a compiler bug. -- Adam
From: Robert A Duff on 13 Mar 2007 13:35 "Adam Beneschan" <adam(a)irvine.com> writes: > I still think 'Address should be the same, though. The definition of > X'Address for an object X is that it is "the address of the first of > the storage elements allocated to X";... Good point. - Bob
From: Simon Wright on 13 Mar 2007 16:56
Judging by the result of compiling with -gnatdg (output intermediate form) and -gnata (assertions), the compiler seems to be complaining that Root_Implementation_Type isn't an interface. So I guess it's confused (which would explain the strange (lack of) error messages). Is this conversion of access values legal in Ada 95? if so -- live and learn! |