This is an automated email from the ASF dual-hosted git repository.
garydgregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-lang.git
The following commit(s) were added to refs/heads/master by this push:
new 184c9e832 WordUtils.wrap() zero-width wrapOn regex match causes
infinite loop. (#1649)
184c9e832 is described below
commit 184c9e83211a0552698a934d45d3ebca2c789881
Author: Gary Gregory <[email protected]>
AuthorDate: Sun May 17 11:29:52 2026 -0400
WordUtils.wrap() zero-width wrapOn regex match causes infinite loop. (#1649)
---
src/main/java/org/apache/commons/lang3/text/WordUtils.java | 8 ++------
src/test/java/org/apache/commons/lang3/text/WordUtilsTest.java | 7 +++++++
2 files changed, 9 insertions(+), 6 deletions(-)
diff --git a/src/main/java/org/apache/commons/lang3/text/WordUtils.java
b/src/main/java/org/apache/commons/lang3/text/WordUtils.java
index ea6c2ad54..ae59a34e3 100644
--- a/src/main/java/org/apache/commons/lang3/text/WordUtils.java
+++ b/src/main/java/org/apache/commons/lang3/text/WordUtils.java
@@ -652,21 +652,19 @@ public static String wrap(final String str, int
wrapLength, String newLineStr, f
str.substring(offset, Math.min((int)
Math.min(Integer.MAX_VALUE, offset + wrapLength + 1L), inputLineLength)));
if (matcher.find()) {
if (matcher.start() == 0) {
- offset += matcher.end();
+ // If the match is zero-width, advance by at least 1 to
avoid infinite loop.
+ offset += matcher.end() > 0 ? matcher.end() : 1;
continue;
}
spaceToWrapAt = matcher.start() + offset;
}
-
// only last line without leading spaces is left
if (inputLineLength - offset <= wrapLength) {
break;
}
-
while (matcher.find()) {
spaceToWrapAt = matcher.start() + offset;
}
-
if (spaceToWrapAt >= offset) {
// normal case
wrappedLine.append(str, offset, spaceToWrapAt);
@@ -696,10 +694,8 @@ public static String wrap(final String str, int
wrapLength, String newLineStr, f
}
}
}
-
// Whatever is left in line is short enough to just pass through
wrappedLine.append(str, offset, str.length());
-
return wrappedLine.toString();
}
diff --git a/src/test/java/org/apache/commons/lang3/text/WordUtilsTest.java
b/src/test/java/org/apache/commons/lang3/text/WordUtilsTest.java
index e59a60567..e14b14cbf 100644
--- a/src/test/java/org/apache/commons/lang3/text/WordUtilsTest.java
+++ b/src/test/java/org/apache/commons/lang3/text/WordUtilsTest.java
@@ -20,10 +20,12 @@
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTimeout;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
+import java.time.Duration;
import org.apache.commons.lang3.AbstractLangTest;
import org.junit.jupiter.api.Test;
@@ -429,4 +431,9 @@ void testWrap_StringIntStringBooleanString() {
expected = "flammableinflam\nmable";
assertEquals(expected, WordUtils.wrap(input, 15, "\n", true, "/"));
}
+
+ @Test
+ void testZeroWidthWrapOnRegex() {
+ assertTimeout(Duration.ofSeconds(2), () ->
assertNotNull(WordUtils.wrap("abcdef", 3, "\n", false, "(?=a)")));
+ }
}