@@ -14,6 +14,22 @@ public class TypeParser
14
14
{
15
15
private static final long serialVersionUID = 1L ;
16
16
17
+ /**
18
+ * Maximum length of canonical type definition we will try to parse.
19
+ * Used as protection for malformed generic type declarations.
20
+ *
21
+ * @since 2.16
22
+ */
23
+ protected static final int MAX_TYPE_LENGTH = 64_000 ;
24
+
25
+ /**
26
+ * Maximum levels of nesting allowed for parameterized types.
27
+ * Used as protection for malformed generic type declarations.
28
+ *
29
+ * @since 2.16
30
+ */
31
+ protected static final int MAX_TYPE_NESTING = 1000 ;
32
+
17
33
protected final TypeFactory _factory ;
18
34
19
35
public TypeParser (TypeFactory f ) {
@@ -29,16 +45,24 @@ public TypeParser withFactory(TypeFactory f) {
29
45
30
46
public JavaType parse (String canonical ) throws IllegalArgumentException
31
47
{
48
+ if (canonical .length () > MAX_TYPE_LENGTH ) {
49
+ throw new IllegalArgumentException (String .format (
50
+ "Failed to parse type %s: too long (%d characters), maximum length allowed: %d" ,
51
+ _quoteTruncated (canonical ),
52
+ canonical .length (),
53
+ MAX_TYPE_LENGTH ));
54
+
55
+ }
32
56
MyTokenizer tokens = new MyTokenizer (canonical .trim ());
33
- JavaType type = parseType (tokens );
57
+ JavaType type = parseType (tokens , MAX_TYPE_NESTING );
34
58
// must be end, now
35
59
if (tokens .hasMoreTokens ()) {
36
60
throw _problem (tokens , "Unexpected tokens after complete type" );
37
61
}
38
62
return type ;
39
63
}
40
64
41
- protected JavaType parseType (MyTokenizer tokens )
65
+ protected JavaType parseType (MyTokenizer tokens , int nestingAllowed )
42
66
throws IllegalArgumentException
43
67
{
44
68
if (!tokens .hasMoreTokens ()) {
@@ -50,7 +74,7 @@ protected JavaType parseType(MyTokenizer tokens)
50
74
if (tokens .hasMoreTokens ()) {
51
75
String token = tokens .nextToken ();
52
76
if ("<" .equals (token )) {
53
- List <JavaType > parameterTypes = parseTypes (tokens );
77
+ List <JavaType > parameterTypes = parseTypes (tokens , nestingAllowed - 1 );
54
78
TypeBindings b = TypeBindings .create (base , parameterTypes );
55
79
return _factory ._fromClass (null , base , b );
56
80
}
@@ -60,12 +84,16 @@ protected JavaType parseType(MyTokenizer tokens)
60
84
return _factory ._fromClass (null , base , TypeBindings .emptyBindings ());
61
85
}
62
86
63
- protected List <JavaType > parseTypes (MyTokenizer tokens )
87
+ protected List <JavaType > parseTypes (MyTokenizer tokens , int nestingAllowed )
64
88
throws IllegalArgumentException
65
89
{
90
+ if (nestingAllowed < 0 ) {
91
+ throw _problem (tokens , "too deeply nested; exceeds maximum of "
92
+ +MAX_TYPE_NESTING +" nesting levels" );
93
+ }
66
94
ArrayList <JavaType > types = new ArrayList <JavaType >();
67
95
while (tokens .hasMoreTokens ()) {
68
- types .add (parseType (tokens ));
96
+ types .add (parseType (tokens , nestingAllowed ));
69
97
if (!tokens .hasMoreTokens ()) break ;
70
98
String token = tokens .nextToken ();
71
99
if (">" .equals (token )) return types ;
@@ -88,10 +116,20 @@ protected Class<?> findClass(String className, MyTokenizer tokens)
88
116
89
117
protected IllegalArgumentException _problem (MyTokenizer tokens , String msg )
90
118
{
91
- return new IllegalArgumentException (String .format ("Failed to parse type '%s' (remaining: '%s'): %s" ,
92
- tokens .getAllInput (), tokens .getRemainingInput (), msg ));
119
+ return new IllegalArgumentException (String .format ("Failed to parse type %s (remaining: %s): %s" ,
120
+ _quoteTruncated (tokens .getAllInput ()),
121
+ _quoteTruncated (tokens .getRemainingInput ()),
122
+ msg ));
93
123
}
94
124
125
+ private static String _quoteTruncated (String str ) {
126
+ if (str .length () <= 1000 ) {
127
+ return "'" +str +"'" ;
128
+ }
129
+ return String .format ("'%s...'[truncated %d charaters]" ,
130
+ str .substring (0 , 1000 ), str .length () - 1000 );
131
+ }
132
+
95
133
final static class MyTokenizer extends StringTokenizer
96
134
{
97
135
protected final String _input ;
0 commit comments