Version 1.1 of ais/ai-00058.txt

Unformatted version of ais/ai-00058.txt version 1.1
Other versions for file ais/ai-00058.txt

!standard E.2.1 (08)          98-03-27 AI95-00058/06
!class ramification 95-06-25
!status work item 95-06-25
!status received 95-06-25
!priority High
!difficulty Hard
!subject Accessibility Rules for Shared_Passive Packages
!summary 98-03-27
Consider a library unit P1, and a shared passive library unit P2. The accessibility level of P1 is considered deeper than, and statically deeper than, that of P2, unless the declaration of P2 depends semantically on the declaration of P1.
Bob will update this to address issues raised in the April 1998 meeting:
???Or within the scope of a with_clause. E.g. if we're in the body of one of the shared passive packages, then we know about more with_clauses, and we want to be able to take advantage of that case.
??Perhaps define "not statically deeper" or "not known to be statically deeper", since the rules require "not statically deeper". "Known to not be statically deeper".
Compile-time accessibility rules are enforced accordingly.
Similarly, for a run-time Accessibility_Check that involves accessibility levels defined in terms of a shared passive library unit and one that is not shared passive, then the check is done as usual -- Program_Error is raised if the check fails.
However, if the accessibility levels to be checked (at run time) are defined in terms of accessibility of two shared passive library units, then an implementation need not perform the check. If the implementation ensures that all shared passive library units have the same lifetime as the program as a whole, then omitting such checks cannot cause dangling pointers. On the other hand, if the implementation allows shared passive partitions to come and go during execution of the program as a whole, then the undetected failure of such a check can cause dangling pointers; ???Improve wording: in that case, the program's execution is defined to be erroneous.
!question 96-09-09
E.2.1(8-8.b) says:
8 {accessibility [from shared passive library units]} {notwithstanding} Notwithstanding the definition of accessibility given in 3.10.2, the declaration of a library unit P1 is not accessible from within the declarative region of a shared passive library unit P2, unless the shared passive library unit P2 depends semantically on P1.
8.a Discussion: We considered a more complex rule, but dropped it. This is the simplest rule that recognizes that a shared passive package may outlive some other library package, unless it depends semantically on that package. In a nondistributed program, all library packages are presumed to have the same lifetime.
8.b Implementations may define additional pragmas that force two library packages to be in the same partition, or to have the same lifetime, which would allow this rule to be relaxed in the presence of such pragmas.
But 3.10.2 uses the notions of "accessibility levels" that are "the same as" or "deeper than" other accessibility levels. So what does E.2.1(8) mean by "accessible from"?
!response 98-03-27
Within a single partition, it is possible to have an access value that designates a library level object in any library package. This model assumes that library-level data is addressable from pretty much anywhere, and that all library units have the same lifetime.
However, in a multi-partition program, these properties do not hold. Data in an active partition is not addressable from any other partition. Data in a shared passive partition may or may not be addressable, depending on the with_clauses. Furthermore, partitions can come and go at arbitrary times. The goal of E.2.1(8) is to prevent dangling pointer problems that could be caused by pointers from shared passive partitions to other (active or shared passive) partitions. By "dangling pointer", we really mean two situations here: (1) dereferencing a pointer to some data in a different partition that is not addressable from this partition; (2) dereferencing a pointer to some data in a different partition, when that partition no longer exists.
Note that Annex E assumes the following properties:
- If a normal package with's a shared passive package, then the
shared passive partition containing the shared passive package lives at least as long as the active partition containing the normal package.
- If a shared passive package with's another shared passive package,
then the shared passive partition containing the second package lives at least as long as the shared passive partition containing the first package.
In other words, a with_clause of A upon (shared passive) B constitutes a statement that the partition containing A will be able to address the partition containing B.
Example 1:
package P1 is X: aliased Integer; end P1;
package P2 is pragma Shared_Passive(P2); type A is access all Integer; Y: A; end P2;
with P1, P2; procedure Main is begin P2.Y := P1.X'access; --Illegal. end Main;
The intent of E.2.1(8) is that the above assignment be illegal, and the above summary achieves that. P1 is part of the active partition. If the above were legal, we would have a pointer from the shared passive partition to the active partition. A different active partition could attempt to dereference P2.Y, when the variable P1.X is not even addressable by that partition. The active partition containing P1.X might not even exist anymore.
Note that the above summary implies that two library units can both be deeper than each other:
Example 2:
package P1 is pragma Shared_Passive(P1); type A is access all Integer; Y: A;
X: aliased Integer; end P1;
package P2 is pragma Shared_Passive(P2); type A is access all Integer; Y: A;
X: aliased Integer; end P2;
with P1, P2; procedure Main is begin P2.Y := P1.X'access; --Illegal. P1.Y := P2.X'access; --Illegal. end Main;
P1 and P2 are both statically deeper than each other. Therefore, both assignments are illegal. This prevents problems caused by one shared passive partition living longer than the other. It also prevents problems of pointers across address spaces -- if another active partition had visibility upon P1, it could follow the invalid pointer into P2, which is not addressable.
If P2 were to say "with P1;" then we would know that P1 lives at least as long as P2, so the "P2.Y := P1.X'Access;" assignment would be legal. Note that the wording of the summary makes it clear that the with_clause has to be on the declaration of P2, not the body. (It corrects the wording of E.2.1(8), which says "unless the shared passive library unit P2 depends semantically on P1", which makes no sense, since semantic dependence is between pairs of library_items, not library units.)
The compile-time accessibility rules must be checked with this potentially-circular notion of deepness in mind. However, implementation of the corresponding run-time checks would be a serious implementation burden, and would be inefficient. Consider:
Example 3:
package P1 is pragma Shared_Passive(P1); X: aliased Integer; end P1;
package P2 is pragma Shared_Passive(P2); type A is access all Integer; Y: A; end P2;
procedure P3(Z: access Integer);
with P2; procedure P3(Z: access Integer) is begin P2.Y := P2.A(Z); -- Erroneous. ??Not on all implementations P2.Y := Z.all'access; -- Erroneous. "Possibly erroneous?" end P3;
with P1, P3; procedure Main is begin P3(Z => P1.X'access); end Main;
In this case, it is not known at compile time of P3, whether Z designates an object in P1. Furthermore, given the potential circularities in deepness, it is not easy to check this at run time. Therefore, we define the above situation to be erroneous.???On some implementations.
The accessibility rules in question are those on 'Access (where the result type is a general access type, or an access-to-subprogram type), type_conversion (where the target type is a general access type, or an access-to-subprogram type), and type extension. Note that the accessibility rule in 9.5.4(6), which has to do with requeues, is irrelevant to this discussion.
However, there is one case in which the run-time error can be easily and efficiently detected: An implementation can prevent the creation of pointers from shared passive partitions to active partitions by assigning an accessibility level of -1 to shared passive library units, and doing the run-time checks accordingly (presuming normal library units are at level 0). This is likely to be a common case. We therefore require this particular case to be detected. Note that this technique is not general, since it does not prevent the creation of pointers from one shared passive partition to another shared passive partition.
If we were to remove the "pragma Shared_Passive(P1);", then P1 would be part of the active partition, and the lines marked "-- Erroneous."??? would instead raise Program_Error.
Example 4 illustrates various consequences of the rules given in this AI:
package P1 is pragma Shared_Passive(P1); type A is access all Integer; Y: A;
X: aliased Integer;
type T1 is tagged null record;
protected type Protected_Type is ... end; -- A return-by-ref type. Protected_Object: Protected_Type; end P1;
package P2 is pragma Elaborate_Body(P2); -- So we can have a body. pragma Shared_Passive(P2); type A is access all Integer; Y: A;
X: aliased Integer; end P2;
with P1; package body P2 is type T2 is new P1.T1 with null record; -- Illegal. -- This is illegal, even though we know that we're going to -- live as long as P1. We don't know that on our spec.
function F return P1.Protected_Type is begin return P1.Protected_Object; -- Erroneous.??? end F;
procedure Proc is begin Y := P1.X'access; -- Illegal. end Proc; end P2;
generic package G is pragma Shared_Passive(G); procedure Proc; end G;
with P1; package body G is function F return P1.Protected_Type is begin return P1.Protected_Object; -- Erroneous.??? end F;
procedure Proc is begin ... F ... end Proc; end G;
package P3 is pragma Elaborate_Body(P3); -- So we can have a body. pragma Shared_Passive(P3); type A is access all Integer; Y: A;
X: aliased Integer; end P3;
with G; package body P3 is package G_Instance is new G; begin G_Instance.Proc; -- Causes erroneous??? execution. end P3;
!appendix

!section E.2.1(08)
!subject Vestigial reference to old accessibility rules
!reference RM9X-E.2.1(8);5.95
!from Norman Cohen
!reference as: 94-5035.c Norman H. Cohen 94-12-19>>
!discussion

This paragraph still talks of "accessibility from" a declarative region
rather than accessibility levels.  Oh well.  A clarification in the AARM
would be in order.

****************************************************************

!section E.2.1(08)
!subject Vestigial reference to old accessibility rules
!reference RM9X-E.2.1(8);5.95
!reference 94-5035.c Norman H. Cohen 94-12-19
!from Bob Duff
!reference as: 94-5037.c Bob Duff 94-12-19>>
!discussion

> This paragraph still talks of "accessibility from" a declarative region
> rather than accessibility levels.  Oh well.  A clarification in the AARM
> would be in order.

Caught red handed!

I knew about this bug, and decided it wasn't worth fixing.
It's not clear how to word it using "levels", since these
things don't have a particular order -- the core language doesn't
have any similar notion, where things are inaccessible from
each other.

However, I think the intent is clear.  We'll see if the compiler writers
agree...

****************************************************************

!section E.2.1(08)
!subject request for clarification
!reference RM95-E.2.1(8)
!from Tom Burger (tom@ixi.saic.com) 95-06-12
!keywords accessible
!reference as: 95-5154.a Tom Burger 95-6-13>>
!discussion
While developing ACVC tests for the Distribution Annex I found
the meaning of this paragraph to be quite elusive.  Further
explanation or an example would be very helpful.  Thanks.

****************************************************************

!section E.2.1(08)
!subject request for clarification
!reference RM95-E.2.1(8)
!from Tom Burger (tom@ixi.saic.com) 95-06-12
!keywords accessible
!reference 95-5154.a Tom Burger 95-6-13
!reference as: 95-5156.a Robert A Duff 95-6-14>>
!discussion

> While developing ACVC tests for the Distribution Annex I found
> the meaning of this paragraph to be quite elusive.  Further
> explanation or an example would be very helpful.  Thanks.

package P1 is
   X: aliased Integer;
end P1;

package P2 is
   type A is access Integer;
   Y: A;
end P2;

Is "Y := X'Access;" legal?  According to 3.10.2, this is legal.
If we make P2 Shared_Passive, it's illegal, by E.2.1(8), unless
we add "with P1;" to P2.

Normally, all library packages are in the same address space, and live
"forever", so you can freely create pointers from one to the other.
But if a P2 is shared passive, it can live longer than P1, which might
be part of a partition that executes and then disappears.  So we don't
allow pointers from P2 to P1.  OTOH, if P2 says "with P1;", then P1 will
live at least as long as P2, so E.2.1(8) doesn't forbid the 'Access in
that case.

The "Y := X'Access;" statement is in some active partition, I'm
assuming, and it says "with" of P1 and P2.

The "accesible from" wording is somewhat of a cheat, I admit, since
3.10.2 is written in terms of "levels" and "deeper than".  In E.2.1,
it's not a question of being deeper, it's just that this thing can't
point to that thing.

- Bob

****************************************************************

!section E.2.1(08)
!section E.2.1(8)
!subject request for clarification
!reference RM95-E.2.1(8)
!reference AARM-E.2.1(8a)
!reference 95-5154.a Tom Burger 95-6-13
!from Anthony Gargaro 95-06-14
!keywords accessible, shared passive packages
!reference as: 95-5157.a Anthony Gargaro  95-6-14>>
!discussion

> While developing ACVC tests for the Distribution Annex I found
> the meaning of this paragraph to be quite elusive.  Further
> explanation or an example would be very helpful.  Thanks.

The purpose of this paragraph is to ensure that values accessible through a
shared passive package always designate valid objects. For example, unless
this rule is present, consider the consequences of compiling and partitioning
the following library units:

package SP is
  pragma Shared_Passive;
  type Ref_F is access function return Integer;
  F : Ref_F;
end SP;

package Abnormal is
  pragma Pure;
  function F return Integer;
end Abnormal;

package body Abnormal is
  function F return Integer is
  begin
    return 100;
  end F;
end Abnormal;

with SP, Abnormal, Text_IO;
procedure Ptn_1 is
begin
  SP.F := Abnormal.F'Access;
  Text_IO.Put_Line("Value is" & Integer'Image(SP.F.all));
end Ptn_1;

with SP, Text_IO;
procedure Ptn_2 is
begin
  Text_IO.Put_Line("Value is" & Integer'Image(SP.F.all));
end Ptn_2;

There is no guarantee that Ptn_1 and Ptn_2 will be assigned to the same
partition; thus, the assignment to SP.F by Ptn_1 may result in Ptn_2
dereferencing an invalid access value in another partition. By requiring that
SP semantically depends upon Abnormal protects against such an invalid
reference.


****************************************************************

!section E.2.1(00)
!subject General access types should be disallowed in Shared_Passive
!reference RM95-E.2.1
!from Laurent Guerby 96-08-23
!keywords distribution, Shared_Passive, general access type
!reference 96-5645.a Laurent Guerby  96-8-23>>
!discussion

E.2.1 Shared Passive Library Units

1   [A shared passive library unit is used for managing global data shared
between active partitions.  The restrictions on shared passive library units
prevent the data or tasks of one active partition from being accessible to
another active partition through references implicit in objects declared in
the shared passive library unit.]

>> Sources showing the issue.

-- On some storage node.
package SP is
   pragma Shared_Passive;

   type A is access all Integer;
   -- General access type.

   P : A;

end SP;

-- On  some processing node
with SP;
package Local_PN is
   I : aliased Integer := 2;
end Local_PN;

with SP, Local_PN;
procedure Main_PN is
begin

   SP.P := Local_PN.I'access;
   -- SP.P points back to PN address space.

end Main_PN;

--
Laurent Guerby <guerby@gnat.com>, Team Ada.
   "Use the Source, Luke. The Source will be with you, always (GPL)."

****************************************************************

!section E.2.1(00)
!subject General access types should be disallowed in Shared_Passive
!reference RM95-E.2.1
!keywords distribution, Shared_Passive, general access type
!reference as: 96-5645.a Laurent Guerby  96-8-23
!from Anthony Gargaro 96-8-24
!reference 96-5648.a Anthony Gargaro  96-8-24>>
!discussion

>> Sources showing the issue.

> ...

>with SP, Local_PN;
>procedure Main_PN is
>begin

>   SP.P := Local_PN.I'access;
>   -- SP.P points back to PN address space.

>end Main_PN;

It is my understanding that this example is illegal since
SP does not depend upon Local_PN as required by E.2.1(8).

****************************************************************

!section E.2.1(00)
!subject General access types should be disallowed in Shared_Passive
!reference RM95-E.2.1
!keywords distribution, Shared_Passive, general access type
!reference 96-5645.a Laurent Guerby  96-8-23
!from Anthony Gargaro 96-8-24
!reference 96-5648.a Anthony Gargaro  96-8-24
!from Bob Duff
!reference 96-5653.a Robert A Duff 96-8-27>>
!discussion

> >> Sources showing the issue.
>
> > ...
>
> >with SP, Local_PN;
> >procedure Main_PN is
> >begin
>
> >   SP.P := Local_PN.I'access;
> >   -- SP.P points back to PN address space.
>
> >end Main_PN;
>
> It is my understanding that this example is illegal since
> SP does not depend upon Local_PN as required by E.2.1(8).

That is certainly the intent.  This is the subject of AI-58, which has
never been considered by the ARG, nor have I written a draft version of
the AI.  Clearly, the above should be illegal.  However, it is not
entirely clear to me what the rule is in the case of dynamic
accessibility checks -- that is, imagine passing Local_PN.I'access as an
access parameter.

- Bob

****************************************************************

!section E.2.1(08)
!subject AI-58: Editorial
!reference AI95-00058/04
!from Offer Pazy 96-11-22
!reference 96-5767.a Offer Pazy  96-11-22>>
!discussion

I believe that there is a small error in the discussion of Example 2:

> ...
>   with P1, P2;
>   procedure Main is
>   begin
>      P2.Y := P1.X'Access; --Illegal.
>      P1.Y := P2.X'Access; --Illegal.
>   end Main;
>
> . . .
>
> If P2 were to say "with P1;" then we would know that
> P2 lives at least as long as P1,
  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> so the "P2.Y := P1.X'Access;" assignment would be legal.

I think that this is backwards: If P2 withes P1, then we know that P1 lives 
as least as long as P2, not the other way arround. The assignment is still 
(or "therefore" :-) legal.

Offer Pazy
48 Be'eri St.
Tel-Aviv 64233
Israel
972-3-695-1923
pazy@world.std.com


****************************************************************

!section E.2.1(08)
!subject AI-58: Drop the support for hierarchical memory configurations
!reference RM95-E.2.1(8)
!reference AI95-00058/04
!from Offer Pazy 96-11-22
!reference 96-5768.a Offer Pazy  96-11-22>>
!discussion

I would like to start by arguing that resorting to erroneous execution in 
this case is very bad news. The features discussed and the interactions 
among them are not considered unsafe, they cannot be easily localized and 
the erroneous usage is likely to result from actions of programmers on the 
one hand and system builders on the other. Also, note that it is very likely 
that the affected applications are (very) large programs. It is not clear to 
me what guidelines one could give to his group to avoid such cases without 
significantly limiting the usefulness of Annex E. Errors resulting from this 
can be extremely subtle and very hard to find (let alone predict in advance) 
even for a more experienced user. Most other cases where we have resorted to 
erroneousness are either obscure or use unsafe features and hence are 
usually marked by a pragma or a certain with clause.  This is not the case 
here, where the constructs are "mainstream: and their usage may appear in 
many places in the code's body.

So this is my main problem and I would like the ARG to consider this AI with 
this in mind, this is a very serious erroneousness case.

Based on this general objective, I would like to propose another approach to 
address the real problem that is expressed in the AI, and that is to abandon 
the (very ambitious) goal of supporting in the standard the idea of 
hierarchical memory configurations (HMCs) (those that allow passive 
partitions to come and go). From the outset, we knew that the support of 
this is at best partial; we leave all issues of explicit partition abort, 
reload, and restart outside the ARM, features that must be provided in some 
form by the implementation to support HMCs. Furthermore, the partitioning 
and configuration steps are treated by the ARM as conceptual only, we give 
very few hints on what they should do.  This was done intentionally since we 
understood that we cannot achieve more standardization here.

Essentially, what has happened at an early stage of the mapping, was that we 
saw this "nice feature" and thought that we could get this interesting model 
 in the annex, almost free. Later revisions, and this AI proved us wrong. In 
order to really support HMCs, much more definition work in needed in the 
language to do it right, and it's not easy. Furthermore, while some may 
argue, I do believe that there are still many applications for the flat 
memory model without supporting HMCs; it's nice to have, but not critical.
If the objective of supporting HMCs causes us to make straight-forward 
distributed programs erroneous in a serious manner, then I think we are 
making the wrong decision.

So basically, my suggestion is to give up on the standard support of HMCs. 
We should leave this entire model as impl-defined (as is most of it now 
anyway) and fix whatever is necessary in the accessibility rules for the 
flat model (the AI does it already as is discussed under the third example). 
The flat model will be the default one and the only model required by the 
annex. Implementations will then be free to support HMCs fully and to add 
whatever pragmas or rules to address this specific problem.

I think that the majority of users will gain by this!!!



Offer Pazy
48 Be'eri St.
Tel-Aviv 64233
Israel
972-3-695-1923
pazy@world.std.com


****************************************************************

Questions? Ask the ACAA Technical Agent