On 11/12/2015 20:38, John Rose wrote:
:


2. downward monotonic
2a. L.in(A) never has more privileges than L (for all L, A)
2b. L.in(A) never has more privileges than a full power lookup on A (for all L, A) 2c. as a corollary, a chain L.in(A).in(B).in(C)… has no more privileges than L or any lookups in A, B, C, …
Preserved with the exception of A, B and C in the same named module M and where the set modules that M reads increases (say where code in M reads additional modules).

Does this mean adding edges to the readability graph at M?
If so, then that's covered by the blanket exception mentioned later.
If you mean something else, maybe we need a point 2d.
Yes, it's adding a directed edge so that M reads other modules. Only code in M can do this.

In graph terms then the vertices in the readability graph are the modules. A directed edge from module M to module M2 means that M reads M2. The graph is mutable in that edges can be added via the API at runtime. Code in module M can add a directed edge so that M reads M2. Code in M2 might add a read edge in the other direction. Code in a module cannot change other modules: M cannot change M2 so that M2 reads M or M3 or any other module. For completeness then I should say that edges are only removed when the the vertices (modules) they connect are GC'ed.


:

That's fine.  There are two main use cases for Lookup.in,
neither of which require the tracking of long chains of L.in(A/B/C…).

A. Agent with full-power lookup wants to invoke another agent with the lookup,
but wants to limit access, because he doesn't fully trust the other agent.
He does a single L.in(A) to a remote-enough type A, creating a non-full-power lookup.
(Note:  Picking A is sometimes non-trivial.  This might be an API flaw.)

B. Agent with full-power lookup wants to get access to private nestmate in A.
He does a single L.in(A) where LC and A are in the same package member.
This works around differences between access checks at JVM and JLS levels,
just as the package-private accessor methods from javac do.  (Yuck!)

Case A is where our current approach might be too limited. This may be tied into the discussion point as to how to choose A. If A is in the same module as LC then it's as before. However if code in named module M creates a full-power lookup and chooses A in another module M2 then the resulting L.in(A) has zero access.

It wouldn't be hard to change this to allow PUBLIC be preserved so that L.in(A) would at least allow access to public types in packages that are exported unconditionally by the modules that m(A) reads. Would that increase usefulness? Would such cases be cases where PL is equally useful?

Preserving PUBLIC would mean compromising on the guarantee that there be no more access that the original but that is only because m(A) might read modules that m(LC) does not read. It would not give access to non-exported types in m(A). It would also not give access to public type in packages that are conditionally exported to m(A).



:


Going back to graceful degradation:

3e. If A is in a named module and LC in the unnamed module (or L is a public lookup), only public names readable from A are retained

And then we get:

4. downward convergence to empty privileges
4a. if A is inaccessible to LC=L.lookupClass, L.in(A) has no privileges
4b. if A and LC are in different named modules, L.in(A) has no privileges (there is no attempt to retain an intersection of readability sets)

Yes to both.



No downward convergence to publicLookup because m(publicLookup.lookupClass) must read all modules, thus a superset of the modules that named modules will read. I should say of course that the publicLookup can only be used to create method handles to public members in packages that are exported unconditionally. So nothing that code in a named module couldn't otherwise access when it increases readability.

Right.  (FWIW, the term "unconditional" is not in the Lookup javadoc.)
I looked over the javadoc after Stanislav's first mail and it does need to be expanded and improved. In particular, It does not make clear that it does not allow access to types in packages that are exported conditionally (or "qualified exports" as we have been calling them).



Should there be a way to build a lookup, for two modules M1/M2, which
reads those names of M2 which M1 can read, except no internals
of M1?  I wonder if such a thing would be useful?  Probably not.

But it would be useful to have a lookup in a module M1 which can
read the exports of *every* M2 that M1 can see, except no M1 internals.
(This includes the unconditionally exported public names of M1.)
This would be a Lookup with an LC in M1 and flags of PUBLIC only.

I guess that is the effect of PL.in(M1) and point 3a, right?
Yes, PL.in(M1) gives us this.

More specifically, if C1 is a public and in a package exported by M1 then PL.in(C1) will result in a Lookup that is C1/public. This lookup can only be used to access public types in packages that are exported unconditionally and only by modules that M1 reads (assume M1 reads itself).

Alternatively, if C2 is a type in M2 that is not in an exported package then PL.in(C2) will result in a Lookup that is C2/noaccess. This is of course because PL.lookupClass() has no access to C2.



:

OK, then:

5. publicLookup has a reasonable minimal set of globally acceptable privileges 5a. this set of privileges is singular, and does not depend on the lookupClass (but it will always be in the unnamed module) 5b. the only possible results of publicLookup.in(A) are no change, and (following 3e) a public-only access from a named module
Yes to all of these.




We have looked of taking snapshots and persisting intersections but it diverges from bytecode behavior which I think rules it out.

Well, other lookups diverge from bytecode behavior also, but only by
dropping away access modes (like private, package, etc.).
This covers use case A above.  You could argue that intersecting
readability sets is useful in a similar way, but it is way too complex.
We don't aspire to create a Lookup object on exactly three API
points and no more—that's overkill.  A hypothetical application
that wants to express intersections (or unions) of Lookup capabilities
can build this on top of lookups.

Yes, the intersection would be complex, more so when qualified exports are taken into account. Preserving PUBLIC might be a compromise, assuming it is useful.

-Alan

Reply via email to