diff --git a/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/Agent.java b/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/Agent.java index aae283da55c..876a07f1fd1 100644 --- a/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/Agent.java +++ b/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/Agent.java @@ -60,6 +60,7 @@ import datadog.trace.bootstrap.instrumentation.jfr.InstrumentationBasedProfiling; import datadog.trace.util.AgentTaskScheduler; import datadog.trace.util.AgentThreadFactory.AgentThread; +import datadog.trace.util.JDK9ModuleAccess; import datadog.trace.util.throwable.FatalAgentMisconfigurationError; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.lang.instrument.Instrumentation; @@ -659,6 +660,8 @@ public InstallDatadogTracerCallback( } installDatadogMeter(initTelemetry); + // Must run before installDatadogTracer, which triggers the ddprof profiler load. + prepareDatadogProfilerContextStorage(instrumentation); installDatadogTracer(initTelemetry, scoClass, sco); maybeInstallLogsIntake(scoClass, sco); maybeStartIast(instrumentation); @@ -1356,6 +1359,33 @@ public void withTracer(TracerAPI tracer) { }); } + /** + * Exports {@code jdk.internal.misc} to the classloader that loads {@code + * com.datadoghq.profiler.*} before the Datadog profiler is loaded. + * + *

On JDK 21+, the profiler scopes its context {@code ThreadContext} storage to the carrier + * thread using {@code jdk.internal.misc.CarrierThreadLocal}, so a mounted virtual thread resolves + * to its current carrier's record — fixing a virtual-thread context use-after-free. That type + * lives in a non-exported package, hence the export. Must run before {@code + * installDatadogTracer}, which loads the profiler via {@link + * #createProfilingContextIntegration()}. + */ + private static void prepareDatadogProfilerContextStorage(Instrumentation inst) { + try { + if (inst == null + || !Config.get().isProfilingEnabled() + || !Config.get().isDatadogProfilerEnabled() + || OperatingSystem.isWindows() + || !isJavaVersionAtLeast(21)) { + return; + } + JDK9ModuleAccess.exportModuleToUnnamedModule( + inst, "java.base", new String[] {"jdk.internal.misc"}, AGENT_CLASSLOADER); + } catch (Throwable t) { + log.debug("Unable to export jdk.internal.misc for the Datadog profiler", t); + } + } + /** * {@see com.datadog.profiling.ddprof.DatadogProfilingIntegration} must not be modified to depend * on JFR.