--- old/src/java.base/share/classes/sun/invoke/util/VerifyAccess.java 2019-07-23 10:54:01.000000000 -0700 +++ new/src/java.base/share/classes/sun/invoke/util/VerifyAccess.java 2019-07-23 10:54:01.000000000 -0700 @@ -88,18 +88,20 @@ * @param defc the class in which the proposed member is actually defined * @param mods modifier flags for the proposed member * @param lookupClass the class for which the access check is being made + * @param prevLookupClass the class for which the access check is being made + * @param allowedModes allowed modes * @return true iff the accessing class can access such a member */ public static boolean isMemberAccessible(Class refc, // symbolic ref class Class defc, // actual def class int mods, // actual member mods Class lookupClass, + Class prevLookupClass, int allowedModes) { if (allowedModes == 0) return false; - assert((allowedModes & PUBLIC) != 0 && - (allowedModes & ~(ALL_ACCESS_MODES|PACKAGE_ALLOWED|MODULE_ALLOWED|UNCONDITIONAL_ALLOWED)) == 0); + assert((allowedModes & ~(ALL_ACCESS_MODES|PACKAGE_ALLOWED|MODULE_ALLOWED|UNCONDITIONAL_ALLOWED)) == 0); // The symbolic reference class (refc) must always be fully verified. - if (!isClassAccessible(refc, lookupClass, allowedModes)) { + if (!isClassAccessible(refc, lookupClass, prevLookupClass, allowedModes)) { return false; } // Usually refc and defc are the same, but verify defc also in case they differ. @@ -109,6 +111,7 @@ switch (mods & ALL_ACCESS_MODES) { case PUBLIC: + assert (allowedModes & PUBLIC) != 0 || (allowedModes & UNCONDITIONAL_ALLOWED) != 0; return true; // already checked above case PROTECTED: assert !defc.isInterface(); // protected members aren't allowed in interfaces @@ -175,14 +178,23 @@ * package that is exported to the module that contains D. *
  • C and D are members of the same runtime package. * + * * @param refc the symbolic reference class to which access is being checked (C) * @param lookupClass the class performing the lookup (D) + * @param prevLookupClass the class from which the lookup was teleported or null + * @param allowedModes allowed modes */ - public static boolean isClassAccessible(Class refc, Class lookupClass, + public static boolean isClassAccessible(Class refc, + Class lookupClass, + Class prevLookupClass, int allowedModes) { if (allowedModes == 0) return false; - assert((allowedModes & PUBLIC) != 0 && - (allowedModes & ~(ALL_ACCESS_MODES|PACKAGE_ALLOWED|MODULE_ALLOWED|UNCONDITIONAL_ALLOWED)) == 0); + assert((allowedModes & ~(ALL_ACCESS_MODES|PACKAGE_ALLOWED|MODULE_ALLOWED|UNCONDITIONAL_ALLOWED)) == 0); + + if ((allowedModes & PACKAGE_ALLOWED) != 0 && + isSamePackage(lookupClass, refc)) + return true; + int mods = getClassModifiers(refc); if (isPublic(mods)) { @@ -195,37 +207,62 @@ return true; } - // trivially allow - if ((allowedModes & MODULE_ALLOWED) != 0 && - (lookupModule == refModule)) - return true; + // allow access to public types in all unconditionally exported packages + if ((allowedModes & UNCONDITIONAL_ALLOWED) != 0) { + return refModule.isExported(refc.getPackageName()); + } - // check readability when UNCONDITIONAL not allowed - if (((allowedModes & UNCONDITIONAL_ALLOWED) != 0) - || lookupModule.canRead(refModule)) { - - // check that refc is in an exported package - if ((allowedModes & MODULE_ALLOWED) != 0) { - if (refModule.isExported(refc.getPackageName(), lookupModule)) - return true; - } else { - // exported unconditionally - if (refModule.isExported(refc.getPackageName())) - return true; - } - - // not exported but allow access during VM initialization - // because java.base does not have its exports setup - if (!jdk.internal.misc.VM.isModuleSystemInited()) + if (lookupModule == refModule && prevLookupClass == null) { + // allow access to all public types in lookupModule + if ((allowedModes & MODULE_ALLOWED) != 0) return true; + + assert (allowedModes & PUBLIC) != 0; + return refModule.isExported(refc.getPackageName()); } + // cross-module access + // 1. refc is in different module from lookupModule, or + // 2. refc is in lookupModule and a different module from prevLookupModule + Module prevLookupModule = prevLookupClass != null ? prevLookupClass.getModule() + : null; + assert refModule != lookupModule || refModule != prevLookupModule; + if (isModuleAccessible(refc, lookupModule, prevLookupModule)) + return true; + + // not exported but allow access during VM initialization + // because java.base does not have its exports setup + if (!jdk.internal.misc.VM.isModuleSystemInited()) + return true; + // public class not accessible to lookupClass return false; } - if ((allowedModes & PACKAGE_ALLOWED) != 0 && - isSamePackage(lookupClass, refc)) - return true; + + return false; + } + + /* + * Tests if a class or interface REFC is accessible to m1 and m2 where m2 + * may be null. + * + * A class or interface REFC in m is accessible to m1 and m2 if and only if + * both m1 and m2 read m and m exports the package of REFC at least to + * both m1 and m2. + */ + public static boolean isModuleAccessible(Class refc, Module m1, Module m2) { + Module refModule = refc.getModule(); + assert refModule != m1 || refModule != m2; + int mods = getClassModifiers(refc); + if (isPublic(mods)) { + if (m1.canRead(refModule) && (m2 == null || m2.canRead(refModule))) { + String pn = refc.getPackageName(); + + // refc is exported package to at least both m1 and m2 + if (refModule.isExported(pn, m1) && (m2 == null || refModule.isExported(pn, m2))) + return true; + } + } return false; }