Skip to content

Commit 619eefa

Browse files
sbrannenBenjamin Reed
authored andcommitted
Improve diagnostics in SpEL for large array creation
Attempting to create a large array in a SpEL expression can result in an OutOfMemoryError. Although the JVM recovers from that, the error message is not very helpful to the user. This commit improves the diagnostics in SpEL for large array creation by throwing a SpelEvaluationException with a meaningful error message in order to improve diagnostics for the user. Closes spring-projectsgh-28257
1 parent 39094e3 commit 619eefa

File tree

2 files changed

+30
-5
lines changed

2 files changed

+30
-5
lines changed

spring-expression/src/main/java/org/springframework/expression/spel/SpelMessage.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -31,6 +31,7 @@
3131
*
3232
* @author Andy Clement
3333
* @author Juergen Hoeller
34+
* @author Sam Brannen
3435
* @since 3.0
3536
*/
3637
public enum SpelMessage {
@@ -255,7 +256,11 @@ public enum SpelMessage {
255256

256257
/** @since 4.3.17 */
257258
FLAWED_PATTERN(Kind.ERROR, 1073,
258-
"Failed to efficiently evaluate pattern ''{0}'': consider redesigning it");
259+
"Failed to efficiently evaluate pattern ''{0}'': consider redesigning it"),
260+
261+
/** @since 5.2.20 */
262+
MAX_ARRAY_ELEMENTS_THRESHOLD_EXCEEDED(Kind.ERROR, 1075,
263+
"Array declares too many elements, exceeding the threshold of ''{0}''");
259264

260265

261266
private final Kind kind;

spring-expression/src/main/java/org/springframework/expression/spel/ast/ConstructorReference.java

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -51,11 +51,19 @@
5151
*
5252
* @author Andy Clement
5353
* @author Juergen Hoeller
54+
* @author Sam Brannen
5455
* @since 3.0
5556
*/
5657
public class ConstructorReference extends SpelNodeImpl {
5758

58-
private boolean isArrayConstructor = false;
59+
/**
60+
* Maximum number of elements permitted in an array declaration, applying
61+
* to one-dimensional as well as multi-dimensional arrays.
62+
* @since 5.2.20
63+
*/
64+
private static final int MAX_ARRAY_ELEMENTS = 256 * 1024; // 256K
65+
66+
private final boolean isArrayConstructor;
5967

6068
private SpelNodeImpl[] dimensions;
6169

@@ -256,14 +264,19 @@ private TypedValue createArray(ExpressionState state) throws EvaluationException
256264
if (this.dimensions.length == 1) {
257265
TypedValue o = this.dimensions[0].getTypedValue(state);
258266
int arraySize = ExpressionUtils.toInt(typeConverter, o);
267+
checkNumElements(arraySize);
259268
newArray = Array.newInstance(componentType, arraySize);
260269
}
261270
else {
262271
// Multi-dimensional - hold onto your hat!
263272
int[] dims = new int[this.dimensions.length];
273+
long numElements = 1;
264274
for (int d = 0; d < this.dimensions.length; d++) {
265275
TypedValue o = this.dimensions[d].getTypedValue(state);
266-
dims[d] = ExpressionUtils.toInt(typeConverter, o);
276+
int arraySize = ExpressionUtils.toInt(typeConverter, o);
277+
dims[d] = arraySize;
278+
numElements *= arraySize;
279+
checkNumElements(numElements);
267280
}
268281
newArray = Array.newInstance(componentType, dims);
269282
}
@@ -323,6 +336,13 @@ else if (arrayTypeCode == TypeCode.SHORT) {
323336
return new TypedValue(newArray);
324337
}
325338

339+
private void checkNumElements(long numElements) {
340+
if (numElements >= MAX_ARRAY_ELEMENTS) {
341+
throw new SpelEvaluationException(getStartPosition(),
342+
SpelMessage.MAX_ARRAY_ELEMENTS_THRESHOLD_EXCEEDED, MAX_ARRAY_ELEMENTS);
343+
}
344+
}
345+
326346
private void populateReferenceTypeArray(ExpressionState state, Object newArray, TypeConverter typeConverter,
327347
InlineList initializer, Class<?> componentType) {
328348

0 commit comments

Comments
 (0)