--- 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 <init>
+ 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 <init>
- 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);
}