diff --git a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/symbol/SymDBEnablement.java b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/symbol/SymDBEnablement.java index e974e8a4078..2f044d2c69f 100644 --- a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/symbol/SymDBEnablement.java +++ b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/symbol/SymDBEnablement.java @@ -143,7 +143,8 @@ private void extractSymbolForLoadedClasses(SymDBReport symDBReport) { try { jarPath = JarScanner.extractJarPath(clazz, symDBReport); } catch (URISyntaxException e) { - throw new RuntimeException(e); + LOGGER.debug("Failed to extract jar path for class {}", clazz.getTypeName(), e); + continue; } if (jarPath == null) { continue; @@ -152,7 +153,11 @@ private void extractSymbolForLoadedClasses(SymDBReport symDBReport) { symDBReport.addMissingJar(jarPath.toString()); continue; } - symbolAggregator.scanJar(symDBReport, jarPath, baos, buffer); + try { + symbolAggregator.scanJar(symDBReport, jarPath, baos, buffer); + } catch (Exception ex) { + LOGGER.debug("Failed to scan jar {}", jarPath, ex); + } } } } diff --git a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/symbol/SymbolAggregator.java b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/symbol/SymbolAggregator.java index 554845d1d90..844c53934a4 100644 --- a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/symbol/SymbolAggregator.java +++ b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/symbol/SymbolAggregator.java @@ -158,7 +158,11 @@ void scanQueuedJars(SymbolAggregator symbolAggregator) { while (!jarsToScanQueue.isEmpty()) { String jarPath = jarsToScanQueue.poll(); LOGGER.debug("Scanning queued jar: {}", jarPath); - scanJar(SymDBReport.NO_OP, Paths.get(jarPath), baos, buffer); + try { + scanJar(SymDBReport.NO_OP, Paths.get(jarPath), baos, buffer); + } catch (Exception ex) { + LOGGER.debug("Failed to scan jar {}", jarPath, ex); + } } } diff --git a/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/symbol/SymDBEnablementTest.java b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/symbol/SymDBEnablementTest.java index 22a46804339..a807c571d68 100644 --- a/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/symbol/SymDBEnablementTest.java +++ b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/symbol/SymDBEnablementTest.java @@ -25,9 +25,11 @@ import java.io.IOException; import java.io.InputStream; import java.lang.instrument.Instrumentation; +import java.net.MalformedURLException; import java.net.URISyntaxException; import java.net.URL; import java.net.URLClassLoader; +import java.nio.file.Path; import java.util.Collections; import java.util.jar.JarEntry; import java.util.jar.JarFile; @@ -111,11 +113,7 @@ public void noIncludesFilterOutDatadogClass() { @Test public void parseLoadedClass() throws ClassNotFoundException, IOException { - final String CLASS_NAME = "com.datadog.debugger.symbol.SymbolExtraction01"; - URL jarFileUrl = getClass().getResource("/debugger-symbol.jar"); - URL jarUrl = new URL("jar:file:" + jarFileUrl.getFile() + "!/"); - URLClassLoader urlClassLoader = new URLClassLoader(new URL[] {jarUrl}, null); - Class testClass = urlClassLoader.loadClass(CLASS_NAME); + Class testClass = loadSymbolClassFromJar(); when(instr.getAllLoadedClasses()).thenReturn(new Class[] {testClass}); when(config.getThirdPartyIncludes()) .thenReturn( @@ -130,7 +128,11 @@ public void parseLoadedClass() throws ClassNotFoundException, IOException { verify(instr).addTransformer(any(SymbolExtractionTransformer.class)); ArgumentCaptor captor = ArgumentCaptor.forClass(String.class); verify(symbolAggregator, times(2)) - .parseClass(any(), captor.capture(), any(), eq(jarFileUrl.getFile())); + .parseClass( + any(), + captor.capture(), + any(), + eq(getClass().getResource("/debugger-symbol.jar").getFile())); assertEquals( "com/datadog/debugger/symbol/SymbolExtraction01.class", captor.getAllValues().get(0)); assertEquals( @@ -138,6 +140,38 @@ public void parseLoadedClass() throws ClassNotFoundException, IOException { captor.getAllValues().get(1)); } + @Test + public void processCorruptedJar() throws ClassNotFoundException, MalformedURLException { + Class testClass = loadSymbolClassFromJar(); + when(instr.getAllLoadedClasses()) + .thenReturn(new Class[] {SymDBEnablementTest.class, testClass}); + ClassNameFiltering classNameFiltering = ClassNameFiltering.allowAll(); + SymbolAggregator symbolAggregatorMock = mock(SymbolAggregator.class); + doAnswer( + invocation -> { + Path arg = invocation.getArgument(1, Path.class); + if (arg.toString().endsWith("/debugger-symbol.jar")) { + return null; + } + throw new IOException("Corrupted jar"); + }) + .when(symbolAggregatorMock) + .scanJar(any(), any(), any(), any()); + SymDBEnablement symDBEnablement = + new SymDBEnablement(instr, config, symbolAggregatorMock, classNameFiltering); + symDBEnablement.startSymbolExtraction(); + verify(symbolAggregatorMock, times(2)).scanJar(any(), any(), any(), any()); + } + + private Class loadSymbolClassFromJar() throws MalformedURLException, ClassNotFoundException { + final String CLASS_NAME = "com.datadog.debugger.symbol.SymbolExtraction01"; + URL jarFileUrl = getClass().getResource("/debugger-symbol.jar"); + URL jarUrl = new URL("jar:file:" + jarFileUrl.getFile() + "!/"); + URLClassLoader urlClassLoader = new URLClassLoader(new URL[] {jarUrl}, null); + Class testClass = urlClassLoader.loadClass(CLASS_NAME); + return testClass; + } + @Test public void parseLoadedClassFromDirectory() throws ClassNotFoundException, IOException, URISyntaxException { diff --git a/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/symbol/SymbolAggregatorTest.java b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/symbol/SymbolAggregatorTest.java index 5ac2455b7d9..4fb5ee83a4b 100644 --- a/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/symbol/SymbolAggregatorTest.java +++ b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/symbol/SymbolAggregatorTest.java @@ -46,6 +46,36 @@ void testScanQueuedJars() { captor.getAllValues().get(2)); } + @Test + void testScanQueuedCorruptedJars() { + SymbolSink symbolSink = mock(SymbolSink.class); + SymbolAggregator symbolAggregator = + spy(new SymbolAggregator(ClassNameFiltering.allowAll(), emptyList(), symbolSink, 1)); + // add first a corrupted jar + URL corruptedUrl = getClass().getResource("/com/datadog/debugger/classfiles/CommandLine.class"); + CodeSource corruptedCodeSource = + new CodeSource(corruptedUrl, (java.security.cert.Certificate[]) null); + ProtectionDomain corruptedProtectionDomain = new ProtectionDomain(corruptedCodeSource, null); + symbolAggregator.parseClass(null, null, corruptedProtectionDomain); + // add second a clean jar + URL jarFileUrl = getClass().getResource("/debugger-symbol.jar"); + CodeSource codeSource = new CodeSource(jarFileUrl, (java.security.cert.Certificate[]) null); + ProtectionDomain protectionDomain = new ProtectionDomain(codeSource, null); + symbolAggregator.parseClass(null, null, protectionDomain); + symbolAggregator.scanQueuedJars(null); + // clean jar should have been processed + ArgumentCaptor captor = ArgumentCaptor.forClass(String.class); + verify(symbolAggregator, atLeastOnce()) + .parseClass(any(), captor.capture(), any(), eq(jarFileUrl.getFile())); + // captor.getAllValues().get(0) is the first argument of the first invocation of parseClass with + // null + assertEquals( + "com/datadog/debugger/symbol/SymbolExtraction01.class", captor.getAllValues().get(1)); + assertEquals( + "BOOT-INF/classes/org/springframework/samples/petclinic/vet/VetController.class", + captor.getAllValues().get(2)); + } + @Test @DisabledIf( value = "datadog.environment.JavaVirtualMachine#isJ9",