!standard 3.10.2 (32) 01-05-20 AI95-00229/02 !class binding interpretation 00-04-10 !status ARG approved 6-0-2 01-05-20 !status work item 01-05-04 !status received 00-04-10 !priority Medium !difficulty Medium !qualifier Omission !subject Accessibility rules and generics !summary The expression P'Access (where P denotes a subprogram declared in a generic specification) is illegal within a generic body if the expected access type is not declared within the generic unit. !question The following piece of code seems to show a case where the accessibility rules allow the creation of reference to a subprogram that doesn't exist anymore. This case doesn't seem to be caught by the "assume the worst" rule in the last sentence of RM95 3.10.2(32), because Foo is not declared in a generic body. procedure Dangle is type Ref is access procedure; P : Ref; generic package G is procedure Foo; end G; package body G is X : Natural := 0; procedure Foo is begin X := X + 1; end Foo; begin P := Foo'Access; -- Legal? (No.) end G; procedure Bar is package I is new G; -- Store a reference to I.Foo in P. begin null; end Bar; begin Bar; P.all; -- Oops, I.X is gone? end Dangle; !recommendation See wording. !wording Add after the last sentence of RM95 3.10.2(32): If the subprogram denoted by P is declared within a generic specification, and the expression P'Access occurs within the body of that generic, then the ultimate ancestor of S shall be declared within the generic unit. !discussion Evidently we want to disallow the above construct, because dangling references are a very serious safety issue. However, there is a compatibility issue here, because there may be code out there that uses access-to-subprogram types in conjunction with generics, and whatever solution we come up with could possible make existing code invalid (even if that code doesn't actually create dangling references). The proposed modification fixes the above dangling reference problem without unnecessarily impacting existing code. !corrigendum 03.10.02(32) @drepl @xindent), as determined by the expected type. The accessibility level of P shall not be statically deeper than that of @i. In addition to the places where Legality Rules normally apply (see 12.3), this rule applies also in the private part of an instance of a generic unit. The profile of P shall be subtype-conformant with the designated profile of @i, and shall not be Intrinsic. If the subprogram denoted by P is declared within a generic body, S shall be declared within the generic body.> @dby @xindent), as determined by the expected type. The accessibility level of P shall not be statically deeper than that of @i. In addition to the places where Legality Rules normally apply (see 12.3), this rule applies also in the private part of an instance of a generic unit. The profile of P shall be subtype-conformant with the designated profile of @i, and shall not be Intrinsic. If the subprogram denoted by P is declared within a generic body, S shall be declared within the generic body. If the subprogram denoted by P is declared within a generic specification, and the expression P'Access occurs within the body of that generic, then ultimate ancestor of @i shall be declared within the generic unit.> !ACATS test A B-Test is needed for this issue. !appendix From: Pascal Leroy Sent: Wednesday, April 05, 2000 3:54 AM The following piece of code seems to show a case where the accessibility rules allow the creation of reference to a subprogram that doesn't exist anymore. This case doesn't seem to be caught by the "assume the worst" rule in the last sentence of RM95 3.10.2(32), because Foo is not declared in a generic body. It seems that we either need a stronger rule (as in: "If the subprogram denoted by P is declared within a generic, S shall be declared within the generic") or a runtime check. Or am I missing something? procedure Dangle is type Ref is access procedure; P : Ref; generic package G is procedure Foo; end G; package body G is X : Natural := 0; procedure Foo is begin X := X + 1; end Foo; begin P := Foo'Access; -- You would hope that this would be illegal. end G; procedure Bar is package I is new G; -- Store a reference to I.Foo in P. begin null; end Bar; begin Bar; P.all; -- Oops, I.X is gone? end Dangle; ************************************************************* From: Steve Baird Sent: Thursday, April 06, 2000 3:44 PM > It seems that we either need a stronger rule (as in: "If the subprogram > denoted by P is declared within a generic, S shall be declared within the > generic") or a runtime check. That rule is a little more restrictive than is necessary. If the use of Some_Subprogram'Access occurs within the spec, not the body, of the generic in which Some_Subprogram is declared, then there is no need to disallow the construct (because instantiation rechecking will handle matters if the generic is instantiated in an inner scope). How bad would it be if Ada95 suddenly started disallowing the following: type Ref is access procedure; generic package G is procedure P; X : Ref := P'Access; end G; package body G is ... ; package I is new G; ? The notion of "inside a generic" may also need to be defined fairly precisely in order to handle interactions with child units of generics. ************************************************************* From: Gray, Michael Sent: Thursday, May 17, 2001 7:22 AM The following Ada 95 Language issues arose in a development we have undertaken at Naval Combat Systems, a group within BAeSYSTEMS. I have collected them together and am submitting them for consideration, as per LRM Introduction paras (58) et seq. !topic Shortcomings in the generic contract model w.r.t. access-to-subprogram types !reference RM95-3.10.2(20) !from Michael Gray !discussion The intent of the language is that access to subprogram types are never subject to run-time accessibility checks. Justification for this assertion is: (i) Rationale sect 3.7.2 para 2 says "Compile-time accessibility rules ensure that a subprogram designated by an access value cannot be called after its enclosing scope has exited.", (ii) LRM 3.10.2 (20) states "For determining whether one level is statically deeper than another when within a generic package body, the generic package is presumed to be instantiated at the same level as where it was declared; run-time checks are needed in the case of more deeply nested instantiations. Para (29), relating to access-to-object says "A check is made that the accessibility level of X is not deeper than that of the access type A. If this check fails, Program_Error is raised." There is no corresponding statement for access-to-subprogram. Consider a generic package, where the spec declares a subprogram Q, and an operation in the body assigns Q'Access to a library-level variable. If the generic instantiation is not library level, this will give rise to a dangling reference. The language could either: (i) make the instantiation illegal because of the assignment in the body - but that's a violation of the generic contract model, or (ii) insert a run-time check, but that's a violation of the principle that access to subprogram types are never subject to run-time accessibility checks. At the very least, the LRM is unclear about what is supposed to happen. This is an area where the generic contract model is rather thin; probably the least bad solution is to make it clear that run-time checks are required in the access-to-subprogam case. AI95-00254 covers some similar issues. ************************************************************* From: Randy Brukardt Sent: Wednesday, May 23, 2001 4:21 PM This issue appears to be the same as the one raised in AI-229. How is this issue different than the one in that AI (considered at last week's ARG meeting)? ************************************************************* From: Gray, Michael Sent: Thursday, May 24, 2001 4:13 AM It is the same issue. Sorry, I'm not up to speed with the protocol for establishing whether comments have previously been raised. I've just had a browse around www.ada-auth.org to try to better understand the process. Since AI-229 was considered at "last week's ARG meeting", I'll defer adding any comments until the minutes appear at www.ada-auth.org; what's the expected timescale for that? ************************************************************* From: Randy Brukardt Sent: Thursday, May 24, 2001 11:39 AM Well, about all you can do is to check the AI cross reference listing for matches. Usually searching the subjects and by the appropriate section is most helpful. Don't feel too bad about; everyone misses these from time to time. > Since AI-229 was considered at "last week's ARG meeting", I'll defer adding > any comments until the minutes appear at www.ada-auth.org; what's the expected > timescale for that? Minutes usually are finalized just before the next meeting. If it helps, here are my (raw) notes for AI-229 (I've expanded the names): > AI-229 > Tuck[er Taft] suggests merging the existing wording sentence with the new one. > Pascal [Leroy] notes that that would be a bigger change (disallows access in > spec). > John [Barnes] then wonders why we don't have this problem with objects. > Tuck[er Taft] notes that there is a runtime check there; and wonders why this > does not apply to access-to-subprogram. > Randy [Brukardt] is asked about the generic sharing problem that led to the > original rule. He explains that the problem is that the "hidden" instantiation > data parameter used for all routines declared in a generic unit cannot be added > when 'Access is used in the body (even through a "thunk" could be generated at > that point, there is no way to identify the appropriate data when calling > through the access-to-subprogram ptr.) This is not a problem for access types > declared in the generic unit as the needed parameter is included in the > profile for such types. > Eventually, the rule as proposed is retained. > Pascal [Leroy] notes that the new sentence should say "ultimate ancestor of the > access type". >Approval with changes: 6-0-2 The "changes" in this case is just the wording change as noted by Pascal. I intend to have the revised AI posted on the web site today. ************************************************************* From: Gray, Michael Sent: Friday, May 25, 2001 5:43 AM I just checked the website and didn't see an update to AI-229. But from what you say below, I think the new rule is "If the subprogram denoted by P is declared within a generic specification, and the expression P'Access occurs within the body of that generic, then the ultimate ancestor of the access type S shall be declared within the generic unit." This will make some existing code illegal. However, I believe that there is a systematic way of dealing with this, namely place: P_Access : Ref := P'Access; in the generic spec (in practice, this would generally be put in the private part of the spec); and within the generic body, replace P'Access by P_Access. That doesn't seem too bad, in terms of code impact. Of course, this could also make some existing instantiations illegal; but since they were instantiations that could give rise to a dangling reference, that doesn't seem to be a bad thing. And specifically, an instantiation at library-level accessibility can never be invalidated by this modification. Do you agree with my analysis? The new rule seems incomplete with respect to child units. In the new rule, doesn't "the expression P'Access occurs within the body of that generic" need to be extended with "or the specification or body of a child of that generic"? ************************************************************* From: Randy Brukardt Sent: Friday, May 25, 2001 9:18 PM > Do you agree with my analysis? Yes. It was expected that some existing code would be made illegal; that's the cost of eliminating dangling references. The work-around is the same one recommended for > The new rule seems incomplete with respect to child units. In the new rule, > doesn't "the expression P'Access occurs within the body of that generic" > need to be extended with "or the specification or body of a child of that > generic"? I don't claim to understand children of generics very well, but I think that they are logically generic units in their own right. Thus, the same (original) rule applies to them as well. Is there a problem case that we haven't thought of?? *************************************************************