From 4b445c95dd1152b9d7272fd03746e4a19003e277 Mon Sep 17 00:00:00 2001 From: Tyler Finethy Date: Mon, 23 Feb 2026 18:17:25 +0100 Subject: [PATCH] Fix Windows path parsing in JarScanner Use Paths.get(URI) instead of Paths.get(String) to correctly handle Windows drive letters in CodeSource locations (e.g. file:/C:/...). [DYNIS-50] --- .../datadog/debugger/symbol/JarScanner.java | 10 ++++++- .../debugger/symbol/JarScannerTest.java | 27 +++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/symbol/JarScanner.java b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/symbol/JarScanner.java index bbddbd37a4e..d8a71fdbb61 100644 --- a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/symbol/JarScanner.java +++ b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/symbol/JarScanner.java @@ -1,5 +1,6 @@ package com.datadog.debugger.symbol; +import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.nio.file.Path; @@ -65,6 +66,13 @@ public static String trimPrefixes(String classFilePath) { private static Path getPathFromPrefixedFileName(String locationStr, String prefix, int endIdx) { String fileName = locationStr.substring(prefix.length(), endIdx); LOGGER.debug("jar filename={}", fileName); - return Paths.get(fileName); + try { + // Reconstruct a file URI and use Paths.get(URI) to correctly handle + // platform-specific paths, including Windows drive letters (e.g. /C:/...) + return Paths.get(new URI("file:" + fileName)); + } catch (URISyntaxException e) { + LOGGER.debug("Failed to parse as URI: {}, falling back to direct path", fileName, e); + return Paths.get(fileName); + } } } diff --git a/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/symbol/JarScannerTest.java b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/symbol/JarScannerTest.java index e9c5b8d90fe..a873fc4f962 100644 --- a/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/symbol/JarScannerTest.java +++ b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/symbol/JarScannerTest.java @@ -8,10 +8,13 @@ import java.net.URISyntaxException; import java.net.URL; import java.net.URLClassLoader; +import java.nio.file.Path; import java.security.CodeSource; import java.security.ProtectionDomain; import java.security.cert.Certificate; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledOnOs; +import org.junit.jupiter.api.condition.OS; class JarScannerTest { @Test @@ -50,4 +53,28 @@ public void extractJarPathFromNestedJar() throws URISyntaxException { assertEquals( jarFileUrl.getFile(), JarScanner.extractJarPath(protectionDomain, null).toString()); } + + @Test + @EnabledOnOs(OS.WINDOWS) + public void extractJarPathFromFileOnWindows() throws URISyntaxException { + URL mockLocation = mock(URL.class); + when(mockLocation.toString()).thenReturn("file:/C:/apps/server/classes/"); + CodeSource codeSource = new CodeSource(mockLocation, (Certificate[]) null); + ProtectionDomain protectionDomain = new ProtectionDomain(codeSource, null); + Path result = JarScanner.extractJarPath(protectionDomain, SymDBReport.NO_OP); + assertNotNull(result); + assertTrue(result.toString().contains("server")); + } + + @Test + @EnabledOnOs(OS.WINDOWS) + public void extractJarPathFromJarOnWindows() throws URISyntaxException { + URL mockLocation = mock(URL.class); + when(mockLocation.toString()).thenReturn("jar:file:/C:/libs/app.jar!/com/example/"); + CodeSource codeSource = new CodeSource(mockLocation, (Certificate[]) null); + ProtectionDomain protectionDomain = new ProtectionDomain(codeSource, null); + Path result = JarScanner.extractJarPath(protectionDomain, SymDBReport.NO_OP); + assertNotNull(result); + assertTrue(result.toString().contains("app.jar")); + } }