-
CSR
-
Resolution: Approved
-
P3
-
None
-
behavioral
-
medium
-
-
Java API
-
SE
Summary
Add a new Lookup::hasFullPrivilegeAccess
method to replace Lookup::hasPrivateAccess
and also update Lookup::defineClass
behavior if this Lookup has full privilege access.
Problem
This CSR is a follow-up due to the change by JDK-8226916
Lookup::hasPrivateAccess
intends to test if this lookup is a full-power lookup; that is created by the original caller class calling MethodHandles::lookup
. The current specification for Lookup::hasPrivateAccess
returns true if the lookup modes contain PRIVATE
but it does not check MODULE
bit.
In addition, the Lookup
class specification contains the Discussion of private access section and Security manager interactions which needs to be re-examined. Prior to Java SE 9, a Lookup with private access is equivalent to a Lookup with full-power access. The list of capabilities need re-examination to determine what capabilities a Lookup with full-power access or with private access (no module access) are allowed.
Solution
MODULE
mode in Java SE 14 is used to represent a Lookup
whose original creator is a member in the module of the lookup class. MODULE
bit will be dropped if teleporting from another module via MethodHandles::privateLookupIn
.
A new correctly named method Lookup::hasFullPrivilegeAccess
is introduced to test if the lookup modes contain PRIVATE
and MODULE
access. Deprecate Lookup::hasPrivateAccess
while Lookup::hasPrivateAccess
is updated to call Lookup::hasFullPrivilegeAccess
to match the original intent of Lookup::hasPrivateAccess
.
MethodHandles::privateLookupIn
provides a mechanism for a framework
to do cross-module teleporting and perform deep reflection on private members of a package opened to the caller module. So Lookup with full-power access is needed only for the capability to create method handle for a caller-sensitive method. A Lookup with PRIVATE
access possesses other capabilities listed in the Discussion of private access section.
W.r.t. security manager interfaction, the security permission check is skipped for full power lookup. Lookup::defineClass
is updated to perform security permission check if the security manager is present and this lookup refuses access, consistent with other Lookup operations.
Specification
(1) MethodHandles::privateLookupIn
/**
* Returns a {@link Lookup lookup object} with
* full capabilities to emulate all supported bytecode behaviors of the caller.
- * These capabilities include <a href="MethodHandles.Lookup.html#privacc">private access</a> to the caller.
+ * These capabilities include {@linkplain Lookup#hasFullPrivilegeAccess() full privilege access} to the caller.
* Factory methods on the lookup object can create
* <a href="MethodHandleInfo.html#directmh">direct method handles</a>
* for any member that the caller has access to via bytecodes,
@@ -210,6 +210,7 @@
* @since 9
* @spec JPMS
* @see Lookup#dropLookupMode
+ * @see Lookup#hasFullPrivilegeAccess()
* @see <a href="MethodHandles.Lookup.html#cross-module-lookup">Cross-module lookups</a>
*/
public static Lookup privateLookupIn(Class<?> targetClass, Lookup caller) throws IllegalAccessException {
(2) Lookup class specification
* <a id="privacc"></a>
- * <em>Discussion of private access:</em>
+ * <em>Discussion of private and module 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
@@ -561,8 +560,6 @@
* 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 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
* <li>avoid <a href="MethodHandles.Lookup.html#secmgr">package access checks</a>
* for classes accessible to the lookup class
@@ -570,6 +567,18 @@
* within the same package member
* </ul>
* <p style="font-size:smaller;">
+ * Similarly, a lookup with module access ensures that the original lookup creator was
+ * a member in the same module as the lookup class.
+ * <p style="font-size:smaller;">
+ * Private and module access are independently determined modes; a lookup may have
+ * either or both or neither. A lookup which possesses both access modes is said to
+ * possess {@link #hasFullPrivilegeAccess() full privilege access}. Such a lookup has
+ * the following additional capability:
+ * <ul style="font-size:smaller;">
+ * <li>create method handles which invoke <a href="MethodHandles.Lookup.html#callsens">caller sensitive</a> methods,
+ * such as {@code Class.forName}
+ * </ul>
+ * <p style="font-size:smaller;">
* Each of these permissions is a consequence of the fact that a lookup object
* with private access can be securely traced back to an originating class,
* whose <a href="MethodHandles.Lookup.html#equiv">bytecode behaviors</a> and Java language access permissions
@@ -644,7 +653,7 @@
* <p>
* {@link MethodHandles#privateLookupIn(Class, Lookup) MethodHandles.privateLookupIn(T.class, lookup)}
* can be used to teleport a {@code lookup} from class {@code C} to class {@code T}
- * and create a new {@code Lookup} with <a href="#privcc">private access</a>
+ * and create a new {@code Lookup} with <a href="#privacc">private access</a>
* if the lookup class is allowed to do <em>deep reflection</em> on {@code T}.
* The {@code lookup} must have {@link #MODULE} and {@link #PRIVATE} access
* to call {@code privateLookupIn}.
@@ -1110,7 +1119,7 @@
* the {@code refc} and {@code defc} values are the class itself.)
* The value {@code lookc} is defined as <em>not present</em>
* if the current lookup object does not have
- * <a href="MethodHandles.Lookup.html#privacc">private access</a>.
+ * {@linkplain #hasFullPrivilegeAccess() full privilege access}.
* The calls are made according to the following rules:
* <ul>
* <li><b>Step 1:</b>
@@ -1141,6 +1150,12 @@
* Therefore, the above rules presuppose a member or class that is public,
* or else that is being accessed from a lookup class that has
* rights to access the member or class.
+ * <p>
+ * If a security manager is present and the current lookup object does not have
+ * {@linkplain #hasFullPrivilegeAccess() full privilege access}, then
+ * {@link #defineClass(byte[]) defineClass}
+ * calls {@link SecurityManager#checkPermission smgr.checkPermission}
+ * with {@code RuntimePermission("defineClass")}.
*
* <h2><a id="callsens"></a>Caller sensitive methods</h2>
* A small number of Java methods have a special property called caller sensitivity.
@@ -1160,8 +1175,8 @@
* <p>
* In cases where the lookup object is
* {@link MethodHandles#publicLookup() publicLookup()},
- * or some other lookup object without
- * <a href="MethodHandles.Lookup.html#privacc">private access</a>,
+ * or some other lookup object without the
+ * {@linkplain #hasFullPrivilegeAccess() full privilege access},
* the lookup class is disregarded.
* In such cases, no caller-sensitive method handle can be created,
* access is forbidden, and the lookup fails with an
(3) Lookup::defineClass
* access is forbidden, and the lookup fails with an
@@ -1514,7 +1525,8 @@
* @apiNote
* A lookup with {@code PACKAGE} but not {@code PRIVATE} mode can safely
* delegate non-public access within the package of the lookup class without
- * conferring private access. A lookup with {@code MODULE} but not
+ * conferring <a href="MethodHandles.Lookup.html#privacc"> private access</a>.
+ * A lookup with {@code MODULE} but not
* {@code PACKAGE} mode can safely delegate {@code PUBLIC} access within
* the module of the lookup class without conferring package access.
* A lookup with a {@linkplain #previousLookupClass() previous lookup class}
@@ -1565,8 +1577,9 @@
* run at a later time, as detailed in section 12.4 of the <em>The Java Language
* Specification</em>. </p>
*
- * <p> If there is a security manager, its {@code checkPermission} method is first called
- * to check {@code RuntimePermission("defineClass")}. </p>
+ * <p> If there is a security manager and this lookup does not have {@linkplain
+ * #hasPrivateAccess() full privilege access}, its {@code checkPermission} method
+ * is first called to check {@code RuntimePermission("defineClass")}. </p>
*
* @param bytes the class bytes
* @return the {@code Class} object for the class
@@ -1575,7 +1588,8 @@
* @throws IllegalAccessException if this lookup does not have {@code PACKAGE} access
* @throws LinkageError if the class is malformed ({@code ClassFormatError}), cannot be
* verified ({@code VerifyError}), is already defined, or another linkage error occurs
- * @throws SecurityException if denied by the security manager
+ * @throws SecurityException if a security manager is present and it
+ * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
* @throws NullPointerException if {@code bytes} is {@code null}
* @since 9
* @spec JPMS
@@ -1584,12 +1598,13 @@
* @see ClassLoader#defineClass(String,byte[],int,int,ProtectionDomain)
(4) Lookup::hasPrivateAccess
/**
- * Returns {@code true} if this lookup has {@code PRIVATE} access.
- * @return {@code true} if this lookup has {@code PRIVATE} access.
+ * Returns {@code true} if this lookup has {@code PRIVATE} and {@code MODULE} access.
+ * @return {@code true} if this lookup has {@code PRIVATE} and {@code MODULE} access.
+ * @deprecated This method was originally designed to test {@code PRIVATE} access
+ * that implies full privilege access but {@code MODULE} access has since become
+ * independent of {@code PRIVATE} access. It is recommended to call
+ * {@link #hasFullPrivilegeAccess()} instead.
* @since 9
*/
+ @Deprecated(since="14")
public boolean hasPrivateAccess() {
(5) Lookup::hasFullPrivilegeAccess
+ /**
+ * Returns {@code true} if this lookup has <em>full privilege access</em>,
+ * i.e. {@code PRIVATE} and {@code MODULE} access.
+ * A {@code Lookup} object must have full privilege access in order to
+ * access all members that are allowed to the {@linkplain #lookupClass() lookup class}.
+ *
+ * @return {@code true} if this lookup has full privilege access.
+ * @since 14
+ * @see <a href="MethodHandles.Lookup.html#privacc">private and module access</a>
+ */
+ public boolean hasFullPrivilegeAccess()
(6) Lookup::findClass
javadoc update is a spec clarification. Not a spec change.
/**
- * Looks up a class by name from the lookup context defined by this {@code Lookup} object. The static
- * initializer of the class is not run.
- * <p>
- * The lookup context here is determined by the {@linkplain #lookupClass() lookup class}, its class
- * loader, and the {@linkplain #lookupModes() lookup modes}. In particular, the method first attempts to
- * load the requested class, and then determines whether the class is accessible to this lookup object.
+ * Looks up a class by name from the lookup context defined by this {@code Lookup} object,
+ * <a href="MethodHandles.Lookup.html#equiv">as if resolved</a> by an {@code ldc} instruction.
+ * Such a resolution, as specified in JVMS 5.4.3.1 section, attempts to locate and load the class,
+ * and then determines whether the class is accessible to this lookup object.
+ * <p>
+ * The lookup context here is determined by the {@linkplain #lookupClass() lookup class},
+ * its class loader, and the {@linkplain #lookupModes() lookup modes}.
*
* @param targetName the fully qualified name of the class to be looked up.
* @return the requested class.
@@ -1948,9 +1968,8 @@
* @throws ClassNotFoundException if the class cannot be loaded by the lookup class' loader.
* @throws IllegalAccessException if the class is not accessible, using the allowed access
* modes.
- * @throws SecurityException if a security manager is present and it
- * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
* @since 9
+ * @jvms 5.4.3.1 Class and Interface Resolution
*/
See attached MethodHandles.Lookup-report-v4.html and MethodHandles-report.html specdiff.
- csr of
-
JDK-8233527 Update Lookup::hasPrivateAccess and Lookup::defineClass spec w.r.t. full power lookup
-
- Resolved
-