MethodHandles.Lookup and modules
stanislav lukyanov
stanislav.lukyanov at oracle.com
Thu Dec 10 19:20:20 UTC 2015
Alan,
thanks for the comments!
Please see below.
On 10.12.2015 1:16, Alan Bateman wrote:
>
> On 09/12/2015 14:54, stanislav lukyanov wrote:
>>
>> 1) Lookup.in() javadoc says
>> "If the lookup for this Lookup is in a named module, and the new
>> lookup class is in a different
>> module M, then no members, not even public members in M's exported
>> packages, will be accessible"
>> However, it seems to be possible to have PUBLIC access after
>> lookupInA.in(ClassInB.class)
>> without breaking "no more access capabilities than the original" rule.
>>
>> Are such transitions intentionally forbidden?
> Yes, this is intention as the lookup class and mode bits would
> otherwise not be sufficient when you teleport through a sequence of
> lookup classes. It might be clearer if you extend the example to
> in(B.class).in(C.class).in(D.class) where B, C and D are in different
> named modules and work out the intersection.
This is connected to the second part of the question (2).
If access to readable modules were allowed only if MODULE bit is set,
transition from A to B would be safe, since only one transition could be
made (actually, same as it is now, but not from unnamed module only).
BTW, 'requires public' chain could be traversed safely even with PUBLIC
mode:
A.in(B).in(C).in(D) would have access to D's exported members and D's
'requires public' - same as A.
WDYT?
>> 2) Lookup.in() javadoc says
>> "If the lookup class for this Lookup is not in a named module, and
>> the new lookup class is
>> in a named module M, then no members in M's non-exported packages
>> will be accessible"
>>
>> Spec says nothing about M's 'requires' and 'exports to M'.
>> In current implementation, modules required by M are still accessible
>> and packages exported to M (with 'exports to') are not accessible.
>>
>> It seems right that packages exported to M are not accessible.
>> Should it be specified in the javadoc, or is it implied due to
>> definitions somewhere else?
> It is implied because the javadoc provides the guarantee that the
> resulting Lookup has no more access than the original. In this case
> there are packages exported by M's friends to M that are not
> accessible to code in unnamed modules. However, I think you are right
> that this could be make clearer in the javadoc. I'm sure that once the
> design settles down that we'll do several passes over the javadoc.
OK, thanks!
Is there a JBS RFE that aggregates such issues, or anything like that?
>
>> :
>>
>> However, this creates some uncertainty.
>> Suppose we have A requires B. From user's point resulting lookup of
>> publicLookup().in(ClassInA.class)
>> may or may not have access to the module B - it depends on module A's
>> 'requires' which user doesn't know about.
>>
>> It may come to the following situation. Code
>> publicLookup().in(BlassInA.class).findStatic(ClassInB.class, "m",
>> ...).invoke()
>> works with version of A that have 'requires B'.
>> In the next version, A removes 'requires B' which should not
>> have any impact on A's users, but the code above stops working.
> Sure, the other thing is that readability graph can mutate at run-time
> so that `A` reads additional modules.
Method handles API is really "conservative" in regard of access control
and I believe it supposed to be nearly as safe
as plain method calls (since Lookup basically reproduces bytecode-level
checks).
I think it shouldn't allow something just because reflection API is able
to do the trick anyway.
After all, it doesn't go easy with method access checks despite we have
Method.setAccessible
>>
>>
>> 3) publicLookup() seems to allow work around the module access control.
>> publicLookup() is available for any module and has access to any
>> module's exported packages.
>> So, if we have modules A and B that do not require each other, we can
>> still access B from A:
>> // code in A
>> publicLookup().in(ClassInB.class)
>>
>> Is it OK to be able to do such tricks?
>
>
> The publicLookup can only be used to access types that are are public
> and in packages that are exported unconditionally. It can't be used to
> break encapsulation, either directly or by teleporting and using a
> lookup class in another module.
>
> Also `A` can call addReads to read any other module so this allows it
> to access any public type in any package exported by other modules if
> it really wants. This means that there is nothing that the
> publicLookup can be used to access that `A` can't access anyway.
I understand that the exported packages could be accessed from outside
anyway, so privacy of B is not violated.
But isn't dependency mechanism supposed to prevent A from using B unless
A have deliberately declared the dependency (via module-info or addReads)?
One more thing about javadoc.
publicLookup() spec says
- "As a matter of pure convention, the lookup class of this lookup
object will be in an unnamed module."
It's not about pure convention anymore - it really matters now where
publicLookup() resides.
- "Discussion: The lookup class can be changed to any other class C
using an expression of the form publicLookup().in(C.class)."
publicLookup().in(A.class) doesn't necessarily preserve access
capabilities anymore, so this text is not true now.
Thanks,
Stas
More information about the jigsaw-dev
mailing list