JDK-8221530 : Field::get and reflective member access not handling caller = null when invoked by JNI code with no java frames on stack
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.lang:reflect
  • Affected Version: 12
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2019-03-27
  • Updated: 2021-06-28
  • Resolved: 2019-04-06
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 12 JDK 13
12.0.2Fixed 13 b16Fixed
Related Reports
CSR :  
Duplicate :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
JDK 12 throws a null-pointer exception in internal JDK implementation code at a simple `java.lang.Integer.TYPE` field access. 

jdk.internal.reflect.Reflection.getCallerClass() is returning null for some reason and thus checkAccess(caller, obj); fails

Fix Request This fixes a regression introduced in JDK 12. The backport will require three (test-only) subsequent fixes: JDK-8222078, JDK-8222082, JDK-8222111 The patch had to be slightly modified, so a review was requested (and approved): http://mail.openjdk.java.net/pipermail/core-libs-dev/2019-April/059717.html Mach 5 (with all four fixes) is green.

[~igerasim] Please exclude the spec change for backport (the spec change is in java/lang/reflect/AccessibleObject.java).

The spec changes are not appropriate to back-port. The original change also had a CSR.

Review thread: http://mail.openjdk.java.net/pipermail/core-libs-dev/2019-March/059360.html

I propose to tighten the check and enforce strong encapsulation: when there is no caller frame, it is allowed to access public members of a public type in an unconditional exported API package. That is, the current access check is performed by checking if a type is in an exported API package at least to the module of a caller class. When the caller class is not available, it will check if a type is exported unconditionally. If a native thread attaches to the VM and attempts to access a non-public member or a public member in a non-exported type e.g. jdk.internal.misc.Unsafe, it will throw IAE whereas the access check succeeds in JDK 11. It is illegal to access a non-exported type and I also think the compatibility risk is low as this only happens to a native code creating its VM and attach to it and access a non-exported type via JNI. webrev: http://cr.openjdk.java.net/~mchung/jdk13/webrevs/8221530/webrev.00/index.html IAE message is something like: Exception in thread "main" java.lang.IllegalAccessException: JNI attached native thread (null caller frame) cannot access class jdk.internal.misc.Unsafe (in module java.base) because module java.base does not export jdk.internal.misc

When a native thread attaches to the VM, there is no caller frame. AFAICT there is no clear semantics what reflection should behave in that case. JNI call to access `java.lang.Integer.TYPE` field happens to work since it is called very early at runtime and AccessibleObject::cache is null and happens to match null caller (cache == caller). Another related note: JDK 8 Reflection::verifyMemberAccess [1] requires currentClass and memberClass be non-null. That checks were not present in JDK 9 (need to understand why that was taken out). [1] http://hg.openjdk.java.net/jdk8u/jdk8u-dev/jdk/file/308ec99c6172/src/share/classes/sun/reflect/Reflection.java#l87