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](https://download.java.net/java/early_access/jdk14/docs/api/java.base/java/lang/invoke/MethodHandles.Lookup.html#privacc) section and [Security manager interactions](https://download.java.net/java/early_access/jdk14/docs/api/java.base/java/lang/invoke/MethodHandles.Lookup.html#secmgr) 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](https://download.java.net/java/early_access/jdk14/docs/api/java.base/java/lang/invoke/MethodHandles.Lookup.html#privacc).
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 <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>, 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.