Browse Source

Improve diagnostics for repeated text size overflow in SpEL

If the resulting size of repeated text in a SpEL expression (using the
repeat operator '*') would exceed MAX_REPEATED_TEXT_SIZE, we currently
throw a SpelEvaluationException with the
MAX_REPEATED_TEXT_SIZE_EXCEEDED message.

However, if the calculation of the repeated text size results in
integer overflow, our max size check fails to detect that, and
String#repeat(int) throws a preemptive OutOfMemoryError from which the
application immediately recovers.

To improve diagnostics for users, this commit ensures that we
consistently throw a SpelEvaluationException with the
MAX_REPEATED_TEXT_SIZE_EXCEEDED message when integer overflow occurs.

Closes gh-31341
pull/31346/head
Sam Brannen 3 years ago
parent
commit
8e83f93bcb
  1. 3
      spring-expression/src/main/java/org/springframework/expression/spel/ast/OpMultiply.java
  2. 6
      spring-expression/src/test/java/org/springframework/expression/spel/OperatorTests.java

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

@ -123,7 +123,8 @@ public class OpMultiply extends Operator { @@ -123,7 +123,8 @@ public class OpMultiply extends Operator {
}
private void checkRepeatedTextSize(String text, int count) {
if (text.length() * count > MAX_REPEATED_TEXT_SIZE) {
int result = text.length() * count;
if (result < 0 || result > MAX_REPEATED_TEXT_SIZE) {
throw new SpelEvaluationException(getStartPosition(),
SpelMessage.MAX_REPEATED_TEXT_SIZE_EXCEEDED, MAX_REPEATED_TEXT_SIZE);
}

6
spring-expression/src/test/java/org/springframework/expression/spel/OperatorTests.java

@ -579,6 +579,12 @@ class OperatorTests extends AbstractExpressionTests { @@ -579,6 +579,12 @@ class OperatorTests extends AbstractExpressionTests {
// 4 is the position of the '*' (repeat operator)
evaluateAndCheckError("'a' * 257", String.class, MAX_REPEATED_TEXT_SIZE_EXCEEDED, 4);
// Integer overflow: 2 * ((Integer.MAX_VALUE / 2) + 1) --> integer overflow
int repeatCount = (Integer.MAX_VALUE / 2) + 1;
assertThat(2 * repeatCount).isNegative();
// 5 is the position of the '*' (repeat operator)
evaluateAndCheckError("'ab' * " + repeatCount, String.class, MAX_REPEATED_TEXT_SIZE_EXCEEDED, 5);
}
@Test

Loading…
Cancel
Save