Signed-off-by: 张梁鹏堃 <zhangliangpengkun@xfusion.com> (cherry picked from commit dd2fbc5fd455392514ca6491c65f70d3680d4455)
143 lines
6.7 KiB
Diff
143 lines
6.7 KiB
Diff
From 12c3f4129dffdc9a120419cb51dff7f7a511174c Mon Sep 17 00:00:00 2001
|
|
From: sbrannen
|
|
Date: Tue, 1 Nov 2022 19:58:40 +0800
|
|
Subject: [PATCH] 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.
|
|
|
|
---
|
|
.../expression/spel/SpelMessage.java | 16 +++++++++++--
|
|
.../spel/ast/ConstructorReference.java | 24 +++++++++++++++++--
|
|
.../spel/ArrayConstructorTests.java | 4 ++++
|
|
3 files changed, 40 insertions(+), 4 deletions(-)
|
|
|
|
diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/SpelMessage.java b/spring-expression/src/main/java/org/springframework/expression/spel/SpelMessage.java
|
|
index 9a42cedb..0cf93915 100644
|
|
--- a/spring-expression/src/main/java/org/springframework/expression/spel/SpelMessage.java
|
|
+++ b/spring-expression/src/main/java/org/springframework/expression/spel/SpelMessage.java
|
|
@@ -1,5 +1,5 @@
|
|
/*
|
|
- * Copyright 2002-2014 the original author or authors.
|
|
+ * Copyright 2002-2022 the original author or authors.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
@@ -34,6 +34,7 @@ import java.text.MessageFormat;
|
|
* if it is known.
|
|
*
|
|
* @author Andy Clement
|
|
+ * @author Sam Brannen
|
|
* @since 3.0
|
|
*/
|
|
public enum SpelMessage {
|
|
@@ -108,8 +109,19 @@ public enum SpelMessage {
|
|
NOT_ASSIGNABLE(Kind.ERROR,1068,"the expression component ''{0}'' is not assignable"),
|
|
MISSING_CHARACTER(Kind.ERROR,1069,"missing expected character ''{0}''"),
|
|
LEFT_OPERAND_PROBLEM(Kind.ERROR,1070, "Problem parsing left operand"),
|
|
- MISSING_SELECTION_EXPRESSION(Kind.ERROR, 1071, "A required selection expression has not been specified");
|
|
+ MISSING_SELECTION_EXPRESSION(Kind.ERROR, 1071, "A required selection expression has not been specified"),
|
|
|
|
+ /** @since 4.1 */
|
|
+ EXCEPTION_RUNNING_COMPILED_EXPRESSION(Kind.ERROR, 1072,
|
|
+ "An exception occurred whilst evaluating a compiled expression"),
|
|
+
|
|
+ /** @since 4.3.17 */
|
|
+ FLAWED_PATTERN(Kind.ERROR, 1073,
|
|
+ "Failed to efficiently evaluate pattern ''{0}'': consider redesigning it"),
|
|
+
|
|
+ /** @since 5.2.20 */
|
|
+ MAX_ARRAY_ELEMENTS_THRESHOLD_EXCEEDED(Kind.ERROR, 1075,
|
|
+ "Array declares too many elements, exceeding the threshold of ''{0}''");
|
|
|
|
private final Kind kind;
|
|
|
|
diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/ConstructorReference.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/ConstructorReference.java
|
|
index c6a25931..4ede5ac3 100644
|
|
--- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/ConstructorReference.java
|
|
+++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/ConstructorReference.java
|
|
@@ -1,5 +1,5 @@
|
|
/*
|
|
- * Copyright 2002-2012 the original author or authors.
|
|
+ * Copyright 2002-2022 the original author or authors.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
@@ -47,12 +47,20 @@ import org.springframework.expression.spel.SpelNode;
|
|
*
|
|
* @author Andy Clement
|
|
* @author Juergen Hoeller
|
|
+ * @author Sam Brannen
|
|
* @since 3.0
|
|
*/
|
|
public class ConstructorReference extends SpelNodeImpl {
|
|
|
|
private boolean isArrayConstructor = false;
|
|
|
|
+ /**
|
|
+ * Maximum number of elements permitted in an array declaration, applying
|
|
+ * to one-dimensional as well as multi-dimensional arrays.
|
|
+ * @since 5.2.20
|
|
+ */
|
|
+ private static final int MAX_ARRAY_ELEMENTS = 256 * 1024; // 256K
|
|
+
|
|
private SpelNodeImpl[] dimensions;
|
|
|
|
// TODO is this caching safe - passing the expression around will mean this executor is also being passed around
|
|
@@ -247,14 +255,19 @@ public class ConstructorReference extends SpelNodeImpl {
|
|
if (this.dimensions.length == 1) {
|
|
TypedValue o = this.dimensions[0].getTypedValue(state);
|
|
int arraySize = ExpressionUtils.toInt(typeConverter, o);
|
|
+ checkNumElements(arraySize);
|
|
newArray = Array.newInstance(componentType, arraySize);
|
|
}
|
|
else {
|
|
// Multi-dimensional - hold onto your hat!
|
|
int[] dims = new int[this.dimensions.length];
|
|
+ long numElements = 1;
|
|
for (int d = 0; d < this.dimensions.length; d++) {
|
|
TypedValue o = this.dimensions[d].getTypedValue(state);
|
|
- dims[d] = ExpressionUtils.toInt(typeConverter, o);
|
|
+ int arraySize = ExpressionUtils.toInt(typeConverter, o);
|
|
+ dims[d] = arraySize;
|
|
+ numElements *= arraySize;
|
|
+ checkNumElements(numElements);
|
|
}
|
|
newArray = Array.newInstance(componentType, dims);
|
|
}
|
|
@@ -314,6 +327,13 @@ public class ConstructorReference extends SpelNodeImpl {
|
|
return new TypedValue(newArray);
|
|
}
|
|
|
|
+ private void checkNumElements(long numElements) {
|
|
+ if (numElements >= MAX_ARRAY_ELEMENTS) {
|
|
+ throw new SpelEvaluationException(getStartPosition(),
|
|
+ SpelMessage.MAX_ARRAY_ELEMENTS_THRESHOLD_EXCEEDED, MAX_ARRAY_ELEMENTS);
|
|
+ }
|
|
+ }
|
|
+
|
|
private void populateReferenceTypeArray(ExpressionState state, Object newArray, TypeConverter typeConverter,
|
|
InlineList initializer, Class<?> componentType) {
|
|
TypeDescriptor toTypeDescriptor = TypeDescriptor.valueOf(componentType);
|
|
diff --git a/spring-expression/src/test/java/org/springframework/expression/spel/ArrayConstructorTests.java b/spring-expression/src/test/java/org/springframework/expression/spel/ArrayConstructorTests.java
|
|
index 16671155..d1ce52f8 100644
|
|
--- a/spring-expression/src/test/java/org/springframework/expression/spel/ArrayConstructorTests.java
|
|
+++ b/spring-expression/src/test/java/org/springframework/expression/spel/ArrayConstructorTests.java
|
|
@@ -80,6 +80,10 @@ public class ArrayConstructorTests extends ExpressionTestCase {
|
|
evaluateAndCheckError("new char[3]{'a','c','d','e'}", SpelMessage.INITIALIZER_LENGTH_INCORRECT);
|
|
evaluateAndCheckError("new char[2]{'hello','world'}", SpelMessage.TYPE_CONVERSION_ERROR);
|
|
evaluateAndCheckError("new String('a','c','d')", SpelMessage.CONSTRUCTOR_INVOCATION_PROBLEM);
|
|
+
|
|
+ int threshold = 256 * 1024; // ConstructorReference.MAX_ARRAY_ELEMENTS
|
|
+ evaluateAndCheckError("new int[T(java.lang.Integer).MAX_VALUE]", SpelMessage.MAX_ARRAY_ELEMENTS_THRESHOLD_EXCEEDED, 0, threshold);
|
|
+ evaluateAndCheckError("new int[1024 * 1024][1024 * 1024]", SpelMessage.MAX_ARRAY_ELEMENTS_THRESHOLD_EXCEEDED, 0, threshold);
|
|
}
|
|
|
|
@Test
|
|
--
|
|
2.27.0
|