8336468: Reflection and MethodHandles should use more precise initializer checks

Reviewed-by: liach, coleenp
This commit is contained in:
Aleksey Shipilev 2024-09-26 15:14:21 +00:00
parent e36ce5f034
commit 376056ca48
5 changed files with 30 additions and 25 deletions

View File

@ -3052,9 +3052,10 @@ void java_lang_ClassFrameInfo::serialize_offsets(SerializeClosure* f) {
static int get_flags(const methodHandle& m) { static int get_flags(const methodHandle& m) {
int flags = (jushort)( m->access_flags().as_short() & JVM_RECOGNIZED_METHOD_MODIFIERS ); int flags = (jushort)( m->access_flags().as_short() & JVM_RECOGNIZED_METHOD_MODIFIERS );
if (m->is_initializer()) { if (m->is_object_initializer()) {
flags |= java_lang_invoke_MemberName::MN_IS_CONSTRUCTOR; flags |= java_lang_invoke_MemberName::MN_IS_CONSTRUCTOR;
} else { } else {
// Note: Static initializers can be here. Record them as plain methods.
flags |= java_lang_invoke_MemberName::MN_IS_METHOD; flags |= java_lang_invoke_MemberName::MN_IS_METHOD;
} }
if (m->caller_sensitive()) { if (m->caller_sensitive()) {

View File

@ -444,9 +444,11 @@ JNI_ENTRY(jobject, jni_ToReflectedMethod(JNIEnv *env, jclass cls, jmethodID meth
methodHandle m (THREAD, Method::resolve_jmethod_id(method_id)); methodHandle m (THREAD, Method::resolve_jmethod_id(method_id));
assert(m->is_static() == (isStatic != 0), "jni_ToReflectedMethod access flags doesn't match"); assert(m->is_static() == (isStatic != 0), "jni_ToReflectedMethod access flags doesn't match");
oop reflection_method; oop reflection_method;
if (m->is_initializer()) { if (m->is_object_initializer()) {
reflection_method = Reflection::new_constructor(m, CHECK_NULL); reflection_method = Reflection::new_constructor(m, CHECK_NULL);
} else { } else {
// Note: Static initializers can theoretically be here, if JNI users manage
// to get their jmethodID. Record them as plain methods.
reflection_method = Reflection::new_method(m, false, CHECK_NULL); reflection_method = Reflection::new_method(m, false, CHECK_NULL);
} }
ret = JNIHandles::make_local(THREAD, reflection_method); ret = JNIHandles::make_local(THREAD, reflection_method);

View File

@ -1826,14 +1826,6 @@ JVM_ENTRY(jobjectArray, JVM_GetRecordComponents(JNIEnv* env, jclass ofClass))
} }
JVM_END JVM_END
static bool select_method(const methodHandle& method, bool want_constructor) {
if (want_constructor) {
return (method->is_initializer() && !method->is_static());
} else {
return (!method->is_initializer() && !method->is_overpass());
}
}
static jobjectArray get_class_declared_methods_helper( static jobjectArray get_class_declared_methods_helper(
JNIEnv *env, JNIEnv *env,
jclass ofClass, jboolean publicOnly, jclass ofClass, jboolean publicOnly,
@ -1866,14 +1858,22 @@ static jobjectArray get_class_declared_methods_helper(
GrowableArray<int>* idnums = new GrowableArray<int>(methods_length); GrowableArray<int>* idnums = new GrowableArray<int>(methods_length);
int num_methods = 0; int num_methods = 0;
// Select methods matching the criteria.
for (int i = 0; i < methods_length; i++) { for (int i = 0; i < methods_length; i++) {
methodHandle method(THREAD, methods->at(i)); Method* method = methods->at(i);
if (select_method(method, want_constructor)) { if (want_constructor && !method->is_object_initializer()) {
if (!publicOnly || method->is_public()) { continue;
idnums->push(method->method_idnum());
++num_methods;
}
} }
if (!want_constructor &&
(method->is_object_initializer() || method->is_static_initializer() ||
method->is_overpass())) {
continue;
}
if (publicOnly && !method->is_public()) {
continue;
}
idnums->push(method->method_idnum());
++num_methods;
} }
// Allocate result // Allocate result
@ -2175,10 +2175,11 @@ static jobject get_method_at_helper(const constantPoolHandle& cp, jint index, bo
THROW_MSG_NULL(vmSymbols::java_lang_RuntimeException(), "Unable to look up method in target class"); THROW_MSG_NULL(vmSymbols::java_lang_RuntimeException(), "Unable to look up method in target class");
} }
oop method; oop method;
if (!m->is_initializer() || m->is_static()) { if (m->is_object_initializer()) {
method = Reflection::new_method(m, true, CHECK_NULL);
} else {
method = Reflection::new_constructor(m, CHECK_NULL); method = Reflection::new_constructor(m, CHECK_NULL);
} else {
// new_method accepts <clinit> as Method here
method = Reflection::new_method(m, true, CHECK_NULL);
} }
return JNIHandles::make_local(THREAD, method); return JNIHandles::make_local(THREAD, method);
} }

View File

@ -313,8 +313,9 @@ oop MethodHandles::init_method_MemberName(Handle mname, CallInfo& info) {
case CallInfo::direct_call: case CallInfo::direct_call:
vmindex = Method::nonvirtual_vtable_index; vmindex = Method::nonvirtual_vtable_index;
if (m->is_static()) { if (m->is_static()) {
assert(!m->is_static_initializer(), "Cannot be static initializer");
flags |= IS_METHOD | (JVM_REF_invokeStatic << REFERENCE_KIND_SHIFT); flags |= IS_METHOD | (JVM_REF_invokeStatic << REFERENCE_KIND_SHIFT);
} else if (m->is_initializer()) { } else if (m->is_object_initializer()) {
flags |= IS_CONSTRUCTOR | (JVM_REF_invokeSpecial << REFERENCE_KIND_SHIFT); flags |= IS_CONSTRUCTOR | (JVM_REF_invokeSpecial << REFERENCE_KIND_SHIFT);
} else { } else {
// "special" reflects that this is a direct call, not that it // "special" reflects that this is a direct call, not that it

View File

@ -766,10 +766,10 @@ static Handle new_type(Symbol* signature, Klass* k, TRAPS) {
} }
oop Reflection::new_method(const methodHandle& method, bool for_constant_pool_access, TRAPS) { oop Reflection::new_method(const methodHandle& method, bool for_constant_pool_access, TRAPS) {
// Allow sun.reflect.ConstantPool to refer to <clinit> methods as java.lang.reflect.Methods. // Allow jdk.internal.reflect.ConstantPool to refer to <clinit> methods as java.lang.reflect.Methods.
assert(!method()->is_initializer() || assert(!method()->is_object_initializer() &&
(for_constant_pool_access && method()->is_static()), (for_constant_pool_access || !method()->is_static_initializer()),
"should call new_constructor instead"); "Should not be the initializer");
InstanceKlass* holder = method->method_holder(); InstanceKlass* holder = method->method_holder();
int slot = method->method_idnum(); int slot = method->method_idnum();
@ -817,7 +817,7 @@ oop Reflection::new_method(const methodHandle& method, bool for_constant_pool_ac
oop Reflection::new_constructor(const methodHandle& method, TRAPS) { oop Reflection::new_constructor(const methodHandle& method, TRAPS) {
assert(method()->is_initializer(), "should call new_method instead"); assert(method()->is_object_initializer(), "Should be the initializer");
InstanceKlass* holder = method->method_holder(); InstanceKlass* holder = method->method_holder();
int slot = method->method_idnum(); int slot = method->method_idnum();