Skip to content

fix: initialize the indy dispatcher without Unsafe on modern JDKs - #4577

Open
mvanhorn wants to merge 3 commits into
elastic:mainfrom
mvanhorn:fix/4519-jdk26-bootstrap-injection
Open

mvanhorn wants to merge 3 commits into
elastic:mainfrom
mvanhorn:fix/4519-jdk26-bootstrap-injection

Conversation

@mvanhorn

Copy link
Copy Markdown

What does this PR do?

On Java 9+, define the java.lang.IndyBootstrapDispatcher resource with Byte Buddy's ClassInjector.UsingLookup: open java.base/java.lang to the agent's actual defining class loader through the existing ElasticApmAgent.openModule API, obtain a private lookup anchored on Object.class, and inject the existing bytes. Keep the Java 7/8 Unsafe path, invoke the newer lookup API reflectively to preserve the Java 7 production API baseline, and retain the initial Class.forName(..., false, null) check so repeated initialization reuses the bootstrap class. Update the production call sites inside IndyBootstrap.java to distinguish the dispatcher lookup anchor from the legacy ModuleSetter injection, and apply the existing J9 module override only when the dispatcher is not already in java.base, comparing modules with Byte Buddy's existing JavaModule abstraction.

On JDK 26+, agent startup can fail while preparing instrumentation because Byte Buddy disables its Unsafe class injector by default. The supplied stack trace reaches IndyBootstrap.loadClassInBootstrap, which still unconditionally uses ClassInjector.UsingUnsafe.ofBootLoader() in this checkout. The maintainer identifies this injection site and suggests method-handle-based injection; -Dnet.bytebuddy.safe=false is a temporary workaround. The June 30 comment says Java 26 was outside the supported-version policy at that time, but neither claims the work nor rejects the proposed code correction.

Fixes #4519

Checklist

  • This is an enhancement of existing features, or a new feature in existing plugins
    • I have added tests that prove my fix is effective or that my feature works
    • I have made corresponding changes to the documentation
  • This is a bugfix
    • I have added tests that would fail without this fix
  • This is a new plugin
    • My code follows the style guidelines of this project
    • I have made corresponding changes to the documentation
    • I have added tests that prove my fix is effective or that my feature works
    • New and existing unit tests pass locally with my changes
  • This is something else

@mvanhorn
mvanhorn requested a review from a team as a code owner September 11, 2026 09:36
@github-actions

Copy link
Copy Markdown

🤖 GitHub comments

Just comment with:

  • run docs-build : Re-trigger the docs validation. (use unformatted text in the comment!)

@github-actions github-actions Bot added agent-java community Issues and PRs created by the community triage labels Sep 11, 2026
Keep both changelog entries under Fixes.
Copilot AI balanced review requested due to automatic review settings October 31, 2026 06:07

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The test leaves Unsafe-disabled startup unverified because agent initialization occurs before it runs; a fresh-JVM regression test must verify successful dispatcher initialization and bootstrap-loader/module placement with -Dnet.bytebuddy.safe=true.

1 open issue
What changed in this PR

This PR addresses #4519 by removing the invokedynamic dispatcher’s dependence on Unsafe injection on Java 9+, avoiding the reported JDK 26+ startup failure while preserving the Java 7/8 fallback.

Changes:

  • Uses reflective lookup-based injection and opens java.lang to the agent’s defining class loader.
  • Preserves dispatcher reuse and limits the J9 module override to cases where it is needed.
  • Adds initialization and failure-path tests, plus a release note.
File Description
CHANGELOG.next-release.md Documents the dispatcher startup fix.
apm-agent-core/​src/​test/​java/​co/​elastic/​apm/​agent/​bci/​IndyBootstrapTest.java Adds dispatcher initialization and failure-path checks; isolates the legacy module-setter test.
apm-agent-core/​src/​main/​java/​co/​elastic/​apm/​agent/​bci/​IndyBootstrap.java Adds lookup-based injection for modern JDKs while retaining legacy Unsafe paths.

Review effort: Balanced

Start a separate JVM with net.bytebuddy.safe=true so Byte Buddy never
enables Unsafe, then check the dispatcher lands in the bootstrap loader
and java.base.
Copilot AI balanced review requested due to automatic review settings October 31, 2026 13:16

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The dispatcher initialization change has no active review issues blocking approval.

No open issues 🎉

1 resolved since last review

Review effort: Balanced

@mergify

mergify Bot commented Nov 12, 2026

Copy link
Copy Markdown
Contributor

Tick the box to add this pull request to the merge queue (same as @mergifyio queue). If it does not match the queue conditions yet, it enters the queue once it does.

  • Queue this pull request

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agent-java community Issues and PRs created by the community triage

Projects

None yet

Development

Successfully merging this pull request may close these issues.

UnsupportedOperationException at startup when using JDK 26+

2 participants