--- a/jdk/src/share/classes/java/lang/invoke/MethodHandles.java Wed Apr 17 10:15:33 2013 +0800
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandles.java Tue Apr 16 21:39:52 2013 -0700
@@ -26,13 +26,17 @@
package java.lang.invoke;
import java.lang.reflect.*;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Arrays;
import sun.invoke.util.ValueConversions;
import sun.invoke.util.VerifyAccess;
import sun.invoke.util.Wrapper;
-import java.util.List;
-import java.util.ArrayList;
-import java.util.Arrays;
+import sun.reflect.CallerSensitive;
import sun.reflect.Reflection;
+import sun.security.util.SecurityConstants;
import static java.lang.invoke.MethodHandleStatics.*;
import static java.lang.invoke.MethodHandleNatives.Constants.*;
@@ -65,8 +69,9 @@
* This lookup object is a <em>capability</em> which may be delegated to trusted agents.
* Do not store it in place where untrusted code can access it.
*/
+ @CallerSensitive
public static Lookup lookup() {
- return new Lookup();
+ return new Lookup(Reflection.getCallerClass());
}
/**
@@ -416,20 +421,13 @@
* for method handle creation.
* Must be called by from a method in this package,
* which in turn is called by a method not in this package.
- * <p>
- * Also, don't make it private, lest javac interpose
- * an access$N method.
*/
- Lookup() {
- this(getCallerClassAtEntryPoint(false), ALL_MODES);
+ Lookup(Class<?> lookupClass) {
+ this(lookupClass, ALL_MODES);
// make sure we haven't accidentally picked up a privileged class:
checkUnprivilegedlookupClass(lookupClass);
}
- Lookup(Class<?> lookupClass) {
- this(lookupClass, ALL_MODES);
- }
-
private Lookup(Class<?> lookupClass, int allowedModes) {
this.lookupClass = lookupClass;
this.allowedModes = allowedModes;
@@ -554,20 +552,6 @@
}
}
- /* Obtain the external caller class, when called from Lookup.<init> or a first-level subroutine. */
- private static Class<?> getCallerClassAtEntryPoint(boolean inSubroutine) {
- final int CALLER_DEPTH = 4;
- // Stack for the constructor entry point (inSubroutine=false):
- // 0: Reflection.getCC, 1: getCallerClassAtEntryPoint,
- // 2: Lookup.<init>, 3: MethodHandles.*, 4: caller
- // The stack is slightly different for a subroutine of a Lookup.find* method:
- // 2: Lookup.*, 3: Lookup.find*.*, 4: caller
- // Note: This should be the only use of getCallerClass in this file.
- assert(Reflection.getCallerClass(CALLER_DEPTH-2) == Lookup.class);
- assert(Reflection.getCallerClass(CALLER_DEPTH-1) == (inSubroutine ? Lookup.class : MethodHandles.class));
- return Reflection.getCallerClass(CALLER_DEPTH);
- }
-
/**
* Produces a method handle for a static method.
* The type of the method handle will be that of the method.
@@ -594,12 +578,14 @@
* <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
* @throws NullPointerException if any argument is null
*/
+ @CallerSensitive
public
MethodHandle findStatic(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
MemberName method = resolveOrFail(REF_invokeStatic, refc, name, type);
- checkSecurityManager(refc, method); // stack walk magic: do not refactor
- Class<?> callerClass = findBoundCallerClass(method); // stack walk magic: do not refactor
- return getDirectMethod(REF_invokeStatic, refc, method, callerClass);
+ Class<?> callerClass = Reflection.getCallerClass();
+ checkSecurityManager(refc, method, callerClass);
+ return getDirectMethod(REF_invokeStatic, refc, method,
+ findBoundCallerClass(method, callerClass));
}
/**
@@ -645,6 +631,7 @@
* <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
* @throws NullPointerException if any argument is null
*/
+ @CallerSensitive
public MethodHandle findVirtual(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
if (refc == MethodHandle.class) {
MethodHandle mh = findVirtualForMH(name, type);
@@ -652,9 +639,10 @@
}
byte refKind = (refc.isInterface() ? REF_invokeInterface : REF_invokeVirtual);
MemberName method = resolveOrFail(refKind, refc, name, type);
- checkSecurityManager(refc, method); // stack walk magic: do not refactor
- Class<?> callerClass = findBoundCallerClass(method);
- return getDirectMethod(refKind, refc, method, callerClass);
+ Class<?> callerClass = Reflection.getCallerClass();
+ checkSecurityManager(refc, method, callerClass);
+ return getDirectMethod(refKind, refc, method,
+ findBoundCallerClass(method, callerClass));
}
private MethodHandle findVirtualForMH(String name, MethodType type) {
// these names require special lookups because of the implicit MethodType argument
@@ -691,10 +679,11 @@
* <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
* @throws NullPointerException if any argument is null
*/
+ @CallerSensitive
public MethodHandle findConstructor(Class<?> refc, MethodType type) throws NoSuchMethodException, IllegalAccessException {
String name = "<init>";
MemberName ctor = resolveOrFail(REF_newInvokeSpecial, refc, name, type);
- checkSecurityManager(refc, ctor); // stack walk magic: do not refactor
+ checkSecurityManager(refc, ctor, Reflection.getCallerClass());
return getDirectConstructor(refc, ctor);
}
@@ -732,14 +721,16 @@
* <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
* @throws NullPointerException if any argument is null
*/
+ @CallerSensitive
public MethodHandle findSpecial(Class<?> refc, String name, MethodType type,
Class<?> specialCaller) throws NoSuchMethodException, IllegalAccessException {
checkSpecialCaller(specialCaller);
Lookup specialLookup = this.in(specialCaller);
MemberName method = specialLookup.resolveOrFail(REF_invokeSpecial, refc, name, type);
- checkSecurityManager(refc, method); // stack walk magic: do not refactor
- Class<?> callerClass = findBoundCallerClass(method);
- return specialLookup.getDirectMethod(REF_invokeSpecial, refc, method, callerClass);
+ Class<?> callerClass = Reflection.getCallerClass();
+ checkSecurityManager(refc, method, callerClass);
+ return specialLookup.getDirectMethod(REF_invokeSpecial, refc, method,
+ findBoundCallerClass(method, callerClass));
}
/**
@@ -759,9 +750,10 @@
* <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
* @throws NullPointerException if any argument is null
*/
+ @CallerSensitive
public MethodHandle findGetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
MemberName field = resolveOrFail(REF_getField, refc, name, type);
- checkSecurityManager(refc, field); // stack walk magic: do not refactor
+ checkSecurityManager(refc, field, Reflection.getCallerClass());
return getDirectField(REF_getField, refc, field);
}
@@ -782,9 +774,10 @@
* <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
* @throws NullPointerException if any argument is null
*/
+ @CallerSensitive
public MethodHandle findSetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
MemberName field = resolveOrFail(REF_putField, refc, name, type);
- checkSecurityManager(refc, field); // stack walk magic: do not refactor
+ checkSecurityManager(refc, field, Reflection.getCallerClass());
return getDirectField(REF_putField, refc, field);
}
@@ -804,9 +797,10 @@
* <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
* @throws NullPointerException if any argument is null
*/
+ @CallerSensitive
public MethodHandle findStaticGetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
MemberName field = resolveOrFail(REF_getStatic, refc, name, type);
- checkSecurityManager(refc, field); // stack walk magic: do not refactor
+ checkSecurityManager(refc, field, Reflection.getCallerClass());
return getDirectField(REF_getStatic, refc, field);
}
@@ -826,9 +820,10 @@
* <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
* @throws NullPointerException if any argument is null
*/
+ @CallerSensitive
public MethodHandle findStaticSetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
MemberName field = resolveOrFail(REF_putStatic, refc, name, type);
- checkSecurityManager(refc, field); // stack walk magic: do not refactor
+ checkSecurityManager(refc, field, Reflection.getCallerClass());
return getDirectField(REF_putStatic, refc, field);
}
@@ -878,12 +873,14 @@
* <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
* @throws NullPointerException if any argument is null
*/
+ @CallerSensitive
public MethodHandle bind(Object receiver, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
Class<? extends Object> refc = receiver.getClass(); // may get NPE
MemberName method = resolveOrFail(REF_invokeSpecial, refc, name, type);
- checkSecurityManager(refc, method); // stack walk magic: do not refactor
- Class<?> callerClass = findBoundCallerClass(method); // stack walk magic: do not refactor
- MethodHandle mh = getDirectMethodNoRestrict(REF_invokeSpecial, refc, method, callerClass);
+ Class<?> callerClass = Reflection.getCallerClass();
+ checkSecurityManager(refc, method, callerClass);
+ MethodHandle mh = getDirectMethodNoRestrict(REF_invokeSpecial, refc, method,
+ findBoundCallerClass(method, callerClass));
return mh.bindReceiver(receiver).setVarargs(method);
}
@@ -908,13 +905,14 @@
* is set and {@code asVarargsCollector} fails
* @throws NullPointerException if the argument is null
*/
+ @CallerSensitive
public MethodHandle unreflect(Method m) throws IllegalAccessException {
MemberName method = new MemberName(m);
byte refKind = method.getReferenceKind();
if (refKind == REF_invokeSpecial)
refKind = REF_invokeVirtual;
assert(method.isMethod());
- Class<?> callerClass = findBoundCallerClass(method); // stack walk magic: do not refactor
+ Class<?> callerClass = findBoundCallerClass(method, Reflection.getCallerClass());
Lookup lookup = m.isAccessible() ? IMPL_LOOKUP : this;
return lookup.getDirectMethod(refKind, method.getDeclaringClass(), method, callerClass);
}
@@ -940,12 +938,13 @@
* is set and {@code asVarargsCollector} fails
* @throws NullPointerException if any argument is null
*/
+ @CallerSensitive
public MethodHandle unreflectSpecial(Method m, Class<?> specialCaller) throws IllegalAccessException {
checkSpecialCaller(specialCaller);
Lookup specialLookup = this.in(specialCaller);
MemberName method = new MemberName(m, true);
assert(method.isMethod());
- Class<?> callerClass = findBoundCallerClass(method); // stack walk magic: do not refactor
+ Class<?> callerClass = findBoundCallerClass(method, Reflection.getCallerClass());
// ignore m.isAccessible: this is a new kind of access
return specialLookup.getDirectMethod(REF_invokeSpecial, method.getDeclaringClass(), method, callerClass);
}
@@ -1050,20 +1049,35 @@
* If this lookup object has private access, then the caller class is the lookupClass.
* Otherwise, it is the caller of the currently executing public API method (e.g., findVirtual).
* This is the same caller class as is used by checkSecurityManager.
- * This function performs stack walk magic: do not refactor it.
*/
- Class<?> findBoundCallerClass(MemberName m) {
+ Class<?> findBoundCallerClass(MemberName m, Class<?> callerAtEntryPoint) {
Class<?> callerClass = null;
if (MethodHandleNatives.isCallerSensitive(m)) {
// Do not refactor this to a more "logical" place, since it is stack walk magic.
// Note that this is the same expression as in Step 2 below in checkSecurityManager.
callerClass = ((allowedModes & PRIVATE) != 0
? lookupClass // for strong access modes, no extra check
- // next line does stack walk magic; do not refactor:
- : getCallerClassAtEntryPoint(true));
+ : callerAtEntryPoint);
}
return callerClass;
}
+
+ /**
+ * Determine whether a security manager has an overridden
+ * SecurityManager.checkMemberAccess method.
+ */
+ private boolean isCheckMemberAccessOverridden(SecurityManager sm) {
+ final Class<? extends SecurityManager> cls = sm.getClass();
+ if (cls == SecurityManager.class) return false;
+
+ try {
+ return cls.getMethod("checkMemberAccess", Class.class, int.class).
+ getDeclaringClass() != SecurityManager.class;
+ } catch (NoSuchMethodException e) {
+ throw new InternalError("should not reach here");
+ }
+ }
+
/**
* Perform necessary <a href="MethodHandles.Lookup.html#secmgr">access checks</a>.
* Determines a trustable caller class to compare with refc, the symbolic reference class.
@@ -1071,46 +1085,55 @@
* Otherwise, it is the caller of the currently executing public API method (e.g., findVirtual).
* This function performs stack walk magic: do not refactor it.
*/
- void checkSecurityManager(Class<?> refc, MemberName m) {
+ void checkSecurityManager(Class<?> refc, MemberName m, Class<?> caller) {
SecurityManager smgr = System.getSecurityManager();
if (smgr == null) return;
if (allowedModes == TRUSTED) return;
+
+ final boolean overridden = isCheckMemberAccessOverridden(smgr);
// Step 1:
- smgr.checkMemberAccess(refc, Member.PUBLIC);
+ {
+ // Default policy is to allow Member.PUBLIC; no need to check
+ // permission if SecurityManager is the default implementation
+ final int which = Member.PUBLIC;
+ final Class<?> clazz = refc;
+ if (overridden) {
+ // Don't refactor; otherwise break the stack depth for
+ // checkMemberAccess of subclasses of SecurityManager as specified.
+ smgr.checkMemberAccess(clazz, which);
+ }
+ }
+
// Step 2:
Class<?> callerClass = ((allowedModes & PRIVATE) != 0
? lookupClass // for strong access modes, no extra check
- // next line does stack walk magic; do not refactor:
- : getCallerClassAtEntryPoint(true));
+ : caller);
if (!VerifyAccess.classLoaderIsAncestor(lookupClass, refc) ||
(callerClass != lookupClass &&
!VerifyAccess.classLoaderIsAncestor(callerClass, refc)))
smgr.checkPackageAccess(VerifyAccess.getPackageName(refc));
+
// Step 3:
if (m.isPublic()) return;
Class<?> defc = m.getDeclaringClass();
- smgr.checkMemberAccess(defc, Member.DECLARED); // STACK WALK HERE
+ {
+ // Inline SecurityManager.checkMemberAccess
+ final int which = Member.DECLARED;
+ final Class<?> clazz = defc;
+ if (!overridden) {
+ if (caller.getClassLoader() != clazz.getClassLoader()) {
+ smgr.checkPermission(SecurityConstants.CHECK_MEMBER_ACCESS_PERMISSION);
+ }
+ } else {
+ // Don't refactor; otherwise break the stack depth for
+ // checkMemberAccess of subclasses of SecurityManager as specified.
+ smgr.checkMemberAccess(clazz, which);
+ }
+ }
+
// Step 4:
if (defc != refc)
smgr.checkPackageAccess(VerifyAccess.getPackageName(defc));
-
- // Comment from SM.checkMemberAccess, where which=DECLARED:
- /*
- * stack depth of 4 should be the caller of one of the
- * methods in java.lang.Class that invoke checkMember
- * access. The stack should look like:
- *
- * someCaller [3]
- * java.lang.Class.someReflectionAPI [2]
- * java.lang.Class.checkMemberAccess [1]
- * SecurityManager.checkMemberAccess [0]
- *
- */
- // For us it is this stack:
- // someCaller [3]
- // Lookup.findSomeMember [2]
- // Lookup.checkSecurityManager [1]
- // SecurityManager.checkMemberAccess [0]
}
void checkMethod(byte refKind, Class<?> refc, MemberName m) throws IllegalAccessException {