mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 14:54:52 +02:00
8010319: Implementation of JEP 181: Nest-Based Access Control
Co-authored-by: Alex Buckley <alex.buckley@oracle.com> Co-authored-by: Maurizio Mimadamore <maurizio.mimadamore@oracle.com> Co-authored-by: Mandy Chung <mandy.chung@oracle.com> Co-authored-by: Tobias Hartmann <tobias.hartmann@oracle.com> Co-authored-by: Vlaidmir Ivanov <vladimir.x.ivanov@oracle.com> Co-authored-by: Karen Kinnear <karen.kinnear@oracle.com> Co-authored-by: Vladimir Kozlov <vladimir.kozlov@oracle.com> Co-authored-by: John Rose <john.r.rose@oracle.com> Co-authored-by: Daniel Smith <daniel.smith@oracle.com> Co-authored-by: Serguei Spitsyn <serguei.spitsyn@oracle.com> Co-authored-by: Kumar Srinivasan <kumardotsrinivasan@gmail.com> Co-authored-by: Boris Ulasevich <boris.ulasevich@bell-sw.com> Reviewed-by: alanb, psandoz, mchung, coleenp, acorn, mcimadamore, forax, jlahoda, sspitsyn, abuckley
This commit is contained in:
parent
6e0bd36f42
commit
95bf19563b
259 changed files with 21354 additions and 890 deletions
|
@ -58,7 +58,8 @@ class DirectMethodHandle extends MethodHandle {
|
|||
if (!member.isResolved()) throw new InternalError();
|
||||
|
||||
if (member.getDeclaringClass().isInterface() &&
|
||||
member.isMethod() && !member.isAbstract()) {
|
||||
member.getReferenceKind() == REF_invokeInterface &&
|
||||
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);
|
||||
|
@ -80,22 +81,28 @@ class DirectMethodHandle extends MethodHandle {
|
|||
mtype = mtype.insertParameterTypes(0, refc);
|
||||
}
|
||||
if (!member.isField()) {
|
||||
// refKind reflects the original type of lookup via findSpecial or
|
||||
// findVirtual etc.
|
||||
switch (refKind) {
|
||||
case REF_invokeSpecial: {
|
||||
member = member.asSpecial();
|
||||
LambdaForm lform = preparedLambdaForm(member, callerClass);
|
||||
Class<?> checkClass = refc; // Class to use for receiver type check
|
||||
if (callerClass != null) {
|
||||
checkClass = callerClass; // potentially strengthen to caller class
|
||||
// if caller is an interface we need to adapt to get the
|
||||
// receiver check inserted
|
||||
if (callerClass == null) {
|
||||
throw new InternalError("callerClass must not be null for REF_invokeSpecial");
|
||||
}
|
||||
return new Special(mtype, lform, member, checkClass);
|
||||
LambdaForm lform = preparedLambdaForm(member, callerClass.isInterface());
|
||||
return new Special(mtype, lform, member, callerClass);
|
||||
}
|
||||
case REF_invokeInterface: {
|
||||
LambdaForm lform = preparedLambdaForm(member, callerClass);
|
||||
// for interfaces we always need the receiver typecheck,
|
||||
// so we always pass 'true' to ensure we adapt if needed
|
||||
// to include the REF_invokeSpecial case
|
||||
LambdaForm lform = preparedLambdaForm(member, true);
|
||||
return new Interface(mtype, lform, member, refc);
|
||||
}
|
||||
default: {
|
||||
LambdaForm lform = preparedLambdaForm(member, callerClass);
|
||||
LambdaForm lform = preparedLambdaForm(member);
|
||||
return new DirectMethodHandle(mtype, lform, member);
|
||||
}
|
||||
}
|
||||
|
@ -165,11 +172,16 @@ class DirectMethodHandle extends MethodHandle {
|
|||
* Cache and share this structure among all methods with
|
||||
* the same basicType and refKind.
|
||||
*/
|
||||
private static LambdaForm preparedLambdaForm(MemberName m, Class<?> callerClass) {
|
||||
private static LambdaForm preparedLambdaForm(MemberName m, boolean adaptToSpecialIfc) {
|
||||
assert(m.isInvocable()) : m; // call preparedFieldLambdaForm instead
|
||||
MethodType mtype = m.getInvocationType().basicType();
|
||||
assert(!m.isMethodHandleInvoke()) : m;
|
||||
int which;
|
||||
// MemberName.getReferenceKind represents the JVM optimized form of the call
|
||||
// as distinct from the "kind" passed to DMH.make which represents the original
|
||||
// bytecode-equivalent request. Specifically private/final methods that use a direct
|
||||
// call have getReferenceKind adapted to REF_invokeSpecial, even though the actual
|
||||
// invocation mode may be invokevirtual or invokeinterface.
|
||||
switch (m.getReferenceKind()) {
|
||||
case REF_invokeVirtual: which = LF_INVVIRTUAL; break;
|
||||
case REF_invokeStatic: which = LF_INVSTATIC; break;
|
||||
|
@ -183,7 +195,7 @@ class DirectMethodHandle extends MethodHandle {
|
|||
preparedLambdaForm(mtype, which);
|
||||
which = LF_INVSTATIC_INIT;
|
||||
}
|
||||
if (which == LF_INVSPECIAL && callerClass != null && callerClass.isInterface()) {
|
||||
if (which == LF_INVSPECIAL && adaptToSpecialIfc) {
|
||||
which = LF_INVSPECIAL_IFC;
|
||||
}
|
||||
LambdaForm lform = preparedLambdaForm(mtype, which);
|
||||
|
@ -195,7 +207,7 @@ class DirectMethodHandle extends MethodHandle {
|
|||
}
|
||||
|
||||
private static LambdaForm preparedLambdaForm(MemberName m) {
|
||||
return preparedLambdaForm(m, null);
|
||||
return preparedLambdaForm(m, false);
|
||||
}
|
||||
|
||||
private static LambdaForm preparedLambdaForm(MethodType mtype, int which) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2008, 2018, 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
|
||||
|
@ -250,6 +250,9 @@ import static java.lang.invoke.MethodHandleStatics.*;
|
|||
* can also be created. These do not perform virtual lookup based on
|
||||
* receiver type. Such a method handle simulates the effect of
|
||||
* an {@code invokespecial} instruction to the same method.
|
||||
* A non-virtual method handle can also be created to simulate the effect
|
||||
* of an {@code invokevirtual} or {@code invokeinterface} instruction on
|
||||
* a private method (as applicable).
|
||||
*
|
||||
* <h1>Usage examples</h1>
|
||||
* Here are some examples of usage:
|
||||
|
|
|
@ -469,15 +469,20 @@ public class MethodHandles {
|
|||
* methods as if they were normal methods, but the JVM bytecode verifier rejects them.
|
||||
* A lookup of such an internal method will produce a {@code NoSuchMethodException}.
|
||||
* <p>
|
||||
* In some cases, access between nested classes is obtained by the Java compiler by creating
|
||||
* an wrapper method to access a private method of another class
|
||||
* in the same top-level declaration.
|
||||
* If the relationship between nested types is expressed directly through the
|
||||
* {@code NestHost} and {@code NestMembers} attributes
|
||||
* (see the Java Virtual Machine Specification, sections 4.7.28 and 4.7.29),
|
||||
* then the associated {@code Lookup} object provides direct access to
|
||||
* the lookup class and all of its nestmates
|
||||
* (see {@link java.lang.Class#getNestHost Class.getNestHost}).
|
||||
* Otherwise, access between nested classes is obtained by the Java compiler creating
|
||||
* a wrapper method to access a private method of another class in the same nest.
|
||||
* For example, a nested class {@code C.D}
|
||||
* can access private members within other related classes such as
|
||||
* {@code C}, {@code C.D.E}, or {@code C.B},
|
||||
* but the Java compiler may need to generate wrapper methods in
|
||||
* those related classes. In such cases, a {@code Lookup} object on
|
||||
* {@code C.E} would be unable to those private members.
|
||||
* {@code C.E} would be unable to access those private members.
|
||||
* A workaround for this limitation is the {@link Lookup#in Lookup.in} method,
|
||||
* which can transform a lookup on {@code C.E} into one on any of those other
|
||||
* classes, without special elevation of privilege.
|
||||
|
@ -499,11 +504,12 @@ public class MethodHandles {
|
|||
* <em>Discussion of private access:</em>
|
||||
* We say that a lookup has <em>private access</em>
|
||||
* if its {@linkplain #lookupModes lookup modes}
|
||||
* include the possibility of accessing {@code private} members.
|
||||
* include the possibility of accessing {@code private} members
|
||||
* (which includes the private members of nestmates).
|
||||
* As documented in the relevant methods elsewhere,
|
||||
* only lookups with private access possess the following capabilities:
|
||||
* <ul style="font-size:smaller;">
|
||||
* <li>access private fields, methods, and constructors of the lookup class
|
||||
* <li>access private fields, methods, and constructors of the lookup class and its nestmates
|
||||
* <li>create method handles which invoke <a href="MethodHandles.Lookup.html#callsens">caller sensitive</a> methods,
|
||||
* such as {@code Class.forName}
|
||||
* <li>create method handles which {@link Lookup#findSpecial emulate invokespecial} instructions
|
||||
|
@ -728,9 +734,7 @@ public class MethodHandles {
|
|||
* <p>
|
||||
* A freshly-created lookup object
|
||||
* on the {@linkplain java.lang.invoke.MethodHandles#lookup() caller's class} has
|
||||
* all possible bits set, except {@code UNCONDITIONAL}. The lookup can be used to
|
||||
* access all members of the caller's class, all public types in the caller's module,
|
||||
* and all public types in packages exported by other modules to the caller's module.
|
||||
* all possible bits set, except {@code UNCONDITIONAL}.
|
||||
* A lookup object on a new lookup class
|
||||
* {@linkplain java.lang.invoke.MethodHandles.Lookup#in created from a previous lookup object}
|
||||
* may have some mode bits set to zero.
|
||||
|
@ -1106,8 +1110,9 @@ assertEquals("[x, y]", MH_asList.invoke("x", "y").toString());
|
|||
* The method and all its argument types must be accessible to the lookup object.
|
||||
* <p>
|
||||
* When called, the handle will treat the first argument as a receiver
|
||||
* and dispatch on the receiver's type to determine which method
|
||||
* and, for non-private methods, dispatch on the receiver's type to determine which method
|
||||
* implementation to enter.
|
||||
* For private methods the named method in {@code refc} will be invoked on the receiver.
|
||||
* (The dispatching action is identical with that performed by an
|
||||
* {@code invokevirtual} or {@code invokeinterface} instruction.)
|
||||
* <p>
|
||||
|
@ -1171,7 +1176,6 @@ assertEquals("", (String) MH_newString.invokeExact());
|
|||
* @throws NoSuchMethodException if the method does not exist
|
||||
* @throws IllegalAccessException if access checking fails,
|
||||
* or if the method is {@code static},
|
||||
* or if the method is {@code private} method of interface,
|
||||
* or if the method's variable arity modifier bit
|
||||
* is set and {@code asVarargsCollector} fails
|
||||
* @exception SecurityException if a security manager is present and it
|
||||
|
@ -2225,17 +2229,13 @@ return mh1;
|
|||
return "member is private to package";
|
||||
}
|
||||
|
||||
private static final boolean ALLOW_NESTMATE_ACCESS = false;
|
||||
|
||||
private void checkSpecialCaller(Class<?> specialCaller, Class<?> refc) throws IllegalAccessException {
|
||||
int allowedModes = this.allowedModes;
|
||||
if (allowedModes == TRUSTED) return;
|
||||
if (!hasPrivateAccess()
|
||||
|| (specialCaller != lookupClass()
|
||||
// ensure non-abstract methods in superinterfaces can be special-invoked
|
||||
&& !(refc != null && refc.isInterface() && refc.isAssignableFrom(specialCaller))
|
||||
&& !(ALLOW_NESTMATE_ACCESS &&
|
||||
VerifyAccess.isSamePackageMember(specialCaller, lookupClass()))))
|
||||
&& !(refc != null && refc.isInterface() && refc.isAssignableFrom(specialCaller))))
|
||||
throw new MemberName(specialCaller).
|
||||
makeAccessException("no private access for invokespecial", this);
|
||||
}
|
||||
|
@ -2246,9 +2246,7 @@ return mh1;
|
|||
if (!method.isProtected() || method.isStatic()
|
||||
|| allowedModes == TRUSTED
|
||||
|| method.getDeclaringClass() == lookupClass()
|
||||
|| VerifyAccess.isSamePackage(method.getDeclaringClass(), lookupClass())
|
||||
|| (ALLOW_NESTMATE_ACCESS &&
|
||||
VerifyAccess.isSamePackageMember(method.getDeclaringClass(), lookupClass())))
|
||||
|| VerifyAccess.isSamePackage(method.getDeclaringClass(), lookupClass()))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
@ -2288,6 +2286,7 @@ return mh1;
|
|||
private MethodHandle getDirectMethodCommon(byte refKind, Class<?> refc, MemberName method,
|
||||
boolean checkSecurity,
|
||||
boolean doRestrict, Class<?> boundCallerClass) throws IllegalAccessException {
|
||||
|
||||
checkMethod(refKind, refc, method);
|
||||
// Optionally check with the security manager; this isn't needed for unreflect* calls.
|
||||
if (checkSecurity)
|
||||
|
@ -2300,6 +2299,7 @@ return mh1;
|
|||
refc != lookupClass().getSuperclass() &&
|
||||
refc.isAssignableFrom(lookupClass())) {
|
||||
assert(!method.getName().equals("<init>")); // not this code path
|
||||
|
||||
// Per JVMS 6.5, desc. of invokespecial instruction:
|
||||
// If the method is in a superclass of the LC,
|
||||
// and if our original search was above LC.super,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue