Skip to content

Commit 61998ec

Browse files
committed
chore(crashtracking): Collapse adjacent redacted path or package segments
1 parent e3ba878 commit 61998ec

3 files changed

Lines changed: 85 additions & 96 deletions

File tree

dd-java-agent/agent-crashtracking/src/main/java/datadog/crashtracking/parsers/RedactUtils.java

Lines changed: 27 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
public final class RedactUtils {
1313

1414
static final String REDACTED = "redacted";
15+
static final String REDACTED_CLASS = "Redacted";
1516
private static final String REDACTED_STRING = "REDACTED";
1617

1718
private static final String[] KNOWN_PACKAGES_PREFIXES = {
@@ -25,6 +26,9 @@ public final class RedactUtils {
2526
// Oracle/Sun vendor packages
2627
"com/sun/",
2728
"com/oracle/",
29+
// Datadog top-level and internal shorthand
30+
"datadog/",
31+
"com/dd/",
2832
};
2933

3034
// " - string: "value"" in String oop dumps
@@ -112,8 +116,9 @@ private static String redactLine(String line, boolean isClassOop) {
112116
/**
113117
* Redacts {@code "value"\{0x...\}} OOP references in oop dump field lines. When {@code
114118
* isClassOop} is true (inside a {@code java.lang.Class} oop dump) the value is treated as a class
115-
* name and its package is redacted. Otherwise — any other oop type — the value is always fully
116-
* redacted to {@code "REDACTED"} since it may be arbitrary application data.
119+
* name and redacted to {@code "redacted.Redacted"} unless it belongs to a known package.
120+
* Otherwise — any other oop type — the value is always fully redacted to {@code "REDACTED"} since
121+
* it may be arbitrary application data.
117122
*/
118123
private static String redactStringOopRef(String line, boolean isClassOop) {
119124
return replaceAll(
@@ -202,8 +207,8 @@ static String redactReadableMemoryHexDump(String line) {
202207
}
203208

204209
/**
205-
* Redacts the package of a slash-separated JVM class name, unless it belongs to a known package.
206-
* <code>com/company/SomeType</code> to <code>redacted/redacted/SomeType</code>; <code>
210+
* Redacts a slash-separated JVM class name, unless it belongs to a known package. Unknown classes
211+
* are fully redacted: <code>com/company/SomeType</code> to <code>redacted/Redacted</code>; <code>
207212
* java/lang/String</code> unchanged.
208213
*/
209214
static String redactJvmClassName(String className) {
@@ -214,9 +219,9 @@ static String redactJvmClassName(String className) {
214219
}
215220

216221
/**
217-
* Redacts the package of a dot-separated class name, unless it belongs to a known package. <code>
218-
* com.company.SomeType</code> to <code>redacted.redacted.SomeType</code>; <code>java.lang.String
219-
* </code> unchanged.
222+
* Redacts a dot-separated class name, unless it belongs to a known package. Unknown classes are
223+
* fully redacted: <code>com.company.SomeType</code> to <code>redacted.Redacted</code>; <code>
224+
* java.lang.String</code> unchanged.
220225
*/
221226
static String redactDottedClassName(String className) {
222227
if (isKnownJvmPackage(className.replace('.', '/'))) {
@@ -227,38 +232,22 @@ static String redactDottedClassName(String className) {
227232

228233
private static String redactClassName(char sep, String className) {
229234
int lastSep = className.lastIndexOf(sep);
230-
if (lastSep < 0) return className;
231-
StringBuilder sb = new StringBuilder();
232-
int pos = 0;
233-
while (pos <= lastSep) {
234-
int next = className.indexOf(sep, pos);
235-
if (sb.length() > 0) sb.append(sep);
236-
sb.append(REDACTED);
237-
pos = next + 1;
238-
}
239-
return sb.append(sep).append(className, lastSep + 1, className.length()).toString();
235+
if (lastSep < 0) return className; // no package — nothing to redact
236+
return REDACTED + sep + REDACTED_CLASS;
240237
}
241238

242239
/**
243-
* Redacts all path segments except the parent directory and filename. <code>/path/to/dir/lib.so
244-
* </code> to <code>/redacted/redacted/dir/lib.so</code>
240+
* Redacts all but the parent directory and filename from a library path, collapsing all
241+
* intermediate segments to a single {@code redacted}. <code>/path/to/dir/lib.so</code> to <code>
242+
* /redacted/dir/lib.so</code>
245243
*/
246-
@SuppressForbidden // split on single-character uses a fast path without regex
247244
static String redactPath(String path) {
248-
String[] parts = path.split("/", -1);
249-
// parts[0] is always "" (before the leading slash)
250-
if (parts.length <= 3) {
251-
return path; // /dir/file or shorter: nothing to redact
252-
}
253-
StringBuilder sb = new StringBuilder();
254-
for (int i = 1; i < parts.length - 2; i++) {
255-
sb.append('/').append(REDACTED);
256-
}
257-
return sb.append('/')
258-
.append(parts[parts.length - 2])
259-
.append('/')
260-
.append(parts[parts.length - 1])
261-
.toString();
245+
int last = path.lastIndexOf('/');
246+
if (last <= 0) return path; // /file or empty — nothing to redact
247+
int secondLast = path.lastIndexOf('/', last - 1);
248+
if (secondLast <= 0) return path; // /dir/file — nothing to redact
249+
// Collapse everything before the second-last slash to a single /redacted
250+
return "/" + REDACTED + path.substring(secondLast);
262251
}
263252

264253
private static boolean isKnownJvmPackage(String slashClassName) {
@@ -267,7 +256,10 @@ private static boolean isKnownJvmPackage(String slashClassName) {
267256
return true;
268257
}
269258
}
270-
return slashClassName.contains("datadog") || slashClassName.startsWith("com/dd/");
259+
// Match *.datadog* — packages whose second segment starts with "datadog"
260+
// e.g. com/datadog/..., org/datadog/..., com/datadoghq/...
261+
int slash = slashClassName.indexOf('/');
262+
return slash > 0 && slashClassName.startsWith("datadog", slash + 1);
271263
}
272264

273265
private static String replaceAll(

dd-java-agent/agent-crashtracking/src/test/java/datadog/crashtracking/parsers/HotspotCrashLogParserTest.java

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -103,18 +103,15 @@ public void testRegisterToMemoryMappingMacosAarch64() throws Exception {
103103
.containsEntry("x2", "0x0 is null")
104104
.containsEntry("x28", "0x0000000100a153f0 is a thread");
105105

106-
// Library path (symbol+offset format) — path must be redacted, keeping only last 2 segments
107-
// /usr/lib/system/libsystem_pthread.dylib → 2 redacted ("usr","lib") + "system/lib..."
106+
// Library path (symbol+offset format) — intermediate segments collapsed to a single /redacted
108107
assertThat(mapping)
109108
.extractingByKey("x16", STRING)
110109
.isEqualTo(
111-
"0x0000000182d709d0: pthread_jit_write_protect_np+0 in /redacted/redacted/system/libsystem_pthread.dylib at 0x0000000182d69000");
112-
// /Users/USER/.local/share/mise/installs/java/25.0.2/lib/server/libjvm.dylib → 9 redacted +
113-
// "server/libjvm.dylib"
110+
"0x0000000182d709d0: pthread_jit_write_protect_np+0 in /redacted/system/libsystem_pthread.dylib at 0x0000000182d69000");
114111
assertThat(mapping)
115112
.extractingByKey("x21", STRING)
116113
.isEqualTo(
117-
"0x0000000106c1ccc0: _ZN19TemplateInterpreter13_active_tableE+0 in /redacted/redacted/redacted/redacted/redacted/redacted/redacted/redacted/redacted/server/libjvm.dylib at 0x0000000105efc000");
114+
"0x0000000106c1ccc0: _ZN19TemplateInterpreter13_active_tableE+0 in /redacted/server/libjvm.dylib at 0x0000000105efc000");
118115

119116
// macOS aarch64 uses address+pipe format — address kept, bytes redacted
120117
assertThat(mapping)
@@ -167,10 +164,10 @@ public void testRegisterToMemoryMapping() throws Exception {
167164
.containsEntry(
168165
"R11",
169166
"{method} {0x00007f3744198b70} 'resize' '()[Ljava/util/HashMap$Node;' in 'java/util/HashMap'")
170-
// unknown packages are redacted; known class names (last segment) are preserved
167+
// unknown packages are fully redacted to redacted/Redacted
171168
.containsEntry(
172169
"RSI",
173-
"{method} {0x00007f3639c2ff00} 'saveJob' '(Lredacted/redacted/redacted/redacted/REDACT_THIS;ILjava/lang/String;)V' in 'redacted/redacted/redacted/redacted/REDACT_THIS'");
170+
"{method} {0x00007f3639c2ff00} 'saveJob' '(Lredacted/Redacted;ILjava/lang/String;)V' in 'redacted/Redacted'");
174171
}
175172

176173
@Test

0 commit comments

Comments
 (0)