On 11/24/20 11:21 AM, Simone Bordet wrote:
Hi,

On Tue, Nov 24, 2020 at 7:35 PM Alan Bateman <alan.bate...@oracle.com> wrote:
On 24/11/2020 18:21, Simone Bordet wrote:
Hi,

testing the Jetty MethodHandle usages we encountered this situation:

.class org.openjdk.mh.Main
----
Class<?> klass = Main.class;
MethodHandles.Lookup lookup = MethodHandles.publicLookup().in(klass);
MethodHandle handle = lookup.findVirtual(klass, "test",
MethodType.methodType(String.class));
----

.module-info.java
----
module org.openjdk.mh {
      exports org.openjdk.mh to com.acme;
}
----

findVirtual() throws:
java.lang.IllegalAccessException: symbolic reference class is not
accessible: class org.openjdk.mh.Main, from
org.openjdk.mh.Main/noaccess (module org.openjdk.mh)

Removing the "to" clause from the exports in module-info.java fixes the issue.

Seems that a class cannot get a MethodHandle on itself, the reason
being that org.openjdk.mh is selectively exported in module-info.java.

Is this intended behavior?
I would have expected that a class could always get a MethodHandle on itself.
I tested this with 11, 15, and 16+25, all fail.

I have a simple reproducer, and I can open an OpenJDK bug.

It looks like you are starting with publicLookup and then teleporting to
mh.Main that is not accessible to that lookup. When you change it from a
qualified export  to exporting it to all modules then it becomes
accessible to the lookup so that is why it works.
The "publicLookup()" should give (minimal) access to public classes
and public methods.

We want this minimal access requirement because Jetty creates a
MethodHandle on classes that are typically written by users.
We don't want Jetty to require that users classes are "opened" (in
JPMS meaning) because we only need to access public classes and public
methods.

The problem stems while trying to run our own test cases that happen
to be in the same module (test classes are patched to main classes of
the module).
In this case, the "user class" is a test class in the same package and
module as the main classes which, differently from real "user
classes", have a more restricted JPMS exports clause.

It broke my least surprise principle that a class cannot get a
MethodHandle on one of its own public methods using publicLookup() --
I assumed a class is implicitly exported to its own module, so why
would it not work?

publicLookup allows you to access public unconditionally-exported classes.
public lookup has no lookup class as the context (as specified in the javadoc that publicLookup.in(C.class) can teleport to another public lookup on C but no change in its access - still can access all public unconditionally-exported classes).

In addition, findVirtual and other method handle lookup operations are *not* caller-sensitive but instead the access check is based on the lookup context.

MethodHandles::lookup has full-privilege access but it does not leak any access as long as the Lookup object is not leaked to other classes/modules accidentally.

You want to access public unconditionally exported user classes.  I think the test should unconditionally exported its classes in the same way as user classes, shouldn't it?


Have you tried starting with MethodHandles.lookup() ?
I do and it solves the issue at hand, but it's not the right way to
obtain the Lookup in our case because it requires more access than
needed to user classes (they must open themselves to Jetty
implementation modules).

I'd like to gently push on "why cannot a publicLookup().in(klass) work
on a public method of klass itself?".

Seems straightforward that it should, independently of exports
declarations, because it's a class "reflecting" on itself.

To detect if a class is in the same module as the caller, the API will need to be caller-sensitive which should be carefully considered [1].  What you are proposing is that Lookup::in should be caller-sensitive that is against the Lookup API design model that does the access check based on the lookup context but not the caller.

Mandy
https://openjdk.java.net/jeps/176

Thanks for bearing with my gentle push :)


Reply via email to