1 /* 2 * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 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 import java.lang.reflect.*; 29 import java.util.HashMap; 30 import java.util.Map; 31 import java.util.Objects; 32 import java.util.Set; 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<?>, Set<String>> fieldFilterMap; 46 private static volatile Map<Class<?>, Set<String>> methodFilterMap; 47 private static final String WILDCARD = "*"; 48 public static final Set<String> ALL_MEMBERS = Set.of(WILDCARD); 49 50 static { 51 fieldFilterMap = Map.of( 52 Reflection.class, ALL_MEMBERS, 53 AccessibleObject.class, ALL_MEMBERS, 54 Class.class, Set.of("classLoader"), 55 ClassLoader.class, ALL_MEMBERS, 56 Constructor.class, ALL_MEMBERS, 57 Field.class, ALL_MEMBERS, 58 Method.class, ALL_MEMBERS, 59 Module.class, ALL_MEMBERS, 60 System.class, Set.of("security") 61 ); 62 methodFilterMap = Map.of(); 63 } 64 65 /** Returns the class of the caller of the method calling this method, 66 ignoring frames associated with java.lang.reflect.Method.invoke() 67 and its implementation. */ 68 @CallerSensitive 69 @HotSpotIntrinsicCandidate 70 public static native Class<?> getCallerClass(); 71 72 /** Retrieves the access flags written to the class file. For 73 inner classes these flags may differ from those returned by 74 Class.getModifiers(), which searches the InnerClasses 75 attribute to find the source-level access flags. This is used 76 instead of Class.getModifiers() for run-time access checks due 77 to compatibility reasons; see 4471811. Only the values of the 78 low 13 bits (i.e., a mask of 0x1FFF) are guaranteed to be 79 valid. */ 80 @HotSpotIntrinsicCandidate 81 public static native int getClassAccessFlags(Class<?> c); 82 83 84 /** 85 * Ensures that access to a member is granted and throws 86 * IllegalAccessException if not. 87 * 88 * @param currentClass the class performing the access 89 * @param memberClass the declaring class of the member being accessed 90 * @param targetClass the class of target object if accessing instance 91 * field or method; 92 * or the declaring class if accessing constructor; 93 * or null if accessing static field or method 94 * @param modifiers the member's access modifiers 95 * @throws IllegalAccessException if access to member is denied 96 */ 97 public static void ensureMemberAccess(Class<?> currentClass, 98 Class<?> memberClass, 99 Class<?> targetClass, 100 int modifiers) 101 throws IllegalAccessException 102 { 103 if (!verifyMemberAccess(currentClass, memberClass, targetClass, modifiers)) { 104 throw newIllegalAccessException(currentClass, memberClass, targetClass, modifiers); 105 } 106 } 107 108 /** 109 * Verify access to a member and return {@code true} if it is granted. 110 * 111 * @param currentClass the class performing the access 112 * @param memberClass the declaring class of the member being accessed 113 * @param targetClass the class of target object if accessing instance 114 * field or method; 115 * or the declaring class if accessing constructor; 116 * or null if accessing static field or method 117 * @param modifiers the member's access modifiers 118 * @return {@code true} if access to member is granted 119 */ 120 public static boolean verifyMemberAccess(Class<?> currentClass, 121 Class<?> memberClass, 122 Class<?> targetClass, 123 int modifiers) 124 { 125 if (currentClass == memberClass) { 126 // Always succeeds 127 return true; 128 } 129 130 if (!verifyModuleAccess(currentClass.getModule(), memberClass)) { 131 return false; 132 } 133 134 boolean gotIsSameClassPackage = false; 135 boolean isSameClassPackage = false; 136 137 if (!Modifier.isPublic(getClassAccessFlags(memberClass))) { 138 isSameClassPackage = isSameClassPackage(currentClass, memberClass); 139 gotIsSameClassPackage = true; 140 if (!isSameClassPackage) { 141 return false; 142 } 143 } 144 145 // At this point we know that currentClass can access memberClass. 146 147 if (Modifier.isPublic(modifiers)) { 148 return true; 149 } 150 151 // Check for nestmate access if member is private 152 if (Modifier.isPrivate(modifiers)) { 153 // Note: targetClass may be outside the nest, but that is okay 154 // as long as memberClass is in the nest. 155 if (areNestMates(currentClass, memberClass)) { 156 return true; 157 } 158 } 159 160 boolean successSoFar = false; 161 162 if (Modifier.isProtected(modifiers)) { 163 // See if currentClass is a subclass of memberClass 164 if (isSubclassOf(currentClass, memberClass)) { 165 successSoFar = true; 166 } 167 } 168 169 if (!successSoFar && !Modifier.isPrivate(modifiers)) { 170 if (!gotIsSameClassPackage) { 171 isSameClassPackage = isSameClassPackage(currentClass, 172 memberClass); 173 gotIsSameClassPackage = true; 174 } 175 176 if (isSameClassPackage) { 177 successSoFar = true; 178 } 179 } 180 181 if (!successSoFar) { 182 return false; 183 } 184 185 // Additional test for protected instance members 186 // and protected constructors: JLS 6.6.2 187 if (targetClass != null && Modifier.isProtected(modifiers) && 188 targetClass != currentClass) 189 { 190 if (!gotIsSameClassPackage) { 191 isSameClassPackage = isSameClassPackage(currentClass, memberClass); 192 gotIsSameClassPackage = true; 193 } 194 if (!isSameClassPackage) { 195 if (!isSubclassOf(targetClass, currentClass)) { 196 return false; 197 } 198 } 199 } 200 201 return true; 202 } 203 204 /** 205 * Returns {@code true} if memberClass's module exports memberClass's 206 * package to currentModule. 207 */ 208 public static boolean verifyModuleAccess(Module currentModule, Class<?> memberClass) { 209 Module memberModule = memberClass.getModule(); 210 if (currentModule == memberModule) { 211 // same module (named or unnamed) or both null if called 212 // before module system is initialized, which means we are 213 // dealing with java.base only. 214 return true; 215 } else { 216 String pkg = memberClass.getPackageName(); 217 return memberModule.isExported(pkg, currentModule); 218 } 219 } 220 221 /** 222 * Returns true if two classes in the same package. 223 */ 224 private static boolean isSameClassPackage(Class<?> c1, Class<?> c2) { 225 if (c1.getClassLoader() != c2.getClassLoader()) 226 return false; 227 return Objects.equals(c1.getPackageName(), c2.getPackageName()); 228 } 229 230 static boolean isSubclassOf(Class<?> queryClass, 231 Class<?> ofClass) 232 { 233 while (queryClass != null) { 234 if (queryClass == ofClass) { 235 return true; 236 } 237 queryClass = queryClass.getSuperclass(); 238 } 239 return false; 240 } 241 242 // fieldNames must contain only interned Strings 243 public static synchronized void registerFieldsToFilter(Class<?> containingClass, 244 Set<String> fieldNames) { 245 fieldFilterMap = 246 registerFilter(fieldFilterMap, containingClass, fieldNames); 247 } 248 249 // methodNames must contain only interned Strings 250 public static synchronized void registerMethodsToFilter(Class<?> containingClass, 251 Set<String> methodNames) { 252 methodFilterMap = 253 registerFilter(methodFilterMap, containingClass, methodNames); 254 } 255 256 private static Map<Class<?>, Set<String>> registerFilter(Map<Class<?>, Set<String>> map, 257 Class<?> containingClass, 258 Set<String> names) { 259 if (map.get(containingClass) != null) { 260 throw new IllegalArgumentException 261 ("Filter already registered: " + containingClass); 262 } 263 map = new HashMap<>(map); 264 map.put(containingClass, Set.copyOf(names)); 265 return map; 266 } 267 268 public static Field[] filterFields(Class<?> containingClass, Field[] fields) { 269 if (fieldFilterMap == null) { 270 // Bootstrapping 271 return fields; 272 } 273 return (Field[])filter(fields, fieldFilterMap.get(containingClass)); 274 } 275 276 public static Method[] filterMethods(Class<?> containingClass, Method[] methods) { 277 if (methodFilterMap == null) { 278 // Bootstrapping 279 return methods; 280 } 281 return (Method[])filter(methods, methodFilterMap.get(containingClass)); 282 } 283 284 private static Member[] filter(Member[] members, Set<String> filteredNames) { 285 if ((filteredNames == null) || (members.length == 0)) { 286 return members; 287 } 288 Class<?> memberType = members[0].getClass(); 289 if (filteredNames.contains(WILDCARD)) { 290 return (Member[]) Array.newInstance(memberType, 0); 291 } 292 int numNewMembers = 0; 293 for (Member member : members) { 294 if (!filteredNames.contains(member.getName())) { 295 ++numNewMembers; 296 } 297 } 298 Member[] newMembers = (Member[])Array.newInstance(memberType, numNewMembers); 299 int destIdx = 0; 300 for (Member member : members) { 301 if (!filteredNames.contains(member.getName())) { 302 newMembers[destIdx++] = member; 303 } 304 } 305 return newMembers; 306 } 307 308 /** 309 * Tests if the given method is caller-sensitive and the declaring class 310 * is defined by either the bootstrap class loader or platform class loader. 311 */ 312 public static boolean isCallerSensitive(Method m) { 313 final ClassLoader loader = m.getDeclaringClass().getClassLoader(); 314 if (VM.isSystemDomainLoader(loader)) { 315 return m.isAnnotationPresent(CallerSensitive.class); 316 } 317 return false; 318 } 319 320 /** 321 * Returns an IllegalAccessException with an exception message based on 322 * the access that is denied. 323 */ 324 public static IllegalAccessException newIllegalAccessException(Class<?> currentClass, 325 Class<?> memberClass, 326 Class<?> targetClass, 327 int modifiers) 328 throws IllegalAccessException 329 { 330 String currentSuffix = ""; 331 String memberSuffix = ""; 332 Module m1 = currentClass.getModule(); 333 if (m1.isNamed()) 334 currentSuffix = " (in " + m1 + ")"; 335 Module m2 = memberClass.getModule(); 336 if (m2.isNamed()) 337 memberSuffix = " (in " + m2 + ")"; 338 339 String memberPackageName = memberClass.getPackageName(); 340 341 String msg = currentClass + currentSuffix + " cannot access "; 342 if (m2.isExported(memberPackageName, m1)) { 343 344 // module access okay so include the modifiers in the message 345 msg += "a member of " + memberClass + memberSuffix + 346 " with modifiers \"" + Modifier.toString(modifiers) + "\""; 347 348 } else { 349 // module access failed 350 msg += memberClass + memberSuffix+ " because " 351 + m2 + " does not export " + memberPackageName; 352 if (m2.isNamed()) msg += " to " + m1; 353 } 354 355 return new IllegalAccessException(msg); 356 } 357 358 /** 359 * Returns true if {@code currentClass} and {@code memberClass} 360 * are nestmates - that is, if they have the same nesthost as 361 * determined by the VM. 362 */ 363 public static native boolean areNestMates(Class<?> currentClass, 364 Class<?> memberClass); 365 }