From b89fa3c89223607b25a9fae768036eb6d8aebb81 Mon Sep 17 00:00:00 2001 From: Ilia Alshanetsky Date: Sun, 16 Aug 2026 11:19:44 -0400 Subject: [PATCH] Stop grapheme_strrev from using UBRK_DONE as a byte index ubrk_previous() returns UBRK_DONE after the first boundary. The loop condition ran before that assignment, so the body treated -1 as an offset and wrote into the zend_string NUL. Break when the iterator is done, and NUL-terminate the result of zend_string_alloc. --- NEWS | 4 +++ ext/intl/grapheme/grapheme_string.cpp | 4 +++ ext/intl/tests/grapheme_strrev_ubrk_done.phpt | 25 +++++++++++++++++++ 3 files changed, 33 insertions(+) create mode 100644 ext/intl/tests/grapheme_strrev_ubrk_done.phpt diff --git a/NEWS b/NEWS index 9977ea3b3409..a64696947579 100644 --- a/NEWS +++ b/NEWS @@ -20,6 +20,10 @@ PHP NEWS left busy for the next fetch, and rows delivered from a result another statement took over. (KentarouTakeda) +- Intl: + . Fixed grapheme_strrev() treating UBRK_DONE as a byte index and leaving + the result without a terminating NUL. (iliaal) + - Phar: . Fixed Phar archives being automatically detected when ".phar" only occurs in a directory name or is not a filename extension in an included file's diff --git a/ext/intl/grapheme/grapheme_string.cpp b/ext/intl/grapheme/grapheme_string.cpp index 5e614be6ae72..a1daae84db9c 100644 --- a/ext/intl/grapheme/grapheme_string.cpp +++ b/ext/intl/grapheme/grapheme_string.cpp @@ -1175,6 +1175,9 @@ U_CFUNC PHP_FUNCTION(grapheme_strrev) current = ZSTR_LEN(string); for (end = pstr; pos != UBRK_DONE; ) { pos = ubrk_previous(bi); + if (pos == UBRK_DONE) { + break; + } end_len = current - pos; for (int32_t j = 0; j < end_len; j++) { *p++ = *(pstr + pos + j); @@ -1182,6 +1185,7 @@ U_CFUNC PHP_FUNCTION(grapheme_strrev) current = pos; } ubrk_end: + ZSTR_VAL(ret)[ZSTR_LEN(ret)] = '\0'; RETVAL_NEW_STR(ret); ubrk_close(bi); close: diff --git a/ext/intl/tests/grapheme_strrev_ubrk_done.phpt b/ext/intl/tests/grapheme_strrev_ubrk_done.phpt new file mode 100644 index 000000000000..6f70f7cd1f7f --- /dev/null +++ b/ext/intl/tests/grapheme_strrev_ubrk_done.phpt @@ -0,0 +1,25 @@ +--TEST-- +grapheme_strrev() stops at UBRK_DONE instead of using it as a byte index +--EXTENSIONS-- +intl +--FILE-- + +--EXPECT-- +3 3 636261 +1 1 61 +9 9 e5baa7e4b88be59c9f +9 9 65747962006c6c756e