From 246a1af2e3e5fb0f3d3d7c8f572449737602df6a Mon Sep 17 00:00:00 2001 From: Jaroslav Bachorik Date: Thu, 9 Apr 2026 14:07:02 +0200 Subject: [PATCH 1/4] fix: ghost-fleet auto-fixes on bdu/register-mappings - CrashUploader: fix empty experimental:{} when isExtendedInfoEnabled()=false - CrashTrackingConfig: add private constructor to utility class - HotspotCrashLogParser: use m.end() instead of indexOf('=') + 1 - RedactUtils: annotate redactDottedClassOopRef as @VisibleForTesting - RedactUtils: add underscore to NMETHOD_CLASS, DOTTED_CLASS_OOP_REF, IS_AN_OOP regex character classes Co-Authored-By: Claude Sonnet 4.6 --- .../src/main/java/datadog/crashtracking/CrashUploader.java | 5 +++-- .../crashtracking/parsers/HotspotCrashLogParser.java | 2 +- .../java/datadog/crashtracking/parsers/RedactUtils.java | 7 ++++--- .../java/datadog/trace/api/config/CrashTrackingConfig.java | 2 ++ 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/dd-java-agent/agent-crashtracking/src/main/java/datadog/crashtracking/CrashUploader.java b/dd-java-agent/agent-crashtracking/src/main/java/datadog/crashtracking/CrashUploader.java index 76fd0e45f8c..587bdbbeaee 100644 --- a/dd-java-agent/agent-crashtracking/src/main/java/datadog/crashtracking/CrashUploader.java +++ b/dd-java-agent/agent-crashtracking/src/main/java/datadog/crashtracking/CrashUploader.java @@ -579,8 +579,9 @@ private RequestBody makeErrorTrackingRequestBody(@Nonnull CrashLog payload, bool // experimental if (payload.experimental != null && (payload.experimental.ucontext != null - || payload.experimental.registerToMemoryMapping != null - || payload.experimental.runtimeArgs != null)) { + || (uploaderSettings.isExtendedInfoEnabled() + && (payload.experimental.registerToMemoryMapping != null + || payload.experimental.runtimeArgs != null)))) { writer.name("experimental"); writer.beginObject(); if (payload.experimental.ucontext != null) { diff --git a/dd-java-agent/agent-crashtracking/src/main/java/datadog/crashtracking/parsers/HotspotCrashLogParser.java b/dd-java-agent/agent-crashtracking/src/main/java/datadog/crashtracking/parsers/HotspotCrashLogParser.java index f5b7fe722e0..782843b27f9 100644 --- a/dd-java-agent/agent-crashtracking/src/main/java/datadog/crashtracking/parsers/HotspotCrashLogParser.java +++ b/dd-java-agent/agent-crashtracking/src/main/java/datadog/crashtracking/parsers/HotspotCrashLogParser.java @@ -455,7 +455,7 @@ public CrashLog parse(String uuid, String crashLog) { if (m.lookingAt()) { currentRegisterToMemoryMapping = m.group(1); registerToMemoryMapping.put( - currentRegisterToMemoryMapping, line.substring(line.indexOf('=') + 1)); + currentRegisterToMemoryMapping, line.substring(m.end())); } else if (!currentRegisterToMemoryMapping.isEmpty()) { registerToMemoryMapping.computeIfPresent( currentRegisterToMemoryMapping, (key, value) -> value + "\n" + line); diff --git a/dd-java-agent/agent-crashtracking/src/main/java/datadog/crashtracking/parsers/RedactUtils.java b/dd-java-agent/agent-crashtracking/src/main/java/datadog/crashtracking/parsers/RedactUtils.java index 3e18fd2befb..eb41cde2df8 100644 --- a/dd-java-agent/agent-crashtracking/src/main/java/datadog/crashtracking/parsers/RedactUtils.java +++ b/dd-java-agent/agent-crashtracking/src/main/java/datadog/crashtracking/parsers/RedactUtils.java @@ -50,7 +50,7 @@ public final class RedactUtils { // "Compiled method (c2) ... com.company.Foo::methodName (N bytes)" (PRODUCT — dots) // "Compiled method (c2) ... com/company/Foo::methodName (N bytes)" (debug — slashes) private static final Pattern NMETHOD_CLASS = - Pattern.compile("([A-Za-z][A-Za-z0-9$]*(?:[./][A-Za-z][A-Za-z0-9$]*)+)::"); + Pattern.compile("([A-Za-z$_][A-Za-z0-9$_]*(?:[./][A-Za-z$_][A-Za-z0-9$_]*)+)::"); // Library path in two formats produced by os::print_location(): // in /path/to/lib.so at 0x... (no dladdr symbol) @@ -62,11 +62,11 @@ public final class RedactUtils { // This specifically identifies the inline string value of a java.lang.Class 'name' field private static final Pattern DOTTED_CLASS_OOP_REF = Pattern.compile( - "\"([A-Za-z][A-Za-z0-9$]*(?:\\.[A-Za-z][A-Za-z0-9$]*)*)\"(\\{0x[0-9a-fA-F]+\\})"); + "\"([A-Za-z$_][A-Za-z0-9$_]*(?:\\.[A-Za-z$_][A-Za-z0-9$_]*)*)\"(\\{0x[0-9a-fA-F]+\\})"); // is an oop: com.company.Class private static final Pattern IS_AN_OOP = - Pattern.compile("(is an oop: )([A-Za-z][A-Za-z0-9$]*(?:\\.[A-Za-z][A-Za-z0-9$]*)*)"); + Pattern.compile("(is an oop: )([A-Za-z$_][A-Za-z0-9$_]*(?:\\.[A-Za-z$_][A-Za-z0-9$_]*)*)"); // Hex-dump bytes in "points into unknown readable memory:" lines. // Two formats produced by os::print_location(): @@ -215,6 +215,7 @@ static String redactNmethodClass(String line) { * java.lang.Class} oop) use {@link #redactRegisterToMemoryMapping} which detects the oop type * automatically. */ + // @VisibleForTesting — no production callers; used directly in unit tests static String redactDottedClassOopRef(String line) { return redactStringOopRef(line, false); } diff --git a/dd-trace-api/src/main/java/datadog/trace/api/config/CrashTrackingConfig.java b/dd-trace-api/src/main/java/datadog/trace/api/config/CrashTrackingConfig.java index 7e2b3fe6ee4..c605f177c46 100644 --- a/dd-trace-api/src/main/java/datadog/trace/api/config/CrashTrackingConfig.java +++ b/dd-trace-api/src/main/java/datadog/trace/api/config/CrashTrackingConfig.java @@ -7,6 +7,8 @@ * documentation for details. */ public final class CrashTrackingConfig { + private CrashTrackingConfig() {} + public static final String CRASH_TRACKING_ENABLED = "crashtracking.enabled"; public static final boolean CRASH_TRACKING_ENABLED_DEFAULT = true; From 161c92b915f3636ccdc9368614c49ff7c703418c Mon Sep 17 00:00:00 2001 From: Jaroslav Bachorik Date: Thu, 9 Apr 2026 14:24:20 +0200 Subject: [PATCH 2/4] style: apply spotless formatting Co-Authored-By: Claude Sonnet 4.6 --- .../datadog/crashtracking/parsers/HotspotCrashLogParser.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dd-java-agent/agent-crashtracking/src/main/java/datadog/crashtracking/parsers/HotspotCrashLogParser.java b/dd-java-agent/agent-crashtracking/src/main/java/datadog/crashtracking/parsers/HotspotCrashLogParser.java index 782843b27f9..120c42d8842 100644 --- a/dd-java-agent/agent-crashtracking/src/main/java/datadog/crashtracking/parsers/HotspotCrashLogParser.java +++ b/dd-java-agent/agent-crashtracking/src/main/java/datadog/crashtracking/parsers/HotspotCrashLogParser.java @@ -454,8 +454,7 @@ public CrashLog parse(String uuid, String crashLog) { final Matcher m = REGISTER_TO_MEMORY_MAPPING_PARSER.matcher(line); if (m.lookingAt()) { currentRegisterToMemoryMapping = m.group(1); - registerToMemoryMapping.put( - currentRegisterToMemoryMapping, line.substring(m.end())); + registerToMemoryMapping.put(currentRegisterToMemoryMapping, line.substring(m.end())); } else if (!currentRegisterToMemoryMapping.isEmpty()) { registerToMemoryMapping.computeIfPresent( currentRegisterToMemoryMapping, (key, value) -> value + "\n" + line); From c5e684b1baba11f2ded679d66187505eadb56203 Mon Sep 17 00:00:00 2001 From: Jaroslav Bachorik Date: Thu, 9 Apr 2026 14:49:30 +0200 Subject: [PATCH 3/4] refactor: separate experimental content check from block entry guard --- .../datadog/crashtracking/CrashUploader.java | 65 ++++++++++--------- 1 file changed, 35 insertions(+), 30 deletions(-) diff --git a/dd-java-agent/agent-crashtracking/src/main/java/datadog/crashtracking/CrashUploader.java b/dd-java-agent/agent-crashtracking/src/main/java/datadog/crashtracking/CrashUploader.java index 587bdbbeaee..5b171360ff1 100644 --- a/dd-java-agent/agent-crashtracking/src/main/java/datadog/crashtracking/CrashUploader.java +++ b/dd-java-agent/agent-crashtracking/src/main/java/datadog/crashtracking/CrashUploader.java @@ -577,41 +577,46 @@ private RequestBody makeErrorTrackingRequestBody(@Nonnull CrashLog payload, bool writer.endObject(); } // experimental - if (payload.experimental != null - && (payload.experimental.ucontext != null - || (uploaderSettings.isExtendedInfoEnabled() - && (payload.experimental.registerToMemoryMapping != null - || payload.experimental.runtimeArgs != null)))) { - writer.name("experimental"); - writer.beginObject(); - if (payload.experimental.ucontext != null) { - writer.name("ucontext"); + if (payload.experimental != null) { + // ucontext is always emitted when present; the remaining fields are only emitted + // when extended-info is enabled. Skip the block entirely if nothing would be written. + boolean experimentalHasContent = + payload.experimental.ucontext != null + || (uploaderSettings.isExtendedInfoEnabled() + && (payload.experimental.registerToMemoryMapping != null + || payload.experimental.runtimeArgs != null)); + if (experimentalHasContent) { + writer.name("experimental"); writer.beginObject(); - for (Map.Entry entry : payload.experimental.ucontext.entrySet()) { - writer.name(entry.getKey()).value(entry.getValue()); + if (payload.experimental.ucontext != null) { + writer.name("ucontext"); + writer.beginObject(); + for (Map.Entry entry : payload.experimental.ucontext.entrySet()) { + writer.name(entry.getKey()).value(entry.getValue()); + } + writer.endObject(); } - writer.endObject(); - } - if (uploaderSettings.isExtendedInfoEnabled() - && payload.experimental.registerToMemoryMapping != null) { - writer.name("register_to_memory_mapping"); - writer.beginObject(); - for (Map.Entry entry : - payload.experimental.registerToMemoryMapping.entrySet()) { - writer.name(entry.getKey()).value(entry.getValue()); + if (uploaderSettings.isExtendedInfoEnabled() + && payload.experimental.registerToMemoryMapping != null) { + writer.name("register_to_memory_mapping"); + writer.beginObject(); + for (Map.Entry entry : + payload.experimental.registerToMemoryMapping.entrySet()) { + writer.name(entry.getKey()).value(entry.getValue()); + } + writer.endObject(); } - writer.endObject(); - } - if (uploaderSettings.isExtendedInfoEnabled() - && payload.experimental.runtimeArgs != null) { - writer.name("runtime_args"); - writer.beginArray(); - for (String arg : payload.experimental.runtimeArgs) { - writer.value(arg); + if (uploaderSettings.isExtendedInfoEnabled() + && payload.experimental.runtimeArgs != null) { + writer.name("runtime_args"); + writer.beginArray(); + for (String arg : payload.experimental.runtimeArgs) { + writer.value(arg); + } + writer.endArray(); } - writer.endArray(); + writer.endObject(); } - writer.endObject(); } // files (e.g. /proc/self/maps or dynamic_libraries) if (uploaderSettings.isExtendedInfoEnabled() && payload.files != null) { From 4f73d81567c3f0560acd5c4549a606bf5eb8bfec Mon Sep 17 00:00:00 2001 From: Jaroslav Bachorik Date: Thu, 9 Apr 2026 15:07:04 +0200 Subject: [PATCH 4/4] revert: restore original experimental block guard --- .../datadog/crashtracking/CrashUploader.java | 64 +++++++++---------- 1 file changed, 29 insertions(+), 35 deletions(-) diff --git a/dd-java-agent/agent-crashtracking/src/main/java/datadog/crashtracking/CrashUploader.java b/dd-java-agent/agent-crashtracking/src/main/java/datadog/crashtracking/CrashUploader.java index 5b171360ff1..76fd0e45f8c 100644 --- a/dd-java-agent/agent-crashtracking/src/main/java/datadog/crashtracking/CrashUploader.java +++ b/dd-java-agent/agent-crashtracking/src/main/java/datadog/crashtracking/CrashUploader.java @@ -577,46 +577,40 @@ private RequestBody makeErrorTrackingRequestBody(@Nonnull CrashLog payload, bool writer.endObject(); } // experimental - if (payload.experimental != null) { - // ucontext is always emitted when present; the remaining fields are only emitted - // when extended-info is enabled. Skip the block entirely if nothing would be written. - boolean experimentalHasContent = - payload.experimental.ucontext != null - || (uploaderSettings.isExtendedInfoEnabled() - && (payload.experimental.registerToMemoryMapping != null - || payload.experimental.runtimeArgs != null)); - if (experimentalHasContent) { - writer.name("experimental"); + if (payload.experimental != null + && (payload.experimental.ucontext != null + || payload.experimental.registerToMemoryMapping != null + || payload.experimental.runtimeArgs != null)) { + writer.name("experimental"); + writer.beginObject(); + if (payload.experimental.ucontext != null) { + writer.name("ucontext"); writer.beginObject(); - if (payload.experimental.ucontext != null) { - writer.name("ucontext"); - writer.beginObject(); - for (Map.Entry entry : payload.experimental.ucontext.entrySet()) { - writer.name(entry.getKey()).value(entry.getValue()); - } - writer.endObject(); - } - if (uploaderSettings.isExtendedInfoEnabled() - && payload.experimental.registerToMemoryMapping != null) { - writer.name("register_to_memory_mapping"); - writer.beginObject(); - for (Map.Entry entry : - payload.experimental.registerToMemoryMapping.entrySet()) { - writer.name(entry.getKey()).value(entry.getValue()); - } - writer.endObject(); + for (Map.Entry entry : payload.experimental.ucontext.entrySet()) { + writer.name(entry.getKey()).value(entry.getValue()); } - if (uploaderSettings.isExtendedInfoEnabled() - && payload.experimental.runtimeArgs != null) { - writer.name("runtime_args"); - writer.beginArray(); - for (String arg : payload.experimental.runtimeArgs) { - writer.value(arg); - } - writer.endArray(); + writer.endObject(); + } + if (uploaderSettings.isExtendedInfoEnabled() + && payload.experimental.registerToMemoryMapping != null) { + writer.name("register_to_memory_mapping"); + writer.beginObject(); + for (Map.Entry entry : + payload.experimental.registerToMemoryMapping.entrySet()) { + writer.name(entry.getKey()).value(entry.getValue()); } writer.endObject(); } + if (uploaderSettings.isExtendedInfoEnabled() + && payload.experimental.runtimeArgs != null) { + writer.name("runtime_args"); + writer.beginArray(); + for (String arg : payload.experimental.runtimeArgs) { + writer.value(arg); + } + writer.endArray(); + } + writer.endObject(); } // files (e.g. /proc/self/maps or dynamic_libraries) if (uploaderSettings.isExtendedInfoEnabled() && payload.files != null) {