Skip to content

Commit 48aff23

Browse files
committed
8272515: JFR: Names should only be valid Java identifiers
Reviewed-by: mgronlun
1 parent 4d95a5d commit 48aff23

File tree

11 files changed

+285
-49
lines changed

11 files changed

+285
-49
lines changed

src/java.base/share/classes/jdk/internal/module/Checks.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2009, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -168,7 +168,7 @@ private static String requireTypeName(String what, String name) {
168168
* Returns true if the given string is a legal Java identifier,
169169
* otherwise false.
170170
*/
171-
private static boolean isJavaIdentifier(String str) {
171+
public static boolean isJavaIdentifier(String str) {
172172
if (str.isEmpty() || RESERVED.contains(str))
173173
return false;
174174

src/jdk.jfr/share/classes/jdk/jfr/EventFactory.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import java.util.Objects;
3434
import java.util.Set;
3535

36+
import jdk.internal.module.Checks;
3637
import jdk.jfr.internal.EventClassBuilder;
3738
import jdk.jfr.internal.JVMSupport;
3839
import jdk.jfr.internal.MetadataRepository;
@@ -135,7 +136,7 @@ public static EventFactory create(List<AnnotationElement> annotationElements, Li
135136
if (!Type.isValidJavaFieldType(v.getTypeName())) {
136137
throw new IllegalArgumentException(v.getTypeName() + " is not a valid type for an event field");
137138
}
138-
if (!Type.isValidJavaIdentifier(v.getName())) {
139+
if (!Checks.isJavaIdentifier(v.getName())) {
139140
throw new IllegalArgumentException(name + " is not a valid name for an event field");
140141
}
141142
if (nameSet.contains(name)) {

src/jdk.jfr/share/classes/jdk/jfr/Name.java

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -33,9 +33,13 @@
3333
/**
3434
* Annotation that sets the default name for an element.
3535
* <p>
36-
* The name must be a valid identifier as specified in the Java language (for
37-
* example, {@code "com.example.Transaction"} for an event class or
38-
* {@code "message"} for an event field).
36+
* For event classes, the name must be a legal class name as specified in the Java
37+
* language, (for example, {@code "com.example.Transaction"}. For event fields
38+
* or event settings, the name must be a valid identifier (for example,
39+
* {@code "message"}). See section 3.8 and 3.9 of the Java Language
40+
* Specification for more information.
41+
* <p>
42+
* If the specified name is invalid, the annotation is ignored.
3943
* <p>
4044
* A stable and easy-to-use event name is of the form:
4145
* <p>

src/jdk.jfr/share/classes/jdk/jfr/ValueDescriptor.java

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -83,12 +83,14 @@ public final class ValueDescriptor {
8383
* </ul>
8484
*
8585
* <p>
86-
* The name must be a valid Java identifier (for example, {@code "maxThroughput"}). See 3.8
87-
* Java Language Specification for more information.
86+
* The name must be a valid Java identifier (for example, {@code "maxThroughput"}). See
87+
* section 3.8 and 3.9 of the Java Language Specification for more information.
8888
*
8989
* @param type the type, not {@code null}
9090
* @param name the name, not {@code null}
9191
*
92+
* @throws IllegalArgumentException if the name is not a valid Java identifier
93+
*
9294
* @throws SecurityException if a security manager is present and the caller
9395
* doesn't have {@code FlightRecorderPermission("registerEvent")}
9496
*
@@ -118,14 +120,16 @@ public ValueDescriptor(Class<?> type, String name) {
118120
* </ul>
119121
*
120122
* <p>
121-
* The name must be a valid Java identifier (for example, {@code "maxThroughput"}). See 3.8
122-
* Java Language Specification for more information.
123+
* The name must be a valid Java identifier (for example, {@code "maxThroughput"}). See
124+
* section 3.8 and 3.9 of the Java Language Specification for more information.
123125
*
124126
* @param type the type, not {@code null}
125127
* @param name the name, not {@code null}
126128
* @param annotations the annotations on the value descriptors, not
127129
* {@code null}
128130
*
131+
* @throws IllegalArgumentException if the name is not a valid Java identifier
132+
*
129133
* @throws SecurityException if a security manager is present and the caller
130134
* doesn't have {@code FlightRecorderPermission("registerEvent")}
131135
*/
@@ -143,6 +147,7 @@ public ValueDescriptor(Class<?> type, String name, List<AnnotationElement> annot
143147
}
144148
}
145149
this.name = Objects.requireNonNull(name, "Name of value descriptor can't be null");
150+
Utils.ensureJavaIdentifier(name);
146151
this.type = Objects.requireNonNull(Utils.getValidType(Objects.requireNonNull(type), Objects.requireNonNull(name)));
147152
this.annotationConstruct = new AnnotationConstruct(annotations);
148153
this.javaFieldName = name; // Needed for dynamic events

src/jdk.jfr/share/classes/jdk/jfr/internal/EventControl.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -150,7 +150,7 @@ private void defineSettings(Class<?> eventClass) {
150150
String name = m.getName();
151151
Name n = m.getAnnotation(Name.class);
152152
if (n != null) {
153-
name = n.value();
153+
name = Utils.validJavaIdentifier(n.value(), name);
154154
}
155155

156156
if (!hasControl(name)) {

src/jdk.jfr/share/classes/jdk/jfr/internal/EventInstrumentation.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -213,13 +213,23 @@ private static List<SettingInfo> buildSettingInfos(Class<?> superClass, ClassNod
213213
Set<String> methodSet = new HashSet<>();
214214
List<SettingInfo> settingInfos = new ArrayList<>();
215215
String settingDescriptor = Type.getType(SettingDefinition.class).getDescriptor();
216+
String nameDescriptor = Type.getType(Name.class).getDescriptor();
216217
for (MethodNode m : classNode.methods) {
217218
if (m.visibleAnnotations != null) {
218219
for (AnnotationNode an : m.visibleAnnotations) {
219220
// We can't really validate the method at this
220221
// stage. We would need to check that the parameter
221222
// is an instance of SettingControl.
222223
if (settingDescriptor.equals(an.desc)) {
224+
String name = m.name;
225+
for (AnnotationNode nameCandidate : m.visibleAnnotations) {
226+
if (nameDescriptor.equals(nameCandidate.desc)) {
227+
List<Object> values = nameCandidate.values;
228+
if (values.size() == 1 && values.get(0) instanceof String s) {
229+
name = Utils.validJavaIdentifier(s, name);
230+
}
231+
}
232+
}
223233
Type returnType = Type.getReturnType(m.desc);
224234
if (returnType.equals(Type.getType(Boolean.TYPE))) {
225235
Type[] args = Type.getArgumentTypes(m.desc);

src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataLoader.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -255,6 +255,9 @@ private void addFields(Map<String, Type> lookup, Map<String, AnnotationElement>
255255
if ("to".equals(f.transition)) {
256256
aes.add(TRANSITION_TO);
257257
}
258+
if (!"package".equals(f.name) && !"java.lang.Class".equals(te.name)) {
259+
Utils.ensureJavaIdentifier(f.name);
260+
}
258261
type.add(PrivateAccess.getInstance().newValueDescriptor(f.name, fieldType, aes, f.array ? 1 : 0, f.constantPool, null));
259262
}
260263
}

src/jdk.jfr/share/classes/jdk/jfr/internal/Type.java

Lines changed: 6 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import java.util.Map;
3434
import java.util.Objects;
3535

36+
import jdk.internal.module.Checks;
3637
import jdk.jfr.AnnotationElement;
3738
import jdk.jfr.Event;
3839
import jdk.jfr.SettingControl;
@@ -76,7 +77,7 @@ private static Type createKnownType(Class<?> clazz) {
7677

7778
private static Type createKnownType(String name, Class<?> clazz) {
7879
long id = JVM.getJVM().getTypeId(name);
79-
Type t = new Type(name, null, id);
80+
Type t = new Type(name, null, id, null);
8081
knownTypes.put(t, clazz);
8182
return t;
8283
}
@@ -99,14 +100,14 @@ private static Type createKnownType(String name, Class<?> clazz) {
99100
*/
100101
public Type(String javaTypeName, String superType, long typeId) {
101102
this(javaTypeName, superType, typeId, null);
103+
if (!Checks.isClassName(javaTypeName)) {
104+
// Should not be able to come here with an invalid type name
105+
throw new InternalError(javaTypeName + " is not a valid Java type");
106+
}
102107
}
103108

104109
Type(String javaTypeName, String superType, long typeId, Boolean simpleType) {
105110
Objects.requireNonNull(javaTypeName);
106-
107-
if (!isValidJavaIdentifier(javaTypeName)) {
108-
throw new IllegalArgumentException(javaTypeName + " is not a valid Java identifier");
109-
}
110111
this.superType = superType;
111112
this.name = javaTypeName;
112113
this.id = typeId;
@@ -126,24 +127,6 @@ static Collection<Type> getKnownTypes() {
126127
return knownTypes.keySet();
127128
}
128129

129-
public static boolean isValidJavaIdentifier(String identifier) {
130-
if (identifier.isEmpty()) {
131-
return false;
132-
}
133-
if (!Character.isJavaIdentifierStart(identifier.charAt(0))) {
134-
return false;
135-
}
136-
for (int i = 1; i < identifier.length(); i++) {
137-
char c = identifier.charAt(i);
138-
if (c != '.') {
139-
if (!Character.isJavaIdentifierPart(c)) {
140-
return false;
141-
}
142-
}
143-
}
144-
return true;
145-
}
146-
147130
public static boolean isValidJavaFieldType(String name) {
148131
for (Map.Entry<Type, Class<?>> entry : knownTypes.entrySet()) {
149132
Class<?> clazz = entry.getValue();

src/jdk.jfr/share/classes/jdk/jfr/internal/TypeLibrary.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -191,7 +191,10 @@ private static Type getType(Class<?> clazz) {
191191
private static Type defineType(Class<?> clazz, String superType, boolean eventType) {
192192
if (!isDefined(clazz)) {
193193
Name name = clazz.getAnnotation(Name.class);
194-
String typeName = name != null ? name.value() : clazz.getName();
194+
String typeName = clazz.getName();
195+
if (name != null) {
196+
typeName = Utils.validTypeName(name.value(), typeName);
197+
}
195198
long id = Type.getTypeId(clazz);
196199
Type t;
197200
if (eventType) {
@@ -317,7 +320,6 @@ static void addImplicitFields(Type type, boolean requestable, boolean hasDuratio
317320
createAnnotationType(Timespan.class);
318321
createAnnotationType(Timestamp.class);
319322
createAnnotationType(Label.class);
320-
defineType(long.class, null, false);
321323
implicitFieldTypes = true;
322324
}
323325
addFields(type, requestable, hasDuration, hasThread, hasStackTrace, hasCutoff);
@@ -363,7 +365,7 @@ private static ValueDescriptor createField(Field field) {
363365
Name name = field.getAnnotation(Name.class);
364366
String useName = fieldName;
365367
if (name != null) {
366-
useName = name.value();
368+
useName = Utils.validJavaIdentifier(name.value(), useName);
367369
}
368370
List<jdk.jfr.AnnotationElement> ans = new ArrayList<>();
369371
for (Annotation a : resolveRepeatedAnnotations(field.getAnnotations())) {

src/jdk.jfr/share/classes/jdk/jfr/internal/Utils.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
import java.util.Map;
5555
import java.util.Objects;
5656

57+
import jdk.internal.module.Checks;
5758
import jdk.internal.org.objectweb.asm.ClassReader;
5859
import jdk.internal.org.objectweb.asm.util.CheckClassAdapter;
5960
import jdk.internal.platform.Metrics;
@@ -841,4 +842,28 @@ public static Instant epochNanosToInstant(long epochNanos) {
841842
public static long timeToNanos(Instant timestamp) {
842843
return timestamp.getEpochSecond() * 1_000_000_000L + timestamp.getNano();
843844
}
845+
846+
public static String validTypeName(String typeName, String defaultTypeName) {
847+
if (Checks.isClassName(typeName)) {
848+
return typeName;
849+
} else {
850+
Logger.log(LogTag.JFR, LogLevel.WARN, "@Name ignored, not a valid Java type name.");
851+
return defaultTypeName;
852+
}
853+
}
854+
855+
public static String validJavaIdentifier(String identifier, String defaultIdentifier) {
856+
if (Checks.isJavaIdentifier(identifier)) {
857+
return identifier;
858+
} else {
859+
Logger.log(LogTag.JFR, LogLevel.WARN, "@Name ignored, not a valid Java identifier.");
860+
return defaultIdentifier;
861+
}
862+
}
863+
864+
public static void ensureJavaIdentifier(String name) {
865+
if (!Checks.isJavaIdentifier(name)) {
866+
throw new IllegalArgumentException("'" + name + "' is not a valid Java identifier");
867+
}
868+
}
844869
}

0 commit comments

Comments
 (0)