src/share/classes/java/lang/reflect/AccessibleObject.java

Print this page
rev 3746 : [mq]: cr6565585.ao

*** 24,33 **** --- 24,34 ---- */ package java.lang.reflect; import java.security.AccessController; + import sun.reflect.Reflection; import sun.reflect.ReflectionFactory; import java.lang.annotation.Annotation; /** * The AccessibleObject class is the base class for Field, Method and
*** 199,204 **** --- 200,274 ---- * @since 1.5 */ public Annotation[] getDeclaredAnnotations() { throw new AssertionError("All subclasses should override this method"); } + + + // Shared access checking logic. + + // For non-public members or members in package-private classes, + // it is necessary to perform somewhat expensive security checks. + // If the security check succeeds for a given class, it will + // always succeed (it is not affected by the granting or revoking + // of permissions); we speed up the check in the common case by + // remembering the last Class for which the check succeeded. + // + // The simple security check for Constructor is to see if + // the caller has already been seen, verified, and cached. + // (See also Class.newInstance(), which uses a similar method.) + // + // A more complicated security check cache is needed for Method and Field + // The cache can be either null (empty cache), a 2-array of {caller,target}, + // or a caller (with target implicitly equal to this.clazz). + // In the 2-array case, the target is always different from the clazz. + volatile Object securityCheckCache; + + void checkAccess(Class<?> caller, Class<?> clazz, Object obj, int modifiers) + throws IllegalAccessException + { + if (caller == clazz) { // quick check + return; // ACCESS IS OK + } + Object cache = securityCheckCache; // read volatile + Class<?> targetClass = clazz; + if (obj != null + && Modifier.isProtected(modifiers) + && ((targetClass = obj.getClass()) != clazz)) { + // Must match a 2-list of { caller, targetClass }. + if (cache instanceof Class[]) { + Class<?>[] cache2 = (Class<?>[]) cache; + if (cache2[1] == targetClass && + cache2[0] == caller) { + return; // 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 obj.class == this.clazz). + return; // ACCESS IS OK + } + + // If no return, fall through to the slow path. + slowCheckMemberAccess(caller, clazz, obj, modifiers, targetClass); + } + + // Keep all this slow stuff out of line: + void slowCheckMemberAccess(Class<?> caller, Class<?> clazz, Object obj, int modifiers, + Class<?> targetClass) + throws IllegalAccessException + { + Reflection.ensureMemberAccess(caller, clazz, obj, modifiers); + + // Success: Update the cache. + Object cache = ((targetClass == clazz) + ? caller + : new Class<?>[] { caller, targetClass }); + + // 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 + } }