From 3a5cf40f311b35f61285e53f6ef2f92e4f4c029b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ey=C3=BCp=20Can=20Akman?= Date: Fri, 17 Jul 2026 03:01:38 +0300 Subject: [PATCH] Fix GH-22779: mb_strrpos() wrong result in a non-UTF-8 encoding mb_find_strpos() converts the haystack and needle to UTF-8 and does the length and offset math on the converted strings. The negative-offset branch computed the needle length from the raw needle instead of needle_u8. mb_fast_strlen_utf8() reads those bytes as UTF-8, so the count is wrong whenever they do not decode one to one. A byte in 0x80-0xBF (ISO-8859-1) undercounts, and a wider encoding such as an ASCII needle in UTF-16 overcounts, so the reverse-search window is shifted. Use needle_u8, the converted needle the rest of the branch already searches with. --- NEWS | 4 ++++ ext/mbstring/mbstring.c | 2 +- ext/mbstring/tests/gh22779.phpt | 34 +++++++++++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 ext/mbstring/tests/gh22779.phpt diff --git a/NEWS b/NEWS index 8a94a173afd8..83a6285ec242 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,10 @@ PHP NEWS - Date: . Fixed leak on double DatePeriod::__construct() call. (ilutov) +- MBString: + . Fixed bug GH-22779 (mb_strrpos() returns the wrong position for a negative + offset in a non-UTF-8 encoding). (Eyüp Can Akman) + 30 Jul 2026, PHP 8.4.24 - Calendar: diff --git a/ext/mbstring/mbstring.c b/ext/mbstring/mbstring.c index c3394e79f021..4893390a8264 100644 --- a/ext/mbstring/mbstring.c +++ b/ext/mbstring/mbstring.c @@ -1931,7 +1931,7 @@ static size_t mb_find_strpos(zend_string *haystack, zend_string *needle, const m } else if (offset >= 0) { found_pos = zend_memnrstr((const char*)offset_pointer, ZSTR_VAL(needle_u8), ZSTR_LEN(needle_u8), ZSTR_VAL(haystack_u8) + ZSTR_LEN(haystack_u8)); } else { - size_t needle_len = pointer_to_offset_utf8((unsigned char*)ZSTR_VAL(needle), (unsigned char*)ZSTR_VAL(needle) + ZSTR_LEN(needle)); + size_t needle_len = pointer_to_offset_utf8((unsigned char*)ZSTR_VAL(needle_u8), (unsigned char*)ZSTR_VAL(needle_u8) + ZSTR_LEN(needle_u8)); offset_pointer = offset_to_pointer_utf8(offset_pointer, (unsigned char*)ZSTR_VAL(haystack_u8) + ZSTR_LEN(haystack_u8), needle_len); if (!offset_pointer) { offset_pointer = (unsigned char*)ZSTR_VAL(haystack_u8) + ZSTR_LEN(haystack_u8); diff --git a/ext/mbstring/tests/gh22779.phpt b/ext/mbstring/tests/gh22779.phpt new file mode 100644 index 000000000000..2983f4e1194a --- /dev/null +++ b/ext/mbstring/tests/gh22779.phpt @@ -0,0 +1,34 @@ +--TEST-- +GH-22779: mb_strrpos() wrong result for a negative offset in a non-UTF-8 encoding +--EXTENSIONS-- +mbstring +--FILE-- + +--EXPECT-- +int(1) +int(1) +int(0) +int(1) +int(2) +int(2) +int(2) +int(1) +int(0) +int(0)