From aa4be16a8b08e8d595c34ed13b74973eb831e021 Mon Sep 17 00:00:00 2001 From: jean-philippe bempel Date: Wed, 5 Mar 2025 17:03:32 +0100 Subject: [PATCH] Optimize the SourceFile tracking We provide a new way to extract the SourceFile attribute from classfile that just scan the byte array to reconstruct the offsets of the constant pool and quickly fetch at the right location the content of the SourceFile attribute --- .../debugger/util/ClassFileHelper.java | 132 +++++++++++++++++- .../debugger/agent/CapturedSnapshotTest.java | 2 +- .../debugger/agent/CapturingTestBase.java | 2 +- .../debugger/agent/DebuggerAgentTest.java | 4 +- .../agent/DebuggerTransformerTest.java | 2 +- .../SourceFileTrackingTransformerTest.java | 2 +- .../TransformerDefinitionMatcherTest.java | 2 +- .../DefaultExceptionDebuggerTest.java | 2 +- .../ExceptionProbeInstrumentationTest.java | 4 +- .../debugger/origin/CodeOriginTest.java | 2 +- .../debugger/trigger/TriggerProbeTest.java | 2 +- .../debugger/util/ClassFileHelperTest.java | 44 +++--- .../com/datadog/debugger/util/TestHelper.java | 49 ------- .../test/java/utils/TestClassFileHelper.java | 25 ++++ .../src/test/java/utils/TestHelper.java | 44 ++++++ .../debugger/classfiles/CommandLine.class | Bin 0 -> 80036 bytes .../datadog/debugger/classfiles/JDK23.class | Bin 0 -> 1913 bytes .../datadog/debugger/classfiles/JDK23.java | 25 ++++ .../datadog/debugger/classfiles/JDK8.class | Bin 0 -> 1856 bytes .../com/datadog/debugger/classfiles/JDK8.java | 25 ++++ 20 files changed, 290 insertions(+), 78 deletions(-) delete mode 100644 dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/util/TestHelper.java create mode 100644 dd-java-agent/agent-debugger/src/test/java/utils/TestClassFileHelper.java create mode 100644 dd-java-agent/agent-debugger/src/test/resources/com/datadog/debugger/classfiles/CommandLine.class create mode 100644 dd-java-agent/agent-debugger/src/test/resources/com/datadog/debugger/classfiles/JDK23.class create mode 100644 dd-java-agent/agent-debugger/src/test/resources/com/datadog/debugger/classfiles/JDK23.java create mode 100644 dd-java-agent/agent-debugger/src/test/resources/com/datadog/debugger/classfiles/JDK8.class create mode 100644 dd-java-agent/agent-debugger/src/test/resources/com/datadog/debugger/classfiles/JDK8.java diff --git a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/util/ClassFileHelper.java b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/util/ClassFileHelper.java index 63a158f4dab..0f1a1d796c3 100644 --- a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/util/ClassFileHelper.java +++ b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/util/ClassFileHelper.java @@ -1,12 +1,20 @@ package com.datadog.debugger.util; +import java.nio.charset.StandardCharsets; import org.objectweb.asm.ClassReader; import org.objectweb.asm.tree.ClassNode; /** Helper class for extracting information of a class file */ public class ClassFileHelper { + private static final int CONSTANT_POOL_COUNT_OFFSET = 8; + private static final int CONSTANT_POOL_BASE_OFFSET = 10; + public static String extractSourceFile(byte[] classFileBuffer) { - // TODO maybe by scanning the byte array directly we can avoid doing an expensive parsing + return extractSourceFileOffsetVersion(classFileBuffer); + } + + // Version using ASM library + private static String extractSourceFileASM(byte[] classFileBuffer) { ClassReader classReader = new ClassReader(classFileBuffer); ClassNode classNode = new ClassNode(); classReader.accept(classNode, ClassReader.SKIP_FRAMES); @@ -33,4 +41,126 @@ public static String stripPackagePath(String classPath) { } return classPath; } + + // Based on JVM spec: https://docs.oracle.com/javase/specs/jvms/se23/html/jvms-4.html + // Extracts the SourceFile attribute from a Java class file byte array with minimal parsing. + // This method is based on the JVM spec and does not use any external libraries. + // We are scanning the constant pool to keep file offsets for later fetching of the SourceFile + // attribute value. As the constant pool is a variable length structure, we need to scan them + // and based on the tag, we can calculate the length of the entry to skip to the next one. + private static String extractSourceFileOffsetVersion(byte[] classFileBytes) { + // Quick validation of minimum class file size and magic number + if (classFileBytes == null + || classFileBytes.length < 10 + || classFileBytes[0] != (byte) 0xCA + || classFileBytes[1] != (byte) 0xFE + || classFileBytes[2] != (byte) 0xBA + || classFileBytes[3] != (byte) 0xBE) { + return null; + } + int constantPoolCount = readUnsignedShort(classFileBytes, CONSTANT_POOL_COUNT_OFFSET); + int[] constantPoolOffsets = new int[constantPoolCount]; + int currentOffset = CONSTANT_POOL_BASE_OFFSET; + // based on the JVM spec, constant pool starts from index 1 until constantPoolCount - 1 + for (int i = 0; i < constantPoolCount - 1; i++) { + constantPoolOffsets[i] = currentOffset; + int tag = classFileBytes[constantPoolOffsets[i]]; + switch (tag) { + case 1: // CONSTANT_Utf8 + int length = readUnsignedShort(classFileBytes, constantPoolOffsets[i] + 1); + currentOffset += 3 + length; + break; + case 7: // CONSTANT_Class + case 8: // CONSTANT_String + case 16: // CONSTANT_MethodType + case 19: // CONSTANT_Module + case 20: // CONSTANT_Package + currentOffset += 3; + break; + case 15: // CONSTANT_MethodHandle + currentOffset += 4; + break; + case 3: // CONSTANT_Integer + case 4: // CONSTANT_Float + case 9: // CONSTANT_Fieldref + case 10: // CONSTANT_Methodref + case 11: // CONSTANT_InterfaceMethodref + case 12: // CONSTANT_NameAndType + case 17: // CONSTANT_Dynamic + case 18: // CONSTANT_InvokeDynamic + currentOffset += 5; + break; + case 5: // CONSTANT_Long + case 6: // CONSTANT_Double + currentOffset += 9; + i++; // Double slot + break; + default: + throw new IllegalArgumentException("Unknown constant pool tag: " + tag); + } + } + currentOffset += 2; // Skip access flags + currentOffset += 2; // Skip this class + currentOffset += 2; // Skip super class + int interfacesCount = readUnsignedShort(classFileBytes, currentOffset); + currentOffset += 2 + interfacesCount * 2; // Skip interfaces + // skip fields + currentOffset = skipFieldsOrMethods(classFileBytes, currentOffset); + // skip Methods + currentOffset = skipFieldsOrMethods(classFileBytes, currentOffset); + int attributesCount = readUnsignedShort(classFileBytes, currentOffset); + currentOffset += 2; // Skip attributes count + for (int i = 0; i < attributesCount; i++) { + int attributeNameIndex = readUnsignedShort(classFileBytes, currentOffset); + currentOffset += 2; // Skip attribute name index + int attributeLength = (int) readUnsignedInt(classFileBytes, currentOffset); + currentOffset += 4; // Skip attribute length + if (attributeNameIndex == 0) { + continue; + } + // read attribute name + int utf8Offset = constantPoolOffsets[attributeNameIndex - 1]; + int utf8Len = readUnsignedShort(classFileBytes, utf8Offset + 1); + String utf8 = new String(classFileBytes, utf8Offset + 3, utf8Len, StandardCharsets.UTF_8); + if ("SourceFile".equals(utf8)) { + // read SourceFile attribute + int sourceFileIndex = readUnsignedShort(classFileBytes, currentOffset); + int sourceFileOffset = constantPoolOffsets[sourceFileIndex - 1]; + int sourceFileLen = readUnsignedShort(classFileBytes, sourceFileOffset + 1); + return new String( + classFileBytes, sourceFileOffset + 3, sourceFileLen, StandardCharsets.UTF_8); + } + currentOffset += attributeLength; // Skip attribute data + } + return null; + } + + private static int skipFieldsOrMethods(byte[] classFileBytes, int currentOffset) { + int fieldsCount = readUnsignedShort(classFileBytes, currentOffset); + currentOffset += 2; // Skip count + for (int i = 0; i < fieldsCount; i++) { + currentOffset += 6; // Skip access flags, name index, descriptor index + int attributesCount = readUnsignedShort(classFileBytes, currentOffset); + currentOffset += 2; // Skip attributes count + for (int j = 0; j < attributesCount; j++) { + currentOffset += 2; // Skip attribute name index + int attributeLength = (int) readUnsignedInt(classFileBytes, currentOffset); + currentOffset += 4 + attributeLength; // Skip attribute length and data + } + } + return currentOffset; + } + + // read unsigned short from byte array + private static int readUnsignedShort(byte[] bytes, int offset) { + return ((bytes[offset] & 0xFF) << 8) | (bytes[offset + 1] & 0xFF); + } + + // read unsigned int from byte array + private static long readUnsignedInt(byte[] bytes, int offset) { + return ((long) (bytes[offset] & 0xFF) << 24) + + ((bytes[offset + 1] & 0xFF) << 16) + + ((bytes[offset + 2] & 0xFF) << 8) + + (bytes[offset + 3] & 0xFF); + } } diff --git a/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/agent/CapturedSnapshotTest.java b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/agent/CapturedSnapshotTest.java index b2bf9f260b3..5f32095d915 100644 --- a/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/agent/CapturedSnapshotTest.java +++ b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/agent/CapturedSnapshotTest.java @@ -7,7 +7,6 @@ import static com.datadog.debugger.util.MoshiSnapshotHelper.REDACTED_IDENT_REASON; import static com.datadog.debugger.util.MoshiSnapshotHelper.REDACTED_TYPE_REASON; import static com.datadog.debugger.util.MoshiSnapshotTestHelper.VALUE_ADAPTER; -import static com.datadog.debugger.util.TestHelper.setFieldInConfig; import static datadog.trace.bootstrap.debugger.util.Redaction.REDACTED_VALUE; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -27,6 +26,7 @@ import static utils.InstrumentationTestHelper.getLineForLineProbe; import static utils.InstrumentationTestHelper.loadClass; import static utils.TestHelper.getFixtureContent; +import static utils.TestHelper.setFieldInConfig; import com.datadog.debugger.el.DSL; import com.datadog.debugger.el.ProbeCondition; diff --git a/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/agent/CapturingTestBase.java b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/agent/CapturingTestBase.java index c9fdfeb2e01..5cd498c5c5f 100644 --- a/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/agent/CapturingTestBase.java +++ b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/agent/CapturingTestBase.java @@ -2,11 +2,11 @@ import static com.datadog.debugger.util.MoshiSnapshotHelper.NOT_CAPTURED_REASON; import static com.datadog.debugger.util.MoshiSnapshotTestHelper.VALUE_ADAPTER; -import static com.datadog.debugger.util.TestHelper.setFieldInConfig; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.mock; +import static utils.TestHelper.setFieldInConfig; import com.datadog.debugger.instrumentation.InstrumentationResult; import com.datadog.debugger.probe.LogProbe; diff --git a/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/agent/DebuggerAgentTest.java b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/agent/DebuggerAgentTest.java index e2f076deffc..1331a80a232 100644 --- a/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/agent/DebuggerAgentTest.java +++ b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/agent/DebuggerAgentTest.java @@ -1,7 +1,5 @@ package com.datadog.debugger.agent; -import static com.datadog.debugger.util.TestHelper.setEnvVar; -import static com.datadog.debugger.util.TestHelper.setFieldInConfig; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assumptions.assumeTrue; @@ -14,6 +12,8 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static utils.TestHelper.setEnvVar; +import static utils.TestHelper.setFieldInConfig; import com.datadog.debugger.util.RemoteConfigHelper; import datadog.common.container.ContainerInfo; diff --git a/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/agent/DebuggerTransformerTest.java b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/agent/DebuggerTransformerTest.java index 11137f50594..55d08740941 100644 --- a/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/agent/DebuggerTransformerTest.java +++ b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/agent/DebuggerTransformerTest.java @@ -1,6 +1,5 @@ package com.datadog.debugger.agent; -import static com.datadog.debugger.util.ClassFileHelperTest.getClassFileBytes; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; import static org.mockito.ArgumentMatchers.any; @@ -10,6 +9,7 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static utils.TestClassFileHelper.getClassFileBytes; import com.datadog.debugger.instrumentation.DiagnosticMessage; import com.datadog.debugger.instrumentation.InstrumentationResult; 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 0a2a5b7968e..ba778b7ba78 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 @@ -1,7 +1,7 @@ package com.datadog.debugger.agent; -import static com.datadog.debugger.util.ClassFileHelperTest.getClassFileBytes; import static org.junit.jupiter.api.Assertions.assertEquals; +import static utils.TestClassFileHelper.getClassFileBytes; import com.datadog.debugger.probe.LogProbe; import java.lang.instrument.IllegalClassFormatException; diff --git a/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/agent/TransformerDefinitionMatcherTest.java b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/agent/TransformerDefinitionMatcherTest.java index 25d976feebd..c669554f41a 100644 --- a/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/agent/TransformerDefinitionMatcherTest.java +++ b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/agent/TransformerDefinitionMatcherTest.java @@ -1,8 +1,8 @@ package com.datadog.debugger.agent; -import static com.datadog.debugger.util.ClassFileHelperTest.getClassFileBytes; import static java.util.Arrays.asList; import static org.junit.jupiter.api.Assertions.*; +import static utils.TestClassFileHelper.getClassFileBytes; import com.datadog.debugger.probe.LogProbe; import com.datadog.debugger.probe.MetricProbe; diff --git a/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/exception/DefaultExceptionDebuggerTest.java b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/exception/DefaultExceptionDebuggerTest.java index aec38f65fd0..aaabb300cc0 100644 --- a/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/exception/DefaultExceptionDebuggerTest.java +++ b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/exception/DefaultExceptionDebuggerTest.java @@ -1,7 +1,6 @@ package com.datadog.debugger.exception; import static com.datadog.debugger.exception.DefaultExceptionDebugger.SNAPSHOT_ID_TAG_FMT; -import static com.datadog.debugger.util.TestHelper.assertWithTimeout; import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; import static java.util.stream.Collectors.toList; @@ -16,6 +15,7 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static utils.TestHelper.assertWithTimeout; import com.datadog.debugger.agent.ConfigurationAcceptor; import com.datadog.debugger.agent.ConfigurationUpdater; diff --git a/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/exception/ExceptionProbeInstrumentationTest.java b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/exception/ExceptionProbeInstrumentationTest.java index b5b63f463e5..f895b503134 100644 --- a/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/exception/ExceptionProbeInstrumentationTest.java +++ b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/exception/ExceptionProbeInstrumentationTest.java @@ -6,13 +6,13 @@ import static com.datadog.debugger.exception.DefaultExceptionDebugger.ERROR_DEBUG_INFO_CAPTURED; import static com.datadog.debugger.exception.DefaultExceptionDebugger.SNAPSHOT_ID_TAG_FMT; import static com.datadog.debugger.util.MoshiSnapshotTestHelper.getValue; -import static com.datadog.debugger.util.TestHelper.assertWithTimeout; -import static com.datadog.debugger.util.TestHelper.setFieldInConfig; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import static utils.InstrumentationTestHelper.compileAndLoadClass; +import static utils.TestHelper.assertWithTimeout; +import static utils.TestHelper.setFieldInConfig; import com.datadog.debugger.agent.ClassesToRetransformFinder; import com.datadog.debugger.agent.Configuration; diff --git a/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/origin/CodeOriginTest.java b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/origin/CodeOriginTest.java index 9d57677de2c..140bc1f1bff 100644 --- a/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/origin/CodeOriginTest.java +++ b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/origin/CodeOriginTest.java @@ -1,6 +1,5 @@ package com.datadog.debugger.origin; -import static com.datadog.debugger.util.TestHelper.setFieldInConfig; import static datadog.trace.api.DDTags.DD_CODE_ORIGIN_FRAME; import static datadog.trace.api.DDTags.DD_CODE_ORIGIN_PREFIX; import static datadog.trace.api.DDTags.DD_CODE_ORIGIN_TYPE; @@ -14,6 +13,7 @@ import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static utils.InstrumentationTestHelper.compileAndLoadClass; +import static utils.TestHelper.setFieldInConfig; import com.datadog.debugger.agent.CapturingTestBase; import com.datadog.debugger.codeorigin.DefaultCodeOriginRecorder; diff --git a/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/trigger/TriggerProbeTest.java b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/trigger/TriggerProbeTest.java index 367080a068d..79ad1e25e22 100644 --- a/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/trigger/TriggerProbeTest.java +++ b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/trigger/TriggerProbeTest.java @@ -1,13 +1,13 @@ package com.datadog.debugger.trigger; import static com.datadog.debugger.el.DSL.*; -import static com.datadog.debugger.util.TestHelper.setFieldInConfig; import static java.lang.String.format; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.verify; import static utils.InstrumentationTestHelper.compileAndLoadClass; +import static utils.TestHelper.setFieldInConfig; import com.datadog.debugger.agent.CapturingTestBase; import com.datadog.debugger.agent.Configuration; diff --git a/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/util/ClassFileHelperTest.java b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/util/ClassFileHelperTest.java index 3913ee4980f..456ad4c6146 100644 --- a/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/util/ClassFileHelperTest.java +++ b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/util/ClassFileHelperTest.java @@ -1,25 +1,37 @@ package com.datadog.debugger.util; -import static datadog.trace.util.Strings.getResourceName; +import static org.junit.jupiter.api.Assertions.assertEquals; -import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.io.InputStream; -import java.net.URL; +import java.net.URISyntaxException; +import java.nio.file.Files; +import java.nio.file.Paths; +import org.junit.jupiter.api.Test; public class ClassFileHelperTest { - public static byte[] getClassFileBytes(Class clazz) { - URL resource = clazz.getResource("/" + getResourceName(clazz.getTypeName())); - byte[] buffer = new byte[4096]; - ByteArrayOutputStream os = new ByteArrayOutputStream(); - try (InputStream is = resource.openStream()) { - int readBytes; - while ((readBytes = is.read(buffer)) != -1) { - os.write(buffer, 0, readBytes); - } - } catch (IOException e) { - e.printStackTrace(); + + @Test + public void extractSourceFile() { + assertEquals( + "JDK8.java", + ClassFileHelper.extractSourceFile( + readClassFileBytes("/com/datadog/debugger/classfiles/JDK8.class"))); + assertEquals( + "JDK23.java", + ClassFileHelper.extractSourceFile( + readClassFileBytes("/com/datadog/debugger/classfiles/JDK23.class"))); + // big classfile (80KB) + assertEquals( + "CommandLine.java", + ClassFileHelper.extractSourceFile( + readClassFileBytes("/com/datadog/debugger/classfiles/CommandLine.class"))); + } + + private static byte[] readClassFileBytes(String fileName) { + try { + return Files.readAllBytes(Paths.get(ClassFileHelperTest.class.getResource(fileName).toURI())); + } catch (IOException | URISyntaxException e) { + throw new RuntimeException(e); } - return os.toByteArray(); } } diff --git a/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/util/TestHelper.java b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/util/TestHelper.java deleted file mode 100644 index b1988cbbd87..00000000000 --- a/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/util/TestHelper.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.datadog.debugger.util; - -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.lang.reflect.Field; -import java.time.Duration; -import java.util.Map; -import java.util.function.BooleanSupplier; - -public class TestHelper { - - public static void setFieldInConfig(Object target, String fieldName, Object value) { - try { - Field field = target.getClass().getDeclaredField(fieldName); - field.setAccessible(true); - field.set(target, value); - } catch (Throwable e) { - e.printStackTrace(); - } - } - - public static void assertWithTimeout(BooleanSupplier predicate, Duration timeout) { - Duration sleepTime = Duration.ofMillis(10); - long count = timeout.toMillis() / sleepTime.toMillis(); - while (count-- > 0 && !predicate.getAsBoolean()) { - try { - Thread.sleep(sleepTime.toMillis()); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - } - assertTrue(predicate.getAsBoolean()); - } - - public static void setEnvVar(String envName, String envValue) { - try { - Class classOfMap = System.getenv().getClass(); - Field field = classOfMap.getDeclaredField("m"); - field.setAccessible(true); - if (envValue == null) { - ((Map) field.get(System.getenv())).remove(envName); - } else { - ((Map) field.get(System.getenv())).put(envName, envValue); - } - } catch (Exception ex) { - ex.printStackTrace(); - } - } -} diff --git a/dd-java-agent/agent-debugger/src/test/java/utils/TestClassFileHelper.java b/dd-java-agent/agent-debugger/src/test/java/utils/TestClassFileHelper.java new file mode 100644 index 00000000000..832ab0aef85 --- /dev/null +++ b/dd-java-agent/agent-debugger/src/test/java/utils/TestClassFileHelper.java @@ -0,0 +1,25 @@ +package utils; + +import static datadog.trace.util.Strings.getResourceName; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; + +public class TestClassFileHelper { + public static byte[] getClassFileBytes(Class clazz) { + URL resource = clazz.getResource("/" + getResourceName(clazz.getTypeName())); + byte[] buffer = new byte[4096]; + ByteArrayOutputStream os = new ByteArrayOutputStream(); + try (InputStream is = resource.openStream()) { + int readBytes; + while ((readBytes = is.read(buffer)) != -1) { + os.write(buffer, 0, readBytes); + } + } catch (IOException e) { + e.printStackTrace(); + } + return os.toByteArray(); + } +} diff --git a/dd-java-agent/agent-debugger/src/test/java/utils/TestHelper.java b/dd-java-agent/agent-debugger/src/test/java/utils/TestHelper.java index 5d89e6cf472..18e01f43ee2 100644 --- a/dd-java-agent/agent-debugger/src/test/java/utils/TestHelper.java +++ b/dd-java-agent/agent-debugger/src/test/java/utils/TestHelper.java @@ -1,10 +1,16 @@ package utils; +import static org.junit.jupiter.api.Assertions.assertTrue; + import java.io.IOException; +import java.lang.reflect.Field; import java.net.URISyntaxException; import java.nio.file.Files; import java.nio.file.Paths; +import java.time.Duration; import java.util.List; +import java.util.Map; +import java.util.function.BooleanSupplier; public class TestHelper { public static String getFixtureContent(String fixture) throws IOException, URISyntaxException { @@ -15,4 +21,42 @@ public static List getFixtureLines(String fixture) throws IOException, URISyntaxException { return Files.readAllLines(Paths.get(TestHelper.class.getResource(fixture).toURI())); } + + public static void setFieldInConfig(Object target, String fieldName, Object value) { + try { + Field field = target.getClass().getDeclaredField(fieldName); + field.setAccessible(true); + field.set(target, value); + } catch (Throwable e) { + e.printStackTrace(); + } + } + + public static void assertWithTimeout(BooleanSupplier predicate, Duration timeout) { + Duration sleepTime = Duration.ofMillis(10); + long count = timeout.toMillis() / sleepTime.toMillis(); + while (count-- > 0 && !predicate.getAsBoolean()) { + try { + Thread.sleep(sleepTime.toMillis()); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + assertTrue(predicate.getAsBoolean()); + } + + public static void setEnvVar(String envName, String envValue) { + try { + Class classOfMap = System.getenv().getClass(); + Field field = classOfMap.getDeclaredField("m"); + field.setAccessible(true); + if (envValue == null) { + ((Map) field.get(System.getenv())).remove(envName); + } else { + ((Map) field.get(System.getenv())).put(envName, envValue); + } + } catch (Exception ex) { + ex.printStackTrace(); + } + } } diff --git a/dd-java-agent/agent-debugger/src/test/resources/com/datadog/debugger/classfiles/CommandLine.class b/dd-java-agent/agent-debugger/src/test/resources/com/datadog/debugger/classfiles/CommandLine.class new file mode 100644 index 0000000000000000000000000000000000000000..d88a1a3df163bdaf0d160010779194cb738e6e7a GIT binary patch literal 80036 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

-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 B++zR$ literal 0 HcmV?d00001 diff --git a/dd-java-agent/agent-debugger/src/test/resources/com/datadog/debugger/classfiles/JDK23.java b/dd-java-agent/agent-debugger/src/test/resources/com/datadog/debugger/classfiles/JDK23.java new file mode 100644 index 00000000000..ed9e9cda38c --- /dev/null +++ b/dd-java-agent/agent-debugger/src/test/resources/com/datadog/debugger/classfiles/JDK23.java @@ -0,0 +1,25 @@ +import java.util.Arrays; + +public class JDK23 implements Runnable { + private static final String JDK23 = "JDK23"; + private static final int INT_CST = 42; + private static final long LONG_CST = 100_000_000_000L; + private static final double DOUBLE_CST = 3.14; + private static final float FLOAT_CST = 2.68F; + + public static void main(String[] args) { + try { + System.out.println("Hello, JDK8!"); + Runnable runnable = new JDK8(); + runnable.run(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + public void run() { + System.out.printf("running %n"); + Arrays.asList("1", "2").stream().forEach(System.out::println); + } +} diff --git a/dd-java-agent/agent-debugger/src/test/resources/com/datadog/debugger/classfiles/JDK8.class b/dd-java-agent/agent-debugger/src/test/resources/com/datadog/debugger/classfiles/JDK8.class new file mode 100644 index 0000000000000000000000000000000000000000..98c5d21bff4a0dfdc7a17ead9e698e975599f751 GIT binary patch literal 1856 zcma)6>sA|86#hYSb+cq8c5ruV60jX$p8bBnK+rS=Okr2<%d9D_?QF?)3~M_l(37{VrYkLXU79UDjsXE>d9C~`Un&cT%L` z+Wod}B}(1k(*9o%Q0I$J<_ZgK%Y1AmG4%4$-#-rvBo+(B*<+Z+$jp?dj7=Ms;ocJn zk58<#uDo5-1yTjW($`w`P2DNWO_Q2PT^g3a!1&X%C3}HAC0ADWR%OHYCox2HT8vOj zcFU>ii-w1i@Y=rS^{inW6AB(`c!b9S+LCUX_SF&3KB}Okp^PUQKE;GUUx%ZGpQ?Jp zHEc`6x@S_E!Xj%UW6YH9_!T#I^{T6317COP1CGh!b^dNBsA%{GPZfNt;X8b<;Te9Q z|D0{RP1li)Ro&gOYt2*)GL6kt6p^%7RTVV_x`r)mbA+9&k6BE>)~QlT2TfP6lMTD& z3iJo;8Fuy|r|q&HUDi4CpvP`C$KLRqO!n44em?Cf-^1s=?8qu9j`^A`f$4KXP7g2O zC^zwjih>qeu3=_p9Y-EC2`!riqscDDy0)Mj$dB;c*j2C3&54Exq?HW|TpDlZ^^Jkn z`vL+s;@i5LH)WGK`;Hy`Z^T#TRP4a`4=2Y(a1~>+>TQX@tu_PQv>tctXWnXARd1iN z-Z$5(>kg|P>{Q)V80WENI}5V9BQVm2egnwFx`JH|d$0wrbQZ+0_U%1ATafk5n&fiH zEm?JK=RhD????)MWD^D3-fK1ZWh`5k?)Z)C3p8KH#tTaw{ z4{Qhu|24`zNTZkiT%a|@%F?uDaE(?4p^AcRgu#3$+Zos4$-o^iqZ)pVy$&d0gI=~93~p5 Rv#9%&HOfo$S;h(;{0k{c$rS(q literal 0 HcmV?d00001 diff --git a/dd-java-agent/agent-debugger/src/test/resources/com/datadog/debugger/classfiles/JDK8.java b/dd-java-agent/agent-debugger/src/test/resources/com/datadog/debugger/classfiles/JDK8.java new file mode 100644 index 00000000000..fb146ed5747 --- /dev/null +++ b/dd-java-agent/agent-debugger/src/test/resources/com/datadog/debugger/classfiles/JDK8.java @@ -0,0 +1,25 @@ +import java.util.Arrays; + +public class JDK8 implements Runnable { + private static final String JDK8 = "JDK8"; + private static final int INT_CST = 42; + private static final long LONG_CST = 100_000_000_000L; + private static final double DOUBLE_CST = 3.14; + private static final float FLOAT_CST = 2.68F; + + public static void main(String[] args) { + try { + System.out.println("Hello, JDK8!"); + Runnable runnable = new JDK8(); + runnable.run(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + public void run() { + System.out.printf("running %n"); + Arrays.asList("1", "2").stream().forEach(System.out::println); + } +}