8244090: public lookup should find public members of public exported types

Reviewed-by: lfoltan, psandoz
This commit is contained in:
Mandy Chung 2020-09-03 12:43:13 -07:00
parent 49a9d49dbd
commit 4e6a4af186
24 changed files with 369 additions and 75 deletions

View File

@ -761,7 +761,7 @@ Method* ciEnv::lookup_method(ciInstanceKlass* accessor,
InstanceKlass* accessor_klass = accessor->get_instanceKlass();
Klass* holder_klass = holder->get_Klass();
Method* dest_method;
LinkInfo link_info(holder_klass, name, sig, accessor_klass, LinkInfo::AccessCheck::required, tag);
LinkInfo link_info(holder_klass, name, sig, accessor_klass, LinkInfo::AccessCheck::required, LinkInfo::LoaderConstraintCheck::required, tag);
switch (bc) {
case Bytecodes::_invokestatic:
dest_method =

View File

@ -809,7 +809,8 @@ ciMethod* ciMethod::resolve_invoke(ciKlass* caller, ciKlass* exact_receiver, boo
Symbol* h_signature = signature()->get_symbol();
LinkInfo link_info(resolved, h_name, h_signature, caller_klass,
check_access ? LinkInfo::AccessCheck::required : LinkInfo::AccessCheck::skip);
check_access ? LinkInfo::AccessCheck::required : LinkInfo::AccessCheck::skip,
check_access ? LinkInfo::LoaderConstraintCheck::required : LinkInfo::LoaderConstraintCheck::skip);
Method* m = NULL;
// Only do exact lookup if receiver klass has been linked. Otherwise,
// the vtable has not been setup, and the LinkResolver will fail.

View File

@ -1134,7 +1134,11 @@ class java_lang_invoke_MemberName: AllStatic {
MN_NESTMATE_CLASS = 0x00000001,
MN_HIDDEN_CLASS = 0x00000002,
MN_STRONG_LOADER_LINK = 0x00000004,
MN_ACCESS_VM_ANNOTATIONS = 0x00000008
MN_ACCESS_VM_ANNOTATIONS = 0x00000008,
// Lookup modes
MN_MODULE_MODE = 0x00000010,
MN_UNCONDITIONAL_MODE = 0x00000020,
MN_TRUSTED_MODE = -1
};
// Accessors for code generation:

View File

@ -2830,7 +2830,7 @@ Handle SystemDictionary::link_method_handle_constant(Klass* caller,
// There's special logic on JDK side to handle them
// (see MethodHandles.linkMethodHandleConstant() and MethodHandles.findVirtualForMH()).
} else {
MethodHandles::resolve_MemberName(mname, caller, /*speculative_resolve*/false, CHECK_(empty));
MethodHandles::resolve_MemberName(mname, caller, 0, false /*speculative_resolve*/, CHECK_(empty));
}
// After method/field resolution succeeded, it's safe to resolve MH signature as well.

View File

@ -241,6 +241,7 @@ LinkInfo::LinkInfo(const constantPoolHandle& pool, int index, const methodHandle
// Coming from the constant pool always checks access
_check_access = true;
_check_loader_constraints = true;
}
LinkInfo::LinkInfo(const constantPoolHandle& pool, int index, TRAPS) {
@ -256,17 +257,20 @@ LinkInfo::LinkInfo(const constantPoolHandle& pool, int index, TRAPS) {
// Coming from the constant pool always checks access
_check_access = true;
_check_loader_constraints = true;
}
#ifndef PRODUCT
void LinkInfo::print() {
ResourceMark rm;
tty->print_cr("Link resolved_klass=%s name=%s signature=%s current_klass=%s check_access=%s",
tty->print_cr("Link resolved_klass=%s name=%s signature=%s current_klass=%s check_access=%s check_loader_constraints=%s",
_resolved_klass->name()->as_C_string(),
_name->as_C_string(),
_signature->as_C_string(),
_current_klass == NULL ? "(none)" : _current_klass->name()->as_C_string(),
_check_access ? "true" : "false");
_check_access ? "true" : "false",
_check_loader_constraints ? "true" : "false");
}
#endif // PRODUCT
//------------------------------------------------------------------------------------------------------------------------
@ -795,7 +799,8 @@ Method* LinkResolver::resolve_method(const LinkInfo& link_info,
resolved_method->method_holder(),
resolved_method,
CHECK_NULL);
}
if (link_info.check_loader_constraints()) {
// check loader constraints
check_method_loader_constraints(link_info, resolved_method, "method", CHECK_NULL);
}
@ -891,7 +896,8 @@ Method* LinkResolver::resolve_interface_method(const LinkInfo& link_info, Byteco
resolved_method->method_holder(),
resolved_method,
CHECK_NULL);
}
if (link_info.check_loader_constraints()) {
check_method_loader_constraints(link_info, resolved_method, "interface method", CHECK_NULL);
}
@ -1055,7 +1061,7 @@ void LinkResolver::resolve_field(fieldDescriptor& fd,
}
}
if ((sel_klass != current_klass) && (current_klass != NULL)) {
if (link_info.check_loader_constraints() && (sel_klass != current_klass) && (current_klass != NULL)) {
check_field_loader_constraints(field, sig, current_klass, sel_klass, CHECK);
}
@ -1089,7 +1095,8 @@ void LinkResolver::resolve_static_call(CallInfo& result,
// Use updated LinkInfo to reresolve with resolved method holder
LinkInfo new_info(resolved_klass, link_info.name(), link_info.signature(),
link_info.current_klass(),
link_info.check_access() ? LinkInfo::AccessCheck::required : LinkInfo::AccessCheck::skip);
link_info.check_access() ? LinkInfo::AccessCheck::required : LinkInfo::AccessCheck::skip,
link_info.check_loader_constraints() ? LinkInfo::LoaderConstraintCheck::required : LinkInfo::LoaderConstraintCheck::skip);
resolved_method = linktime_resolve_static_method(new_info, CHECK);
}
@ -1250,7 +1257,7 @@ void LinkResolver::runtime_resolve_special_method(CallInfo& result,
ss.print("'");
THROW_MSG(vmSymbols::java_lang_AbstractMethodError(), ss.as_string());
// check loader constraints if found a different method
} else if (sel_method() != resolved_method()) {
} else if (link_info.check_loader_constraints() && sel_method() != resolved_method()) {
check_method_loader_constraints(link_info, sel_method, "method", CHECK);
}
}

View File

@ -141,10 +141,12 @@ class LinkInfo : public StackObj {
Klass* _current_klass; // class that owns the constant pool
methodHandle _current_method; // sending method
bool _check_access;
bool _check_loader_constraints;
constantTag _tag;
public:
enum class AccessCheck { required, skip };
enum class LoaderConstraintCheck { required, skip };
LinkInfo(const constantPoolHandle& pool, int index, const methodHandle& current_method, TRAPS);
LinkInfo(const constantPoolHandle& pool, int index, TRAPS);
@ -152,33 +154,38 @@ class LinkInfo : public StackObj {
// Condensed information from other call sites within the vm.
LinkInfo(Klass* resolved_klass, Symbol* name, Symbol* signature, Klass* current_klass,
AccessCheck check_access = AccessCheck::required,
LoaderConstraintCheck check_loader_constraints = LoaderConstraintCheck::required,
constantTag tag = JVM_CONSTANT_Invalid) :
_name(name),
_signature(signature), _resolved_klass(resolved_klass), _current_klass(current_klass), _current_method(methodHandle()),
_check_access(check_access == AccessCheck::required), _tag(tag) {}
_check_access(check_access == AccessCheck::required),
_check_loader_constraints(check_loader_constraints == LoaderConstraintCheck::required), _tag(tag) {}
LinkInfo(Klass* resolved_klass, Symbol* name, Symbol* signature, const methodHandle& current_method,
AccessCheck check_access = AccessCheck::required,
LoaderConstraintCheck check_loader_constraints = LoaderConstraintCheck::required,
constantTag tag = JVM_CONSTANT_Invalid) :
_name(name),
_signature(signature), _resolved_klass(resolved_klass), _current_klass(current_method->method_holder()), _current_method(current_method),
_check_access(check_access == AccessCheck::required), _tag(tag) {}
_check_access(check_access == AccessCheck::required),
_check_loader_constraints(check_loader_constraints == LoaderConstraintCheck::required), _tag(tag) {}
// Case where we just find the method and don't check access against the current class
LinkInfo(Klass* resolved_klass, Symbol*name, Symbol* signature) :
_name(name),
_signature(signature), _resolved_klass(resolved_klass), _current_klass(NULL), _current_method(methodHandle()),
_check_access(false), _tag(JVM_CONSTANT_Invalid) {}
_check_access(false), _check_loader_constraints(false), _tag(JVM_CONSTANT_Invalid) {}
// accessors
Symbol* name() const { return _name; }
Symbol* signature() const { return _signature; }
Klass* resolved_klass() const { return _resolved_klass; }
Klass* current_klass() const { return _current_klass; }
Method* current_method() const { return _current_method(); }
constantTag tag() const { return _tag; }
bool check_access() const { return _check_access; }
Symbol* name() const { return _name; }
Symbol* signature() const { return _signature; }
Klass* resolved_klass() const { return _resolved_klass; }
Klass* current_klass() const { return _current_klass; }
Method* current_method() const { return _current_method(); }
constantTag tag() const { return _tag; }
bool check_access() const { return _check_access; }
bool check_loader_constraints() const { return _check_loader_constraints; }
void print() PRODUCT_RETURN;
};

View File

@ -90,7 +90,7 @@ void HotSpotJVMCI::compute_offset(int &dest_offset, Klass* klass, const char* na
#ifndef PRODUCT
static void check_resolve_method(const char* call_type, Klass* resolved_klass, Symbol* method_name, Symbol* method_signature, TRAPS) {
Method* method;
LinkInfo link_info(resolved_klass, method_name, method_signature, NULL, LinkInfo::AccessCheck::skip);
LinkInfo link_info(resolved_klass, method_name, method_signature, NULL, LinkInfo::AccessCheck::skip, LinkInfo::LoaderConstraintCheck::skip);
if (strcmp(call_type, "call_static") == 0) {
method = LinkResolver::resolve_static_call_or_null(link_info);
} else if (strcmp(call_type, "call_virtual") == 0) {

View File

@ -1327,7 +1327,7 @@ Method* JVMCIRuntime::lookup_method(InstanceKlass* accessor,
assert(check_klass_accessibility(accessor, holder), "holder not accessible");
Method* dest_method;
LinkInfo link_info(holder, name, sig, accessor, LinkInfo::AccessCheck::required, tag);
LinkInfo link_info(holder, name, sig, accessor, LinkInfo::AccessCheck::required, LinkInfo::LoaderConstraintCheck::required, tag);
switch (bc) {
case Bytecodes::_invokestatic:
dest_method =

View File

@ -132,6 +132,9 @@ enum {
REFERENCE_KIND_MASK = java_lang_invoke_MemberName::MN_REFERENCE_KIND_MASK,
SEARCH_SUPERCLASSES = java_lang_invoke_MemberName::MN_SEARCH_SUPERCLASSES,
SEARCH_INTERFACES = java_lang_invoke_MemberName::MN_SEARCH_INTERFACES,
LM_UNCONDITIONAL = java_lang_invoke_MemberName::MN_UNCONDITIONAL_MODE,
LM_MODULE = java_lang_invoke_MemberName::MN_MODULE_MODE,
LM_TRUSTED = java_lang_invoke_MemberName::MN_TRUSTED_MODE,
ALL_KINDS = IS_METHOD | IS_CONSTRUCTOR | IS_FIELD | IS_TYPE
};
@ -672,11 +675,10 @@ oop MethodHandles::field_signature_type_or_null(Symbol* s) {
return NULL;
}
// An unresolved member name is a mere symbolic reference.
// Resolving it plants a vmtarget/vmindex in it,
// which refers directly to JVM internals.
Handle MethodHandles::resolve_MemberName(Handle mname, Klass* caller,
Handle MethodHandles::resolve_MemberName(Handle mname, Klass* caller, int lookup_mode,
bool speculative_resolve, TRAPS) {
Handle empty;
assert(java_lang_invoke_MemberName::is_instance(mname()), "");
@ -745,16 +747,21 @@ Handle MethodHandles::resolve_MemberName(Handle mname, Klass* caller,
TempNewSymbol type = lookup_signature(type_str(), (mh_invoke_id != vmIntrinsics::_none), CHECK_(empty));
if (type == NULL) return empty; // no such signature exists in the VM
// skip access check if it's trusted lookup
LinkInfo::AccessCheck access_check = caller != NULL ?
LinkInfo::AccessCheck::required :
LinkInfo::AccessCheck::skip;
// skip loader constraints if it's trusted lookup or a public lookup
LinkInfo::LoaderConstraintCheck loader_constraint_check = (caller != NULL && (lookup_mode & LM_UNCONDITIONAL) == 0) ?
LinkInfo::LoaderConstraintCheck::required :
LinkInfo::LoaderConstraintCheck::skip;
// Time to do the lookup.
switch (flags & ALL_KINDS) {
case IS_METHOD:
{
CallInfo result;
LinkInfo link_info(defc, name, type, caller, access_check);
LinkInfo link_info(defc, name, type, caller, access_check, loader_constraint_check);
{
assert(!HAS_PENDING_EXCEPTION, "");
if (ref_kind == JVM_REF_invokeStatic) {
@ -795,7 +802,7 @@ Handle MethodHandles::resolve_MemberName(Handle mname, Klass* caller,
case IS_CONSTRUCTOR:
{
CallInfo result;
LinkInfo link_info(defc, name, type, caller, access_check);
LinkInfo link_info(defc, name, type, caller, access_check, loader_constraint_check);
{
assert(!HAS_PENDING_EXCEPTION, "");
if (name == vmSymbols::object_initializer_name()) {
@ -820,7 +827,7 @@ Handle MethodHandles::resolve_MemberName(Handle mname, Klass* caller,
fieldDescriptor result; // find_field initializes fd if found
{
assert(!HAS_PENDING_EXCEPTION, "");
LinkInfo link_info(defc, name, type, caller, LinkInfo::AccessCheck::skip);
LinkInfo link_info(defc, name, type, caller, LinkInfo::AccessCheck::skip, loader_constraint_check);
LinkResolver::resolve_field(result, link_info, Bytecodes::_nop, false, THREAD);
if (HAS_PENDING_EXCEPTION) {
if (speculative_resolve) {
@ -1117,6 +1124,9 @@ void MethodHandles::trace_method_handle_interpreter_entry(MacroAssembler* _masm,
template(java_lang_invoke_MemberName,MN_HIDDEN_CLASS) \
template(java_lang_invoke_MemberName,MN_STRONG_LOADER_LINK) \
template(java_lang_invoke_MemberName,MN_ACCESS_VM_ANNOTATIONS) \
template(java_lang_invoke_MemberName,MN_MODULE_MODE) \
template(java_lang_invoke_MemberName,MN_UNCONDITIONAL_MODE) \
template(java_lang_invoke_MemberName,MN_TRUSTED_MODE) \
/*end*/
#define IGNORE_REQ(req_expr) /* req_expr */
@ -1190,13 +1200,17 @@ JVM_END
// void resolve(MemberName self, Class<?> caller)
JVM_ENTRY(jobject, MHN_resolve_Mem(JNIEnv *env, jobject igcls, jobject mname_jh, jclass caller_jh,
jboolean speculative_resolve)) {
jint lookup_mode, jboolean speculative_resolve)) {
if (mname_jh == NULL) { THROW_MSG_NULL(vmSymbols::java_lang_InternalError(), "mname is null"); }
Handle mname(THREAD, JNIHandles::resolve_non_null(mname_jh));
// The trusted Java code that calls this method should already have performed
// access checks on behalf of the given caller. But, we can verify this.
if (VerifyMethodHandles && caller_jh != NULL &&
// This only verifies from the context of the lookup class. It does not
// verify the lookup context for a Lookup object teleported from one module
// to another. Such Lookup object can only access the intersection of the set
// of accessible classes from both lookup class and previous lookup class.
if (VerifyMethodHandles && (lookup_mode & LM_TRUSTED) == LM_TRUSTED && caller_jh != NULL &&
java_lang_invoke_MemberName::clazz(mname()) != NULL) {
Klass* reference_klass = java_lang_Class::as_Klass(java_lang_invoke_MemberName::clazz(mname()));
if (reference_klass != NULL && reference_klass->is_objArray_klass()) {
@ -1207,18 +1221,25 @@ JVM_ENTRY(jobject, MHN_resolve_Mem(JNIEnv *env, jobject igcls, jobject mname_jh,
if (reference_klass != NULL && reference_klass->is_instance_klass()) {
// Emulate LinkResolver::check_klass_accessability.
Klass* caller = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(caller_jh));
if (caller != SystemDictionary::Object_klass()
// access check on behalf of the caller if this is not a public lookup
// i.e. lookup mode is not UNCONDITIONAL
if ((lookup_mode & LM_UNCONDITIONAL) == 0
&& Reflection::verify_class_access(caller,
InstanceKlass::cast(reference_klass),
true) != Reflection::ACCESS_OK) {
THROW_MSG_NULL(vmSymbols::java_lang_InternalError(), reference_klass->external_name());
ResourceMark rm(THREAD);
stringStream ss;
ss.print("caller %s tried to access %s", caller->class_in_module_of_loader(),
reference_klass->class_in_module_of_loader());
THROW_MSG_NULL(vmSymbols::java_lang_InternalError(), ss.as_string());
}
}
}
Klass* caller = caller_jh == NULL ? NULL :
java_lang_Class::as_Klass(JNIHandles::resolve_non_null(caller_jh));
Handle resolved = MethodHandles::resolve_MemberName(mname, caller, speculative_resolve == JNI_TRUE,
Handle resolved = MethodHandles::resolve_MemberName(mname, caller, lookup_mode,
speculative_resolve == JNI_TRUE,
CHECK_NULL);
if (resolved.is_null()) {
@ -1518,7 +1539,7 @@ JVM_END
static JNINativeMethod MHN_methods[] = {
{CC "init", CC "(" MEM "" OBJ ")V", FN_PTR(MHN_init_Mem)},
{CC "expand", CC "(" MEM ")V", FN_PTR(MHN_expand_Mem)},
{CC "resolve", CC "(" MEM "" CLS "Z)" MEM, FN_PTR(MHN_resolve_Mem)},
{CC "resolve", CC "(" MEM "" CLS "IZ)" MEM, FN_PTR(MHN_resolve_Mem)},
// static native int getNamedCon(int which, Object[] name)
{CC "getNamedCon", CC "(I[" OBJ ")I", FN_PTR(MHN_getNamedCon)},
// static native int getMembers(Class<?> defc, String matchName, String matchSig,

View File

@ -60,7 +60,7 @@ class MethodHandles: AllStatic {
public:
// working with member names
static Handle resolve_MemberName(Handle mname, Klass* caller,
static Handle resolve_MemberName(Handle mname, Klass* caller, int lookup_mode,
bool speculative_resolve, TRAPS); // compute vmtarget/vmindex from name/type
static void expand_MemberName(Handle mname, int suppress, TRAPS); // expand defc/name/type if missing
static oop init_MemberName(Handle mname_h, Handle target_h, TRAPS); // compute vmtarget/vmindex from target

View File

@ -28,7 +28,7 @@ package java.lang.invoke;
import java.util.Arrays;
import static java.lang.invoke.LambdaForm.*;
import static java.lang.invoke.LambdaForm.Kind.*;
import static java.lang.invoke.MethodHandleNatives.Constants.REF_invokeVirtual;
import static java.lang.invoke.MethodHandleNatives.Constants.*;
import static java.lang.invoke.MethodHandleStatics.*;
/**
@ -177,7 +177,7 @@ abstract class DelegatingMethodHandle extends MethodHandle {
MethodType.methodType(MethodHandle.class), REF_invokeVirtual);
NF_getTarget = new NamedFunction(
MemberName.getFactory()
.resolveOrFail(REF_invokeVirtual, member, DelegatingMethodHandle.class, NoSuchMethodException.class));
.resolveOrFail(REF_invokeVirtual, member, DelegatingMethodHandle.class, LM_TRUSTED, NoSuchMethodException.class));
} catch (ReflectiveOperationException ex) {
throw newInternalError(ex);
}

View File

@ -63,7 +63,7 @@ class DirectMethodHandle extends MethodHandle {
member.isMethod() && !member.isAbstract()) {
// Check for corner case: invokeinterface of Object method
MemberName m = new MemberName(Object.class, member.getName(), member.getMethodType(), member.getReferenceKind());
m = MemberName.getFactory().resolveOrNull(m.getReferenceKind(), m, null);
m = MemberName.getFactory().resolveOrNull(m.getReferenceKind(), m, null, LM_TRUSTED);
if (m != null && m.isPublic()) {
assert(member.getReferenceKind() == m.getReferenceKind()); // else this.form is wrong
member = m;
@ -260,7 +260,8 @@ class DirectMethodHandle extends MethodHandle {
.changeReturnType(void.class); // <init> returns void
MemberName linker = new MemberName(MethodHandle.class, linkerName, mtypeWithArg, REF_invokeStatic);
try {
linker = IMPL_NAMES.resolveOrFail(REF_invokeStatic, linker, null, NoSuchMethodException.class);
linker = IMPL_NAMES.resolveOrFail(REF_invokeStatic, linker, null, LM_TRUSTED,
NoSuchMethodException.class);
} catch (ReflectiveOperationException ex) {
throw newInternalError(ex);
}
@ -771,7 +772,8 @@ class DirectMethodHandle extends MethodHandle {
linkerType = MethodType.methodType(void.class, Object.class, long.class, ft);
MemberName linker = new MemberName(Unsafe.class, kind.methodName, linkerType, REF_invokeVirtual);
try {
linker = IMPL_NAMES.resolveOrFail(REF_invokeVirtual, linker, null, NoSuchMethodException.class);
linker = IMPL_NAMES.resolveOrFail(REF_invokeVirtual, linker, null, LM_TRUSTED,
NoSuchMethodException.class);
} catch (ReflectiveOperationException ex) {
throw newInternalError(ex);
}
@ -914,13 +916,15 @@ class DirectMethodHandle extends MethodHandle {
case NF_UNSAFE:
MemberName member = new MemberName(MethodHandleStatics.class, "UNSAFE", Unsafe.class, REF_getField);
return new NamedFunction(
MemberName.getFactory()
.resolveOrFail(REF_getField, member, DirectMethodHandle.class, NoSuchMethodException.class));
MemberName.getFactory().resolveOrFail(REF_getField, member,
DirectMethodHandle.class, LM_TRUSTED,
NoSuchMethodException.class));
case NF_checkReceiver:
member = new MemberName(DirectMethodHandle.class, "checkReceiver", OBJ_OBJ_TYPE, REF_invokeVirtual);
return new NamedFunction(
MemberName.getFactory()
.resolveOrFail(REF_invokeVirtual, member, DirectMethodHandle.class, NoSuchMethodException.class));
MemberName.getFactory().resolveOrFail(REF_invokeVirtual, member,
DirectMethodHandle.class, LM_TRUSTED,
NoSuchMethodException.class));
default:
throw newInternalError("Unknown function: " + func);
}
@ -934,8 +938,9 @@ class DirectMethodHandle extends MethodHandle {
{
MemberName member = new MemberName(DirectMethodHandle.class, name, type, REF_invokeStatic);
return new NamedFunction(
MemberName.getFactory()
.resolveOrFail(REF_invokeStatic, member, DirectMethodHandle.class, NoSuchMethodException.class));
MemberName.getFactory().resolveOrFail(REF_invokeStatic, member,
DirectMethodHandle.class, LM_TRUSTED,
NoSuchMethodException.class));
}
static {

View File

@ -322,7 +322,9 @@ class InvokerBytecodeGenerator {
private static MemberName resolveInvokerMember(Class<?> invokerClass, String name, MethodType type) {
MemberName member = new MemberName(invokerClass, name, type, REF_invokeStatic);
try {
member = MEMBERNAME_FACTORY.resolveOrFail(REF_invokeStatic, member, HOST_CLASS, ReflectiveOperationException.class);
member = MEMBERNAME_FACTORY.resolveOrFail(REF_invokeStatic, member,
HOST_CLASS, LM_TRUSTED,
ReflectiveOperationException.class);
} catch (ReflectiveOperationException e) {
throw newInternalError(e);
}
@ -693,7 +695,7 @@ class InvokerBytecodeGenerator {
private static MemberName resolveFrom(String name, MethodType type, Class<?> holder) {
MemberName member = new MemberName(holder, name, type, REF_invokeStatic);
MemberName resolvedMember = MemberName.getFactory().resolveOrNull(REF_invokeStatic, member, holder);
MemberName resolvedMember = MemberName.getFactory().resolveOrNull(REF_invokeStatic, member, holder, LM_TRUSTED);
if (TRACE_RESOLVE) {
System.out.println("[LF_RESOLVE] " + holder.getName() + " " + name + " " +
shortenSignature(basicTypeSignature(type)) + (resolvedMember != null ? " (success)" : " (fail)") );

View File

@ -661,7 +661,7 @@ class Invokers {
MemberName member = new MemberName(Invokers.class, name, type, REF_invokeStatic);
return new NamedFunction(
MemberName.getFactory()
.resolveOrFail(REF_invokeStatic, member, Invokers.class, NoSuchMethodException.class));
.resolveOrFail(REF_invokeStatic, member, Invokers.class, LM_TRUSTED, NoSuchMethodException.class));
}
private static class Lazy {

View File

@ -40,7 +40,7 @@ import java.util.Arrays;
import java.util.HashMap;
import static java.lang.invoke.LambdaForm.BasicType.*;
import static java.lang.invoke.MethodHandleNatives.Constants.REF_invokeStatic;
import static java.lang.invoke.MethodHandleNatives.Constants.*;
import static java.lang.invoke.MethodHandleStatics.*;
/**
@ -1758,10 +1758,10 @@ class LambdaForm {
MemberName idMem = new MemberName(LambdaForm.class, "identity_"+btChar, idType, REF_invokeStatic);
MemberName zeMem = null;
try {
idMem = IMPL_NAMES.resolveOrFail(REF_invokeStatic, idMem, null, NoSuchMethodException.class);
idMem = IMPL_NAMES.resolveOrFail(REF_invokeStatic, idMem, null, LM_TRUSTED, NoSuchMethodException.class);
if (!isVoid) {
zeMem = new MemberName(LambdaForm.class, "zero_"+btChar, zeType, REF_invokeStatic);
zeMem = IMPL_NAMES.resolveOrFail(REF_invokeStatic, zeMem, null, NoSuchMethodException.class);
zeMem = IMPL_NAMES.resolveOrFail(REF_invokeStatic, zeMem, null, LM_TRUSTED, NoSuchMethodException.class);
}
} catch (IllegalAccessException|NoSuchMethodException ex) {
throw newInternalError(ex);

View File

@ -1064,7 +1064,7 @@ final class MemberName implements Member, Cloneable {
* If lookup fails or access is not permitted, null is returned.
* Otherwise a fresh copy of the given member is returned, with modifier bits filled in.
*/
private MemberName resolve(byte refKind, MemberName ref, Class<?> lookupClass,
private MemberName resolve(byte refKind, MemberName ref, Class<?> lookupClass, int allowedModes,
boolean speculativeResolve) {
MemberName m = ref.clone(); // JVM will side-effect the ref
assert(refKind == m.getReferenceKind());
@ -1084,7 +1084,7 @@ final class MemberName implements Member, Cloneable {
//
// REFC view on PTYPES doesn't matter, since it is used only as a starting point for resolution and doesn't
// participate in method selection.
m = MethodHandleNatives.resolve(m, lookupClass, speculativeResolve);
m = MethodHandleNatives.resolve(m, lookupClass, allowedModes, speculativeResolve);
if (m == null && speculativeResolve) {
return null;
}
@ -1108,10 +1108,12 @@ final class MemberName implements Member, Cloneable {
* Otherwise a fresh copy of the given member is returned, with modifier bits filled in.
*/
public <NoSuchMemberException extends ReflectiveOperationException>
MemberName resolveOrFail(byte refKind, MemberName m, Class<?> lookupClass,
Class<NoSuchMemberException> nsmClass)
MemberName resolveOrFail(byte refKind, MemberName m,
Class<?> lookupClass, int allowedModes,
Class<NoSuchMemberException> nsmClass)
throws IllegalAccessException, NoSuchMemberException {
MemberName result = resolve(refKind, m, lookupClass, false);
assert lookupClass != null || allowedModes == LM_TRUSTED;
MemberName result = resolve(refKind, m, lookupClass, allowedModes, false);
if (result.isResolved())
return result;
ReflectiveOperationException ex = result.makeAccessException();
@ -1124,8 +1126,9 @@ final class MemberName implements Member, Cloneable {
* If lookup fails or access is not permitted, return null.
* Otherwise a fresh copy of the given member is returned, with modifier bits filled in.
*/
public MemberName resolveOrNull(byte refKind, MemberName m, Class<?> lookupClass) {
MemberName result = resolve(refKind, m, lookupClass, true);
public MemberName resolveOrNull(byte refKind, MemberName m, Class<?> lookupClass, int allowedModes) {
assert lookupClass != null || allowedModes == LM_TRUSTED;
MemberName result = resolve(refKind, m, lookupClass, allowedModes, true);
if (result != null && result.isResolved())
return result;
return null;

View File

@ -51,7 +51,7 @@ class MethodHandleNatives {
static native void init(MemberName self, Object ref);
static native void expand(MemberName self);
static native MemberName resolve(MemberName self, Class<?> caller,
static native MemberName resolve(MemberName self, Class<?> caller, int lookupMode,
boolean speculativeResolve) throws LinkageError, ClassNotFoundException;
static native int getMembers(Class<?> defc, String matchName, String matchSig,
int matchFlags, Class<?> caller, int skip, MemberName[] results);
@ -149,6 +149,15 @@ class MethodHandleNatives {
HIDDEN_CLASS = 0x00000002,
STRONG_LOADER_LINK = 0x00000004,
ACCESS_VM_ANNOTATIONS = 0x00000008;
/**
* Lookup modes
*/
static final int
LM_MODULE = Lookup.MODULE,
LM_UNCONDITIONAL = Lookup.UNCONDITIONAL,
LM_TRUSTED = -1;
}
static boolean refKindIsValid(int refKind) {
@ -561,7 +570,7 @@ class MethodHandleNatives {
guardType, REF_invokeStatic);
linker = MemberName.getFactory().resolveOrNull(REF_invokeStatic, linker,
VarHandleGuards.class);
VarHandleGuards.class, LM_TRUSTED);
if (linker != null) {
return linker;
}

View File

@ -1409,14 +1409,7 @@ public class MethodHandles {
// This is just for calling out to MethodHandleImpl.
private Class<?> lookupClassOrNull() {
if (allowedModes == TRUSTED) {
return null;
}
if (allowedModes == UNCONDITIONAL) {
// use Object as the caller to pass to VM doing resolution
return Object.class;
}
return lookupClass;
return (allowedModes == TRUSTED) ? null : lookupClass;
}
/** Tells which access-protection classes of members this lookup object can produce.
@ -3442,7 +3435,7 @@ return mh1;
checkSymbolicClass(refc); // do this before attempting to resolve
Objects.requireNonNull(name);
Objects.requireNonNull(type);
return IMPL_NAMES.resolveOrFail(refKind, new MemberName(refc, name, type, refKind), lookupClassOrNull(),
return IMPL_NAMES.resolveOrFail(refKind, new MemberName(refc, name, type, refKind), lookupClassOrNull(), allowedModes,
NoSuchFieldException.class);
}
@ -3451,7 +3444,7 @@ return mh1;
Objects.requireNonNull(name);
Objects.requireNonNull(type);
checkMethodName(refKind, name); // NPE check on name
return IMPL_NAMES.resolveOrFail(refKind, new MemberName(refc, name, type, refKind), lookupClassOrNull(),
return IMPL_NAMES.resolveOrFail(refKind, new MemberName(refc, name, type, refKind), lookupClassOrNull(), allowedModes,
NoSuchMethodException.class);
}
@ -3459,7 +3452,7 @@ return mh1;
checkSymbolicClass(member.getDeclaringClass()); // do this before attempting to resolve
Objects.requireNonNull(member.getName());
Objects.requireNonNull(member.getType());
return IMPL_NAMES.resolveOrFail(refKind, member, lookupClassOrNull(),
return IMPL_NAMES.resolveOrFail(refKind, member, lookupClassOrNull(), allowedModes,
ReflectiveOperationException.class);
}
@ -3470,7 +3463,7 @@ return mh1;
}
Objects.requireNonNull(member.getName());
Objects.requireNonNull(member.getType());
return IMPL_NAMES.resolveOrNull(refKind, member, lookupClassOrNull());
return IMPL_NAMES.resolveOrNull(refKind, member, lookupClassOrNull(), allowedModes);
}
void checkSymbolicClass(Class<?> refc) throws IllegalAccessException {
@ -3774,7 +3767,7 @@ return mh1;
method.getName(),
method.getMethodType(),
REF_invokeSpecial);
m2 = IMPL_NAMES.resolveOrNull(refKind, m2, lookupClassOrNull());
m2 = IMPL_NAMES.resolveOrNull(refKind, m2, lookupClassOrNull(), allowedModes);
} while (m2 == null && // no method is found yet
refc != refcAsSuper); // search up to refc
if (m2 == null) throw new InternalError(method.toString());

View File

@ -0,0 +1,30 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 8244090
* @build m1/* m2/*
* @run main/othervm m1/p.Main
* @summary Tests public lookups produced from MethodHandles.publicLookup()::in
*/

View File

@ -0,0 +1,26 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
module m1 {
requires m2;
exports p;
}

View File

@ -0,0 +1,107 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package p;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.invoke.MethodType;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Paths;
import java.util.Arrays;
import static java.lang.invoke.MethodHandles.Lookup.*;
public class Main {
/*
* Each Test object loads q.EndPoint and q.T with a custom loader.
* These types are used to look up a method handle "EndPoint::test(T)".
*/
static class Test {
final ClassLoader loader;
final Class<?> target;
final Class<?> param;
Test(String name) throws Exception {
URL url = Paths.get(System.getProperty("test.classes"), "modules", "m2")
.toUri().toURL();
this.loader = new URLClassLoader(name, new URL[]{url}, null);
this.target = Class.forName("q.EndPoint", true, loader);
this.param = Class.forName("q.T", true, loader);
assertTrue(target != q.EndPoint.class);
assertTrue(param != q.T.class);
}
/*
*
*/
public void verifyAccess(Lookup... publicLookups) throws Throwable {
System.err.println(loader.getName() + ": verify access for " + Arrays.toString(publicLookups));
for (Lookup lookup : publicLookups) {
assertTrue((lookup.lookupModes() & UNCONDITIONAL) == UNCONDITIONAL);
assertTrue((lookup.lookupModes() & PUBLIC) == 0);
MethodHandle mh = lookup.findVirtual(target, "test", MethodType.methodType(void.class, param));
mh.invoke(target.newInstance(), param.newInstance());
checkTypeConsistency(mh);
}
}
}
/*
* Verify that publicLookup can teleport to:
* 1) q.EndPoint defined in m2
* 2) q.EndPoint defined by a custom loader CL1 in one unnamed module
* 3) q.EndPoint defined by a custom loader CL2 in another unnamed module
*
* All the resulting Lookup objects are public lookups and can find
* any public accessible member.
*/
public static void main(String... args) throws Throwable {
Test test1 = new Test("CL1");
Test test2 = new Test("CL2");
Lookup lookup1 = MethodHandles.publicLookup();
Lookup lookup2 = MethodHandles.publicLookup().in(test1.target);
Lookup lookup3 = MethodHandles.publicLookup().in(test2.target);
assertTrue(lookup2.lookupClass().getClassLoader() != lookup3.lookupClass().getClassLoader());
test1.verifyAccess(lookup1, lookup2, lookup3);
test2.verifyAccess(lookup1, lookup2, lookup3);
}
static void checkTypeConsistency(MethodHandle mh) throws Throwable {
try {
mh.invoke(new q.EndPoint(), new q.T());
throw new Error("expect fail to invoke due to type inconsistency");
} catch (ClassCastException e) {
assertTrue(e.getMessage().startsWith("Cannot cast q."));
}
}
static void assertTrue(boolean v) {
if (!v) {
throw new AssertionError("unexpected result");
}
}
}

View File

@ -0,0 +1,25 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
module m2 {
exports q;
}

View File

@ -0,0 +1,28 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package q;
public class EndPoint {
public void test(T t) {
}
}

View File

@ -0,0 +1,26 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package q;
public class T {
}