JDK-8177036 : Class.checkMemberAccess throws NPE when calling Class methods via JNI
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.lang
  • Affected Version: 9
  • Priority: P2
  • Status: Closed
  • Resolution: Fixed
  • OS: other
  • CPU: x86
  • Submitted: 2017-03-11
  • Updated: 2017-06-06
  • Resolved: 2017-03-20
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 10 JDK 9
10Fixed 9 b163Fixed
Related Reports
Relates :  
Relates :  
Description
FULL PRODUCT VERSION :
java 9-ea
Java(TM) SE Runtime Environment (build 9-ea+159)
Java HotSpot(TM) 64-Bit Server VM (build 9-ea+159, mixed mode)

ADDITIONAL OS VERSION INFORMATION :
Windows 10 Enterprise

A DESCRIPTION OF THE PROBLEM :
I call Class method (e.g. getDeclaredFields) from JNI -- no Java code on thread stack before Class.getDeclaredFields.

checkMemberAccess in this case always throws NPE:
java.lang.NullPointerException
	at java.base/java.lang.Class.checkMemberAccess(Unknown Source)
	at java.base/java.lang.Class.getDeclaredFields(Unknown Source)
        <My JNI code>

Problematic line of code (\java.base\java\lang\Class.java:2774) :
final ClassLoader ccl = caller.getClassLoader0();

caller is always null in my case.

Proposal:
final ClassLoader ccl = ClassLoader.getClassLoader(caller);


REGRESSION.  Last worked in version 8u121


REPRODUCIBILITY :
This bug can be reproduced always.


Comments
From submitter: --------------------- >>> What language is your native code in, will it be possible for you to provide a complete test case (including native code) with which we could reproduce the issue at our end. I have C++ code that perform Java calls via JNI. Unfortunately, I am unable to provide my code. >>> The bug report has been created as a regression, so want to confirm that the reported issue does not exist in JDK 8u121 , but only in JDK 9-ea. I can confirm -- no issue with Java 8u121. Problematic code in Class.checkMemberAccess appeared in Java 9. Java 9-ea+159: private void checkMemberAccess(SecurityManager sm, int which, Class<?> caller, boolean checkProxyInterfaces) { /* Default policy allows access to all {@link Member#PUBLIC} members, * as well as access to classes that have the same class loader as the caller. * In all other cases, it requires RuntimePermission("accessDeclaredMembers") * permission. */ final ClassLoader ccl = caller.getClassLoader0(); if (which != Member.PUBLIC) { final ClassLoader cl = getClassLoader0(); if (ccl != cl) { sm.checkPermission(SecurityConstants.CHECK_MEMBER_ACCESS_PERMISSION); } } this.checkPackageAccess(sm, ccl, checkProxyInterfaces); } Java 8u121: private void checkMemberAccess(int which, Class<?> caller, boolean checkProxyInterfaces) { final SecurityManager s = System.getSecurityManager(); if (s != null) { /* Default policy allows access to all {@link Member#PUBLIC} members, * as well as access to classes that have the same class loader as the caller. * In all other cases, it requires RuntimePermission("accessDeclaredMembers") * permission. */ final ClassLoader ccl = ClassLoader.getClassLoader(caller); final ClassLoader cl = getClassLoader0(); if (which != Member.PUBLIC) { if (ccl != cl) { s.checkPermission(SecurityConstants.CHECK_MEMBER_ACCESS_PERMISSION); } } this.checkPackageAccess(ccl, checkProxyInterfaces); } } In my case (JNI call) caller is null, so caller.getClassLoader0() throws NPE in Java9. In Java 8u121 ClassLoader.getClassLoader(caller) returns null.
20-03-2017

Reverting this particular line seems like the obvious fix, but it seems we lack testing in this area so I'd like to work one out.
17-03-2017

This is a regression caused by JDK-8037325 that replaced the call from: final ClassLoader ccl = ClassLoader.getClassLoader(caller); to final ClassLoader ccl = caller.getClassLoader0();
17-03-2017

Threads can be attached with JNI AttachCurrentThread, I assume that is what the submitter is doing.
17-03-2017

There is an assumption that there is a caller on the stack. The JDK 8 implementation obtained the caller's class loader in a different way which is probably why it was not seen. Probably all @CS methods should be checked to see how they behave when invoked from native code with no callers on the stack.
17-03-2017

To submitter: ---------------- The bug report has been created as a regression, so want to confirm that the reported issue does not exist in JDK 8u121 , but only in JDK 9-ea. What language is your native code in, will it be possible for you to provide a complete test case (including native code) with which we could reproduce the issue at our end.
17-03-2017