--- old/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java 2017-03-19 18:36:28.425224957 +0100 +++ new/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java 2017-03-19 18:36:28.288227293 +0100 @@ -483,10 +483,7 @@ } else { targetClass = Modifier.isStatic(modifiers) ? null : obj.getClass(); } - return Reflection.verifyMemberAccess(caller, - declaringClass, - targetClass, - modifiers); + return verifyAccess(caller, declaringClass, targetClass, modifiers); } /** @@ -527,7 +524,7 @@ return AnnotatedElement.super.isAnnotationPresent(annotationClass); } - /** + /** * @throws NullPointerException {@inheritDoc} * @since 1.8 */ @@ -598,8 +595,17 @@ Class targetClass, int modifiers) throws IllegalAccessException { + if (!verifyAccess(caller, memberClass, targetClass, modifiers)) { + Reflection.throwIllegalAccessException( + caller, memberClass, targetClass, modifiers); + } + } + + 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,38 +616,40 @@ 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); - - // Success: Update the cache. - Object cache = (targetClass != null - && Modifier.isProtected(modifiers) - && targetClass != memberClass) - ? new Class[] { caller, targetClass } - : caller; - - // 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 + if (Reflection.verifyMemberAccess(caller, memberClass, targetClass, modifiers)) { + // Success: Update the cache. + Object cache = (targetClass != null + && Modifier.isProtected(modifiers) + && targetClass != memberClass) + ? new Class[] { caller, targetClass } + : caller; + + // 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; + } else { + return false; + } } } --- old/src/java.base/share/classes/jdk/internal/reflect/Reflection.java 2017-03-19 18:36:28.732219720 +0100 +++ new/src/java.base/share/classes/jdk/internal/reflect/Reflection.java 2017-03-19 18:36:28.612221767 +0100 @@ -104,39 +104,43 @@ int modifiers) throws IllegalAccessException { - if (currentClass == null || memberClass == null) { - throw new InternalError(); - } - if (!verifyMemberAccess(currentClass, memberClass, targetClass, modifiers)) { throwIllegalAccessException(currentClass, memberClass, targetClass, modifiers); } } /** - * Verify access to a member, returning {@code false} if no access + * Verify access to a member and return {@code true} if it is granted. + * + * @param currentClass the class performing the access + * @param memberClass the declaring class of the member being accessed + * @param targetClass the class of target object if accessing instance + * field or method; + * or the declaring class if accessing constructor; + * or null if accessing static field or method + * @param modifiers the member's access modifiers + * @return {@code true} if access to member is granted */ public static boolean verifyMemberAccess(Class currentClass, Class memberClass, Class targetClass, int modifiers) { - // Verify that currentClass can access a field, method, or - // constructor of memberClass, where that member's access bits are - // "modifiers". - - boolean gotIsSameClassPackage = false; - boolean isSameClassPackage = false; + Objects.requireNonNull(currentClass, "currentClass"); + Objects.requireNonNull(memberClass, "memberClass"); if (currentClass == memberClass) { // Always succeeds return true; } - if (!verifyModuleAccess(currentClass, memberClass)) { + if (!verifyModuleAccess(currentClass.getModule(), memberClass)) { return false; } + boolean gotIsSameClassPackage = false; + boolean isSameClassPackage = false; + if (!Modifier.isPublic(getClassAccessFlags(memberClass))) { isSameClassPackage = isSameClassPackage(currentClass, memberClass); gotIsSameClassPackage = true; @@ -197,19 +201,18 @@ /** * Returns {@code true} if memberClass's's module exports memberClass's - * package to currentClass's module. + * package to currentModule. */ - public static boolean verifyModuleAccess(Class currentClass, - Class memberClass) { - return verifyModuleAccess(currentClass.getModule(), memberClass); - } - public static boolean verifyModuleAccess(Module currentModule, Class memberClass) { + if (VM.isModuleSystemInited()) + Objects.requireNonNull(currentModule, "currentModule"); + Objects.requireNonNull(memberClass, "memberClass"); + Module memberModule = memberClass.getModule(); - // module may be null during startup (initLevel 0) + // module may be null during startup (initLevel < VM.MODULE_SYSTEM_INITED) if (currentModule == memberModule) - return true; // same module (named or unnamed) + return true; // same module (named or unnamed) or both are null String pkg = memberClass.getPackageName(); boolean allowed = memberModule.isExported(pkg, currentModule); @@ -378,11 +381,13 @@ /** * Throws IllegalAccessException with the an exception message based on - * the access that is denied. + * the access that is denied. This method throws meaningful exception only + * when {@link #verifyMemberAccess(Class, Class, Class, int)} returns false + * for the same parameters. */ - private static void throwIllegalAccessException(Class currentClass, + public static void throwIllegalAccessException(Class currentClass, Class memberClass, - Object target, + Class targetClass, int modifiers) throws IllegalAccessException {