Java 11 vs 14 MethodHandle behavior change

Mandy Chung mandy.chung at oracle.com
Wed Apr 29 22:32:14 UTC 2020



On 4/29/20 2:07 AM, Simone Bordet wrote:
>> Did you get any exception in 14?  Is it from findVirtual or from in?
>  From findVirtual():
>
> Exception in thread "main" java.lang.IllegalAccessException: no such
> method: org.module1.MyEndPoint.onMessage(MyString)void/invokeVirtual
>      at java.base/java.lang.invoke.MemberName.makeAccessException(MemberName.java:971)
>      at java.base/java.lang.invoke.MemberName$Factory.resolveOrFail(MemberName.java:1114)
>      at java.base/java.lang.invoke.MethodHandles$Lookup.resolveOrFail(MethodHandles.java:2785)
>      at java.base/java.lang.invoke.MethodHandles$Lookup.findVirtual(MethodHandles.java:1883)
>      at org.module2.Main.main(Main.java:28)
> Caused by: java.lang.LinkageError: loader constraint violation: when
> resolving method 'void
> org.module1.MyEndPoint.onMessage(org.module1.MyString)' the class
> loader 'bootstrap' of the current class, java/lang/Object, and the
> class loader java.net.URLClassLoader @7291c18f for the method's
> defining class, org/module1/MyEndPoint, have different Class objects
> for the type org/module1/MyString used in the signature
> (java.lang.Object is in module java.base of loader 'bootstrap';
> org.module1.MyEndPoint is in unnamed module of loader
> java.net.URLClassLoader @7291c18f, parent loader 'app')
>      at java.base/java.lang.invoke.MethodHandleNatives.resolve(Native Method)
>      at java.base/java.lang.invoke.MemberName$Factory.resolve(MemberName.java:1084)
>      at java.base/java.lang.invoke.MemberName$Factory.resolveOrFail(MemberName.java:1111)
>      ... 3 more

Thanks for the reproducer.

`publicLookup().in(endPointClass1)` in JDK 13 produces a Lookup object 
on endPointClass1 with PUBLIC access only. UNCONDITIONAL bit was lost. 
The resulting Lookup can access classes unconditionally exported from 
module M that the module of endPointClass1 can read. The resulting 
Lookup is no longer a public lookup, i.e. the lookup context is the 
lookup class (i.e. endPointClass1) and the lookup mode (i.e. PUBLIC).

`publicLookup().in(endPointClass1)` in JDK 14 produces a Lookup object 
on endPointClass1 with UNCONDITIONAL bit due to the spec change for 
JDK-8173978. The resulting Lookup remains to be a public lookup which 
can access any unconditionally exported classes from any module.   
Although the lookup class of the teleported public Lookup is 
endPointClass1, it should not affect the lookup context. Unfortunately, 
the workaround for JDK-8228671 causes this bug.

The reproducer shows that the new public Lookup uses Object as the 
lookup clsas that violates the loader constraint. lookup1 finds 
"org.module1.MyEndPoint" loaded by CL1 and it adds a loader constraint 
with the boot loader (rather than CL1) due to the workaround fixed by 
JDK-8228671 that uses Object as the lookup class. When lookup2 finds 
"org.module1.MyEndPoint" loaded by CL2, the lookup fails with loader 
constraint violation.
>> The current implementation already does that.
>>
>>          private Class<?> lookupClassOrNull() {
>>              if (allowedModes == TRUSTED) {
>>                  return null;
>>              }
>>              if (allowedModes == UNCONDITIONAL) {
>>                  // use Object as the caller to pass to VM doing resolution
>>                  return Object.class;
>>              }
>>              return lookupClass;
>>          }
>>
>> What exactly have you changed?
> if (allowedModes == UNCONDITIONAL) {
>      return lookupClass;
> }

This patch will hit the assertion that JDK-8228671 ran into.   We need a 
long-term fix (perhaps to look into JDK-8173977)

> https://bugs.openjdk.java.net/browse/JDK-8244090
>

Thanks.  I will look into it.

Mandy


More information about the core-libs-dev mailing list