--- old/src/share/vm/classfile/verifier.cpp 2013-11-25 13:19:16.283303000 -0500 +++ new/src/share/vm/classfile/verifier.cpp 2013-11-25 13:19:15.014740000 -0500 @@ -2302,6 +2302,24 @@ } } +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* 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 @@ 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 --- old/src/share/vm/classfile/verifier.hpp 2013-11-25 13:19:20.343358000 -0500 +++ new/src/share/vm/classfile/verifier.hpp 2013-11-25 13:19:19.208361000 -0500 @@ -345,6 +345,9 @@ // 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, --- old/src/share/vm/interpreter/linkResolver.cpp 2013-11-25 13:19:24.338704000 -0500 +++ new/src/share/vm/interpreter/linkResolver.cpp 2013-11-25 13:19:23.110959000 -0500 @@ -914,6 +914,25 @@ ); 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()) { --- old/src/share/vm/oops/instanceKlass.cpp 2013-11-25 13:19:28.420958000 -0500 +++ new/src/share/vm/oops/instanceKlass.cpp 2013-11-25 13:19:27.138558000 -0500 @@ -1051,6 +1051,18 @@ 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)) { --- old/src/share/vm/oops/instanceKlass.hpp 2013-11-25 13:19:32.950699000 -0500 +++ new/src/share/vm/oops/instanceKlass.hpp 2013-11-25 13:19:31.651311000 -0500 @@ -777,6 +777,7 @@ // 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