diff -r d090627aedb8 -r 11431bbc9549 hotspot/src/share/vm/interpreter/linkResolver.cpp --- a/hotspot/src/share/vm/interpreter/linkResolver.cpp Wed Apr 19 14:37:11 2017 +0200 +++ b/hotspot/src/share/vm/interpreter/linkResolver.cpp Thu Dec 01 14:21:31 2016 -0500 @@ -1057,12 +1057,14 @@ void LinkResolver::resolve_special_call(CallInfo& result, + Handle recv, const LinkInfo& link_info, TRAPS) { methodHandle resolved_method = linktime_resolve_special_method(link_info, CHECK); runtime_resolve_special_method(result, resolved_method, link_info.resolved_klass(), link_info.current_klass(), + recv, link_info.check_access(), CHECK); } @@ -1149,6 +1151,7 @@ const methodHandle& resolved_method, KlassHandle resolved_klass, KlassHandle current_klass, + Handle recv, bool check_access, TRAPS) { // resolved method is selected method unless we have an old-style lookup @@ -1157,21 +1160,19 @@ // no checks for shadowing methodHandle sel_method(THREAD, resolved_method()); - // check if this is an old-style super call and do a new lookup if so - { KlassHandle method_klass = KlassHandle(THREAD, - resolved_method->method_holder()); + if (check_access && + // check if the method is not + resolved_method->name() != vmSymbols::object_initializer_name()) { - if (check_access && + // check if this is an old-style super call and do a new lookup if so // a) check if ACC_SUPER flag is set for the current class - (current_klass->is_super() || !AllowNonVirtualCalls) && + if ((current_klass->is_super() || !AllowNonVirtualCalls) && // b) check if the class of the resolved_klass is a superclass // (not supertype in order to exclude interface classes) of the current class. // This check is not performed for super.invoke for interface methods // in super interfaces. current_klass->is_subclass_of(resolved_klass()) && - current_klass() != resolved_klass() && - // c) check if the method is not - resolved_method->name() != vmSymbols::object_initializer_name()) { + current_klass() != resolved_klass()) { // Lookup super method KlassHandle super_klass(THREAD, current_klass->super()); sel_method = lookup_instance_method_in_klasses(super_klass, @@ -1186,6 +1187,27 @@ resolved_method->signature())); } } + + // Check that the class of objectref (the receiver) is the current class or interface, + // or a subtype of the current class or interface (the sender), otherwise invokespecial + // throws IllegalAccessError. + // The verifier checks that the sender is a subtype of the class in the I/MR operand. + // The verifier also checks that the receiver is a subtype of the sender, if the sender is + // a class. If the sender is an interface, the check has to be performed at runtime. + InstanceKlass* sender = InstanceKlass::cast(current_klass()); + sender = sender->is_anonymous() ? sender->host_klass() : sender; + if (sender->is_interface() && recv.not_null()) { + Klass* receiver_klass = recv->klass(); + if (!receiver_klass->is_subtype_of(sender)) { + ResourceMark rm(THREAD); + char buf[500]; + jio_snprintf(buf, sizeof(buf), + "Receiver class %s must be the current class or a subtype of interface %s", + receiver_klass->name()->as_C_string(), + sender->name()->as_C_string()); + THROW_MSG(vmSymbols::java_lang_IllegalAccessError(), buf); + } + } } // check if not static @@ -1518,7 +1540,7 @@ methodHandle LinkResolver::resolve_special_call_or_null(const LinkInfo& link_info) { EXCEPTION_MARK; CallInfo info; - resolve_special_call(info, link_info, THREAD); + resolve_special_call(info, Handle(), link_info, THREAD); if (HAS_PENDING_EXCEPTION) { CLEAR_PENDING_EXCEPTION; return methodHandle(); @@ -1534,7 +1556,7 @@ void LinkResolver::resolve_invoke(CallInfo& result, Handle recv, const constantPoolHandle& pool, int index, Bytecodes::Code byte, TRAPS) { switch (byte) { case Bytecodes::_invokestatic : resolve_invokestatic (result, pool, index, CHECK); break; - case Bytecodes::_invokespecial : resolve_invokespecial (result, pool, index, CHECK); break; + case Bytecodes::_invokespecial : resolve_invokespecial (result, recv, pool, index, CHECK); break; case Bytecodes::_invokevirtual : resolve_invokevirtual (result, recv, pool, index, CHECK); break; case Bytecodes::_invokehandle : resolve_invokehandle (result, pool, index, CHECK); break; case Bytecodes::_invokedynamic : resolve_invokedynamic (result, pool, index, CHECK); break; @@ -1563,7 +1585,7 @@ resolve_static_call(result, link_info, /*initialize_class=*/false, CHECK); break; case Bytecodes::_invokespecial: - resolve_special_call(result, link_info, CHECK); + resolve_special_call(result, recv, link_info, CHECK); break; default: fatal("bad call: %s", Bytecodes::name(byte)); @@ -1576,9 +1598,10 @@ } -void LinkResolver::resolve_invokespecial(CallInfo& result, const constantPoolHandle& pool, int index, TRAPS) { +void LinkResolver::resolve_invokespecial(CallInfo& result, Handle recv, + const constantPoolHandle& pool, int index, TRAPS) { LinkInfo link_info(pool, index, CHECK); - resolve_special_call(result, link_info, CHECK); + resolve_special_call(result, recv, link_info, CHECK); }