Trying to fix JDK-8013527 - 1st Prototype

Mandy Chung mandy.chung at oracle.com
Wed Feb 3 03:22:45 UTC 2021


Hi Johannes,

I reconsidered the solution I implemented for JDK-8013527 that I 
mentioned [1].  I finally had the time to get back to this.   I see the 
merit of your idea to bind directly to an alternate implementation of 
MethodHandles::lookup taking an additional caller class parameter (but 
not any other caller-sensitive methods).

Please see https://github.com/openjdk/jdk/pull/2367.   I added you as a 
contributor in this PR.

Mandy
[1] 
https://mail.openjdk.java.net/pipermail/core-libs-dev/2021-January/073220.html

On 1/17/21 9:02 AM, Johannes Kuhn wrote:
> JDK-8013527[1] has somehow become the umbrella bug for "Using 
> MethodHandles to call caller sensitive methods leads to interesting 
> results".
>
> To recap: A caller sensitive method knows about who called it, and can 
> behave differently when called from an other context.
> Examples are: Class.forName, MethodHandles.lookup, Method.invoke...
>
> A MethodHandle on the other hand should not be caller sensitive.
> To archive this, a MethodHandle will "bind" the lookup class as caller 
> for caller sensitive methods.
>
> This is currently done by injecting a hidden class (InjectedInvoker" 
> that acts as a trampoline for calling caller sensitive methods.
>
> This injected invoker shares many properties of the original caller:
> Same ClassLoader, same Module, same Package, same ProtectionDomain, 
> but it's not the same class or a nestmate of it.
>
> For caller sensitive methods that do look at more than just the 
> injected invoker, this leads to "unexpected" results when called 
> through a MethodHandle:
>
> * MethodHandles.lookup() returns a full privileged lookup for the 
> injected invoker.
> * jlr.Field.get*/set*, jlr.Constructor.newInstance, jlr.Method.invoke 
> may fail with an IllegalAccessException if the target is private. See 
> JDK-8257874[2].
>
> -----------------------------------
>
> After reading one of John Rose's comments[3], I thought that this 
> might be a way to solve this general problem.
>
> So I implemented some of it here[4].
>
> The basic idea is that there is a private overload of the caller 
> sensitive method which accepts the caller as a tailing argument.
>
> The good news:
> * tier1 Tests pass.
> * ((Lookup) lookup.findStatic(MethodHandles.class, "lookup", 
> MethodType.methodType(Lookup.class)).invokeExact()).lookupClass() == 
> lookup.lookupClass();
> * JDK-8257874 can't be reproduced with Field.* or Constructor.
> * Performance is likely better. (InjectedInvoker collects all 
> arguments into an Object[].)
>
> The bad news:
> * If you use a MethodHandle to call Method.invoke for a caller 
> sensitive method, then you can still observe the injected invoker.
>
> -----------------------------------
>
> Moving forward, there are 3 ways:
> 1. Do nothing. Won't fix any bug.
> 2. Use the current prototype, and accept Method.invoke is odd when 
> calling it through a MethodHandle.
> 3. Go all in:
>   * Require **every** caller sensitive method to have a private overload.
>   * Method.invoke will also use that private overload.
>
> The problems with the 3rd approach are:
>   * What about methods that can be called virtually? 
> (Thread.getContextClassLoader())
>   * Requires a few changes to MethodAccessor. Maybe implementing 
> JDK-6824466[5] first?
>   * What about methods that do stack walks?
>
> I have to think more about the problems listed above - but maybe you 
> have some input that could help me on that.
>
> - Johannes
>
>
> [1]: https://bugs.openjdk.java.net/browse/JDK-8013527
> [2]: https://bugs.openjdk.java.net/browse/JDK-8257874
> [3]: 
> https://bugs.openjdk.java.net/browse/JDK-8020968?focusedCommentId=13611844&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#comment-13611844
> [4]: https://github.com/openjdk/jdk/pull/2117/files
> [5]: https://bugs.openjdk.java.net/browse/JDK-6824466



More information about the core-libs-dev mailing list