8356942: invokeinterface Throws AbstractMethodError Instead of IncompatibleClassChangeError

Reviewed-by: coleenp, iklam
This commit is contained in:
David Holmes 2025-07-14 22:53:45 +00:00
parent 5cf672e778
commit f36147b326
2 changed files with 68 additions and 58 deletions

View File

@ -1180,38 +1180,42 @@ void klassItable::check_constraints(GrowableArray<Method*>* supers, TRAPS) {
Method* interface_method = supers->at(i); // method overridden
if (target != nullptr && interface_method != nullptr) {
InstanceKlass* method_holder = target->method_holder();
InstanceKlass* interf = interface_method->method_holder();
HandleMark hm(THREAD);
Handle method_holder_loader(THREAD, method_holder->class_loader());
Handle interface_loader(THREAD, interf->class_loader());
// Do not check loader constraints for overpass methods because overpass
// methods are created by the jvm to throw exceptions.
if (!target->is_overpass()) {
InstanceKlass* method_holder = target->method_holder();
InstanceKlass* interf = interface_method->method_holder();
HandleMark hm(THREAD);
Handle method_holder_loader(THREAD, method_holder->class_loader());
Handle interface_loader(THREAD, interf->class_loader());
if (method_holder_loader() != interface_loader()) {
ResourceMark rm(THREAD);
Symbol* failed_type_symbol =
SystemDictionary::check_signature_loaders(target->signature(),
_klass,
method_holder_loader,
interface_loader,
true);
if (failed_type_symbol != nullptr) {
stringStream ss;
ss.print("loader constraint violation in interface itable"
" initialization for class %s: when selecting method '",
_klass->external_name());
interface_method->print_external_name(&ss),
ss.print("' the class loader %s for super interface %s, and the class"
" loader %s of the selected method's %s, %s have"
" different Class objects for the type %s used in the signature (%s; %s)",
interf->class_loader_data()->loader_name_and_id(),
interf->external_name(),
method_holder->class_loader_data()->loader_name_and_id(),
method_holder->external_kind(),
method_holder->external_name(),
failed_type_symbol->as_klass_external_name(),
interf->class_in_module_of_loader(false, true),
method_holder->class_in_module_of_loader(false, true));
THROW_MSG(vmSymbols::java_lang_LinkageError(), ss.as_string());
if (method_holder_loader() != interface_loader()) {
ResourceMark rm(THREAD);
Symbol* failed_type_symbol =
SystemDictionary::check_signature_loaders(target->signature(),
_klass,
method_holder_loader,
interface_loader,
true);
if (failed_type_symbol != nullptr) {
stringStream ss;
ss.print("loader constraint violation in interface itable"
" initialization for class %s: when selecting method '",
_klass->external_name());
interface_method->print_external_name(&ss),
ss.print("' the class loader %s for super interface %s, and the class"
" loader %s of the selected method's %s, %s have"
" different Class objects for the type %s used in the signature (%s; %s)",
interf->class_loader_data()->loader_name_and_id(),
interf->external_name(),
method_holder->class_loader_data()->loader_name_and_id(),
method_holder->external_kind(),
method_holder->external_name(),
failed_type_symbol->as_klass_external_name(),
interf->class_in_module_of_loader(false, true),
method_holder->class_in_module_of_loader(false, true));
THROW_MSG(vmSymbols::java_lang_LinkageError(), ss.as_string());
}
}
}
}
@ -1333,11 +1337,9 @@ void klassItable::initialize_itable_for_interface(int method_table_offset, Insta
target = LinkResolver::lookup_instance_method_in_klasses(_klass, m->name(), m->signature(),
Klass::PrivateLookupMode::skip);
}
if (target == nullptr || !target->is_public() || target->is_abstract() || target->is_overpass()) {
assert(target == nullptr || !target->is_overpass() || target->is_public(),
"Non-public overpass method!");
if (target == nullptr || !target->is_public() || target->is_abstract()) {
// Entry does not resolve. Leave it empty for AbstractMethodError or other error.
if (!(target == nullptr) && !target->is_public()) {
if (target != nullptr && !target->is_public()) {
// Stuff an IllegalAccessError throwing method in there instead.
itableOffsetEntry::method_entry(_klass, method_table_offset)[m->itable_index()].
initialize(_klass, Universe::throw_illegal_access_error());

View File

@ -82,6 +82,8 @@ public class ConflictingDefaultsTest extends DefMethTest {
* class C implements I, J {}
*
* TEST: C c = new C(); c.m() ==> ICCE
* TEST: I c = new C(); c.m() ==> ICCE
* TEST: J c = new C(); c.m() ==> ICCE
*/
public void testConflict(TestBuilder b) {
Interface I = b.intf("I")
@ -95,7 +97,13 @@ public class ConflictingDefaultsTest extends DefMethTest {
ConcreteClass C = b.clazz("C").implement(I,J).build();
b.test().callSite(C, C, "m","()I")
.throws_(IncompatibleClassChangeError.class)
.throwsExact(IncompatibleClassChangeError.class)
.done()
.test().callSite(I, C, "m","()I")
.throwsExact(IncompatibleClassChangeError.class)
.done()
.test().callSite(J, C, "m","()I")
.throwsExact(IncompatibleClassChangeError.class)
.done();
}
@ -145,7 +153,7 @@ public class ConflictingDefaultsTest extends DefMethTest {
ConcreteClass C = b.clazz("C").implement(J).build();
b.test().callSite(C, C, "m","()I")
.throws_(AbstractMethodError.class)
.throwsExact(AbstractMethodError.class)
.done();
}
@ -177,16 +185,16 @@ public class ConflictingDefaultsTest extends DefMethTest {
.build();
b.test().callSite(C, C, "m","()I")
.throws_(AbstractMethodError.class)
.throwsExact(AbstractMethodError.class)
.done()
.test().callSite(J, C, "m","()I")
.throws_(AbstractMethodError.class)
.throwsExact(AbstractMethodError.class)
.done()
.test().callSite(I, C, "m","()I")
.throws_(AbstractMethodError.class)
.throwsExact(AbstractMethodError.class)
.done()
.test().callSite(D, D, "m","()I")
.throws_(AbstractMethodError.class)
.throwsExact(AbstractMethodError.class)
.done();
}
@ -218,7 +226,7 @@ public class ConflictingDefaultsTest extends DefMethTest {
ConcreteClass C = b.clazz("C").extend(A).implement(K).build();
b.test().callSite(A, C, "m","()I")
.throws_(AbstractMethodError.class)
.throwsExact(AbstractMethodError.class)
.done();
}
@ -259,13 +267,13 @@ public class ConflictingDefaultsTest extends DefMethTest {
ConcreteClass D = b.clazz("D").extend(C).implement(L).build();
b.test().callSite(I, A, "m","()I")
.throws_(IncompatibleClassChangeError.class)
.throwsExact(IncompatibleClassChangeError.class)
.done()
.test().callSite(K, C, "m","()I")
.throws_(AbstractMethodError.class)
.throwsExact(AbstractMethodError.class)
.done()
.test().callSite(L, D, "m","()I")
.throws_(AbstractMethodError.class)
.throwsExact(AbstractMethodError.class)
.done();
}
@ -307,10 +315,10 @@ public class ConflictingDefaultsTest extends DefMethTest {
.build();
b.test().callSite(I, A, "m","()I")
.throws_(IncompatibleClassChangeError.class)
.throwsExact(IncompatibleClassChangeError.class)
.done()
.test().callSite(L, D, "m","()I")
.throws_(AbstractMethodError.class)
.throwsExact(AbstractMethodError.class)
.done();
}
@ -370,22 +378,22 @@ public class ConflictingDefaultsTest extends DefMethTest {
}
b.test().callSite(A, C, "m", "()I")
.throws_(expectedError2)
.throwsExact(expectedError2)
.done()
.test().callSite(C, C, "m", "()I")
.throws_(expectedError2)
.throwsExact(expectedError2)
.done()
.test().callSite(J, C, "m", "()I")
.throws_(expectedError1)
.throwsExact(expectedError1)
.done()
.test().callSite(I, C, "m", "()I")
.throws_(expectedError1)
.throwsExact(expectedError1)
.done()
.test().callSite(C, C, "test_Cmethod_ISMR", "()V")
.throws_(expectedError2)
.throwsExact(expectedError2)
.done()
.test().callSite(A, C, "test_Amethod_ISIMR", "()V")
.throws_(expectedError2)
.throwsExact(expectedError2)
.done();
}
@ -486,13 +494,13 @@ public class ConflictingDefaultsTest extends DefMethTest {
.test()
.callSite(I, C, "m","(I)I")
.params(0)
.throws_(NoSuchMethodError.class)
.throwsExact(NoSuchMethodError.class)
.done()
// J j = new C(); ...
.test()
.callSite(J, C, "m","()I")
.throws_(NoSuchMethodError.class)
.throwsExact(NoSuchMethodError.class)
.done()
.test()
.callSite(J, C, "m","(I)I")
@ -539,19 +547,19 @@ public class ConflictingDefaultsTest extends DefMethTest {
// I i = new C(); ...
b.test()
.callSite(I, C, "m","()I")
.throws_(IncompatibleClassChangeError.class)
.throwsExact(IncompatibleClassChangeError.class)
.done()
// J j = new C(); ...
.test()
.callSite(J, C, "m","()I")
.throws_(IncompatibleClassChangeError.class)
.throwsExact(IncompatibleClassChangeError.class)
.done()
// C c = new C(); ...
.test()
.callSite(C, C, "m","()I")
.throws_(IncompatibleClassChangeError.class)
.throwsExact(IncompatibleClassChangeError.class)
.done()
.test()
.callSite(C, C, "m","(I)I")