--- old/src/share/vm/classfile/verifier.cpp 2013-11-24 16:16:19.756814000 -0500 +++ new/src/share/vm/classfile/verifier.cpp 2013-11-24 16:16:19.017609000 -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,36 @@ 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 same_or_direct = false; 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)); + // Recheck for same or direct interface relevant to the host class + same_or_direct = 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 (!same_or_direct && + cp->tag_at(index).value() == JVM_CONSTANT_InterfaceMethodref) { + 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-24 16:16:22.115868000 -0500 +++ new/src/share/vm/classfile/verifier.hpp 2013-11-24 16:16:21.471881000 -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-24 16:16:24.657147000 -0500 +++ new/src/share/vm/interpreter/linkResolver.cpp 2013-11-24 16:16:23.885019000 -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-24 16:16:27.147253000 -0500 +++ new/src/share/vm/oops/instanceKlass.cpp 2013-11-24 16:16:26.434449000 -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-24 16:16:29.820662000 -0500 +++ new/src/share/vm/oops/instanceKlass.hpp 2013-11-24 16:16:29.008878000 -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