< prev index next >

src/java.base/share/classes/java/lang/reflect/AccessibleObject.java

Print this page

        

@@ -26,13 +26,16 @@
 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,43 +289,42 @@
 
         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());
+        String pn = declaringClass.getPackageName();
         int modifiers;
         if (this instanceof Executable) {
             modifiers = ((Executable) this).getModifiers();
         } else {
             modifiers = ((Field) this).getModifiers();
         }
-        if (isExported && isClassPublic) {
 
+        // 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)) {
-                dumpStackIfExportedReflectively(declaringModule, pn, callerModule);
+                logIfExportedByBackdoor(caller, declaringClass);
                 return true;
             }
 
             // member is protected-static
             if (Modifier.isProtected(modifiers)
                 && Modifier.isStatic(modifiers)
                 && isSubclassOf(caller, declaringClass)) {
-                dumpStackIfExportedReflectively(declaringModule, pn, callerModule);
+                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,11 +333,11 @@
                 msg += "exports";
             else
                 msg += "opens";
             msg += " " + pn + "\" to " + callerModule;
             InaccessibleObjectException e = new InaccessibleObjectException(msg);
-            if (Reflection.printStackTraceWhenAccessFails()) {
+            if (printStackTraceWhenAccessFails()) {
                 e.printStackTrace(System.err);
             }
             throw e;
         }
         return false;

@@ -349,52 +351,39 @@
             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();
+    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);
                 }
-            }.printStackTrace(System.err);
         }
     }
 
     /**
-     * Returns the package name of the given class.
+     * Returns a short descriptive string to describe this object in log messages.
      */
-    private static String packageName(Class<?> c) {
-        while (c.isArray()) {
-            c = c.getComponentType();
-        }
-        String pn = c.getPackageName();
-        return (pn != null) ? pn : "";
+    String toShortString() {
+        return toString();
     }
 
     /**
      * Get the value of the {@code accessible} flag for this reflected object.
      *

@@ -407,10 +396,11 @@
      * 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,14 +471,11 @@
         if (this instanceof Constructor) {
             targetClass = declaringClass;
         } else {
             targetClass = Modifier.isStatic(modifiers) ? null : obj.getClass();
         }
-        return Reflection.verifyMemberAccess(caller,
-                                             declaringClass,
-                                             targetClass,
-                                             modifiers);
+        return verifyAccess(caller, declaringClass, targetClass, modifiers);
     }
 
     /**
      * Constructor: only used by the Java Virtual Machine.
      */

@@ -596,42 +583,60 @@
 
     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;             // ACCESS IS OK
+            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;     // ACCESS IS OK
+                    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;             // ACCESS IS OK
+            return true;             // ACCESS IS OK
         }
 
         // If no return, fall through to the slow path.
-        slowCheckMemberAccess(caller, memberClass, targetClass, modifiers);
+        return slowVerifyAccess(caller, memberClass, targetClass, modifiers);
     }
 
     // Keep all this slow stuff out of line:
-    void slowCheckMemberAccess(Class<?> caller, Class<?> memberClass,
+    private boolean slowVerifyAccess(Class<?> caller, Class<?> memberClass,
                                Class<?> targetClass, int modifiers)
-        throws IllegalAccessException
     {
-        Reflection.ensureMemberAccess(caller, memberClass, targetClass, 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,7 +646,29 @@
         // 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 >