< prev index next >
src/java.base/share/classes/java/lang/reflect/AccessibleObject.java
Print this page
*** 26,38 ****
--- 26,41 ----
package java.lang.reflect;
import java.lang.annotation.Annotation;
import java.security.AccessController;
+ import jdk.internal.misc.VM;
+ import jdk.internal.module.IllegalAccessLogger;
import jdk.internal.reflect.CallerSensitive;
import jdk.internal.reflect.Reflection;
import jdk.internal.reflect.ReflectionFactory;
+ import sun.security.action.GetPropertyAction;
/**
* The {@code AccessibleObject} class is the base class for {@code Field},
* {@code Method}, and {@code Constructor} objects (known as <em>reflected
* objects</em>). It provides the ability to flag a reflected object as
*** 286,328 ****
if (callerModule == declaringModule) return true;
if (callerModule == Object.class.getModule()) return true;
if (!declaringModule.isNamed()) return true;
! // package is open to caller
! String pn = packageName(declaringClass);
! if (declaringModule.isOpen(pn, callerModule)) {
! dumpStackIfOpenedReflectively(declaringModule, pn, callerModule);
! return true;
! }
!
! // package is exported to caller
! boolean isExported = declaringModule.isExported(pn, callerModule);
! boolean isClassPublic = Modifier.isPublic(declaringClass.getModifiers());
int modifiers;
if (this instanceof Executable) {
modifiers = ((Executable) this).getModifiers();
} else {
modifiers = ((Field) this).getModifiers();
}
- if (isExported && isClassPublic) {
// member is public
if (Modifier.isPublic(modifiers)) {
! dumpStackIfExportedReflectively(declaringModule, pn, callerModule);
return true;
}
// member is protected-static
if (Modifier.isProtected(modifiers)
&& Modifier.isStatic(modifiers)
&& isSubclassOf(caller, declaringClass)) {
! dumpStackIfExportedReflectively(declaringModule, pn, callerModule);
return true;
}
}
if (throwExceptionIfDenied) {
// not accessible
String msg = "Unable to make ";
if (this instanceof Field)
msg += "field ";
--- 289,330 ----
if (callerModule == declaringModule) return true;
if (callerModule == Object.class.getModule()) return true;
if (!declaringModule.isNamed()) return true;
! String pn = declaringClass.getPackageName();
int modifiers;
if (this instanceof Executable) {
modifiers = ((Executable) this).getModifiers();
} else {
modifiers = ((Field) this).getModifiers();
}
+ // class is public and package is exported to caller
+ boolean isClassPublic = Modifier.isPublic(declaringClass.getModifiers());
+ if (isClassPublic && declaringModule.isExported(pn, callerModule)) {
// member is public
if (Modifier.isPublic(modifiers)) {
! logIfExportedByBackdoor(caller, declaringClass);
return true;
}
// member is protected-static
if (Modifier.isProtected(modifiers)
&& Modifier.isStatic(modifiers)
&& isSubclassOf(caller, declaringClass)) {
! logIfExportedByBackdoor(caller, declaringClass);
return true;
}
}
+ // package is open to caller
+ if (declaringModule.isOpen(pn, callerModule)) {
+ logIfOpenedByBackdoor(caller, declaringClass);
+ return true;
+ }
+
if (throwExceptionIfDenied) {
// not accessible
String msg = "Unable to make ";
if (this instanceof Field)
msg += "field ";
*** 331,341 ****
msg += "exports";
else
msg += "opens";
msg += " " + pn + "\" to " + callerModule;
InaccessibleObjectException e = new InaccessibleObjectException(msg);
! if (Reflection.printStackTraceWhenAccessFails()) {
e.printStackTrace(System.err);
}
throw e;
}
return false;
--- 333,343 ----
msg += "exports";
else
msg += "opens";
msg += " " + pn + "\" to " + callerModule;
InaccessibleObjectException e = new InaccessibleObjectException(msg);
! if (printStackTraceWhenAccessFails()) {
e.printStackTrace(System.err);
}
throw e;
}
return false;
*** 349,400 ****
queryClass = queryClass.getSuperclass();
}
return false;
}
! private void dumpStackIfOpenedReflectively(Module module,
! String pn,
! Module other) {
! dumpStackIfExposedReflectively(module, pn, other, true);
! }
!
! private void dumpStackIfExportedReflectively(Module module,
! String pn,
! Module other) {
! dumpStackIfExposedReflectively(module, pn, other, false);
! }
!
! private void dumpStackIfExposedReflectively(Module module,
! String pn,
! Module other,
! boolean open)
! {
! if (Reflection.printStackTraceWhenAccessSucceeds()
! && !module.isStaticallyExportedOrOpen(pn, other, open))
! {
! String msg = other + " allowed to invoke setAccessible on ";
! if (this instanceof Field)
! msg += "field ";
! msg += this;
! new Exception(msg) {
! private static final long serialVersionUID = 42L;
! public String toString() {
! return "WARNING: " + getMessage();
}
- }.printStackTrace(System.err);
}
}
/**
! * Returns the package name of the given class.
*/
! private static String packageName(Class<?> c) {
! while (c.isArray()) {
! c = c.getComponentType();
! }
! String pn = c.getPackageName();
! return (pn != null) ? pn : "";
}
/**
* Get the value of the {@code accessible} flag for this reflected object.
*
--- 351,389 ----
queryClass = queryClass.getSuperclass();
}
return false;
}
! private void logIfOpenedByBackdoor(Class<?> caller, Class<?> declaringClass) {
! Module callerModule = caller.getModule();
! Module targetModule = declaringClass.getModule();
! // callerModule is null during early startup
! if (callerModule != null && !callerModule.isNamed() && targetModule.isNamed()) {
! IllegalAccessLogger logger = IllegalAccessLogger.illegalAccessLogger();
! if (logger != null) {
! logger.logIfOpenedByBackdoor(caller, declaringClass, this::toShortString);
! }
! }
! }
!
! private void logIfExportedByBackdoor(Class<?> caller, Class<?> declaringClass) {
! Module callerModule = caller.getModule();
! Module targetModule = declaringClass.getModule();
! // callerModule is null during early startup
! if (callerModule != null && !callerModule.isNamed() && targetModule.isNamed()) {
! IllegalAccessLogger logger = IllegalAccessLogger.illegalAccessLogger();
! if (logger != null) {
! logger.logIfExportedByBackdoor(caller, declaringClass, this::toShortString);
}
}
}
/**
! * Returns a short descriptive string to describe this object in log messages.
*/
! String toShortString() {
! return toString();
}
/**
* Get the value of the {@code accessible} flag for this reflected object.
*
*** 407,416 ****
--- 396,406 ----
* This method may return {@code false} on a reflected object that is
* accessible to the caller. To test if this reflected object is accessible,
* it should use {@link #canAccess(Object)}.
*
* @revised 9
+ * @spec JPMS
*/
@Deprecated(since="9")
public boolean isAccessible() {
return override;
}
*** 481,494 ****
if (this instanceof Constructor) {
targetClass = declaringClass;
} else {
targetClass = Modifier.isStatic(modifiers) ? null : obj.getClass();
}
! return Reflection.verifyMemberAccess(caller,
! declaringClass,
! targetClass,
! modifiers);
}
/**
* Constructor: only used by the Java Virtual Machine.
*/
--- 471,481 ----
if (this instanceof Constructor) {
targetClass = declaringClass;
} else {
targetClass = Modifier.isStatic(modifiers) ? null : obj.getClass();
}
! return verifyAccess(caller, declaringClass, targetClass, modifiers);
}
/**
* Constructor: only used by the Java Virtual Machine.
*/
*** 596,637 ****
final void checkAccess(Class<?> caller, Class<?> memberClass,
Class<?> targetClass, int modifiers)
throws IllegalAccessException
{
if (caller == memberClass) { // quick check
! return; // ACCESS IS OK
}
Object cache = securityCheckCache; // read volatile
if (targetClass != null // instance member or constructor
&& Modifier.isProtected(modifiers)
&& targetClass != memberClass) {
// Must match a 2-list of { caller, targetClass }.
if (cache instanceof Class[]) {
Class<?>[] cache2 = (Class<?>[]) cache;
if (cache2[1] == targetClass &&
cache2[0] == caller) {
! return; // ACCESS IS OK
}
// (Test cache[1] first since range check for [1]
// subsumes range check for [0].)
}
} else if (cache == caller) {
// Non-protected case (or targetClass == memberClass or static member).
! return; // ACCESS IS OK
}
// If no return, fall through to the slow path.
! slowCheckMemberAccess(caller, memberClass, targetClass, modifiers);
}
// Keep all this slow stuff out of line:
! void slowCheckMemberAccess(Class<?> caller, Class<?> memberClass,
Class<?> targetClass, int modifiers)
- throws IllegalAccessException
{
! Reflection.ensureMemberAccess(caller, memberClass, targetClass, modifiers);
// Success: Update the cache.
Object cache = (targetClass != null
&& Modifier.isProtected(modifiers)
&& targetClass != memberClass)
--- 583,642 ----
final void checkAccess(Class<?> caller, Class<?> memberClass,
Class<?> targetClass, int modifiers)
throws IllegalAccessException
{
+ if (!verifyAccess(caller, memberClass, targetClass, modifiers)) {
+ IllegalAccessException e = Reflection.newIllegalAccessException(
+ caller, memberClass, targetClass, modifiers);
+ if (printStackTraceWhenAccessFails()) {
+ e.printStackTrace(System.err);
+ }
+ throw e;
+ }
+ }
+
+ final boolean verifyAccess(Class<?> caller, Class<?> memberClass,
+ Class<?> targetClass, int modifiers)
+ {
if (caller == memberClass) { // quick check
! return true; // ACCESS IS OK
}
Object cache = securityCheckCache; // read volatile
if (targetClass != null // instance member or constructor
&& Modifier.isProtected(modifiers)
&& targetClass != memberClass) {
// Must match a 2-list of { caller, targetClass }.
if (cache instanceof Class[]) {
Class<?>[] cache2 = (Class<?>[]) cache;
if (cache2[1] == targetClass &&
cache2[0] == caller) {
! return true; // ACCESS IS OK
}
// (Test cache[1] first since range check for [1]
// subsumes range check for [0].)
}
} else if (cache == caller) {
// Non-protected case (or targetClass == memberClass or static member).
! return true; // ACCESS IS OK
}
// If no return, fall through to the slow path.
! return slowVerifyAccess(caller, memberClass, targetClass, modifiers);
}
// Keep all this slow stuff out of line:
! private boolean slowVerifyAccess(Class<?> caller, Class<?> memberClass,
Class<?> targetClass, int modifiers)
{
! if (!Reflection.verifyMemberAccess(caller, memberClass, targetClass, modifiers)) {
! // access denied
! return false;
! }
!
! // access okay
! logIfExportedByBackdoor(caller, memberClass);
// Success: Update the cache.
Object cache = (targetClass != null
&& Modifier.isProtected(modifiers)
&& targetClass != memberClass)
*** 641,647 ****
--- 646,674 ----
// Note: The two cache elements are not volatile,
// but they are effectively final. The Java memory model
// guarantees that the initializing stores for the cache
// elements will occur before the volatile write.
securityCheckCache = cache; // write volatile
+ return true;
+ }
+
+ // true to print a stack trace when access fails
+ private static volatile boolean printStackWhenAccessFails;
+
+ // true if printStack* values are initialized
+ private static volatile boolean printStackPropertiesSet;
+
+ /**
+ * Returns true if a stack trace should be printed when access fails.
+ */
+ private static boolean printStackTraceWhenAccessFails() {
+ if (!printStackPropertiesSet && VM.initLevel() >= 1) {
+ String s = GetPropertyAction.privilegedGetProperty(
+ "sun.reflect.debugModuleAccessChecks");
+ if (s != null) {
+ printStackWhenAccessFails = !s.equalsIgnoreCase("false");
+ }
+ printStackPropertiesSet = true;
+ }
+ return printStackWhenAccessFails;
}
}
< prev index next >