Skip to content

Harden agent bootstrap-classpath append in AwsAgentBootstrap (whole agent JAR appended twice; only bridge classes need bootstrap visibility) #1396

Description

@srprash

Summary

AwsAgentBootstrap.premain appends the entire agent JAR to the bootstrap classloader search via inst.appendToBootstrapClassLoaderSearch(agentJar), and then delegates to OpenTelemetryAgent.agentmainstartAgentinstallBootstrapJar, which appends the same whole JAR again. So the agent JAR ends up on the bootstrap search path twice, and in both cases it's the whole JAR (~1000+ root classes, including the upstream io.opentelemetry.javaagent.* launcher classes), even though only a small set of classes actually need to be bootstrap-visible.

The classes that genuinely need to be on the bootstrap classloader (so they're shared between ByteBuddy advice running in the application classloader and the collectors running in the agent classloader) are:

  • software.amazon.opentelemetry.javaagent.bootstrap.AwsInstrumentationHolder
  • the software.amazon.opentelemetry.javaagent.bootstrap.di.* bridge package
  • the software.amazon.opentelemetry.serviceevents.* bridge package

Why this is worth improving

This isn't an outright break on current JDKs, but it's a latent hazard and a minor regression:

  • It defeats CDS / AppCDS. Each append emits OpenJDK ... warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended, disabling class-data sharing (a startup-time/footprint cost) and printing a warning on stderr.
  • The JDK Instrumentation#appendToBootstrapClassLoaderSearch javadoc explicitly states the agent "should take care to ensure that the JAR does not contain any classes or resources other than those to be defined by the bootstrap class loader," warning that violating this can cause "unexpected behavior that is difficult to diagnose." Appending the whole agent JAR (which contains the upstream launcher/SDK classes, not just bootstrap-intended classes) — and doing so twice — works against that guidance and compounds boot-classpath mutation during the fragile startup window.
  • The duplicate append is simply redundant work.

What is not the problem (so a fix can be scoped correctly)

These were checked empirically and are reassuring:

  • It does not measurably increase memory or loaded-class count — a class is defined exactly once regardless of how many times the JAR is appended; appendToBootstrapClassLoaderSearch only adds a search-path entry.
  • It does not create duplicate getResources() results for the application — boot-appended JAR resources do not surface through user-visible resource enumeration, so there's no ServiceLoader/SPI duplication.
  • Removing the premain append entirely is not a valid fix: AwsInstrumentationHolder then resolves as different copies in premain vs. the agent-classloader customizer, and the runtime feature that relies on the shared Instrumentation handle silently fails to initialize (getInstrumentation() returns null).

Suggested improvement

Append a minimal bootstrap JAR containing only AwsInstrumentationHolder + the two bridge packages, instead of the whole agent JAR — and avoid the redundant second append (or make it idempotent). This keeps the cross-classloader sharing intact, removes the duplicate append, aligns with the JDK guidance, and avoids unnecessarily disabling CDS.

Notes

Related to (but independent of) #1395, which addresses a separate Java 25 issue. This bootstrap-append item is lower priority — a future hardening/maintainability improvement, not a functional break on current JDKs.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions