From 0d6ab5321d237286aa068f08c817594a421a6e0b 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 6b42bbf1cbdf..e4667b1d3b99 100644 --- a/NEWS +++ b/NEWS @@ -12,6 +12,10 @@ PHP NEWS attribute node that collides by local name with a namespaced attribute). (David Carlier) +- 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) + - Sockets: . Fixed various memory related issues in ext/sockets. (David Carlier) 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)