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:
parent
49ff52087b
commit
7aaf76c529
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* 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);
|
return new NativeAccessor(ctor);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final int PARAM_COUNT_MASK = 0x00FF;
|
private final int paramCount;
|
||||||
private static final int NONZERO_BIT = 0x8000_0000;
|
|
||||||
|
|
||||||
private final int paramFlags;
|
|
||||||
private final MethodHandle target;
|
private final MethodHandle target;
|
||||||
|
|
||||||
DirectConstructorHandleAccessor(Constructor<?> ctor, MethodHandle target) {
|
DirectConstructorHandleAccessor(Constructor<?> ctor, MethodHandle target) {
|
||||||
this.paramFlags = (ctor.getParameterCount() & PARAM_COUNT_MASK) | NONZERO_BIT;
|
this.paramCount = ctor.getParameterCount();
|
||||||
this.target = target;
|
this.target = target;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object newInstance(Object[] args) throws InstantiationException, InvocationTargetException {
|
public Object newInstance(Object[] args) throws InstantiationException, InvocationTargetException {
|
||||||
int argc = args != null ? args.length : 0;
|
int argc = args != null ? args.length : 0;
|
||||||
// only check argument count for specialized forms
|
if (argc != paramCount) {
|
||||||
int paramCount = paramFlags & PARAM_COUNT_MASK;
|
|
||||||
if (paramCount <= SPECIALIZED_PARAM_COUNT && argc != paramCount) {
|
|
||||||
throw new IllegalArgumentException("wrong number of arguments: " + argc + " expected: " + paramCount);
|
throw new IllegalArgumentException("wrong number of arguments: " + argc + " expected: " + paramCount);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@ -87,7 +82,7 @@ class DirectConstructorHandleAccessor extends ConstructorAccessorImpl {
|
|||||||
@Hidden
|
@Hidden
|
||||||
@ForceInline
|
@ForceInline
|
||||||
Object invokeImpl(Object[] args) throws Throwable {
|
Object invokeImpl(Object[] args) throws Throwable {
|
||||||
return switch (paramFlags & PARAM_COUNT_MASK) {
|
return switch (paramCount) {
|
||||||
case 0 -> target.invokeExact();
|
case 0 -> target.invokeExact();
|
||||||
case 1 -> target.invokeExact(args[0]);
|
case 1 -> target.invokeExact(args[0]);
|
||||||
case 2 -> target.invokeExact(args[0], args[1]);
|
case 2 -> target.invokeExact(args[0], args[1]);
|
||||||
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* 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 java.lang.reflect.Modifier;
|
||||||
|
|
||||||
import static java.lang.invoke.MethodType.genericMethodType;
|
import static java.lang.invoke.MethodType.genericMethodType;
|
||||||
import static jdk.internal.reflect.MethodHandleAccessorFactory.SPECIALIZED_PARAM_COUNT;
|
|
||||||
import static jdk.internal.reflect.MethodHandleAccessorFactory.LazyStaticHolder.JLIA;
|
import static jdk.internal.reflect.MethodHandleAccessorFactory.LazyStaticHolder.JLIA;
|
||||||
|
|
||||||
class DirectMethodHandleAccessor extends MethodAccessorImpl {
|
class DirectMethodHandleAccessor extends MethodAccessorImpl {
|
||||||
@ -329,9 +328,6 @@ class DirectMethodHandleAccessor extends MethodAccessorImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void checkArgumentCount(int paramCount, Object[] args) {
|
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;
|
int argc = args != null ? args.length : 0;
|
||||||
if (argc != paramCount) {
|
if (argc != paramCount) {
|
||||||
throw new IllegalArgumentException("wrong number of arguments: " + argc + " expected: " + paramCount);
|
throw new IllegalArgumentException("wrong number of arguments: " + argc + " expected: " + paramCount);
|
||||||
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* @test
|
* @test
|
||||||
* @bug 8271820
|
* @bug 8271820 8300924
|
||||||
* @modules java.base/jdk.internal.reflect
|
* @modules java.base/jdk.internal.reflect
|
||||||
* @summary Test compliance of ConstructorAccessor, FieldAccessor, MethodAccessor implementations
|
* @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
|
* @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;
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
public class MethodHandleAccessorsTest {
|
public class MethodHandleAccessorsTest {
|
||||||
|
static final boolean newImpl = Boolean.getBoolean("jdk.reflect.useDirectMethodHandle");
|
||||||
|
|
||||||
|
|
||||||
public static void public_static_V() {}
|
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 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 void public_I_V(int i) {}
|
||||||
|
|
||||||
public int public_I_I(int i) { return i; }
|
public int public_I_I(int i) { return i; }
|
||||||
@ -146,6 +154,14 @@ public class MethodHandleAccessorsTest {
|
|||||||
this(varargs_object(first, rest));
|
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) {
|
public Public(RuntimeException exc) {
|
||||||
throw exc;
|
throw exc;
|
||||||
}
|
}
|
||||||
@ -405,6 +421,10 @@ public class MethodHandleAccessorsTest {
|
|||||||
private static final Throwable[] wrong_argument_count_no_details = new Throwable[] {
|
private static final Throwable[] wrong_argument_count_no_details = new Throwable[] {
|
||||||
new IllegalArgumentException("wrong number of arguments")
|
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[] {
|
private static final Throwable[] wrong_argument_count = new Throwable[] {
|
||||||
new IllegalArgumentException("wrong number of arguments"),
|
new IllegalArgumentException("wrong number of arguments"),
|
||||||
new IllegalArgumentException("array is not of length 1")
|
new IllegalArgumentException("array is not of length 1")
|
||||||
@ -462,7 +482,6 @@ public class MethodHandleAccessorsTest {
|
|||||||
private Object[][] testOneArgMethods() {
|
private Object[][] testOneArgMethods() {
|
||||||
MethodHandleAccessorsTest inst = new MethodHandleAccessorsTest();
|
MethodHandleAccessorsTest inst = new MethodHandleAccessorsTest();
|
||||||
Object wrongInst = new Object();
|
Object wrongInst = new Object();
|
||||||
boolean newImpl = Boolean.getBoolean("jdk.reflect.useDirectMethodHandle");
|
|
||||||
return new Object[][]{
|
return new Object[][]{
|
||||||
new Object[] {"public_static_I_V", int.class, null, new Object[]{12}, null, noException},
|
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},
|
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")
|
@DataProvider(name = "testMethodsWithVarargs")
|
||||||
private Object[][] testMethodsWithVarargs() {
|
private Object[][] testMethodsWithVarargs() {
|
||||||
Class<?>[] paramTypes = new Class<?>[] { int[].class };
|
Class<?>[] paramTypes = new Class<?>[] { int[].class };
|
||||||
@ -523,6 +563,12 @@ public class MethodHandleAccessorsTest {
|
|||||||
doTest(MethodHandleAccessorsTest.class.getDeclaredMethod(methodname, paramType), target, args, expectedReturn, expectedExpections);
|
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")
|
@Test(dataProvider = "testMethodsWithVarargs")
|
||||||
public void testMethodsWithVarargs(String methodname, Class<?>[] paramTypes, Object target, Object[] args,
|
public void testMethodsWithVarargs(String methodname, Class<?>[] paramTypes, Object target, Object[] args,
|
||||||
Object expectedReturn, Throwable[] expectedExpections) throws Exception {
|
Object expectedReturn, Throwable[] expectedExpections) throws Exception {
|
||||||
@ -561,6 +607,26 @@ public class MethodHandleAccessorsTest {
|
|||||||
doTest(Public.class.getDeclaredConstructor(paramTypes), args, expectedReturn, expectedExpections);
|
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
|
@Test
|
||||||
public void testOtherConstructors() throws Exception {
|
public void testOtherConstructors() throws Exception {
|
||||||
doTest(Private.class.getDeclaredConstructor(), new Object[]{}, new Private());
|
doTest(Private.class.getDeclaredConstructor(), new Object[]{}, new Private());
|
||||||
|
Loading…
Reference in New Issue
Block a user