diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpMultiply.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpMultiply.java index 75a5bb10ccc..4952d24fa64 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpMultiply.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpMultiply.java @@ -127,9 +127,9 @@ public class OpMultiply extends Operator { throw new SpelEvaluationException(getStartPosition(), SpelMessage.NEGATIVE_REPEATED_TEXT_COUNT, count); } - int result = text.length() * count; + long result = (long) text.length() * (long) count; if (result < 0 || result > MAX_REPEATED_TEXT_SIZE) { - throw new SpelEvaluationException(getStartPosition(), + throw new SpelEvaluationException(getRightOperand().getStartPosition(), SpelMessage.MAX_REPEATED_TEXT_SIZE_EXCEEDED, MAX_REPEATED_TEXT_SIZE); } } diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpPlus.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpPlus.java index fe04f8cf9e8..bfd171784c8 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpPlus.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpPlus.java @@ -153,16 +153,19 @@ public class OpPlus extends Operator { } private void checkStringLength(String string) { - if (string.length() > MAX_CONCATENATED_STRING_LENGTH) { + checkStringLength(string.length()); + } + + private void checkStringLength(int stringLength) { + if (stringLength > MAX_CONCATENATED_STRING_LENGTH) { throw new SpelEvaluationException(getStartPosition(), SpelMessage.MAX_CONCATENATED_STRING_LENGTH_EXCEEDED, MAX_CONCATENATED_STRING_LENGTH); } } private TypedValue concatenate(String leftString, String rightString) { - String result = leftString + rightString; - checkStringLength(result); - return new TypedValue(result); + checkStringLength(leftString.length() + rightString.length()); + return new TypedValue(leftString + rightString); } @Override diff --git a/spring-expression/src/test/java/org/springframework/expression/spel/OperatorTests.java b/spring-expression/src/test/java/org/springframework/expression/spel/OperatorTests.java index 2059be38634..aadc76ad90a 100644 --- a/spring-expression/src/test/java/org/springframework/expression/spel/OperatorTests.java +++ b/spring-expression/src/test/java/org/springframework/expression/spel/OperatorTests.java @@ -574,21 +574,26 @@ class OperatorTests extends AbstractExpressionTests { @Test void stringRepeat() { - evaluate("'abc' * 0", "", String.class); - evaluate("'abc' * 1", "abc", String.class); - evaluate("'abc' * 2", "abcabc", String.class); + String EMPTY = ""; + evaluate("'' * 0", EMPTY, String.class); + evaluate("'' * 2", EMPTY, String.class); + evaluate("'abc' * 0", EMPTY, String.class); + + evaluate("'Abc' * 1", "Abc", String.class); + evaluate("'Abc' * 2", "AbcAbc", String.class); + evaluate("'Abc' * 3", "AbcAbcAbc", String.class); Expression expr = parser.parseExpression("'a' * 256"); assertThat(expr.getValue(context, String.class)).hasSize(256); - // 4 is the position of the '*' (repeat operator) - evaluateAndCheckError("'a' * 257", String.class, MAX_REPEATED_TEXT_SIZE_EXCEEDED, 4); + // 6 is the position of the repeatCount + evaluateAndCheckError("'a' * 257", String.class, MAX_REPEATED_TEXT_SIZE_EXCEEDED, 6); // 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); + // 7 is the position of the repeatCount + evaluateAndCheckError("'ab' * " + repeatCount, String.class, MAX_REPEATED_TEXT_SIZE_EXCEEDED, 7); } @Test @@ -623,12 +628,19 @@ class OperatorTests extends AbstractExpressionTests { assertThat(expr.getValue(context, String.class)).hasSize(maxSize); // Text is too big + context.setVariable("text1", createString(maxSize)); + context.setVariable("text2", createString(maxSize)); + evaluateAndCheckError("#text1 + #text2", String.class, MAX_CONCATENATED_STRING_LENGTH_EXCEEDED, 7); + context.setVariable("text1", createString(maxSize + 1)); evaluateAndCheckError("#text1 + ''", String.class, MAX_CONCATENATED_STRING_LENGTH_EXCEEDED, 7); evaluateAndCheckError("#text1 + true", String.class, MAX_CONCATENATED_STRING_LENGTH_EXCEEDED, 7); evaluateAndCheckError("'' + #text1", String.class, MAX_CONCATENATED_STRING_LENGTH_EXCEEDED, 3); evaluateAndCheckError("true + #text1", String.class, MAX_CONCATENATED_STRING_LENGTH_EXCEEDED, 5); + context.setVariable("text1", createString(maxSize - 1)); + evaluateAndCheckError("#text1 + 'YZ'", String.class, MAX_CONCATENATED_STRING_LENGTH_EXCEEDED, 7); + context.setVariable("text1", createString(maxSize / 2)); context.setVariable("text2", createString((maxSize / 2) + 1)); evaluateAndCheckError("#text1 + #text2", String.class, MAX_CONCATENATED_STRING_LENGTH_EXCEEDED, 7);