mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 23:04:50 +02:00
8221642: AccessibleObject::setAccessible throws NPE when invoked by JNI code with no java frame on stack
Reviewed-by: alanb
This commit is contained in:
parent
4dbebb62aa
commit
9c0104b9c9
3 changed files with 174 additions and 27 deletions
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -168,6 +168,15 @@ public class AccessibleObject implements AnnotatedElement {
|
|||
* open module. </li>
|
||||
* </ul>
|
||||
*
|
||||
* <p> This method may be used by <a href="{@docRoot}/../specs/jni/index.html">JNI code</a>
|
||||
* with no caller class on the stack to enable access to a {@link Member member}
|
||||
* of {@link Member#getDeclaringClass() declaring class} {@code D} if and only if:
|
||||
* <ul>
|
||||
* <li> The member is {@code public} and {@code D} is {@code public} in
|
||||
* a package that the module containing {@code D} {@link
|
||||
* Module#isExported(String,Module) exports} unconditionally. </li>
|
||||
* </ul>
|
||||
*
|
||||
* <p> This method cannot be used to enable access to private members,
|
||||
* members with default (package) access, protected instance members, or
|
||||
* protected constructors when the declaring class is in a different module
|
||||
|
@ -246,6 +255,11 @@ public class AccessibleObject implements AnnotatedElement {
|
|||
* }
|
||||
* }</pre>
|
||||
*
|
||||
* <p> If this method is invoked by <a href="{@docRoot}/../specs/jni/index.html">JNI code</a>
|
||||
* with no caller class on the stack, the {@code accessible} flag can
|
||||
* only be set if the member and the declaring class are public, and
|
||||
* the class is in a package that is exported unconditionally. </p>
|
||||
*
|
||||
* <p> If there is a security manager, its {@code checkPermission} method
|
||||
* is first called with a {@code ReflectPermission("suppressAccessChecks")}
|
||||
* permission. </p>
|
||||
|
@ -304,6 +318,16 @@ public class AccessibleObject implements AnnotatedElement {
|
|||
throw new IllegalCallerException(); // should not happen
|
||||
}
|
||||
|
||||
if (caller == null) {
|
||||
// No caller frame when a native thread attaches to the VM
|
||||
// only allow access to a public accessible member
|
||||
boolean canAccess = Reflection.verifyPublicMemberAccess(declaringClass, declaringClass.getModifiers());
|
||||
if (!canAccess && throwExceptionIfDenied) {
|
||||
throwInaccessibleObjectException(caller, declaringClass);
|
||||
}
|
||||
return canAccess;
|
||||
}
|
||||
|
||||
Module callerModule = caller.getModule();
|
||||
Module declaringModule = declaringClass.getModule();
|
||||
|
||||
|
@ -312,12 +336,7 @@ public class AccessibleObject implements AnnotatedElement {
|
|||
if (!declaringModule.isNamed()) return true;
|
||||
|
||||
String pn = declaringClass.getPackageName();
|
||||
int modifiers;
|
||||
if (this instanceof Executable) {
|
||||
modifiers = ((Executable) this).getModifiers();
|
||||
} else {
|
||||
modifiers = ((Field) this).getModifiers();
|
||||
}
|
||||
int modifiers = ((Member)this).getModifiers();
|
||||
|
||||
// class is public and package is exported to caller
|
||||
boolean isClassPublic = Modifier.isPublic(declaringClass.getModifiers());
|
||||
|
@ -341,25 +360,37 @@ public class AccessibleObject implements AnnotatedElement {
|
|||
}
|
||||
|
||||
if (throwExceptionIfDenied) {
|
||||
// not accessible
|
||||
String msg = "Unable to make ";
|
||||
if (this instanceof Field)
|
||||
msg += "field ";
|
||||
msg += this + " accessible: " + declaringModule + " does not \"";
|
||||
if (isClassPublic && Modifier.isPublic(modifiers))
|
||||
msg += "exports";
|
||||
else
|
||||
msg += "opens";
|
||||
msg += " " + pn + "\" to " + callerModule;
|
||||
InaccessibleObjectException e = new InaccessibleObjectException(msg);
|
||||
if (printStackTraceWhenAccessFails()) {
|
||||
e.printStackTrace(System.err);
|
||||
}
|
||||
throw e;
|
||||
throwInaccessibleObjectException(caller, declaringClass);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void throwInaccessibleObjectException(Class<?> caller, Class<?> declaringClass) {
|
||||
boolean isClassPublic = Modifier.isPublic(declaringClass.getModifiers());
|
||||
String pn = declaringClass.getPackageName();
|
||||
int modifiers = ((Member)this).getModifiers();
|
||||
|
||||
// not accessible
|
||||
String msg = "Unable to make ";
|
||||
if (this instanceof Field)
|
||||
msg += "field ";
|
||||
msg += this + " accessible";
|
||||
msg += caller == null ? " by JNI attached native thread with no caller frame: " : ": ";
|
||||
msg += declaringClass.getModule() + " does not \"";
|
||||
if (isClassPublic && Modifier.isPublic(modifiers))
|
||||
msg += "exports";
|
||||
else
|
||||
msg += "opens";
|
||||
msg += " " + pn + "\"" ;
|
||||
if (caller != null)
|
||||
msg += " to " + caller.getModule();
|
||||
InaccessibleObjectException e = new InaccessibleObjectException(msg);
|
||||
if (printStackTraceWhenAccessFails()) {
|
||||
e.printStackTrace(System.err);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
|
||||
private boolean isSubclassOf(Class<?> queryClass, Class<?> ofClass) {
|
||||
while (queryClass != null) {
|
||||
if (queryClass == ofClass) {
|
||||
|
@ -409,7 +440,11 @@ public class AccessibleObject implements AnnotatedElement {
|
|||
* is set to {@code true}, i.e. the checks for Java language access control
|
||||
* are suppressed, or if the caller can access the member as
|
||||
* specified in <cite>The Java Language Specification</cite>,
|
||||
* with the variation noted in the class description. </p>
|
||||
* with the variation noted in the class description.
|
||||
* If this method is invoked by <a href="{@docRoot}/../specs/jni/index.html">JNI code</a>
|
||||
* with no caller class on the stack, this method returns {@code true}
|
||||
* if the member and the declaring class are public, and the class is in
|
||||
* a package that is exported unconditionally. </p>
|
||||
*
|
||||
* @param obj an instance object of the declaring class of this reflected
|
||||
* object if it is an instance method or field
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue