Commit f817996280d for php
commit f817996280d7dc184a27b93dca29a2e4a8633090
Author: Nicolas Grekas <nicolas.grekas@gmail.com>
Date: Mon Oct 5 19:44:36 2026 +0200
Fix wordwrap() ignoring an existing break at the end of the string (#24116)
When a multi-character break or $cut_long_words is used, an existing
break was only recognized when at least one character followed it. A
trailing break was handled as regular text, so wordwrap("abc\n", 3,
"\n", true) returned "abc\n\n" and wordwrap("ab cd\n", 5, "\n", true)
returned "ab\ncd\n". The single-character fast path was not affected.
diff --git a/NEWS b/NEWS
index 6134971c6ba..14b0d0b08db 100644
--- a/NEWS
+++ b/NEWS
@@ -219,6 +219,8 @@ PHP NEWS
PROCESS_INFORMATION, an indeterminate comspec pointer after a failed
lookup, and an unchecked CreateFileA() failure. (Ilia Alshanetsky)
. Fix persistent stream context lifetime during shutdown (Levi Morrison)
+ . Fix wordwrap() ignoring an existing break at the end of the string
+ (Nicolas Grekas)
- Tidy:
. Fixed a use-after-free when a tidyNode is used after its document is
diff --git a/ext/standard/string.c b/ext/standard/string.c
index 34444d80d18..40b05135a8e 100644
--- a/ext/standard/string.c
+++ b/ext/standard/string.c
@@ -779,7 +779,7 @@ PHP_FUNCTION(wordwrap)
/* when we hit an existing break, copy to new buffer, and
* fix up laststart and lastspace */
if (ZSTR_VAL(text)[current] == breakchar[0]
- && current + breakchar_len < ZSTR_LEN(text)
+ && current + breakchar_len <= ZSTR_LEN(text)
&& !strncmp(ZSTR_VAL(text) + current, breakchar, breakchar_len)) {
memcpy(ZSTR_VAL(newtext) + newtextlen, ZSTR_VAL(text) + laststart, current - laststart + breakchar_len);
newtextlen += current - laststart + breakchar_len;
diff --git a/ext/standard/tests/strings/wordwrap_trailing_break.phpt b/ext/standard/tests/strings/wordwrap_trailing_break.phpt
new file mode 100644
index 00000000000..2e57ce17666
--- /dev/null
+++ b/ext/standard/tests/strings/wordwrap_trailing_break.phpt
@@ -0,0 +1,28 @@
+--TEST--
+wordwrap() recognizes an existing break at the end of the string
+--FILE--
+<?php
+$tests = [
+ ["abc\n", 3, "\n", true],
+ ["ab cd\n", 5, "\n", true],
+ ["abcd\n", 3, "\n", true],
+ ["abc\nabc\n", 3, "\n", true],
+ ["abc-", 3, "-", true],
+ ["abc\r\n", 3, "\r\n", true],
+ ["\r\n", 1, "\r\n", true],
+ ["ab cd\r\n", 5, "\r\n", false],
+];
+
+foreach ($tests as [$text, $width, $break, $cut]) {
+ echo json_encode(wordwrap($text, $width, $break, $cut)), "\n";
+}
+?>
+--EXPECT--
+"abc\n"
+"ab cd\n"
+"abc\nd\n"
+"abc\nabc\n"
+"abc-"
+"abc\r\n"
+"\r\n"
+"ab cd\r\n"