@@ -168,21 +168,26 @@ void testRedactLibraryPath_leavesUnrelatedLinesUnchanged() {
168168 }
169169
170170 @ Test
171- void testRedactDottedClassOopRef_redactsUnknownPackage () {
171+ void testRedactDottedClassOopRef_redactsAnyStringOopRef () {
172+ // Without oop-type context, all "value"{0x...} OOP refs are treated as arbitrary application
173+ // data and fully redacted — even if the value looks like a class name
172174 assertThat (
173175 RedactUtils .redactDottedClassOopRef (
174176 " - private transient 'name' 'Ljava/lang/String;' @44 \" com.company.SomeType\" {0x00000007142f7200} (0xe285ee40)" ))
175177 .isEqualTo (
176- " - private transient 'name' 'Ljava/lang/String;' @44 \" redacted.redacted.SomeType\" {0x00000007142f7200} (0xe285ee40)" );
177- }
178-
179- @ Test
180- void testRedactDottedClassOopRef_keepsKnownPackage () {
178+ " - private transient 'name' 'Ljava/lang/String;' @44 \" REDACTED\" {0x00000007142f7200} (0xe285ee40)" );
179+ // Dotted names with known packages are also fully redacted — any string can be a secret
181180 assertThat (
182181 RedactUtils .redactDottedClassOopRef (
183182 " - private transient 'name' 'Ljava/lang/String;' @44 \" jdk.internal.misc.Unsafe\" {0x00000007142f7200} (0xe285ee40)" ))
184183 .isEqualTo (
185- " - private transient 'name' 'Ljava/lang/String;' @44 \" jdk.internal.misc.Unsafe\" {0x00000007142f7200} (0xe285ee40)" );
184+ " - private transient 'name' 'Ljava/lang/String;' @44 \" REDACTED\" {0x00000007142f7200} (0xe285ee40)" );
185+ // Plain single-word strings (no dots) are also redacted
186+ assertThat (
187+ RedactUtils .redactDottedClassOopRef (
188+ " - final 'value' 'Ljava/lang/String;' @40 \" SourceFile\" {0x00000007ffe7a6a0} (0xfffcf4d4)" ))
189+ .isEqualTo (
190+ " - final 'value' 'Ljava/lang/String;' @40 \" REDACTED\" {0x00000007ffe7a6a0} (0xfffcf4d4)" );
186191 }
187192
188193 @ Test
@@ -209,25 +214,48 @@ void testRedactRegisterToMemoryMapping_methodDescriptor() {
209214
210215 @ Test
211216 void testRedactRegisterToMemoryMapping_multilineOopDump () {
212- // Mirrors the java.lang.Class oop dump format: the 'name' field holds a dotted class name
213- // as an inline string value followed by an OOP ref, and 'loader' holds a typed object ref .
217+ // Non- java.lang.Class oop: ALL "value"{0x...} OOP refs are fully redacted to "REDACTED"
218+ // regardless of their shape — any string value may be a secret .
214219 String value =
215- "0x00000007ffe85850 is an oop: com.company.Config \n "
216- + "{0x00000007ffe85850} - klass: 'com/company/Config'\n "
217- + " - ---- fields (total size 3 words):\n "
218- + " - private transient 'name' 'Ljava/lang/String;' @12 \" com.company.Config\" {0x00000007aabbccdd} (0x12345678)\n "
219- + " - private 'owner' 'Lcom/company/User;' @16 null (0x00000000)\n "
220+ "0x00000007142f8848 is an oop: com.company.SymbolEntry \n "
221+ + "{0x00000007142f8848} - klass: 'com/company/SymbolEntry'\n "
222+ + " - ---- fields (total size 9 words):\n "
223+ + " - final 'tag' 'Ljava/lang/String;' @12 \" SourceFile\" {0x00000007ffe7a6a0} (0xfffcf4d4)\n "
224+ + " - final 'value' 'Ljava/lang/String;' @16 \" com.company.Config\" {0x00000007aabbccdd} (0x12345678)\n "
225+ + " - final 'hint' 'Ljava/lang/String;' @20 \" java.vendor.url.bug\" {0x00000007aabbccee} (0x12345679)\n "
226+ + " - final 'owner' 'Ljava/lang/String;' @24 null (0x00000000)\n "
220227 + " - string: \" some sensitive value\" " ;
221228 assertThat (RedactUtils .redactRegisterToMemoryMapping (value ))
222229 .isEqualTo (
223- "0x00000007ffe85850 is an oop: redacted.redacted.Config \n "
224- + "{0x00000007ffe85850} - klass: 'redacted/redacted/Config'\n "
225- + " - ---- fields (total size 3 words):\n "
226- + " - private transient 'name' 'Ljava/lang/String;' @12 \" redacted.redacted.Config\" {0x00000007aabbccdd} (0x12345678)\n "
227- + " - private 'owner' 'Lredacted/redacted/User;' @16 null (0x00000000)\n "
230+ "0x00000007142f8848 is an oop: redacted.redacted.SymbolEntry \n "
231+ + "{0x00000007142f8848} - klass: 'redacted/redacted/SymbolEntry'\n "
232+ + " - ---- fields (total size 9 words):\n "
233+ + " - final 'tag' 'Ljava/lang/String;' @12 \" REDACTED\" {0x00000007ffe7a6a0} (0xfffcf4d4)\n "
234+ + " - final 'value' 'Ljava/lang/String;' @16 \" REDACTED\" {0x00000007aabbccdd} (0x12345678)\n "
235+ + " - final 'hint' 'Ljava/lang/String;' @20 \" REDACTED\" {0x00000007aabbccee} (0x12345679)\n "
236+ + " - final 'owner' 'Ljava/lang/String;' @24 null (0x00000000)\n "
228237 + " - string: \" REDACTED\" " );
229238 }
230239
240+ @ Test
241+ void testRedactRegisterToMemoryMapping_javaLangClassOopPreservesClassName () {
242+ // java.lang.Class oop: String OOP refs in field values are treated as class names and
243+ // get package redaction (not full redaction), since that is what java.lang.Class stores.
244+ String value =
245+ "0x00000007ffe85850 is an oop: java.lang.Class \n "
246+ + "{0x00000007ffe85850} - klass: 'java/lang/Class'\n "
247+ + " - ---- fields (total size 25 words):\n "
248+ + " - private transient 'name' 'Ljava/lang/String;' @44 \" com.company.Config\" {0x00000007aabbccdd} (0x12345678)\n "
249+ + " - private transient 'name' 'Ljava/lang/String;' @44 \" jdk.internal.misc.Unsafe\" {0x00000007142f7200} (0xe285ee40)" ;
250+ assertThat (RedactUtils .redactRegisterToMemoryMapping (value ))
251+ .isEqualTo (
252+ "0x00000007ffe85850 is an oop: java.lang.Class \n "
253+ + "{0x00000007ffe85850} - klass: 'java/lang/Class'\n "
254+ + " - ---- fields (total size 25 words):\n "
255+ + " - private transient 'name' 'Ljava/lang/String;' @44 \" redacted.redacted.Config\" {0x00000007aabbccdd} (0x12345678)\n "
256+ + " - private transient 'name' 'Ljava/lang/String;' @44 \" jdk.internal.misc.Unsafe\" {0x00000007142f7200} (0xe285ee40)" );
257+ }
258+
231259 @ Test
232260 void testRedactRegisterToMemoryMapping_libraryPath () {
233261 assertThat (
0 commit comments