8300924: Method::invoke throws wrong exception type when passing wrong number of arguments to method with 4 or more parameters

Reviewed-by: rriggs
This commit is contained in:
Mandy Chung 2023-01-27 17:13:54 +00:00
parent 49ff52087b
commit 7aaf76c529
3 changed files with 75 additions and 18 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -44,23 +44,18 @@ class DirectConstructorHandleAccessor extends ConstructorAccessorImpl {
return new NativeAccessor(ctor);
}
private static final int PARAM_COUNT_MASK = 0x00FF;
private static final int NONZERO_BIT = 0x8000_0000;
private final int paramFlags;
private final int paramCount;
private final MethodHandle target;
DirectConstructorHandleAccessor(Constructor<?> ctor, MethodHandle target) {
this.paramFlags = (ctor.getParameterCount() & PARAM_COUNT_MASK) | NONZERO_BIT;
this.paramCount = ctor.getParameterCount();
this.target = target;
}
@Override
public Object newInstance(Object[] args) throws InstantiationException, InvocationTargetException {
int argc = args != null ? args.length : 0;
// only check argument count for specialized forms
int paramCount = paramFlags & PARAM_COUNT_MASK;
if (paramCount <= SPECIALIZED_PARAM_COUNT && argc != paramCount) {
if (argc != paramCount) {
throw new IllegalArgumentException("wrong number of arguments: " + argc + " expected: " + paramCount);
}
try {
@ -87,7 +82,7 @@ class DirectConstructorHandleAccessor extends ConstructorAccessorImpl {
@Hidden
@ForceInline
Object invokeImpl(Object[] args) throws Throwable {
return switch (paramFlags & PARAM_COUNT_MASK) {
return switch (paramCount) {
case 0 -> target.invokeExact();
case 1 -> target.invokeExact(args[0]);
case 2 -> target.invokeExact(args[0], args[1]);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -39,7 +39,6 @@ import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import static java.lang.invoke.MethodType.genericMethodType;
import static jdk.internal.reflect.MethodHandleAccessorFactory.SPECIALIZED_PARAM_COUNT;
import static jdk.internal.reflect.MethodHandleAccessorFactory.LazyStaticHolder.JLIA;
class DirectMethodHandleAccessor extends MethodAccessorImpl {
@ -329,9 +328,6 @@ class DirectMethodHandleAccessor extends MethodAccessorImpl {
}
private static void checkArgumentCount(int paramCount, Object[] args) {
// only check argument count for specialized forms
if (paramCount > SPECIALIZED_PARAM_COUNT) return;
int argc = args != null ? args.length : 0;
if (argc != paramCount) {
throw new IllegalArgumentException("wrong number of arguments: " + argc + " expected: " + paramCount);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -23,7 +23,7 @@
/*
* @test
* @bug 8271820
* @bug 8271820 8300924
* @modules java.base/jdk.internal.reflect
* @summary Test compliance of ConstructorAccessor, FieldAccessor, MethodAccessor implementations
* @run testng/othervm --add-exports java.base/jdk.internal.reflect=ALL-UNNAMED -Djdk.reflect.useDirectMethodHandle=true -XX:-ShowCodeDetailsInExceptionMessages MethodHandleAccessorsTest
@ -55,6 +55,8 @@ import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
public class MethodHandleAccessorsTest {
static final boolean newImpl = Boolean.getBoolean("jdk.reflect.useDirectMethodHandle");
public static void public_static_V() {}
@ -68,6 +70,12 @@ public class MethodHandleAccessorsTest {
public static int public_static_I_I(int i) { return i; }
public static void public_static_V_L3(Object o1, Object o2, Object o3) { }
public static void public_static_V_L4(Object o1, Object o2, Object o3, Object o4) { }
public static void public_V_L5(Object o1, Object o2, Object o3, Object o4, Object o5) { }
public void public_I_V(int i) {}
public int public_I_I(int i) { return i; }
@ -146,6 +154,14 @@ public class MethodHandleAccessorsTest {
this(varargs_object(first, rest));
}
public Public(Object o1, Object o2, Object o3) {
this("3-arg constructor");
}
public Public(Object o1, Object o2, Object o3, Object o4) {
this("4-arg constructor");
}
public Public(RuntimeException exc) {
throw exc;
}
@ -405,6 +421,10 @@ public class MethodHandleAccessorsTest {
private static final Throwable[] wrong_argument_count_no_details = new Throwable[] {
new IllegalArgumentException("wrong number of arguments")
};
private static final Throwable[] wrong_argument_count_zero_args = new Throwable[] {
new IllegalArgumentException("wrong number of arguments: 0 expected:")
};
private static final Throwable[] wrong_argument_count = new Throwable[] {
new IllegalArgumentException("wrong number of arguments"),
new IllegalArgumentException("array is not of length 1")
@ -462,7 +482,6 @@ public class MethodHandleAccessorsTest {
private Object[][] testOneArgMethods() {
MethodHandleAccessorsTest inst = new MethodHandleAccessorsTest();
Object wrongInst = new Object();
boolean newImpl = Boolean.getBoolean("jdk.reflect.useDirectMethodHandle");
return new Object[][]{
new Object[] {"public_static_I_V", int.class, null, new Object[]{12}, null, noException},
new Object[] {"public_static_I_I", int.class, null, new Object[]{12}, 12, noException},
@ -493,6 +512,27 @@ public class MethodHandleAccessorsTest {
};
}
@DataProvider(name = "testMultiArgMethods")
private Object[][] testMultiArgMethods() {
MethodHandleAccessorsTest inst = new MethodHandleAccessorsTest();
Class<?>[] params_L3 = new Class<?>[] { Object.class, Object.class, Object.class};
Class<?>[] params_L4 = new Class<?>[] { Object.class, Object.class, Object.class, Object.class};
Class<?>[] params_L5 = new Class<?>[] { Object.class, Object.class, Object.class, Object.class, Object.class};
return new Object[][]{
new Object[]{"public_static_V_L3", params_L3, null, new Object[3], null, noException},
new Object[]{"public_static_V_L4", params_L4, null, new Object[4], null, noException},
new Object[]{"public_V_L5", params_L5, inst, new Object[5], null, noException},
// wrong arguments
new Object[]{"public_static_V_L3", params_L3, null, null, null,
newImpl ? wrong_argument_count_zero_args : wrong_argument_count_no_details},
new Object[]{"public_static_V_L4", params_L4, null, new Object[0], null,
newImpl ? wrong_argument_count_zero_args : wrong_argument_count_no_details},
new Object[]{"public_V_L5", params_L5, inst, null, null,
newImpl ? wrong_argument_count_zero_args : wrong_argument_count_no_details},
};
}
@DataProvider(name = "testMethodsWithVarargs")
private Object[][] testMethodsWithVarargs() {
Class<?>[] paramTypes = new Class<?>[] { int[].class };
@ -523,6 +563,12 @@ public class MethodHandleAccessorsTest {
doTest(MethodHandleAccessorsTest.class.getDeclaredMethod(methodname, paramType), target, args, expectedReturn, expectedExpections);
}
@Test(dataProvider = "testMultiArgMethods")
public void testMultiArgMethod(String methodname, Class<?>[] paramTypes, Object target, Object[] args,
Object expectedReturn, Throwable[] expectedExpections) throws Exception {
doTest(MethodHandleAccessorsTest.class.getDeclaredMethod(methodname, paramTypes), target, args, expectedReturn, expectedExpections);
}
@Test(dataProvider = "testMethodsWithVarargs")
public void testMethodsWithVarargs(String methodname, Class<?>[] paramTypes, Object target, Object[] args,
Object expectedReturn, Throwable[] expectedExpections) throws Exception {
@ -561,6 +607,26 @@ public class MethodHandleAccessorsTest {
doTest(Public.class.getDeclaredConstructor(paramTypes), args, expectedReturn, expectedExpections);
}
@DataProvider(name = "testMultiArgConstructors")
private Object[][] testMultiArgConstructors() {
Class<?>[] params_L3 = new Class<?>[] { Object.class, Object.class, Object.class};
Class<?>[] params_L4 = new Class<?>[] { Object.class, Object.class, Object.class, Object.class};
Object o = "arg";
return new Object[][]{
new Object[]{params_L3, new Object[3], new Public(o, o, o), noException},
new Object[]{params_L4, new Object[4], new Public(o, o, o, o), noException},
new Object[]{params_L3, new Object[]{}, null,
newImpl ? wrong_argument_count_zero_args : wrong_argument_count_no_details},
new Object[]{params_L4, null, null,
newImpl ? wrong_argument_count_zero_args : wrong_argument_count_no_details},
};
}
@Test(dataProvider = "testMultiArgConstructors")
public void testMultiArgConstructors(Class<?>[] paramTypes, Object[] args, Object expectedReturn, Throwable[] expectedExpections) throws Exception {
doTest(Public.class.getDeclaredConstructor(paramTypes), args, expectedReturn, expectedExpections);
}
@Test
public void testOtherConstructors() throws Exception {
doTest(Private.class.getDeclaredConstructor(), new Object[]{}, new Private());