Skip to content

Commit c832f00

Browse files
committed
8359593: JFR: Instrumentation of java.lang.String corrupts recording
Reviewed-by: mgronlun Backport-of: 2f2acb2
1 parent e5ac75a commit c832f00

File tree

2 files changed

+117
-12
lines changed

2 files changed

+117
-12
lines changed

src/jdk.jfr/share/classes/jdk/jfr/internal/tracing/ExcludeList.java

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,38 +24,46 @@
2424
*/
2525
package jdk.jfr.internal.tracing;
2626

27+
import java.util.Set;
28+
2729
// // The JVM will skip all classes in the jdk.jfr module, so it's not added here.
2830
public final class ExcludeList {
2931
private static final String[] EXCLUDED_CLASSES = {
3032
// Used by MethodTiming event to accumulate invocations.
3133
"java/util/concurrent/atomic/AtomicLong",
32-
// Used by EventWriter
34+
// Used by EventWriter, directly or indirectly.
3335
"sun/misc/Unsafe",
34-
"jdk/internal/misc/Unsafe;",
36+
"jdk/internal/misc/Unsafe",
37+
"java/lang/StringLatin1",
38+
"java/lang/StringUTF16",
3539
};
3640

3741
private static final String[] EXCLUDED_PREFIX = {
3842
// Used by MethodTiming event to store invocations, including inner classes.
3943
"java/util/concurrent/ConcurrentHashMap",
4044
// Can't trigger <clinit> of these classes during PlatformTracer::onMethodTrace(...)
41-
"jdk/internal/", // jdk/internal/classfile, jdk/internal/loader and jdk/internal/foreign
45+
// Also to avoid recursion with EventWriter::putString
46+
"jdk/internal/", // jdk/internal/classfile, // jdk/internal/vm, jdk/internal/util, jdk/internal/loader and jdk/internal/foreign
4247
"java/lang/classfile/"
4348
};
4449

45-
private static final String[] EXCLUDED_METHODS = {
50+
private static final Set<String> EXCLUDED_METHODS = Set.of(
4651
// Long used by MethodTiming event when looking up entry for timing entry
4752
"java.lang.Long::<init>",
4853
"java.lang.Long::valueOf",
49-
"java.lang.Number::<init>"
50-
};
54+
"java.lang.Number::<init>",
55+
// Used by EventWriter::putString, directly or indirectly.
56+
"java.lang.String::charAt",
57+
"java.lang.String::length",
58+
"java.lang.String::coder", // Used by charAt(int)
59+
"java.lang.String::checkIndex", // Used by charAt(int)
60+
"java.lang.String::isLatin1", // Used by charAt()
61+
"java.lang.String::equals", // Used by StringPool
62+
"java.lang.String::hashCode" // Used by StringPool
63+
);
5164

5265
public static boolean containsMethod(String methodName) {
53-
for (String method : EXCLUDED_METHODS) {
54-
if (method.equals(methodName)) {
55-
return true;
56-
}
57-
}
58-
return false;
66+
return EXCLUDED_METHODS.contains(methodName);
5967
}
6068

6169
public static boolean containsClass(String className) {
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
/*
2+
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
package jdk.jfr.event.tracing;
24+
25+
import java.nio.file.Path;
26+
27+
import jdk.jfr.Configuration;
28+
import jdk.jfr.Name;
29+
import jdk.jfr.Recording;
30+
import jdk.jfr.consumer.RecordedEvent;
31+
import jdk.jfr.consumer.RecordingFile;
32+
33+
/**
34+
* @test
35+
* @summary Tests that java.lang.String can be traced.
36+
* @requires vm.flagless
37+
* @requires vm.hasJFR
38+
* @library /test/lib
39+
* @run main/othervm jdk.jfr.event.tracing.TestTracedString
40+
**/
41+
public class TestTracedString {
42+
private static long SEED = System.currentTimeMillis();
43+
44+
@Name("Message")
45+
static class MessageEvent extends jdk.jfr.Event {
46+
String message;
47+
long checkSum;
48+
}
49+
50+
public static void main(String[] args) throws Exception {
51+
Configuration c = Configuration.getConfiguration("default");
52+
Path file = Path.of("recording.jfr");
53+
try (Recording r = new Recording(c)) {
54+
r.enable("jdk.MethodTrace").with("filter", "java.lang.String");
55+
r.start();
56+
emit(100, "");
57+
emit(100, "short");
58+
emit(100, "medium medium medium medium medium medium 1");
59+
emit(100, "medium medium medium medium medium medium 2");
60+
emit(100, "long".repeat(100));
61+
r.stop();
62+
r.dump(file);
63+
int count = 0;
64+
for (RecordedEvent e : RecordingFile.readAllEvents(file)) {
65+
if (e.getEventType().getName().equals("Message")) {
66+
String text = e.getString("message");
67+
long checkSum = e.getLong("checkSum");
68+
if (checkSum(text) != checkSum) {
69+
throw new Exception("Incorrect checksum for text " + text);
70+
}
71+
count++;
72+
}
73+
}
74+
if (count != 500) {
75+
throw new Exception("Expected 500 Message events. Got " + count);
76+
}
77+
}
78+
}
79+
80+
private static void emit(int count, String text) {
81+
long checkSum = checkSum(text);
82+
for (int i = 0; i < count; i++) {
83+
MessageEvent m = new MessageEvent();
84+
m.message = text;
85+
m.checkSum = checkSum;
86+
m.commit();
87+
}
88+
}
89+
90+
private static long checkSum(String text) {
91+
long checkSum = SEED;
92+
for (int i = 0; i < text.length(); i++) {
93+
checkSum += 17 * text.charAt(i);
94+
}
95+
return checkSum;
96+
}
97+
}

0 commit comments

Comments
 (0)