8026065: InterfaceMethodref for invokespecial must name a direct superinterface
Add verification to check that invokespecial of an InterfaceMethodref names a method in a direct superinterface of the current class or interface in accordance with JSR 335, JVMS 4.9.2 Structural Constraints. Reviewed-by: acorn, hseigel, coleenp
This commit is contained in:
parent
b1e3461fe5
commit
28557bc30e
@ -2302,6 +2302,24 @@ void ClassVerifier::verify_invoke_init(
|
||||
}
|
||||
}
|
||||
|
||||
bool ClassVerifier::is_same_or_direct_interface(
|
||||
instanceKlassHandle klass,
|
||||
VerificationType klass_type,
|
||||
VerificationType ref_class_type) {
|
||||
if (ref_class_type.equals(klass_type)) return true;
|
||||
Array<Klass*>* local_interfaces = klass->local_interfaces();
|
||||
if (local_interfaces != NULL) {
|
||||
for (int x = 0; x < local_interfaces->length(); x++) {
|
||||
Klass* k = local_interfaces->at(x);
|
||||
assert (k != NULL && k->is_interface(), "invalid interface");
|
||||
if (ref_class_type.equals(VerificationType::reference_type(k->name()))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ClassVerifier::verify_invoke_instructions(
|
||||
RawBytecodeStream* bcs, u4 code_length, StackMapFrame* current_frame,
|
||||
bool *this_uninit, VerificationType return_type,
|
||||
@ -2432,23 +2450,38 @@ void ClassVerifier::verify_invoke_instructions(
|
||||
return;
|
||||
}
|
||||
} else if (opcode == Bytecodes::_invokespecial
|
||||
&& !ref_class_type.equals(current_type())
|
||||
&& !is_same_or_direct_interface(current_class(), current_type(), ref_class_type)
|
||||
&& !ref_class_type.equals(VerificationType::reference_type(
|
||||
current_class()->super()->name()))) {
|
||||
bool subtype = false;
|
||||
bool have_imr_indirect = cp->tag_at(index).value() == JVM_CONSTANT_InterfaceMethodref;
|
||||
if (!current_class()->is_anonymous()) {
|
||||
subtype = ref_class_type.is_assignable_from(
|
||||
current_type(), this, CHECK_VERIFY(this));
|
||||
} else {
|
||||
subtype = ref_class_type.is_assignable_from(VerificationType::reference_type(
|
||||
current_class()->host_klass()->name()), this, CHECK_VERIFY(this));
|
||||
VerificationType host_klass_type =
|
||||
VerificationType::reference_type(current_class()->host_klass()->name());
|
||||
subtype = ref_class_type.is_assignable_from(host_klass_type, this, CHECK_VERIFY(this));
|
||||
|
||||
// If invokespecial of IMR, need to recheck for same or
|
||||
// direct interface relative to the host class
|
||||
have_imr_indirect = (have_imr_indirect &&
|
||||
!is_same_or_direct_interface(
|
||||
InstanceKlass::cast(current_class()->host_klass()),
|
||||
host_klass_type, ref_class_type));
|
||||
}
|
||||
if (!subtype) {
|
||||
verify_error(ErrorContext::bad_code(bci),
|
||||
"Bad invokespecial instruction: "
|
||||
"current class isn't assignable to reference class.");
|
||||
return;
|
||||
} else if (have_imr_indirect) {
|
||||
verify_error(ErrorContext::bad_code(bci),
|
||||
"Bad invokespecial instruction: "
|
||||
"interface method reference is in an indirect superinterface.");
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
// Match method descriptor with operand stack
|
||||
for (int i = nargs - 1; i >= 0; i--) { // Run backwards
|
||||
|
@ -345,6 +345,9 @@ class ClassVerifier : public StackObj {
|
||||
// that a class has been verified and prepared for execution.
|
||||
bool was_recursively_verified() { return _klass->is_rewritten(); }
|
||||
|
||||
bool is_same_or_direct_interface(instanceKlassHandle klass,
|
||||
VerificationType klass_type, VerificationType ref_class_type);
|
||||
|
||||
public:
|
||||
enum {
|
||||
BYTECODE_OFFSET = 1,
|
||||
|
@ -915,6 +915,25 @@ void LinkResolver::linktime_resolve_special_method(methodHandle& resolved_method
|
||||
return;
|
||||
}
|
||||
|
||||
// check if invokespecial's interface method reference is in an indirect superinterface
|
||||
if (!current_klass.is_null() && resolved_klass->is_interface()) {
|
||||
Klass *klass_to_check = !InstanceKlass::cast(current_klass())->is_anonymous() ?
|
||||
current_klass() :
|
||||
InstanceKlass::cast(current_klass())->host_klass();
|
||||
|
||||
if (!InstanceKlass::cast(klass_to_check)->is_same_or_direct_interface(resolved_klass())) {
|
||||
ResourceMark rm(THREAD);
|
||||
char buf[200];
|
||||
jio_snprintf(buf, sizeof(buf),
|
||||
"Interface method reference: %s, is in an indirect superinterface of %s",
|
||||
Method::name_and_sig_as_C_string(resolved_klass(),
|
||||
resolved_method->name(),
|
||||
resolved_method->signature()),
|
||||
current_klass->external_name());
|
||||
THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(), buf);
|
||||
}
|
||||
}
|
||||
|
||||
// check if not static
|
||||
if (resolved_method->is_static()) {
|
||||
ResourceMark rm(THREAD);
|
||||
|
@ -1051,6 +1051,18 @@ bool InstanceKlass::implements_interface(Klass* k) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool InstanceKlass::is_same_or_direct_interface(Klass *k) const {
|
||||
// Verify direct super interface
|
||||
if (this == k) return true;
|
||||
assert(k->is_interface(), "should be an interface class");
|
||||
for (int i = 0; i < local_interfaces()->length(); i++) {
|
||||
if (local_interfaces()->at(i) == k) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
objArrayOop InstanceKlass::allocate_objArray(int n, int length, TRAPS) {
|
||||
if (length < 0) THROW_0(vmSymbols::java_lang_NegativeArraySizeException());
|
||||
if (length > arrayOopDesc::max_array_length(T_OBJECT)) {
|
||||
|
@ -777,6 +777,7 @@ class InstanceKlass: public Klass {
|
||||
|
||||
// subclass/subinterface checks
|
||||
bool implements_interface(Klass* k) const;
|
||||
bool is_same_or_direct_interface(Klass* k) const;
|
||||
|
||||
// Access to the implementor of an interface.
|
||||
Klass* implementor() const
|
||||
|
Loading…
Reference in New Issue
Block a user