Skip to content

Commit f9aec02

Browse files
committedJan 2, 2024
8321540: ClassSignature.parseFrom() throws StringIndexOutOfBoundsException for invalid signatures
Reviewed-by: jpai
1 parent 7455b1b commit f9aec02

File tree

2 files changed

+131
-33
lines changed

2 files changed

+131
-33
lines changed
 

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

+51-32
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2022, 2024, 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
@@ -44,49 +44,64 @@ public SignaturesImpl() {
4444
public ClassSignature parseClassSignature(String signature) {
4545
this.sig = signature;
4646
sigp = 0;
47-
List<TypeParam> typeParamTypes = parseParamTypes();
48-
RefTypeSig superclass = referenceTypeSig();
49-
ArrayList<RefTypeSig> superinterfaces = null;
50-
while (sigp < sig.length()) {
51-
if (superinterfaces == null)
52-
superinterfaces = new ArrayList<>();
53-
superinterfaces.add(referenceTypeSig());
47+
try {
48+
List<TypeParam> typeParamTypes = parseParamTypes();
49+
RefTypeSig superclass = referenceTypeSig();
50+
ArrayList<RefTypeSig> superinterfaces = null;
51+
while (sigp < sig.length()) {
52+
if (superinterfaces == null)
53+
superinterfaces = new ArrayList<>();
54+
superinterfaces.add(referenceTypeSig());
55+
}
56+
return new ClassSignatureImpl(typeParamTypes, superclass, null2Empty(superinterfaces));
57+
} catch (IndexOutOfBoundsException e) {
58+
throw error("Not a valid class signature");
5459
}
55-
return new ClassSignatureImpl(typeParamTypes, superclass, null2Empty(superinterfaces));
5660
}
5761

5862
public MethodSignature parseMethodSignature(String signature) {
5963
this.sig = signature;
6064
sigp = 0;
61-
List<TypeParam> typeParamTypes = parseParamTypes();
62-
assert sig.charAt(sigp) == '(';
63-
sigp++;
64-
ArrayList<Signature> paramTypes = null;
65-
while (sig.charAt(sigp) != ')') {
66-
if (paramTypes == null)
67-
paramTypes = new ArrayList<>();
68-
paramTypes.add(typeSig());
69-
}
70-
sigp++;
71-
Signature returnType = typeSig();
72-
ArrayList<ThrowableSig> throwsTypes = null;
73-
while (sigp < sig.length() && sig.charAt(sigp) == '^') {
65+
try {
66+
List<TypeParam> typeParamTypes = parseParamTypes();
67+
if (sig.charAt(sigp) != '(') throw error("Expected ( at possition %d of signature".formatted(sigp));
68+
sigp++;
69+
ArrayList<Signature> paramTypes = null;
70+
while (sig.charAt(sigp) != ')') {
71+
if (paramTypes == null)
72+
paramTypes = new ArrayList<>();
73+
paramTypes.add(typeSig());
74+
}
7475
sigp++;
75-
if (throwsTypes == null)
76-
throwsTypes = new ArrayList<>();
77-
var t = typeSig();
78-
if (t instanceof ThrowableSig ts)
79-
throwsTypes.add(ts);
80-
else
81-
throw new IllegalArgumentException("not a valid type signature: " + sig);
76+
Signature returnType = typeSig();
77+
ArrayList<ThrowableSig> throwsTypes = null;
78+
while (sigp < sig.length()) {
79+
if (sig.charAt(sigp) != '^') throw error("Expected ^ at possition %d of signature".formatted(sigp));
80+
sigp++;
81+
if (throwsTypes == null)
82+
throwsTypes = new ArrayList<>();
83+
var t = referenceTypeSig();
84+
if (t instanceof ThrowableSig ts)
85+
throwsTypes.add(ts);
86+
else
87+
throw error("Not a valid throwable signature %s in".formatted(t.signatureString()));
88+
}
89+
return new MethodSignatureImpl(typeParamTypes, null2Empty(throwsTypes), returnType, null2Empty(paramTypes));
90+
} catch (IndexOutOfBoundsException e) {
91+
throw error("Not a valid method signature");
8292
}
83-
return new MethodSignatureImpl(typeParamTypes, null2Empty(throwsTypes), returnType, null2Empty(paramTypes));
8493
}
8594

8695
public Signature parseSignature(String signature) {
8796
this.sig = signature;
8897
sigp = 0;
89-
return typeSig();
98+
try {
99+
var s = typeSig();
100+
if (sigp == signature.length())
101+
return s;
102+
} catch (IndexOutOfBoundsException e) {
103+
}
104+
throw error("Not a valid type signature");
90105
}
91106

92107
private List<TypeParam> parseParamTypes() {
@@ -157,7 +172,7 @@ private RefTypeSig referenceTypeSig() {
157172
return ty;
158173
case '[': return ArrayTypeSig.of(typeSig());
159174
}
160-
throw new IllegalArgumentException("not a valid type signature: " + sig);
175+
throw error("Unexpected character %c at possition %d of signature".formatted(c, sigp - 1));
161176
}
162177

163178
private TypeArg typeArg() {
@@ -292,4 +307,8 @@ public String signatureString() {
292307
private static <T> List<T> null2Empty(ArrayList<T> l) {
293308
return l == null ? List.of() : Collections.unmodifiableList(l);
294309
}
310+
311+
private IllegalArgumentException error(String message) {
312+
return new IllegalArgumentException("%s: %s".formatted(message, sig));
313+
}
295314
}

‎test/jdk/jdk/classfile/SignaturesTest.java

+80-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2022, 2024, 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
@@ -24,6 +24,7 @@
2424
/*
2525
* @test
2626
* @summary Testing Signatures.
27+
* @bug 8321540
2728
* @run junit SignaturesTest
2829
*/
2930
import java.io.IOException;
@@ -46,8 +47,11 @@
4647
import java.lang.classfile.Attributes;
4748
import org.junit.jupiter.api.Test;
4849
import static org.junit.jupiter.api.Assertions.assertEquals;
50+
import org.junit.jupiter.api.Assertions;
4951
import static helpers.ClassRecord.assertEqualsDeep;
5052
import static java.lang.constant.ConstantDescs.*;
53+
import java.util.function.Consumer;
54+
import java.util.function.Function;
5155

5256
class SignaturesTest {
5357

@@ -186,4 +190,79 @@ void testClassSignatureClassDesc() throws IOException {
186190
assertEquals(Outer.Inner.class.describeConstable().orElseThrow(), innerSig.classDesc(),
187191
"ClassDesc derived from signature");
188192
}
193+
194+
@Test
195+
void testBadTypeSignatures() {
196+
"""
197+
LObject
198+
LObject;B
199+
LIterable<LFoo>
200+
LIterable<<
201+
TBar
202+
TBar<LFoo;>
203+
B<LFoo;>
204+
B<LFoo;>;V
205+
X
206+
[LObject
207+
[LIterable<LFoo>
208+
[LIterable<<
209+
[TBar
210+
[TBar<LFoo;>
211+
[B<LFoo;>
212+
[X
213+
LSet<+Kind<**>;>;
214+
LSet<?Kind<*>;>;
215+
()V
216+
""".lines().forEach(assertThrows(Signature::parseFrom));
217+
}
218+
219+
@Test
220+
void testBadClassSignatures() {
221+
"""
222+
Ljava/lang/Object;Ljava/lang/Iterable<LFoo;>
223+
LObject
224+
LObject;B
225+
LIterable<LFoo>
226+
LIterable<<
227+
TBar
228+
TBar<LFoo;>
229+
B<LFoo;>
230+
B<LFoo;>;V
231+
X
232+
LFoo<TK;>.It;L
233+
<K+LObject;>LFoo<TK;;>;LFoo<TK;>;LBar;
234+
<K:LObject;>>LFoo<TK;>;
235+
<K:LObject;>LFoo<+>;
236+
()V
237+
""".lines().forEach(assertThrows(ClassSignature::parseFrom));
238+
}
239+
240+
@Test
241+
void testBadMethodSignatures() {
242+
"""
243+
LObject;
244+
B
245+
()V^
246+
()V^B
247+
()V^X
248+
(LObject;)
249+
(LObject)V
250+
()LIterable<LFoo>
251+
()LIterable<<
252+
()TBar
253+
()TBar;B
254+
(TBar<LFoo;>)V
255+
(B<LFoo;>)V
256+
(X)
257+
()X
258+
()VB
259+
()LSet<+Kind<**>;>;
260+
(LSet<?Kind<*>;>;)V
261+
<T::LA>()V
262+
""".lines().forEach(assertThrows(MethodSignature::parseFrom));
263+
}
264+
265+
private Consumer<String> assertThrows(Function<String, ?> parser) {
266+
return s -> Assertions.assertThrows(IllegalArgumentException.class, () -> parser.apply(s), s);
267+
}
189268
}

0 commit comments

Comments
 (0)
Please sign in to comment.