< prev index next >

src/java.base/share/classes/sun/invoke/util/VerifyAccess.java

Print this page

        

@@ -86,31 +86,34 @@
      *
      * @param refc the class used in the symbolic reference to the proposed member
      * @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.
         if (defc == lookupClass  &&
             (allowedModes & PRIVATE) != 0)
             return true;        // easy check; all self-access is OK with a private lookup
 
         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
             if ((allowedModes & PROTECTED_OR_PACKAGE_ALLOWED) != 0 &&
                 isSamePackage(defc, lookupClass))

@@ -173,18 +176,27 @@
      * <li>C is public and in the same module as D.
      * <li>D is in a module that reads the module containing C, C is public and in a
      * package that is exported to the module that contains D.
      * <li>C and D are members of the same runtime package.
      * </ul>
+     *
      * @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)) {
 
             Module lookupModule = lookupClass.getModule();
             Module refModule = refc.getModule();

@@ -193,41 +205,66 @@
             if (lookupModule == null) {
                 assert refModule == null;
                 return true;
             }
 
-            // trivially allow
-            if ((allowedModes & MODULE_ALLOWED) != 0 &&
-                (lookupModule == refModule))
-                return true;
-
-            // 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()))
+            // allow access to public types in all unconditionally exported packages
+            if ((allowedModes & UNCONDITIONAL_ALLOWED) != 0) {
+                return refModule.isExported(refc.getPackageName());
+            }
+
+            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 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;
     }
 
     /**
      * Decide if the given method type, attributed to a member or symbolic
< prev index next >