提交 d28f1918 编写于 作者: J jrose

8001105: findVirtual of Object[].clone produces internal error

Summary: Replicate JVM logic for access control that makes Object.clone appear public when applied to an array type.
Reviewed-by: twisti
上级 ee089afc
......@@ -1204,6 +1204,26 @@ return mh1;
int allowedModes = this.allowedModes;
if (allowedModes == TRUSTED) return;
int mods = m.getModifiers();
if (Modifier.isProtected(mods) &&
refKind == REF_invokeVirtual &&
m.getDeclaringClass() == Object.class &&
m.getName().equals("clone") &&
refc.isArray()) {
// The JVM does this hack also.
// (See ClassVerifier::verify_invoke_instructions
// and LinkResolver::check_method_accessability.)
// Because the JVM does not allow separate methods on array types,
// there is no separate method for int[].clone.
// All arrays simply inherit Object.clone.
// But for access checking logic, we make Object.clone
// (normally protected) appear to be public.
// Later on, when the DirectMethodHandle is created,
// its leading argument will be restricted to the
// requested array type.
// N.B. The return type is not adjusted, because
// that is *not* the bytecode behavior.
mods ^= Modifier.PROTECTED | Modifier.PUBLIC;
}
if (Modifier.isFinal(mods) &&
MethodHandleNatives.refKindIsSetter(refKind))
throw m.makeAccessException("unexpected set of a final field", this);
......
......@@ -140,7 +140,7 @@ public class MethodHandlesTest {
Object actual = calledLog.get(calledLog.size() - 1);
if (expected.equals(actual) && verbosity < 9) return;
System.out.println("assertCalled "+name+":");
System.out.println("expected: "+expected);
System.out.println("expected: "+deepToString(expected));
System.out.println("actual: "+actual);
System.out.println("ex. types: "+getClasses(expected));
System.out.println("act. types: "+getClasses(actual));
......@@ -148,7 +148,25 @@ public class MethodHandlesTest {
}
static void printCalled(MethodHandle target, String name, Object... args) {
if (verbosity >= 3)
System.out.println("calling MH="+target+" to "+name+Arrays.toString(args));
System.out.println("calling MH="+target+" to "+name+deepToString(args));
}
static String deepToString(Object x) {
if (x == null) return "null";
if (x instanceof Collection)
x = ((Collection)x).toArray();
if (x instanceof Object[]) {
Object[] ax = (Object[]) x;
ax = Arrays.copyOf(ax, ax.length, Object[].class);
for (int i = 0; i < ax.length; i++)
ax[i] = deepToString(ax[i]);
x = Arrays.deepToString(ax);
}
if (x.getClass().isArray())
try {
x = Arrays.class.getMethod("toString", x.getClass()).invoke(null, x);
} catch (ReflectiveOperationException ex) { throw new Error(ex); }
assert(!(x instanceof Object[]));
return x.toString();
}
static Object castToWrapper(Object value, Class<?> dst) {
......@@ -230,6 +248,12 @@ public class MethodHandlesTest {
{ param = c; break; }
}
}
if (param.isArray()) {
Class<?> ctype = param.getComponentType();
Object arg = Array.newInstance(ctype, 2);
Array.set(arg, 0, randomArg(ctype));
return arg;
}
if (param.isInterface() && param.isAssignableFrom(List.class))
return Arrays.asList("#"+nextArg());
if (param.isInterface() || param.isAssignableFrom(String.class))
......@@ -568,6 +592,16 @@ public class MethodHandlesTest {
testFindVirtual(IntExample.Impl.class, IntExample.class, void.class, "Int/v0");
}
@Test
public void testFindVirtualClone() throws Throwable {
// test some ad hoc system methods
testFindVirtual(false, PUBLIC, Object.class, Object.class, "clone");
testFindVirtual(true, PUBLIC, Object[].class, Object.class, "clone");
testFindVirtual(true, PUBLIC, int[].class, Object.class, "clone");
for (Class<?> cls : new Class<?>[]{ boolean[].class, long[].class, float[].class, char[].class })
testFindVirtual(true, PUBLIC, cls, Object.class, "clone");
}
void testFindVirtual(Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
Class<?> rcvc = defc;
testFindVirtual(rcvc, defc, ret, name, params);
......@@ -580,6 +614,9 @@ public class MethodHandlesTest {
void testFindVirtual(Lookup lookup, Class<?> rcvc, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
testFindVirtual(true, lookup, rcvc, defc, ret, name, params);
}
void testFindVirtual(boolean positive, Lookup lookup, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
testFindVirtual(positive, lookup, defc, defc, ret, name, params);
}
void testFindVirtual(boolean positive, Lookup lookup, Class<?> rcvc, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
countTest(positive);
String methodName = name.substring(1 + name.indexOf('/')); // foo/bar => foo
......@@ -618,8 +655,21 @@ public class MethodHandlesTest {
Object[] argsWithSelf = randomArgs(paramsWithSelf);
if (selfc.isAssignableFrom(rcvc) && rcvc != selfc) argsWithSelf[0] = randomArg(rcvc);
printCalled(target, name, argsWithSelf);
target.invokeWithArguments(argsWithSelf);
assertCalled(name, argsWithSelf);
Object res = target.invokeWithArguments(argsWithSelf);
if (Example.class.isAssignableFrom(defc) || IntExample.class.isAssignableFrom(defc)) {
assertCalled(name, argsWithSelf);
} else if (name.equals("clone")) {
// Ad hoc method call outside Example. For Object[].clone.
printCalled(target, name, argsWithSelf);
assertEquals(MethodType.methodType(Object.class, rcvc), target.type());
Object orig = argsWithSelf[0];
assertEquals(orig.getClass(), res.getClass());
if (res instanceof Object[])
assertArrayEquals((Object[])res, (Object[])argsWithSelf[0]);
assert(Arrays.deepEquals(new Object[]{res}, new Object[]{argsWithSelf[0]}));
} else {
assert(false) : Arrays.asList(positive, lookup, rcvc, defc, ret, name, deepToString(params));
}
if (verbosity >= 1)
System.out.print(':');
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册