diff --git a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/agent/ClassesToRetransformFinder.java b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/agent/ClassesToRetransformFinder.java index cc92360c7ab..271fbbda594 100644 --- a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/agent/ClassesToRetransformFinder.java +++ b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/agent/ClassesToRetransformFinder.java @@ -111,4 +111,8 @@ private static boolean lookupClass(Trie changedClasses, Class clazz) { String simpleName = extractSimpleName(clazz); return changedClasses.contains(reverseStr(simpleName)); } + + ConcurrentMap getClassNamesBySourceFile() { + return classNamesBySourceFile; + } } diff --git a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/agent/DebuggerAgent.java b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/agent/DebuggerAgent.java index 36eafade871..38b600fc12c 100644 --- a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/agent/DebuggerAgent.java +++ b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/agent/DebuggerAgent.java @@ -324,6 +324,10 @@ private static String getDiagnosticEndpoint( private static void setupSourceFileTracking( Instrumentation instrumentation, ClassesToRetransformFinder finder) { + if (!Config.get().isDebuggerSourceFileTrackingEnabled()) { + LOGGER.debug("Source file tracking is disabled"); + return; + } SourceFileTrackingTransformer sourceFileTrackingTransformer = new SourceFileTrackingTransformer(finder); sourceFileTrackingTransformer.start(); diff --git a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/agent/SourceFileTrackingTransformer.java b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/agent/SourceFileTrackingTransformer.java index 4976ef01c8f..b3df4fc220f 100644 --- a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/agent/SourceFileTrackingTransformer.java +++ b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/agent/SourceFileTrackingTransformer.java @@ -75,6 +75,9 @@ private void registerSourceFile(String className, byte[] classfileBuffer) { if (sourceFile == null) { return; } + if (!isExtensionAllowed(sourceFile)) { + return; + } String simpleClassName = stripPackagePath(className); String simpleSourceFile = removeExtension(sourceFile); if (simpleClassName.equals(simpleSourceFile)) { @@ -83,6 +86,13 @@ private void registerSourceFile(String className, byte[] classfileBuffer) { finder.register(sourceFile, className); } + private boolean isExtensionAllowed(String sourceFile) { + return sourceFile.endsWith(".java") + || sourceFile.endsWith(".kt") + || sourceFile.endsWith(".scala") + || sourceFile.endsWith(".groovy"); + } + private static class SourceFileItem { final String className; final byte[] classfileBuffer; diff --git a/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/agent/SourceFileTrackingTransformerTest.java b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/agent/SourceFileTrackingTransformerTest.java index d07e02ad580..44c8f0f101d 100644 --- a/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/agent/SourceFileTrackingTransformerTest.java +++ b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/agent/SourceFileTrackingTransformerTest.java @@ -79,6 +79,38 @@ void transformInner() throws IllegalClassFormatException { assertEquals(InnerHelper.MySecondInner.class, changedClasses.get(2)); } + @Test + void transformNotAllowed() throws IllegalClassFormatException { + ClassesToRetransformFinder finder = new ClassesToRetransformFinder(); + SourceFileTrackingTransformer sourceFileTrackingTransformer = + new SourceFileTrackingTransformer(finder); + ConfigurationComparer comparer = createComparer("TopLevelHelper.java"); + byte[] classFileBytes = getClassFileBytes(TopLevelHelper.class); + replaceInByteArray( + classFileBytes, "TopLevelHelper.java".getBytes(), "TopLevelHelper.cloj".getBytes()); + sourceFileTrackingTransformer.transform(null, "", null, null, classFileBytes); + sourceFileTrackingTransformer.flush(); + List> changedClasses = + finder.getAllLoadedChangedClasses(new Class[] {InnerHelper.class}, comparer); + assertEquals(0, finder.getClassNamesBySourceFile().size()); + } + + private static void replaceInByteArray(byte[] buffer, byte[] oldBytes, byte[] newBytes) { + int oldIdx = 0; + for (int i = 0; i < buffer.length; i++) { + if (buffer[i] == oldBytes[oldIdx]) { + oldIdx++; + if (oldIdx == oldBytes.length) { + // Found the oldBytes, replace with newBytes + System.arraycopy(newBytes, 0, buffer, i - oldIdx + 1, newBytes.length); + oldIdx = 0; // Reset for next search + } + } else { + oldIdx = 0; // Reset if current byte does not match + } + } + } + private ConfigurationComparer createComparer(String sourceFile) { Configuration emptyConfig = Configuration.builder().setService("service-name").build(); Configuration newConfig = diff --git a/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java b/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java index a6d5888e76f..f5a79493b96 100644 --- a/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java +++ b/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java @@ -207,6 +207,7 @@ public final class ConfigDefaults { static final int DEFAULT_DEBUGGER_EXCEPTION_MAX_CAPTURED_FRAMES = 3; static final int DEFAULT_DEBUGGER_EXCEPTION_CAPTURE_INTERVAL_SECONDS = 60 * 60; static final boolean DEFAULT_DISTRIBUTED_DEBUGGER_ENABLED = false; + static final boolean DEFAULT_DEBUGGER_SOURCE_FILE_TRACKING_ENABLED = true; static final boolean DEFAULT_TRACE_REPORT_HOSTNAME = false; static final String DEFAULT_TRACE_ANNOTATIONS = null; diff --git a/dd-trace-api/src/main/java/datadog/trace/api/config/DebuggerConfig.java b/dd-trace-api/src/main/java/datadog/trace/api/config/DebuggerConfig.java index c92d5705962..536821c9a25 100644 --- a/dd-trace-api/src/main/java/datadog/trace/api/config/DebuggerConfig.java +++ b/dd-trace-api/src/main/java/datadog/trace/api/config/DebuggerConfig.java @@ -61,6 +61,8 @@ public final class DebuggerConfig { public static final String DEBUGGER_EXCEPTION_CAPTURE_INTERMEDIATE_SPANS_ENABLED = "exception.replay.capture.intermediate.spans.enabled"; public static final String DISTRIBUTED_DEBUGGER_ENABLED = "distributed.debugger.enabled"; + public static final String DEBUGGER_SOURCE_FILE_TRACKING_ENABLED = + "dynamic.instrumentation.source.file.tracking.enabled"; public static final String THIRD_PARTY_INCLUDES = "third.party.includes"; public static final String THIRD_PARTY_EXCLUDES = "third.party.excludes"; public static final String THIRD_PARTY_SHADING_IDENTIFIERS = "third.party.shading.identifiers"; diff --git a/internal-api/src/main/java/datadog/trace/api/Config.java b/internal-api/src/main/java/datadog/trace/api/Config.java index 8f1c06837ce..51ee1ac6966 100644 --- a/internal-api/src/main/java/datadog/trace/api/Config.java +++ b/internal-api/src/main/java/datadog/trace/api/Config.java @@ -60,6 +60,7 @@ import static datadog.trace.api.ConfigDefaults.DEFAULT_DEBUGGER_EXCEPTION_MAX_CAPTURED_FRAMES; import static datadog.trace.api.ConfigDefaults.DEFAULT_DEBUGGER_EXCEPTION_ONLY_LOCAL_ROOT; import static datadog.trace.api.ConfigDefaults.DEFAULT_DEBUGGER_MAX_EXCEPTION_PER_SECOND; +import static datadog.trace.api.ConfigDefaults.DEFAULT_DEBUGGER_SOURCE_FILE_TRACKING_ENABLED; import static datadog.trace.api.ConfigDefaults.DEFAULT_DISTRIBUTED_DEBUGGER_ENABLED; import static datadog.trace.api.ConfigDefaults.DEFAULT_DOGSTATSD_PORT; import static datadog.trace.api.ConfigDefaults.DEFAULT_DOGSTATSD_START_DELAY; @@ -281,6 +282,7 @@ import static datadog.trace.api.config.DebuggerConfig.DEBUGGER_EXCEPTION_MAX_CAPTURED_FRAMES; import static datadog.trace.api.config.DebuggerConfig.DEBUGGER_EXCEPTION_ONLY_LOCAL_ROOT; import static datadog.trace.api.config.DebuggerConfig.DEBUGGER_MAX_EXCEPTION_PER_SECOND; +import static datadog.trace.api.config.DebuggerConfig.DEBUGGER_SOURCE_FILE_TRACKING_ENABLED; import static datadog.trace.api.config.DebuggerConfig.DISTRIBUTED_DEBUGGER_ENABLED; import static datadog.trace.api.config.DebuggerConfig.DYNAMIC_INSTRUMENTATION_CAPTURE_TIMEOUT; import static datadog.trace.api.config.DebuggerConfig.DYNAMIC_INSTRUMENTATION_CLASSFILE_DUMP_ENABLED; @@ -1048,6 +1050,7 @@ public static String getHostName() { private final boolean debuggerCodeOriginEnabled; private final int debuggerCodeOriginMaxUserFrames; private final boolean distributedDebuggerEnabled; + private final boolean debuggerSourceFileTrackingEnabled; private final Set debuggerThirdPartyIncludes; private final Set debuggerThirdPartyExcludes; @@ -2385,6 +2388,9 @@ PROFILING_DATADOG_PROFILER_ENABLED, isDatadogProfilerSafeInCurrentEnvironment()) configProvider.getInteger( DEBUGGER_EXCEPTION_CAPTURE_INTERVAL_SECONDS, DEFAULT_DEBUGGER_EXCEPTION_CAPTURE_INTERVAL_SECONDS); + debuggerSourceFileTrackingEnabled = + configProvider.getBoolean( + DEBUGGER_SOURCE_FILE_TRACKING_ENABLED, DEFAULT_DEBUGGER_SOURCE_FILE_TRACKING_ENABLED); debuggerThirdPartyIncludes = tryMakeImmutableSet(configProvider.getList(THIRD_PARTY_INCLUDES)); debuggerThirdPartyExcludes = tryMakeImmutableSet(configProvider.getList(THIRD_PARTY_EXCLUDES)); @@ -3988,6 +3994,10 @@ public boolean isDistributedDebuggerEnabled() { return distributedDebuggerEnabled; } + public boolean isDebuggerSourceFileTrackingEnabled() { + return debuggerSourceFileTrackingEnabled; + } + public Set getThirdPartyIncludes() { return debuggerThirdPartyIncludes; }