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 0ea3250df WordUtils.wrap(wrapLongWords=false, the 2-arg default) 
copies the entire remaining string every iteration (f009).
0ea3250df is described below

commit 0ea3250df71c74d68cbf30c7f52c641b63d146ee
Author: Gary Gregory <[email protected]>
AuthorDate: Sat Sep 5 08:00:36 2026 -0400

    WordUtils.wrap(wrapLongWords=false, the 2-arg default) copies the entire
    remaining string every iteration (f009).
    
    ~1 MB of crafted text costs ~45 GB of allocation churn.
---
 src/changes/changes.xml                                    |  1 +
 src/main/java/org/apache/commons/lang3/text/WordUtils.java | 12 ++++++++----
 2 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index ae949589c..e2e06396f 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -258,6 +258,7 @@ java.lang.NullPointerException: Cannot invoke
     <action                   type="fix" dev="ggregory" due-to="Gary 
Gregory">LocaleUtils static caches no longer grows on invalid input to 
LocaleUtils.countriesByLanguage(String) (f007).</action>
     <action                   type="fix" dev="ggregory" due-to="Gary 
Gregory">LocaleUtils static caches no longer grows on invalid input to 
LocaleUtils.countriesByLanguage(String) (f007).</action>
     <action                   type="fix" dev="ggregory" due-to="Gary 
Gregory">ExtendedMessageFormat.applyPattern() is quadratic: full 
pattern.toCharArray() per token (f008).</action>
+    <action                   type="fix" dev="ggregory" due-to="Gary 
Gregory">WordUtils.wrap(wrapLongWords=false, the 2-arg default) copies the 
entire remaining string every iteration. (f009).</action>
     <!-- ADD -->
     <action                   type="add" dev="ggregory" due-to="Gary 
Gregory">Add JavaVersion.JAVA_27.</action>
     <action                   type="add" dev="ggregory" due-to="Gary 
Gregory">Add SystemUtils.IS_JAVA_27.</action>
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 23b4f424b..a03a2b8b7 100644
--- a/src/main/java/org/apache/commons/lang3/text/WordUtils.java
+++ b/src/main/java/org/apache/commons/lang3/text/WordUtils.java
@@ -713,12 +713,16 @@ public static String wrap(final String str, int 
wrapLength, String newLineStr, f
                 wrappedLine.append(newLineStr);
                 offset = wrapAt;
             } else {
-                // do not wrap really long word, just extend beyond limit
-                matcher = patternToWrapOn.matcher(str.substring(offset + 
wrapLength));
+                // do not wrap really long word, just extend beyond limit;
+                // match against a region of the original string rather than 
copying the entire
+                // unbounded remainder per output line (which is quadratic), 
mirroring the
+                // windowed substring used by the main loop above
+                matcher = patternToWrapOn.matcher(str);
+                matcher.region(offset + wrapLength, inputLineLength);
                 spaceToWrapAt = -1;
                 if (matcher.find()) {
-                    spaceToWrapAt = matcher.start() + offset + wrapLength;
-                    endOfWrapAt = matcher.end() + offset + wrapLength;
+                    spaceToWrapAt = matcher.start();
+                    endOfWrapAt = matcher.end();
                 }
 
                 if (spaceToWrapAt >= 0) {

Reply via email to