--- a/jdk/src/share/classes/java/lang/invoke/MethodHandles.java Tue Feb 26 10:38:58 2013 -0800
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandles.java Tue Feb 26 20:36:52 2013 +0100
@@ -598,7 +598,8 @@
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
- return getDirectMethod(REF_invokeStatic, refc, method);
+ Class<?> callerClass = findBoundCallerClass(method); // stack walk magic: do not refactor
+ return getDirectMethod(REF_invokeStatic, refc, method, callerClass);
}
/**
@@ -652,7 +653,8 @@
byte refKind = (refc.isInterface() ? REF_invokeInterface : REF_invokeVirtual);
MemberName method = resolveOrFail(refKind, refc, name, type);
checkSecurityManager(refc, method); // stack walk magic: do not refactor
- return getDirectMethod(refKind, refc, method);
+ Class<?> callerClass = findBoundCallerClass(method);
+ return getDirectMethod(refKind, refc, method, callerClass);
}
private MethodHandle findVirtualForMH(String name, MethodType type) {
// these names require special lookups because of the implicit MethodType argument
@@ -736,7 +738,8 @@
Lookup specialLookup = this.in(specialCaller);
MemberName method = specialLookup.resolveOrFail(REF_invokeSpecial, refc, name, type);
checkSecurityManager(refc, method); // stack walk magic: do not refactor
- return specialLookup.getDirectMethod(REF_invokeSpecial, refc, method);
+ Class<?> callerClass = findBoundCallerClass(method);
+ return specialLookup.getDirectMethod(REF_invokeSpecial, refc, method, callerClass);
}
/**
@@ -879,7 +882,8 @@
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
- MethodHandle mh = getDirectMethodNoRestrict(REF_invokeSpecial, refc, method);
+ Class<?> callerClass = findBoundCallerClass(method); // stack walk magic: do not refactor
+ MethodHandle mh = getDirectMethodNoRestrict(REF_invokeSpecial, refc, method, callerClass);
return mh.bindReceiver(receiver).setVarargs(method);
}
@@ -910,8 +914,9 @@
if (refKind == REF_invokeSpecial)
refKind = REF_invokeVirtual;
assert(method.isMethod());
+ Class<?> callerClass = findBoundCallerClass(method); // stack walk magic: do not refactor
Lookup lookup = m.isAccessible() ? IMPL_LOOKUP : this;
- return lookup.getDirectMethod(refKind, method.getDeclaringClass(), method);
+ return lookup.getDirectMethod(refKind, method.getDeclaringClass(), method, callerClass);
}
/**
@@ -940,8 +945,9 @@
Lookup specialLookup = this.in(specialCaller);
MemberName method = new MemberName(m, true);
assert(method.isMethod());
+ Class<?> callerClass = findBoundCallerClass(method); // stack walk magic: do not refactor
// ignore m.isAccessible: this is a new kind of access
- return specialLookup.getDirectMethod(REF_invokeSpecial, method.getDeclaringClass(), method);
+ return specialLookup.getDirectMethod(REF_invokeSpecial, method.getDeclaringClass(), method, callerClass);
}
/**
@@ -1040,7 +1046,29 @@
}
/**
+ * Find my trustable caller class if m is a caller sensitive method.
+ * 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<?> 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));
+ }
+ return callerClass;
+ }
+ /**
* Perform necessary <a href="MethodHandles.Lookup.html#secmgr">access checks</a>.
+ * Determines a trustable caller class to compare with refc, the symbolic reference class.
+ * 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 function performs stack walk magic: do not refactor it.
*/
void checkSecurityManager(Class<?> refc, MemberName m) {
@@ -1195,22 +1223,22 @@
return mh.viewAsType(narrowType);
}
- private MethodHandle getDirectMethod(byte refKind, Class<?> refc, MemberName method) throws IllegalAccessException {
+ private MethodHandle getDirectMethod(byte refKind, Class<?> refc, MemberName method, Class<?> callerClass) throws IllegalAccessException {
return getDirectMethodCommon(refKind, refc, method,
(refKind == REF_invokeSpecial ||
(MethodHandleNatives.refKindHasReceiver(refKind) &&
- restrictProtectedReceiver(method))));
+ restrictProtectedReceiver(method))), callerClass);
}
- private MethodHandle getDirectMethodNoRestrict(byte refKind, Class<?> refc, MemberName method) throws IllegalAccessException {
- return getDirectMethodCommon(refKind, refc, method, false);
+ private MethodHandle getDirectMethodNoRestrict(byte refKind, Class<?> refc, MemberName method, Class<?> callerClass) throws IllegalAccessException {
+ return getDirectMethodCommon(refKind, refc, method, false, callerClass);
}
private MethodHandle getDirectMethodCommon(byte refKind, Class<?> refc, MemberName method,
- boolean doRestrict) throws IllegalAccessException {
+ boolean doRestrict, Class<?> callerClass) throws IllegalAccessException {
checkMethod(refKind, refc, method);
if (method.isMethodHandleInvoke())
return fakeMethodHandleInvoke(method);
MethodHandle mh = DirectMethodHandle.make(refKind, refc, method);
- mh = maybeBindCaller(method, mh);
+ mh = maybeBindCaller(method, mh, callerClass);
mh = mh.setVarargs(method);
if (doRestrict)
mh = restrictReceiver(method, mh, lookupClass());
@@ -1219,12 +1247,14 @@
private MethodHandle fakeMethodHandleInvoke(MemberName method) {
return throwException(method.getReturnType(), UnsupportedOperationException.class);
}
- private MethodHandle maybeBindCaller(MemberName method, MethodHandle mh) throws IllegalAccessException {
+ private MethodHandle maybeBindCaller(MemberName method, MethodHandle mh,
+ Class<?> callerClass)
+ throws IllegalAccessException {
if (allowedModes == TRUSTED || !MethodHandleNatives.isCallerSensitive(method))
return mh;
Class<?> hostClass = lookupClass;
if ((allowedModes & PRIVATE) == 0) // caller must use full-power lookup
- hostClass = null;
+ hostClass = callerClass; // callerClass came from a security manager style stack walk
MethodHandle cbmh = MethodHandleImpl.bindCaller(mh, hostClass);
// Note: caller will apply varargs after this step happens.
return cbmh;
@@ -1262,7 +1292,7 @@
} else if (MethodHandleNatives.refKindIsMethod(refKind)) {
MemberName method = (resolved != null) ? resolved
: resolveOrFail(refKind, defc, name, (MethodType) type);
- return getDirectMethod(refKind, defc, method);
+ return getDirectMethod(refKind, defc, method, lookupClass);
} else if (refKind == REF_newInvokeSpecial) {
assert(name == null || name.equals("<init>"));
MemberName ctor = (resolved != null) ? resolved