Avoiding sun.misc.Unsafe and embracing modules in Java libraries: missing links
mandy.chung at oracle.com
Sun Apr 15 06:33:13 UTC 2018
FYI. I have sent a proposal  for item #1 to serviceability-dev and
you for discussion. JBS issue is:
On 4/2/18 5:02 AM, Rafael Winterhalter wrote:
> 1. Java agents cannot define auxiliary classes.
> Byte Buddy does support the JPMS fully, however, it still relies on
> sun.misc.Unsafe::defineClass for its Java agent API and currently breaks on
> Java 11 as this method was removed in a recent EA build. The reason for
> using Unsafe is that many instrumentations need to define auxiliary classes
> to aid an instrumentation similar to javac which sometimes needs to define
> anonymous classes or even synthetic classes. For example, if a Java agent
> wants to register an event listener to some framework, such listeners often
> declare multiple methods what makes it impossible to fullfil the listener
> contract using a lambda expression. Instead, one typically injects an
> additional class into the same package as the instrumented class. In this
> case, it is not possible to use MethodHandles.Lookup::defineClass as the
> class file transformer does not necessarily have private access to the
> lookup of the instrumented class.
> The current workarounds are:
> a) Open the package jdk.internal.misc to gain access to this package's
> Unsafe class. This can be done via Instrumentation::redefineModule.
> b) Open the java.lang package to access ClassLoader via reflection.
> c) Open the java.lang package to access the internal lookup with global
> access rights.
> Of these solutions only (b) relies on standard API and is guaranteed to
> function in the future but the solution still feels hacky and does not work
> for instrumentations of classes on the bootstrap loader. Opening packages
> also implies a risk of being applied carelessly since opening the package
> to the agent's module most likely opens the package to the unnamed module
> of the system class loader what invites to breaches of the JPMS
> encapsulation by code that does not ship with the agent.
> To offer a better solution, I would like to suggest one of the following:
> a) Add a method defineClass(ClassLoader, byte, ProtectionDomain) to the
> Instrumentation interface that works similar to Unsafe::defineClass. This
> would provide a very simple migration path. Since agents have access to
> jdk.internal.misc, adding this method does not add any capabilities to the
> agent, it merley avoids using internal API that might change.
> b) Supply a MethodHandles.Lookup instance to the
> ClassFileTransformer::transform API where the instance represents the
> instrumented class's access rights. This does however carry the risk of
> invoking the lookupClass method which would either load the instrumented
> class prematurely causing a circularity error or return an unexpected value
> such as null. Since the lookup API generally relies on loaded types, there
> are probably other problems such as invoking Lookup::privateLookupIn before
> all involved types are loaded.
> For the sake of simlicity and since easy migration paths make a quick
> adoption easier, I would suggestion solution (a), also in the light that
> quick and dirty migrations might still choose option (b) to save time and
> also since (b) might cause problems when types are not yet loaded.
More information about the jigsaw-dev