Skip to content

Commit f9b91a7

Browse files
committed
8368050: Validation missing in ClassFile signature factories
Reviewed-by: asotona
1 parent 4bc86a2 commit f9b91a7

File tree

5 files changed

+227
-32
lines changed

5 files changed

+227
-32
lines changed

src/java.base/share/classes/java/lang/classfile/MethodSignature.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,13 +113,14 @@ public static MethodSignature of(MethodTypeDesc methodDescriptor) {
113113
*
114114
* @param result signature for the return type
115115
* @param arguments signatures for the method parameters
116+
* @throws IllegalArgumentException if any of {@code arguments} is void
116117
*/
117118
public static MethodSignature of(Signature result,
118119
Signature... arguments) {
119120
return new SignaturesImpl.MethodSignatureImpl(List.of(),
120121
List.of(),
121122
requireNonNull(result),
122-
List.of(arguments));
123+
SignaturesImpl.validateArgumentList(arguments));
123124
}
124125

125126
/**
@@ -131,6 +132,7 @@ public static MethodSignature of(Signature result,
131132
* @param exceptions signatures for the exceptions
132133
* @param result signature for the return type
133134
* @param arguments signatures for the method parameters
135+
* @throws IllegalArgumentException if any of {@code arguments} is void
134136
*/
135137
public static MethodSignature of(List<Signature.TypeParam> typeParameters,
136138
List<Signature.ThrowableSig> exceptions,
@@ -140,7 +142,7 @@ public static MethodSignature of(List<Signature.TypeParam> typeParameters,
140142
List.copyOf(requireNonNull(typeParameters)),
141143
List.copyOf(requireNonNull(exceptions)),
142144
requireNonNull(result),
143-
List.of(arguments));
145+
SignaturesImpl.validateArgumentList(arguments));
144146
}
145147

146148
/**

src/java.base/share/classes/java/lang/classfile/Signature.java

Lines changed: 75 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@
4343

4444
/**
4545
* Models generic Java type signatures, as defined in JVMS {@jvms 4.7.9.1}.
46+
* <p>
47+
* Names in signatures are <dfn id="identifier">identifiers</dfn>, which must
48+
* not be empty and must not contain any of the ASCII characters {@code
49+
* . ; [ / < > :}. Top-level class and interface names are denoted by
50+
* slash-separated identifiers.
4651
*
4752
* @see Type
4853
* @see SignatureAttribute
@@ -73,6 +78,8 @@ public static Signature parseFrom(String javaTypeSignature) {
7378
* signature represents a reifiable type (JLS {@jls 4.7}).
7479
*
7580
* @param classDesc the symbolic description of the Java type
81+
* @throws IllegalArgumentException if the field descriptor cannot be
82+
* {@linkplain ##identifier denoted}
7683
*/
7784
public static Signature of(ClassDesc classDesc) {
7885
requireNonNull(classDesc);
@@ -139,6 +146,31 @@ public sealed interface RefTypeSig
139146

140147
/**
141148
* Models the signature of a possibly-parameterized class or interface type.
149+
* <p>
150+
* These are examples of class type signatures:
151+
* <ul>
152+
* <li>{@code Lcom/example/Outer;} for {@code Outer}
153+
* <br>Has class name {@code com/example/Outer} and no outer type or type
154+
* argument.
155+
* <li>{@code Lcom/example/Outer$Nested<TA;>;} for {@code Outer.Nested<A>}
156+
* <br>Has class name {@code com/example/Outer$Nested} representing a nested
157+
* class, no outer type, and a single type argument of type variable
158+
* {@code A}.
159+
* <li>{@code Lcom/example/GenericOuter<TA;>.Inner;} for {@code
160+
* GenericOuter<A>.Inner}
161+
* <br>Has class name {@code Inner}, a simple class name, outer type
162+
* {@code Lcom/example/GenericOuter<TA;>;} for {@code GenericOuter<A>},
163+
* and no type argument.
164+
* </ul>
165+
* <p>
166+
* If the {@linkplain #outerType() outer type} exists, the {@linkplain
167+
* #className() class name} is the simple name of the nested type.
168+
* Otherwise, it is a {@linkplain ClassEntry##internalname binary name in
169+
* internal form} (separated by {@code /}).
170+
* <p>
171+
* If a nested type does not have any enclosing parameterization, it may
172+
* be represented without an outer type and as an internal binary name,
173+
* in which nesting is represented by {@code $} instead of {@code .}.
142174
*
143175
* @see Type
144176
* @see ParameterizedType
@@ -152,7 +184,8 @@ public sealed interface ClassTypeSig
152184
/**
153185
* {@return the signature of the class that this class is a member of,
154186
* only if this is a member class} Note that the outer class may be
155-
* absent if it is not a parameterized type.
187+
* absent if this is a member class without any parameterized enclosing
188+
* type.
156189
*
157190
* @jls 4.5 Parameterized Types
158191
*/
@@ -161,7 +194,8 @@ public sealed interface ClassTypeSig
161194
/**
162195
* {@return the class or interface name; includes the {@linkplain
163196
* ClassEntry##internalname slash-separated} package name if there is no
164-
* outer type}
197+
* outer type} Note this may indicate a nested class name with {@code $}
198+
* separators if there is no parameterized enclosing type.
165199
*/
166200
String className();
167201

@@ -188,10 +222,11 @@ default ClassDesc classDesc() {
188222
* @param className the name of the class or interface
189223
* @param typeArgs the type arguments
190224
* @throws IllegalArgumentException if {@code className} does not
191-
* represent a class or interface
225+
* represent a class or interface, or if it cannot be
226+
* {@linkplain Signature##identifier denoted}
192227
*/
193228
public static ClassTypeSig of(ClassDesc className, TypeArg... typeArgs) {
194-
return of(null, className, typeArgs);
229+
return of(null, Util.toInternalName(className), typeArgs);
195230
}
196231

197232
/**
@@ -201,8 +236,15 @@ public static ClassTypeSig of(ClassDesc className, TypeArg... typeArgs) {
201236
* @param className the name of this class or interface
202237
* @param typeArgs the type arguments
203238
* @throws IllegalArgumentException if {@code className} does not
204-
* represent a class or interface
239+
* represent a class or interface, or if it cannot be
240+
* {@linkplain Signature##identifier denoted}
241+
* @deprecated
242+
* The resulting signature does not denote the class represented by
243+
* {@code className} when {@code outerType} is not null. Use {@link
244+
* #of(ClassTypeSig, String, TypeArg...) of(ClassTypeSig, String, TypeArg...)}
245+
* instead.
205246
*/
247+
@Deprecated(since = "26", forRemoval = true)
206248
public static ClassTypeSig of(ClassTypeSig outerType, ClassDesc className, TypeArg... typeArgs) {
207249
requireNonNull(className);
208250
return of(outerType, Util.toInternalName(className), typeArgs);
@@ -211,8 +253,11 @@ public static ClassTypeSig of(ClassTypeSig outerType, ClassDesc className, TypeA
211253
/**
212254
* {@return a class or interface signature without an outer type}
213255
*
214-
* @param className the name of the class or interface
256+
* @param className the name of the class or interface, may use
257+
* {@code /} to separate
215258
* @param typeArgs the type arguments
259+
* @throws IllegalArgumentException if {@code className} cannot be
260+
* {@linkplain Signature##identifier denoted}
216261
*/
217262
public static ClassTypeSig of(String className, TypeArg... typeArgs) {
218263
return of(null, className, typeArgs);
@@ -222,12 +267,19 @@ public static ClassTypeSig of(String className, TypeArg... typeArgs) {
222267
* {@return a class type signature}
223268
*
224269
* @param outerType signature of the outer type, may be {@code null}
225-
* @param className the name of this class or interface
270+
* @param className the name of this class or interface, may use
271+
* {@code /} to separate if outer type is absent
226272
* @param typeArgs the type arguments
273+
* @throws IllegalArgumentException if {@code className} cannot be
274+
* {@linkplain Signature##identifier denoted}
227275
*/
228276
public static ClassTypeSig of(ClassTypeSig outerType, String className, TypeArg... typeArgs) {
229-
requireNonNull(className);
230-
return new SignaturesImpl.ClassTypeSigImpl(Optional.ofNullable(outerType), className.replace(".", "/"), List.of(typeArgs));
277+
if (outerType != null) {
278+
SignaturesImpl.validateIdentifier(className);
279+
} else {
280+
SignaturesImpl.validatePackageSpecifierPlusIdentifier(className);
281+
}
282+
return new SignaturesImpl.ClassTypeSigImpl(Optional.ofNullable(outerType), className, List.of(typeArgs));
231283
}
232284
}
233285

@@ -383,9 +435,11 @@ public sealed interface TypeVarSig
383435
* {@return a signature for a type variable}
384436
*
385437
* @param identifier the name of the type variable
438+
* @throws IllegalArgumentException if the name cannot be {@linkplain
439+
* Signature##identifier denoted}
386440
*/
387441
public static TypeVarSig of(String identifier) {
388-
return new SignaturesImpl.TypeVarSigImpl(requireNonNull(identifier));
442+
return new SignaturesImpl.TypeVarSigImpl(SignaturesImpl.validateIdentifier(identifier));
389443
}
390444
}
391445

@@ -408,20 +462,22 @@ public sealed interface ArrayTypeSig
408462
/**
409463
* {@return an array type with the given component type}
410464
* @param componentSignature the component type
465+
* @throws IllegalArgumentException if the component type is void
411466
*/
412467
public static ArrayTypeSig of(Signature componentSignature) {
413-
return of(1, requireNonNull(componentSignature));
468+
return of(1, SignaturesImpl.validateNonVoid(componentSignature));
414469
}
415470

416471
/**
417472
* {@return a signature for an array type}
418473
* @param dims the dimension of the array
419474
* @param componentSignature the component type
420475
* @throws IllegalArgumentException if {@code dims < 1} or the
421-
* resulting array type exceeds 255 dimensions
476+
* resulting array type exceeds 255 dimensions or the component
477+
* type is void
422478
*/
423479
public static ArrayTypeSig of(int dims, Signature componentSignature) {
424-
requireNonNull(componentSignature);
480+
SignaturesImpl.validateNonVoid(componentSignature);
425481
if (componentSignature instanceof SignaturesImpl.ArrayTypeSigImpl arr) {
426482
if (dims < 1 || dims > 255 - arr.arrayDepth())
427483
throw new IllegalArgumentException("illegal array depth value");
@@ -469,10 +525,12 @@ public sealed interface TypeParam
469525
* @param identifier the name of the type parameter
470526
* @param classBound the class bound of the type parameter, may be {@code null}
471527
* @param interfaceBounds the interface bounds of the type parameter
528+
* @throws IllegalArgumentException if the name cannot be {@linkplain
529+
* Signature##identifier denoted}
472530
*/
473531
public static TypeParam of(String identifier, RefTypeSig classBound, RefTypeSig... interfaceBounds) {
474532
return new SignaturesImpl.TypeParamImpl(
475-
requireNonNull(identifier),
533+
SignaturesImpl.validateIdentifier(identifier),
476534
Optional.ofNullable(classBound),
477535
List.of(interfaceBounds));
478536
}
@@ -483,10 +541,12 @@ public static TypeParam of(String identifier, RefTypeSig classBound, RefTypeSig.
483541
* @param identifier the name of the type parameter
484542
* @param classBound the optional class bound of the type parameter
485543
* @param interfaceBounds the interface bounds of the type parameter
544+
* @throws IllegalArgumentException if the name cannot be {@linkplain
545+
* Signature##identifier denoted}
486546
*/
487547
public static TypeParam of(String identifier, Optional<RefTypeSig> classBound, RefTypeSig... interfaceBounds) {
488548
return new SignaturesImpl.TypeParamImpl(
489-
requireNonNull(identifier),
549+
SignaturesImpl.validateIdentifier(identifier),
490550
requireNonNull(classBound),
491551
List.of(interfaceBounds));
492552
}

src/java.base/share/classes/jdk/internal/classfile/impl/ClassRemapperImpl.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2023, 2025, 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
@@ -309,7 +309,7 @@ <S extends Signature> S mapSignature(S signature) {
309309
case Signature.ClassTypeSig cts ->
310310
Signature.ClassTypeSig.of(
311311
cts.outerType().map(this::mapSignature).orElse(null),
312-
map(cts.classDesc()),
312+
Util.toInternalName(map(cts.classDesc())),
313313
cts.typeArgs().stream().map(ta -> switch (ta) {
314314
case Signature.TypeArg.Unbounded u -> u;
315315
case Signature.TypeArg.Bounded bta -> Signature.TypeArg.bounded(

src/java.base/share/classes/jdk/internal/classfile/impl/SignaturesImpl.java

Lines changed: 78 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2022, 2025, 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
@@ -73,7 +73,7 @@ public MethodSignature parseMethodSignature() {
7373
while (!match(')')) {
7474
if (paramTypes == null)
7575
paramTypes = new ArrayList<>();
76-
paramTypes.add(typeSig());
76+
paramTypes.add(validateNonVoid(typeSig()));
7777
}
7878
Signature returnType = typeSig();
7979
ArrayList<ThrowableSig> throwsTypes = null;
@@ -226,13 +226,9 @@ private void require(char c) {
226226
*/
227227
private int requireIdentifier() {
228228
int start = sigp;
229-
l:
230229
while (sigp < sig.length()) {
231-
switch (sig.charAt(sigp)) {
232-
case '.', ';', '[', '/', '<', '>', ':' -> {
233-
break l;
234-
}
235-
}
230+
if (isNonIdentifierChar(sig.charAt(sigp)))
231+
break;
236232
sigp++;
237233
}
238234
if (start == sigp) {
@@ -241,6 +237,77 @@ private int requireIdentifier() {
241237
return sigp;
242238
}
243239

240+
// Non-identifier chars in ascii 0 to 63, note [ is larger
241+
private static final long SMALL_NON_IDENTIFIER_CHARS_SET = (1L << '.')
242+
| (1L << ';')
243+
| (1L << '/')
244+
| (1L << '<')
245+
| (1L << '>')
246+
| (1L << ':');
247+
248+
private static boolean isNonIdentifierChar(char c) {
249+
return c < Long.SIZE ? (SMALL_NON_IDENTIFIER_CHARS_SET & (1L << c)) != 0 : c == '[';
250+
}
251+
252+
/// {@return exclusive end of the next identifier}
253+
public static int nextIdentifierEnd(String st, int start) {
254+
int end = st.length();
255+
for (int i = start; i < end; i++) {
256+
if (isNonIdentifierChar(st.charAt(i))) {
257+
return i;
258+
}
259+
}
260+
return end;
261+
}
262+
263+
/// Validates this string as a simple identifier.
264+
public static String validateIdentifier(String st) {
265+
var len = st.length(); // implicit null check
266+
if (len == 0 || nextIdentifierEnd(st, 0) != len) {
267+
throw new IllegalArgumentException("Not a valid identifier: " + st);
268+
}
269+
return st;
270+
}
271+
272+
/// Validates this string as slash-separated one or more identifiers.
273+
public static String validatePackageSpecifierPlusIdentifier(String st) {
274+
int nextIdentifierStart = 0;
275+
int len = st.length();
276+
while (nextIdentifierStart < len) {
277+
int end = nextIdentifierEnd(st, nextIdentifierStart);
278+
if (end == len)
279+
return st;
280+
if (end == nextIdentifierStart || st.charAt(end) != '/')
281+
throw new IllegalArgumentException("Not a class name: " + st);
282+
nextIdentifierStart = end + 1;
283+
}
284+
// Couldn't get an identifier initially or after a separator.
285+
throw new IllegalArgumentException("Not a class name: " + st);
286+
}
287+
288+
/// Validates the signature to be non-void (a valid field type).
289+
public static Signature validateNonVoid(Signature incoming) {
290+
Objects.requireNonNull(incoming);
291+
if (incoming instanceof Signature.BaseTypeSig baseType && baseType.baseType() == 'V')
292+
throw new IllegalArgumentException("void");
293+
return incoming;
294+
}
295+
296+
/// Returns the validated immutable argument list or fails with IAE.
297+
public static List<Signature> validateArgumentList(Signature[] signatures) {
298+
return validateArgumentList(List.of(signatures));
299+
}
300+
301+
/// Returns the validated immutable argument list or fails with IAE.
302+
public static List<Signature> validateArgumentList(List<Signature> signatures) {
303+
var res = List.copyOf(signatures); // deep null checks
304+
for (var sig : signatures) {
305+
if (sig instanceof Signature.BaseTypeSig baseType && baseType.baseType() == 'V')
306+
throw new IllegalArgumentException("void");
307+
}
308+
return res;
309+
}
310+
244311
public static record BaseTypeSigImpl(char baseType) implements Signature.BaseTypeSig {
245312

246313
@Override
@@ -316,13 +383,13 @@ public static record TypeParamImpl(String identifier, Optional<RefTypeSig> class
316383

317384
private static StringBuilder printTypeParameters(List<TypeParam> typeParameters) {
318385
var sb = new StringBuilder();
319-
if (typeParameters != null && !typeParameters.isEmpty()) {
386+
if (!typeParameters.isEmpty()) {
320387
sb.append('<');
321388
for (var tp : typeParameters) {
322389
sb.append(tp.identifier()).append(':');
323390
if (tp.classBound().isPresent())
324391
sb.append(tp.classBound().get().signatureString());
325-
if (tp.interfaceBounds() != null) for (var is : tp.interfaceBounds())
392+
for (var is : tp.interfaceBounds())
326393
sb.append(':').append(is.signatureString());
327394
}
328395
sb.append('>');
@@ -337,7 +404,7 @@ public static record ClassSignatureImpl(List<TypeParam> typeParameters, ClassTyp
337404
public String signatureString() {
338405
var sb = printTypeParameters(typeParameters);
339406
sb.append(superclassSignature.signatureString());
340-
if (superinterfaceSignatures != null) for (var in : superinterfaceSignatures)
407+
for (var in : superinterfaceSignatures)
341408
sb.append(in.signatureString());
342409
return sb.toString();
343410
}

0 commit comments

Comments
 (0)