14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package jdk.internal.reflect; 27 28 29 import java.lang.reflect.*; 30 import java.util.HashMap; 31 import java.util.Map; 32 import java.util.Objects; 33 import jdk.internal.HotSpotIntrinsicCandidate; 34 import jdk.internal.misc.SharedSecrets; 35 import jdk.internal.misc.VM; 36 import sun.security.action.GetPropertyAction; 37 38 /** Common utility routines used by both java.lang and 39 java.lang.reflect */ 40 41 public class Reflection { 42 43 /** Used to filter out fields and methods from certain classes from public 44 view, where they are sensitive or they may contain VM-internal objects. 45 These Maps are updated very rarely. Rather than synchronize on 46 each access, we use copy-on-write */ 47 private static volatile Map<Class<?>,String[]> fieldFilterMap; 48 private static volatile Map<Class<?>,String[]> methodFilterMap; 49 50 static { 51 Map<Class<?>,String[]> map = new HashMap<Class<?>,String[]>(); 52 map.put(Reflection.class, 53 new String[] {"fieldFilterMap", "methodFilterMap"}); 54 map.put(System.class, new String[] {"security"}); 55 map.put(Class.class, new String[] {"classLoader"}); 56 fieldFilterMap = map; 87 88 /** 89 * Ensures that access to a member is granted and throws 90 * IllegalAccessException if not. 91 * 92 * @param currentClass the class performing the access 93 * @param memberClass the declaring class of the member being accessed 94 * @param targetClass the class of target object if accessing instance 95 * field or method; 96 * or the declaring class if accessing constructor; 97 * or null if accessing static field or method 98 * @param modifiers the member's access modifiers 99 * @throws IllegalAccessException if access to member is denied 100 */ 101 public static void ensureMemberAccess(Class<?> currentClass, 102 Class<?> memberClass, 103 Class<?> targetClass, 104 int modifiers) 105 throws IllegalAccessException 106 { 107 if (currentClass == null || memberClass == null) { 108 throw new InternalError(); 109 } 110 111 if (!verifyMemberAccess(currentClass, memberClass, targetClass, modifiers)) { 112 throwIllegalAccessException(currentClass, memberClass, targetClass, modifiers); 113 } 114 } 115 116 /** 117 * Verify access to a member, returning {@code false} if no access 118 */ 119 public static boolean verifyMemberAccess(Class<?> currentClass, 120 Class<?> memberClass, 121 Class<?> targetClass, 122 int modifiers) 123 { 124 // Verify that currentClass can access a field, method, or 125 // constructor of memberClass, where that member's access bits are 126 // "modifiers". 127 128 boolean gotIsSameClassPackage = false; 129 boolean isSameClassPackage = false; 130 131 if (currentClass == memberClass) { 132 // Always succeeds 133 return true; 134 } 135 136 if (!verifyModuleAccess(currentClass, memberClass)) { 137 return false; 138 } 139 140 if (!Modifier.isPublic(getClassAccessFlags(memberClass))) { 141 isSameClassPackage = isSameClassPackage(currentClass, memberClass); 142 gotIsSameClassPackage = true; 143 if (!isSameClassPackage) { 144 return false; 145 } 146 } 147 148 // At this point we know that currentClass can access memberClass. 149 150 if (Modifier.isPublic(modifiers)) { 151 return true; 152 } 153 154 boolean successSoFar = false; 155 156 if (Modifier.isProtected(modifiers)) { 157 // See if currentClass is a subclass of memberClass 158 if (isSubclassOf(currentClass, memberClass)) { 159 successSoFar = true; 179 // Additional test for protected instance members 180 // and protected constructors: JLS 6.6.2 181 if (targetClass != null && Modifier.isProtected(modifiers) && 182 targetClass != currentClass) 183 { 184 if (!gotIsSameClassPackage) { 185 isSameClassPackage = isSameClassPackage(currentClass, memberClass); 186 gotIsSameClassPackage = true; 187 } 188 if (!isSameClassPackage) { 189 if (!isSubclassOf(targetClass, currentClass)) { 190 return false; 191 } 192 } 193 } 194 195 return true; 196 } 197 198 /** 199 * Returns {@code true} if memberClass's's module exports memberClass's 200 * package to currentClass's module. 201 */ 202 public static boolean verifyModuleAccess(Class<?> currentClass, 203 Class<?> memberClass) { 204 return verifyModuleAccess(currentClass.getModule(), memberClass); 205 } 206 207 public static boolean verifyModuleAccess(Module currentModule, Class<?> memberClass) { 208 Module memberModule = memberClass.getModule(); 209 210 // module may be null during startup (initLevel 0) 211 if (currentModule == memberModule) 212 return true; // same module (named or unnamed) 213 214 String pkg = memberClass.getPackageName(); 215 boolean allowed = memberModule.isExported(pkg, currentModule); 216 if (allowed && memberModule.isNamed() && printStackTraceWhenAccessSucceeds()) { 217 if (!SharedSecrets.getJavaLangReflectModuleAccess() 218 .isStaticallyExported(memberModule, pkg, currentModule)) { 219 String msg = currentModule + " allowed access to member of " + memberClass; 220 new Exception(msg).printStackTrace(System.err); 221 } 222 } 223 return allowed; 224 } 225 226 /** 227 * Returns true if two classes in the same package. 228 */ 229 private static boolean isSameClassPackage(Class<?> c1, Class<?> c2) { 230 if (c1.getClassLoader() != c2.getClassLoader()) 231 return false; 232 return Objects.equals(c1.getPackageName(), c2.getPackageName()); 233 } 234 235 static boolean isSubclassOf(Class<?> queryClass, 236 Class<?> ofClass) 237 { 238 while (queryClass != null) { 239 if (queryClass == ofClass) { 240 return true; 241 } 242 queryClass = queryClass.getSuperclass(); 243 } 327 */ 328 public static boolean isCallerSensitive(Method m) { 329 final ClassLoader loader = m.getDeclaringClass().getClassLoader(); 330 if (VM.isSystemDomainLoader(loader) || isExtClassLoader(loader)) { 331 return m.isAnnotationPresent(CallerSensitive.class); 332 } 333 return false; 334 } 335 336 private static boolean isExtClassLoader(ClassLoader loader) { 337 ClassLoader cl = ClassLoader.getSystemClassLoader(); 338 while (cl != null) { 339 if (cl.getParent() == null && cl == loader) { 340 return true; 341 } 342 cl = cl.getParent(); 343 } 344 return false; 345 } 346 347 348 // true to print a stack trace when access fails 349 private static volatile boolean printStackWhenAccessFails; 350 351 // true to print a stack trace when access succeeds 352 private static volatile boolean printStackWhenAccessSucceeds; 353 354 // true if printStack* values are initialized 355 private static volatile boolean printStackPropertiesSet; 356 357 private static void ensurePrintStackPropertiesSet() { 358 if (!printStackPropertiesSet && VM.initLevel() >= 1) { 359 String s = GetPropertyAction.privilegedGetProperty( 360 "sun.reflect.debugModuleAccessChecks"); 361 if (s != null) { 362 printStackWhenAccessFails = !s.equalsIgnoreCase("false"); 363 printStackWhenAccessSucceeds = s.equalsIgnoreCase("access"); 364 } 365 printStackPropertiesSet = true; 366 } 367 } 368 369 public static boolean printStackTraceWhenAccessFails() { 370 ensurePrintStackPropertiesSet(); 371 return printStackWhenAccessFails; 372 } 373 374 public static boolean printStackTraceWhenAccessSucceeds() { 375 ensurePrintStackPropertiesSet(); 376 return printStackWhenAccessSucceeds; 377 } 378 379 /** 380 * Throws IllegalAccessException with the an exception message based on 381 * the access that is denied. 382 */ 383 private static void throwIllegalAccessException(Class<?> currentClass, 384 Class<?> memberClass, 385 Object target, 386 int modifiers) 387 throws IllegalAccessException 388 { 389 String currentSuffix = ""; 390 String memberSuffix = ""; 391 Module m1 = currentClass.getModule(); 392 if (m1.isNamed()) 393 currentSuffix = " (in " + m1 + ")"; 394 Module m2 = memberClass.getModule(); 395 if (m2.isNamed()) 396 memberSuffix = " (in " + m2 + ")"; 397 398 String memberPackageName = memberClass.getPackageName(); 399 400 String msg = currentClass + currentSuffix + " cannot access "; 401 if (m2.isExported(memberPackageName, m1)) { 402 403 // module access okay so include the modifiers in the message 404 msg += "a member of " + memberClass + memberSuffix + 405 " with modifiers \"" + Modifier.toString(modifiers) + "\""; 406 407 } else { 408 // module access failed 409 msg += memberClass + memberSuffix+ " because " 410 + m2 + " does not export " + memberPackageName; 411 if (m2.isNamed()) msg += " to " + m1; 412 } 413 414 throwIllegalAccessException(msg); 415 } 416 417 /** 418 * Throws IllegalAccessException with the given exception message. 419 */ 420 public static void throwIllegalAccessException(String msg) 421 throws IllegalAccessException 422 { 423 IllegalAccessException e = new IllegalAccessException(msg); 424 ensurePrintStackPropertiesSet(); 425 if (printStackWhenAccessFails) { 426 e.printStackTrace(System.err); 427 } 428 throw e; 429 } 430 } | 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package jdk.internal.reflect; 27 28 29 import java.lang.reflect.*; 30 import java.util.HashMap; 31 import java.util.Map; 32 import java.util.Objects; 33 import jdk.internal.HotSpotIntrinsicCandidate; 34 import jdk.internal.misc.VM; 35 36 /** Common utility routines used by both java.lang and 37 java.lang.reflect */ 38 39 public class Reflection { 40 41 /** Used to filter out fields and methods from certain classes from public 42 view, where they are sensitive or they may contain VM-internal objects. 43 These Maps are updated very rarely. Rather than synchronize on 44 each access, we use copy-on-write */ 45 private static volatile Map<Class<?>,String[]> fieldFilterMap; 46 private static volatile Map<Class<?>,String[]> methodFilterMap; 47 48 static { 49 Map<Class<?>,String[]> map = new HashMap<Class<?>,String[]>(); 50 map.put(Reflection.class, 51 new String[] {"fieldFilterMap", "methodFilterMap"}); 52 map.put(System.class, new String[] {"security"}); 53 map.put(Class.class, new String[] {"classLoader"}); 54 fieldFilterMap = map; 85 86 /** 87 * Ensures that access to a member is granted and throws 88 * IllegalAccessException if not. 89 * 90 * @param currentClass the class performing the access 91 * @param memberClass the declaring class of the member being accessed 92 * @param targetClass the class of target object if accessing instance 93 * field or method; 94 * or the declaring class if accessing constructor; 95 * or null if accessing static field or method 96 * @param modifiers the member's access modifiers 97 * @throws IllegalAccessException if access to member is denied 98 */ 99 public static void ensureMemberAccess(Class<?> currentClass, 100 Class<?> memberClass, 101 Class<?> targetClass, 102 int modifiers) 103 throws IllegalAccessException 104 { 105 if (!verifyMemberAccess(currentClass, memberClass, targetClass, modifiers)) { 106 throw newIllegalAccessException(currentClass, memberClass, targetClass, modifiers); 107 } 108 } 109 110 /** 111 * Verify access to a member and return {@code true} if it is granted. 112 * 113 * @param currentClass the class performing the access 114 * @param memberClass the declaring class of the member being accessed 115 * @param targetClass the class of target object if accessing instance 116 * field or method; 117 * or the declaring class if accessing constructor; 118 * or null if accessing static field or method 119 * @param modifiers the member's access modifiers 120 * @return {@code true} if access to member is granted 121 */ 122 public static boolean verifyMemberAccess(Class<?> currentClass, 123 Class<?> memberClass, 124 Class<?> targetClass, 125 int modifiers) 126 { 127 if (currentClass == memberClass) { 128 // Always succeeds 129 return true; 130 } 131 132 if (!verifyModuleAccess(currentClass.getModule(), memberClass)) { 133 return false; 134 } 135 136 boolean gotIsSameClassPackage = false; 137 boolean isSameClassPackage = false; 138 139 if (!Modifier.isPublic(getClassAccessFlags(memberClass))) { 140 isSameClassPackage = isSameClassPackage(currentClass, memberClass); 141 gotIsSameClassPackage = true; 142 if (!isSameClassPackage) { 143 return false; 144 } 145 } 146 147 // At this point we know that currentClass can access memberClass. 148 149 if (Modifier.isPublic(modifiers)) { 150 return true; 151 } 152 153 boolean successSoFar = false; 154 155 if (Modifier.isProtected(modifiers)) { 156 // See if currentClass is a subclass of memberClass 157 if (isSubclassOf(currentClass, memberClass)) { 158 successSoFar = true; 178 // Additional test for protected instance members 179 // and protected constructors: JLS 6.6.2 180 if (targetClass != null && Modifier.isProtected(modifiers) && 181 targetClass != currentClass) 182 { 183 if (!gotIsSameClassPackage) { 184 isSameClassPackage = isSameClassPackage(currentClass, memberClass); 185 gotIsSameClassPackage = true; 186 } 187 if (!isSameClassPackage) { 188 if (!isSubclassOf(targetClass, currentClass)) { 189 return false; 190 } 191 } 192 } 193 194 return true; 195 } 196 197 /** 198 * Returns {@code true} if memberClass's module exports memberClass's 199 * package to currentModule. 200 */ 201 public static boolean verifyModuleAccess(Module currentModule, Class<?> memberClass) { 202 Module memberModule = memberClass.getModule(); 203 if (currentModule == memberModule) { 204 // same module (named or unnamed) or both null if called 205 // before module system is initialized, which means we are 206 // dealing with java.base only. 207 return true; 208 } else { 209 String pkg = memberClass.getPackageName(); 210 return memberModule.isExported(pkg, currentModule); 211 } 212 } 213 214 /** 215 * Returns true if two classes in the same package. 216 */ 217 private static boolean isSameClassPackage(Class<?> c1, Class<?> c2) { 218 if (c1.getClassLoader() != c2.getClassLoader()) 219 return false; 220 return Objects.equals(c1.getPackageName(), c2.getPackageName()); 221 } 222 223 static boolean isSubclassOf(Class<?> queryClass, 224 Class<?> ofClass) 225 { 226 while (queryClass != null) { 227 if (queryClass == ofClass) { 228 return true; 229 } 230 queryClass = queryClass.getSuperclass(); 231 } 315 */ 316 public static boolean isCallerSensitive(Method m) { 317 final ClassLoader loader = m.getDeclaringClass().getClassLoader(); 318 if (VM.isSystemDomainLoader(loader) || isExtClassLoader(loader)) { 319 return m.isAnnotationPresent(CallerSensitive.class); 320 } 321 return false; 322 } 323 324 private static boolean isExtClassLoader(ClassLoader loader) { 325 ClassLoader cl = ClassLoader.getSystemClassLoader(); 326 while (cl != null) { 327 if (cl.getParent() == null && cl == loader) { 328 return true; 329 } 330 cl = cl.getParent(); 331 } 332 return false; 333 } 334 335 /** 336 * Returns an IllegalAccessException with an exception message based on 337 * the access that is denied. 338 */ 339 public static IllegalAccessException newIllegalAccessException(Class<?> currentClass, 340 Class<?> memberClass, 341 Class<?> targetClass, 342 int modifiers) 343 throws IllegalAccessException 344 { 345 String currentSuffix = ""; 346 String memberSuffix = ""; 347 Module m1 = currentClass.getModule(); 348 if (m1.isNamed()) 349 currentSuffix = " (in " + m1 + ")"; 350 Module m2 = memberClass.getModule(); 351 if (m2.isNamed()) 352 memberSuffix = " (in " + m2 + ")"; 353 354 String memberPackageName = memberClass.getPackageName(); 355 356 String msg = currentClass + currentSuffix + " cannot access "; 357 if (m2.isExported(memberPackageName, m1)) { 358 359 // module access okay so include the modifiers in the message 360 msg += "a member of " + memberClass + memberSuffix + 361 " with modifiers \"" + Modifier.toString(modifiers) + "\""; 362 363 } else { 364 // module access failed 365 msg += memberClass + memberSuffix+ " because " 366 + m2 + " does not export " + memberPackageName; 367 if (m2.isNamed()) msg += " to " + m1; 368 } 369 370 return new IllegalAccessException(msg); 371 } 372 } |