RFR: 8200559: Java agents doing instrumentation need a means to define auxilary classes

Rafael Winterhalter rafael.wth at gmail.com
Sun Apr 18 21:05:43 UTC 2021

As for the need to inject classes into 'new' packages, in Mockito we solve
this easily by 'claiming' a package by defining a static dummy class within
it which we then use as a hook for injection using a lookup. This works
well for us, and I do of course not know the explicit requirements of
others, but personally, I do not see a big need for this functionality

I remember the discussions about the dynamic agent attachment rather well,
it cuts into my line of work. The main (!) reason why dynamic attachment is
so popular is that it allows monitoring a JVM without additional
configuration. In this light, it does not make much of a difference if a
user has to set a special parameter to allow for dynamic attachment or if
the user has to set up the agent parameter itself, both add about the same
costs to operations. This is the cost you want to avoid by dynamic
attachment in the first place. Imagine an enterprise with thousands of JVM
deployments which are managed by different teams in different styles, with
different technical understanding relying on long chains of communication.
It can take years to roll out a tracing tool that requires explicit
configuration in an org like this. Thanks to dynamic attachment, all you
need is to drop an application per host which discovers all running JVMs
and attaches to them. A tracing tool that is missing only a few VMs by
misconfiguration will render a very incomplete picture of the tracing
state, making it an expensive toy. Easily avoiding such simple misses is an
important selling point for the JVM compared to other platforms where this
is not possible. I know this problem does not sound like much, it's
overcomeable, but orgs will not change, and reducing the capabilities of
dynamic agents would take much more out of the JVM's attractiveness than
the added security and consistency would bring to it.

As for the proposed API, I understand that it needs thought, my hope is
still that Java 17 would allow to write agents without Unsafe, since 17
will be a baseline for many years to come. I'd like to stress out that the
proposed API only encapsulates something that is already implicitly
possible today if one puts in the work.

I think that the problem you want to solve is rather that JVMs should not
attach to themselves to get hold of an instance of Instrumentation for
their own JVM. In this context, one would need to restrict the use of JNI
and prevent that a JVM starts new (Java) processes. I think it would be
better to tackle the issue from this angle rather than taking away a
feature that significantly adds to the JVMs attractiveness.

Am So., 18. Apr. 2021 um 18:24 Uhr schrieb Alan Bateman <
Alan.Bateman at oracle.com>:

> On 16/04/2021 21:09, Rafael Winterhalter wrote:
> > I have never seen a need for a non-agent to define a class in a
> > non-existing package. Injection is typically required if you want to work
> > with package-private types or methods which is really only relevant for
> the
> > Spring framework, but even there I do not think it's such a big area that
> > it cannot be addressed. Non-agent code generation is typically the use of
> > proxies where the code generation framework is sharing a class loader
> with
> > the user code and there is normally a way to weave it. Agents on the
> other
> > hand have to deal with unknown class loader hierarchies and it can be
> > necessary to inject code into a common class loader parent without
> > instrumenting classes in this loader or even knowing any classes of this
> > loader.
> Yes, the injection of proxy classes and the like is mainly the same
> run-time package as an existing class and these are the use-cases that
> Lookup.defineClass and Lookup.defineHiddenClass are intended for. There
> has been a few requests for defining proxy classes into "new/empty
> packages" but has a few challenges, like extending the set of packages
> in a named module. In general I wouldn't expect Java agents, which was
> intending for tools, to be using Lookup objects.
> > I have never heard about a 'discussion [that] will eventually lead into
> > putting at least some restrictions on agents loaded into a running VM'
> and
> > as a heavy user and someone who has helped to write a long row of
> > commercial agents and followed them into their use in production and who
> > has seen how helpful they are in reducing deployment complexity, I can
> only
> > hope that you will change your mind on this.
> > :
> >
> > That said, even if it was restricted in the future, this would mean that
> > some of the Instrumentation API methods will throw exceptions in the
> > future. There would not be much difference if an introduced defineClass
> > method would do the same.
> There was fuss on this topic during JDK 9. I'll try to find the mails in
> the archive, it would have been on serviceability-dev in 2016 or 2017.
> The compromise at the time was to introduce the
> -XX:EnableDynamicAgentLoading option with an initial value of "true" and
> re-visit it later. Flipping the default would mean that JVMTI and Java
> agents could not be loaded into a target VM without opt-in on the
> command line. No impact to agents specified on the command line with
> -javaagent, no impact to other usages of the attach mechanism so jcmd
> and the other diagnostic tools would continue to work.
> To re-cap, the main concern is the Instrumentation object is
> all-powerful and is intended for tools and the instrumentation is
> intended to be benign to support use-cases such as monitoring and
> tracing. It was never intended to a back-door into JDK internals.
> Specifying an agent on the command line with -javaagent is the opt-in to
> trust that agent. A tool run by the same user that loads its agent into
> a target VM is the use-case we targeted when we added the attach
> mechanism and the late binding agent support in JDK 6. The issue with
> that (and it's a regret now) is that the mechanism doesn't distinguish
> usage by a tool from a library/application using the attach mechanism to
> load an agent into the current VM (directly or using an intermediate VM).
> Time has moved on and maybe a better approach is to not change the XX
> option but instead load the agents with reduced capabilities. It would
> require opt-in on the command line to give these agents the same
> capabilities as agents specified on the command line with -javaagent. It
> would require exploration but it might be that unrecognized agents would
> not be allowed to redefine java.base or other core modules or instrument
> classes in those modules. The APIs are already specified to allow
> Unmodified{Module,Class}Exception be thrown as there have been cases in
> the past where some classes could not be transformed. Project Panama is
> currently exploring how to restrict and grant access to native code and
> maybe it should be the same mechanism or at least be consistent.
> Hopefully this helps sets some context as to why we have to be cautious
> with this PR. If the proposal were a defineClass that was limited to
> agents specified on the command line then it might okay. This would
> serve use-cases with tool agents that are way more advanced that the
> use-cases that we envisaged back in Java 5/6. The previous exploration
> into allowing non-public auxiliary classes be defined in the same
> run-time package as the class being instrumented was also okay.
> -Alan

More information about the core-libs-dev mailing list