Skip to content

Commit 3ddb175

Browse files
committed
chore(crashtracking): Redact other things
1 parent 61998ec commit 3ddb175

File tree

2 files changed

+136
-11
lines changed

2 files changed

+136
-11
lines changed

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

Lines changed: 49 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,21 @@ public final class RedactUtils {
3737
// Type descriptors like Lcom/company/Type;
3838
private static final Pattern TYPE_DESCRIPTOR = Pattern.compile("L([A-Za-z$_][A-Za-z0-9$_/]*);");
3939

40-
// klass/interface references: - klass: 'com/company/Class'
41-
private static final Pattern KLASS_REF = Pattern.compile("((?:klass|interface): ')([^']+)(')");
40+
// klass references: - klass: 'com/company/Class'
41+
private static final Pattern KLASS_REF = Pattern.compile("(klass: ')([^']+)'");
4242

4343
// 'in 'class'' clause in {method} descriptor entries
44-
private static final Pattern METHOD_IN_CLASS = Pattern.compile("( in ')([^']+)(')");
44+
private static final Pattern METHOD_IN_CLASS = Pattern.compile("( in ')([^']+)'");
45+
46+
// Object-reference field values in oop dumps: a 'com/company/Class'{0x...}
47+
private static final Pattern OBJ_FIELD_REF =
48+
Pattern.compile("(a ')([A-Za-z$_][A-Za-z0-9$_/]*)'");
49+
50+
// Class name in nmethod compiled-method output (JDK 11+):
51+
// "Compiled method (c2) ... com.company.Foo::methodName (N bytes)" (PRODUCT — dots)
52+
// "Compiled method (c2) ... com/company/Foo::methodName (N bytes)" (debug — slashes)
53+
private static final Pattern NMETHOD_CLASS =
54+
Pattern.compile("([A-Za-z][A-Za-z0-9$]*(?:[./][A-Za-z][A-Za-z0-9$]*)+)::");
4555

4656
// Library path in two formats produced by os::print_location():
4757
// <offset 0x...> in /path/to/lib.so at 0x... (no dladdr symbol)
@@ -106,6 +116,8 @@ private static String redactLine(String line, boolean isClassOop) {
106116
line = redactTypeDescriptors(line);
107117
line = redactKlassReference(line);
108118
line = redactMethodClass(line);
119+
line = redactObjFieldRef(line);
120+
line = redactNmethodClass(line);
109121
line = redactLibraryPath(line);
110122
line = redactStringOopRef(line, isClassOop);
111123
line = redactOopClassName(line);
@@ -140,39 +152,65 @@ static String redactStringTypeValue(String line) {
140152

141153
/**
142154
* Redacts the package of type descriptors in a line: <code>Lcom/company/Type;</code> to <code>
143-
* Lredacted/redacted/Type;</code>
155+
* Lredacted/Redacted;</code>
144156
*/
145157
static String redactTypeDescriptors(String line) {
146158
return replaceAll(TYPE_DESCRIPTOR, line, m -> "L" + redactJvmClassName(m.group(1)) + ";");
147159
}
148160

149161
/**
150-
* Redacts klass/interface references in a line: <code>klass: 'com/company/Class'</code> to <code>
151-
* klass: 'redacted/redacted/Class'</code>
162+
* Redacts klass references in a line: <code>klass: 'com/company/Class'</code> to <code>
163+
* klass: 'redacted/Redacted'</code>
152164
*/
153165
static String redactKlassReference(String line) {
154166
return replaceAll(
155-
KLASS_REF, line, m -> m.group(1) + redactJvmClassName(m.group(2)) + m.group(3));
167+
KLASS_REF, line, m -> m.group(1) + redactJvmClassName(m.group(2)) + "'");
156168
}
157169

158170
/**
159171
* Redacts the class in a method descriptor's {@code in 'class'} clause: <code>
160-
* in 'com/company/Class'</code> to <code>in 'redacted/redacted/Class'</code>
172+
* in 'com/company/Class'</code> to <code>in 'redacted/Redacted'</code>
161173
*/
162174
static String redactMethodClass(String line) {
163175
return replaceAll(
164-
METHOD_IN_CLASS, line, m -> m.group(1) + redactJvmClassName(m.group(2)) + m.group(3));
176+
METHOD_IN_CLASS, line, m -> m.group(1) + redactJvmClassName(m.group(2)) + "'");
165177
}
166178

167179
/**
168180
* Redacts all but the parent directory and filename from a library path. Handles both <code>
169181
* &lt;offset 0x...&gt; in /path/to/dir/lib.so</code> and <code>symbol+0 in
170-
* /path/to/dir/lib.so</code> to <code>... in /redacted/redacted/dir/lib.so</code>
182+
* /path/to/dir/lib.so</code> to <code>... in /redacted/dir/lib.so</code>
171183
*/
172184
static String redactLibraryPath(String line) {
173185
return replaceAll(LIBRARY_PATH, line, m -> m.group(1) + redactPath(m.group(2)));
174186
}
175187

188+
/**
189+
* Redacts the class name in oop dump object-reference field values: <code>a
190+
* 'com/company/Class'</code> to <code>a 'redacted/Redacted'</code>.
191+
*/
192+
static String redactObjFieldRef(String line) {
193+
return replaceAll(
194+
OBJ_FIELD_REF, line, m -> m.group(1) + redactJvmClassName(m.group(2)) + "'");
195+
}
196+
197+
/**
198+
* Redacts the class name in nmethod {@code Compiled method} output (JDK 11+): <code>
199+
* com.company.Foo::methodName</code> to <code>redacted.Redacted::methodName</code>. Handles both
200+
* dot-separated (PRODUCT build) and slash-separated (debug build) class names.
201+
*/
202+
static String redactNmethodClass(String line) {
203+
return replaceAll(
204+
NMETHOD_CLASS,
205+
line,
206+
m -> {
207+
String cls = m.group(1);
208+
String redacted =
209+
cls.indexOf('/') >= 0 ? redactJvmClassName(cls) : redactDottedClassName(cls);
210+
return redacted + "::";
211+
});
212+
}
213+
176214
/**
177215
* Redacts any {@code "value"\{0x...\}} OOP reference to {@code "REDACTED"\{0x...\}}. This is the
178216
* safe default for lines that are not part of a {@code java.lang.Class} oop dump, where the
@@ -186,7 +224,7 @@ static String redactDottedClassOopRef(String line) {
186224

187225
/**
188226
* Redacts the class name in {@code is an oop: ClassName}: <code>is an oop: com.company.Class
189-
* </code> to <code>is an oop: redacted.redacted.Class</code>
227+
* </code> to <code>is an oop: redacted.Redacted</code>
190228
*/
191229
static String redactOopClassName(String line) {
192230
return replaceAll(IS_AN_OOP, line, m -> m.group(1) + redactDottedClassName(m.group(2)));

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

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,4 +300,91 @@ void testRedactReadableMemoryHexDump_leavesUnrelatedLinesUnchanged() {
300300
assertThat(RedactUtils.redactReadableMemoryHexDump("0x00007f37a16e2590 is an unknown value"))
301301
.isEqualTo("0x00007f37a16e2590 is an unknown value");
302302
}
303+
304+
@Test
305+
void testRedactObjFieldRef_redactsUnknownPackage() {
306+
assertThat(
307+
RedactUtils.redactObjFieldRef(
308+
" - 'owner' 'Lcom/company/Owner;' @12 a 'com/company/Owner'{0x00007f3700001234} (0x12345678)"))
309+
.isEqualTo(
310+
" - 'owner' 'Lcom/company/Owner;' @12 a 'redacted/Redacted'{0x00007f3700001234} (0x12345678)");
311+
}
312+
313+
@Test
314+
void testRedactObjFieldRef_keepsKnownPackage() {
315+
assertThat(
316+
RedactUtils.redactObjFieldRef(
317+
" - 'loader' 'Ljava/lang/ClassLoader;' @12 a 'java/lang/ClassLoader'{0x00007f3700001234} (0x12345678)"))
318+
.isEqualTo(
319+
" - 'loader' 'Ljava/lang/ClassLoader;' @12 a 'java/lang/ClassLoader'{0x00007f3700001234} (0x12345678)");
320+
}
321+
322+
@Test
323+
void testRedactObjFieldRef_leavesUnrelatedLinesUnchanged() {
324+
assertThat(RedactUtils.redactObjFieldRef("0x00007f37a16e2590 is an unknown value"))
325+
.isEqualTo("0x00007f37a16e2590 is an unknown value");
326+
}
327+
328+
@Test
329+
void testRedactNmethodClass_dottedUnknownPackage() {
330+
assertThat(
331+
RedactUtils.redactNmethodClass(
332+
"Compiled method (c2) 3068 4 com.company.Foo::methodName (456 bytes)"))
333+
.isEqualTo("Compiled method (c2) 3068 4 redacted.Redacted::methodName (456 bytes)");
334+
}
335+
336+
@Test
337+
void testRedactNmethodClass_dottedKnownPackage() {
338+
assertThat(
339+
RedactUtils.redactNmethodClass(
340+
"Compiled method (c2) 3068 4 java.util.HashMap::resize (456 bytes)"))
341+
.isEqualTo(
342+
"Compiled method (c2) 3068 4 java.util.HashMap::resize (456 bytes)");
343+
}
344+
345+
@Test
346+
void testRedactNmethodClass_slashUnknownPackage() {
347+
assertThat(RedactUtils.redactNmethodClass("com/company/Foo::methodName"))
348+
.isEqualTo("redacted/Redacted::methodName");
349+
}
350+
351+
@Test
352+
void testRedactNmethodClass_slashKnownPackage() {
353+
assertThat(RedactUtils.redactNmethodClass("java/util/HashMap::resize"))
354+
.isEqualTo("java/util/HashMap::resize");
355+
}
356+
357+
@Test
358+
void testRedactNmethodClass_leavesUnrelatedLinesUnchanged() {
359+
assertThat(RedactUtils.redactNmethodClass("0x00007f37a16e2590 is an unknown value"))
360+
.isEqualTo("0x00007f37a16e2590 is an unknown value");
361+
}
362+
363+
@Test
364+
void testRedactRegisterToMemoryMapping_objFieldRef() {
365+
// Non-java.lang.Class oop with object-reference field: a 'ClassName' is redacted
366+
String value =
367+
"0x00000007142f8848 is an oop: com.company.Holder \n"
368+
+ "{0x00000007142f8848} - klass: 'com/company/Holder'\n"
369+
+ " - ---- fields (total size 3 words):\n"
370+
+ " - 'ref' 'Ljava/lang/Object;' @12 a 'com/company/Inner'{0x00007f1200003456} (0xabcdef01)";
371+
assertThat(RedactUtils.redactRegisterToMemoryMapping(value))
372+
.isEqualTo(
373+
"0x00000007142f8848 is an oop: redacted.Redacted \n"
374+
+ "{0x00000007142f8848} - klass: 'redacted/Redacted'\n"
375+
+ " - ---- fields (total size 3 words):\n"
376+
+ " - 'ref' 'Ljava/lang/Object;' @12 a 'redacted/Redacted'{0x00007f1200003456} (0xabcdef01)");
377+
}
378+
379+
@Test
380+
void testRedactRegisterToMemoryMapping_nmethodCompiledMethod() {
381+
// nmethod entry (JDK 11+): "Compiled method" line class name is redacted
382+
String value =
383+
"0x00007f36cd2b1600 is at entry_point+13512 in (nmethod*) 0x00007f36cd2b1510\n"
384+
+ "Compiled method (c2) 3068 4 com.company.Foo::processRequest (456 bytes)";
385+
assertThat(RedactUtils.redactRegisterToMemoryMapping(value))
386+
.isEqualTo(
387+
"0x00007f36cd2b1600 is at entry_point+13512 in (nmethod*) 0x00007f36cd2b1510\n"
388+
+ "Compiled method (c2) 3068 4 redacted.Redacted::processRequest (456 bytes)");
389+
}
303390
}

0 commit comments

Comments
 (0)