CVS difference for ai05s/ai05-0234-1.txt
--- ai05s/ai05-0234-1.txt 2010/11/18 07:07:36 1.2
+++ ai05s/ai05-0234-1.txt 2010/11/19 04:36:43 1.3
@@ -1,4 +1,4 @@
-!standard 7.6(17.1/3) 10-11-15 AI05-0234-1/00
+!standard 6.5(21/3) 10-11-18 AI05-0234-1/01
!class binding interpretation 10-11-15
!status work item 10-11-15
!status received 10-10-31
@@ -8,6 +8,8 @@
!subject Hole in AI05-0051-1
!summary
+Plug access discriminant accessibility checking holes for functions and
+allocators.
!question
@@ -55,15 +57,213 @@
& Integer'Image (Extension (Ptr.all).Discrim.all));
end Cw_Alloc;
+Are the access discriminant accessibility checks associated with allocators and
+function returns performed even in the case where the existence of those
+discriminants is not known statically at the point of the check? (Yes.)
+Are access discriminants of subcomponents also checked in the case where the
+subtype of the subcomponent is unconstrained? (Yes.)
+
!wording
+Modify 4.8(10.1/3) as (modified by AI05-0051-1) as follows:
+
+ For any allocator, if the designated type of the type of the
+ allocator is class-wide, then a check is made that the
+ accessibility level of the type determined by the
+ subtype_indication, or by the tag of the value of the
+ qualified_expression, is not deeper than that of the type of the
+ allocator. If the subtype determined by the subtype_indication or
+ qualified_ expression {(or by the tag of the value of the qualified
+ expression if the type of the qualified expression is class-wide)}
+ of the allocator has one or more access discriminants, then a
+ check is made that the accessibility level of the anonymous access
+ type of each access discriminant is not deeper than that of the
+ type of the allocator. Program_Error is raised if either such check
+ fails.
+
+Replace 6.5(21/3) (as modified by AI05-0051-1) with:
+
+ If any part (ignoring the values of bounds and discriminants) of the return
+ object of a function (or a coextension thereof) has one or more access
+ discriminants whose value is not constrained by the result subtype of the
+ function, a check is made that the accessibility level of the anonymous
+ access type of each access discriminant is not deeper than the level of the
+ return object as determined by the point of call (see 3.10.2). If this check
+ fails, Program_Error is raised.
+
+Add a (massive) AARM note after 6.5(21/3):
+
+ For a function with a classwide result type, the access values that
+ need to be checked are determined by the tag of the return object.
+ In order to implement this accessibility check in the case where
+ the tag of the result is not known statically at the point of the
+ return statement, an implementation may need to somehow
+ associate with the tag of a specific tagged
+ type an indication of whether the type has unconstrained access
+ discriminants (explicit or inherited) or has any subcomponents
+ with such discriminants. If an implementation is already maintaining
+ a statically initialized descriptor of some kind for each specific
+ tagged type, then an additional Boolean could be added to this
+ descriptor.
+
+ Note that the flag should only be queried in the case where any
+ access discriminants which the result object might have would
+ have subtypes with "bad" accessibility levels (as determined by
+ the rules of 3.10.2 for determining the accessibility level of
+ the type of an access discriminant in the expression or
+ return_subtype_indication of a return statement).
+
+ Thus, in a case like
+
+ type Global is access T'Class;
+ function F (Ptr : Global) return T'Class is
+ begin
+ return Ptr.all;
+ end F;
+
+ there is no need for a runtime accessibility check. The setting
+ of the bit doesn't matter and there is no need to query it.
+
+ On the other hand, given
+
+ function F return T'Class is
+ Local : T'Class := ... ;
+ begin
+ return Local;
+ end F;
+
+ In this case, a check would typically be required.
+
+ The need for including subcomponents in this check is illustrated by
+ the following example:
+
+ X : aliased Integer;
+
+ type Component_Type (Discrim : access Integer := X'Access)
+ is limited null record;
+
+ type Undiscriminated is record
+ Fld : Component_Type;
+ end record;
+
+ function F return Undiscriminated is
+ Local : aliaed Integer;
+ begin
+ return X : Untagged := (Fld => (Discrim => Local'Access)) do
+ Foo;
+ end return;
+ -- raises Program_Error after calling Foo.
+ end F;
+
+ Ramification:
+ In the case where the tag of the result is not known statically
+ at the point of the return statement and the runtime accessibility
+ check is needed, discriminant values and array bounds
+ play no role in performing this check. That is, array components are
+ assumed to have non-zero length and components declared
+ within variant parts are assumed to be present Thus, the check
+ may be implemented simply by testing the aforementioned descriptor
+ bit and conditionally raising Program_Error.
!discussion
+The language already specifies accessibility checks for access discriminants in
+the case of allocators (to ensure that discriminant values refer do not refer to
+something that is shorter-lived than the access type) and for function results
+(to ensure that discriminant values do not refer to something that is
+shorter-lived than the eventual destination of the function result, as
+determined by the point of call).
+
+In the case where the designated type of an access type is classwide, say
+T'Class, it needs to be made clear that this check is based on the tag of the
+allocated object. A check may be required even if, for example, T is
+undiscriminated.
+
+In the case where a function result type is classwide, a similar check is
+needed. The problem is illustrated by the following two examples:
+
+ procedure Cw_Alloc is
+ type Root is tagged null record;
+ type Ref is access Root'Class;
+
+ type Extension (Discrim : access Integer)
+ is new Root with null record;
+
+ function Bad_News return Ref is
+ Local_Int : aliased Integer := 123;
+ Local_Ext : aliased Extension (Discrim => Local_Int'Access);
+ type Local_Ref is access all Root'Class;
+ for Local_Ref'Storage_Size use 0;
+ Local_Ptr : Local_Ref := Local_Ext'Access;
+ begin
+ return new Root'Class'(Local_Ptr.all);
+ -- fails accessibility check? (yes)
+ end Bad_News;
+
+ Ptr : Ref := Bad_News;
+ begin
+ -- If we reach this point, Ptr.Discrim is a dangling reference
+ ...
+ end Cw_Alloc;
+
+ procedure Cw_Return is
+ type Root is tagged null record;
+ type Extension (Discrim : access Integer)
+ is new Root with null record;
+
+ function Bad_News return Root'Class is
+ Local_Int : aliased Integer := 123;
+ Local_Ext : aliased Extension (Discrim => Local_Int'Access);
+ type Local_Ref is access all Root'Class;
+ for Local_Ref'Storage_Size use 0;
+ Local_Ptr : Local_Ref := Local_Ext'Access;
+ begin
+ return Local_Ptr.all;
+ -- fails accessibility check? (yes)
+ end Bad_News;
+
+ Obj : Root'Class := Bad_News;
+
+ begin
+ -- If we reach this point, Obj.Discrim is a dangling reference
+ ...
+ end Cw_Return;
+
+In addition, these checks also need to be generalized to handle the case of a
+subcomponent which has defaulted access discriminant values, as in
+
+ X : aliased Integer;
+
+ type Subcomponent_Type (Discrim : access Integer := X'Access)
+ is limited null record;
+
+ type Component_Type is record S : Subcomponent_Type; end record;
+ type Undiscriminated is record
+ Fld : Component_Type;
+ end record;
+
+ function F return Undiscriminated is
+ Local : aliaed Integer;
+ begin
+ return X : Untagged
+ := (Fld => (S => (Discrim => Local'Access))) do
+
+ Foo;
+ end return;
+ -- raises Program_Error after calling Foo.
+ end F;
+
!ACATS Test
+Add an ACATS C-Test to check that the exception is raised in examples like the
+ones given in this AI.
+
+!ASIS
+
+No impact.
+
From: Steve Baird
Sent: Tuesday, November 2, 2010 8:08 PM
@@ -1320,6 +1520,78 @@
a Ramification that makes it clear that we intended that result. It's not a TBH,
simply because the wording says precisely this ("any part" means exactly that,
not any part that happens to be currently selected).
+
+****************************************************************
+
+From: Steve Baird
+Sent: Thursday, November 18, 2010 7:19 PM
+
+[Most of this note became version /01 of the AI - Editor.]
+
+...
+ To be honest:
+ In the case where the tag of the result is not known statically
+ at the point of the return statement and the runtime accessibility
+ check is needed, discriminant values and array bounds
+ play no role in performing this check. That is, array components are
+ assumed to have non-zero length and components declared
+ within variant parts are assumed to be present Thus, the check
+ may be implemented simply by testing the aforementioned descriptor
+ bit and conditionally raising Program_Error.
+
+ [Randy - if I understand you correctly, you don't think this needs a
+ TBH label. My concern is in the opposite direction - it seems to
+ me that this requires explicit RM wording. We haven't talked
+ at all about the "vanilla" (i.e., specific result type) case, but
+ what about
+
+ Might_Be_Zero : Natural := ...;
+
+ type T (D : access Integer := null) is
+ limited tagged null record;
+
+ type Vector is array (1 .. Might_Be_Zero) of T;
+
+ function F return Vector is
+ Local : aliased Integer;
+ Result : Vector := (others => (D => Local'Access));
+ begin
+ return Result;
+ end F;
+
+ Clearly this fails the accessibility check if Might_Be_Zero
+ is nonzero. What happens if Might_Be_Zero equals zero?
+
+ It would be odd to allow conservative "assume all arrays
+ have non-zero length" behavior in the classwide result type
+ case described above, but not in this case. It seems that
+ this needs to be nailed down one way or the other. Bother!
+ I was hoping we were almost done with this one.]
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Thursday, November 18, 2010 10:15 PM
+
+I don't see the problem. The operative wording is "any part of the return
+object"; "any part" is something that has to be determined statically, and thus
+the values of bounds and discriminants are irrelevant (they cannot be known in
+general).
+
+If there is a problem, it occurs because this is a dynamic semantics rule, and
+thus someone could be confused by the fact that "any part" is determined
+statically. (It is *always* determined statically, so far as I know, but that
+isn't obvious.)
+
+If this was just English wording, I would probably suggest adding "possible":
+
+ If any possible part of the return object...
+
+But that isn't formal enough. Probably you are right and normative words need to
+be added:
+
+ If any part of the return object (ignoring the values of bounds and
+ discriminants) of a function ...
****************************************************************
Questions? Ask the ACAA Technical Agent