jdk/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java
changeset 44359 c6761862ca0b
parent 43712 5dfd0950317c
child 45652 33342314ce89
--- a/jdk/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java	Thu Mar 16 16:34:36 2017 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java	Wed Mar 22 16:26:27 2017 +0000
@@ -28,9 +28,12 @@
 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},
@@ -288,27 +291,20 @@
         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;
             }
 
@@ -316,11 +312,17 @@
             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 ";
@@ -333,7 +335,7 @@
                 msg += "opens";
             msg += " " + pn + "\" to " + callerModule;
             InaccessibleObjectException e = new InaccessibleObjectException(msg);
-            if (Reflection.printStackTraceWhenAccessFails()) {
+            if (printStackTraceWhenAccessFails()) {
                 e.printStackTrace(System.err);
             }
             throw e;
@@ -351,48 +353,35 @@
         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 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 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);
+    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 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();
     }
 
     /**
@@ -409,6 +398,7 @@
      * it should use {@link #canAccess(Object)}.
      *
      * @revised 9
+     * @spec JPMS
      */
     @Deprecated(since="9")
     public boolean isAccessible() {
@@ -483,10 +473,7 @@
         } else {
             targetClass = Modifier.isStatic(modifiers) ? null : obj.getClass();
         }
-        return Reflection.verifyMemberAccess(caller,
-                                             declaringClass,
-                                             targetClass,
-                                             modifiers);
+        return verifyAccess(caller, declaringClass, targetClass, modifiers);
     }
 
     /**
@@ -527,7 +514,7 @@
         return AnnotatedElement.super.isAnnotationPresent(annotationClass);
     }
 
-   /**
+    /**
      * @throws NullPointerException {@inheritDoc}
      * @since 1.8
      */
@@ -598,8 +585,21 @@
                            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
@@ -610,26 +610,31 @@
                 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,
-                               Class<?> targetClass, int modifiers)
-        throws IllegalAccessException
+    private boolean slowVerifyAccess(Class<?> caller, Class<?> memberClass,
+                                     Class<?> targetClass, int modifiers)
     {
-        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
@@ -643,5 +648,27 @@
         // 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;
     }
 }