--- 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