JDK-8281765 : MethodHandles::lookup throws NPE if caller is null
  • Type: CSR
  • Component: core-libs
  • Sub-Component: java.lang.invoke
  • Priority: P4
  • Status: Draft
  • Resolution: Unresolved
  • Fix Versions: 19
  • Submitted: 2022-02-14
  • Updated: 2022-02-15
Related Reports
CSR :  
Description
Summary
-------

Specify `MethodHandles::lookup` to throw `IllegalCallerException`  if invoked from JNI attached thread with no caller frame

Problem
-------

The `MethodHandles::lookup` method is a caller sensitive method but does not specify what should happen when there are no stack frames to determine the caller.  A NullPointerException results which doesn't provide much diagnostic information.  If a call is made from JNI attached thread, the thread will have no call frame to determine the caller.

Solution
--------

When there is no caller frame on the stack,  simply throw an `IllegalCallerException` to provide better diagnostics.  

Specification
-------------

The spec of `java.lang.invoke.MethodHandles::lookup` is updated as follows:

```
@@ -107,18 +107,29 @@
      * This lookup object is a <em>capability</em> which may be delegated to trusted agents.
      * Do not store it in place where untrusted code can access it.
      * <p>
      * This method is caller sensitive, which means that it may return different
      * values to different callers.
+     * In cases where {@code MethodHandles.lookup} is called from a context where
+     * there is no caller frame on the stack (e.g. when called directly
+     * from a JNI attached thread), {@code IllegalCallerException} is thrown.
+     * To obtain a {@link Lookup lookup object} in such a context, use an auxiliary class that will
+     * implicitly be identified as the caller, or use {@link MethodHandles#publicLookup()}
+     * to obtain a low-privileged lookup instead.
      * @return a lookup object for the caller of this method, with
      * {@linkplain Lookup#ORIGINAL original} and
      * {@linkplain Lookup#hasFullPrivilegeAccess() full privilege access}.
+     * @throws IllegalCallerException if there is no caller frame on the stack.
      */
```