diff --git a/NEWS b/NEWS index ad524d0bb94c..bb6b59d37d4b 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,10 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ?? ??? ????, PHP 8.2.36 +- MBString: + . Fixed mb_ereg_replace() emitting a NUL or out-of-bounds bytes in the + replacement when a \k backref has no closing delimiter. + (Ilia Alshanetsky) 21 Oct 2026, PHP 8.2.35 diff --git a/ext/mbstring/php_mbregex.c b/ext/mbstring/php_mbregex.c index 82479ecdfab4..0c4f667e0726 100644 --- a/ext/mbstring/php_mbregex.c +++ b/ext/mbstring/php_mbregex.c @@ -771,7 +771,7 @@ static inline void mb_regex_substitute( clen = (int) php_mb_mbchar_bytes(++p, enc); if (clen != 1 || p == eos || (p[0] != '<' && p[0] != '\'')) { /* not a backref delimiter */ - p += clen; + p = MIN(p + clen, eos); smart_str_appendl(pbuf, sp, p - sp); continue; } @@ -791,12 +791,13 @@ static inline void mb_regex_substitute( if (maybe_num && !isdigit((unsigned char)name_end[0])) maybe_num = 0; name_end++; } - p = name_end + 1; if (name_end - name < 1 || name_end >= eos) { /* the backref was empty or we failed to find the end delimiter */ + p = MIN(name_end + 1, eos); smart_str_appendl(pbuf, sp, p - sp); continue; } + p = name_end + 1; /* we have either a name or a number */ if (maybe_num) { if (!onig_noname_group_capture_is_active(regexp)) { diff --git a/ext/mbstring/tests/mb_ereg_replace_kname_unterminated_nul.phpt b/ext/mbstring/tests/mb_ereg_replace_kname_unterminated_nul.phpt new file mode 100644 index 000000000000..67a39dc9f95c --- /dev/null +++ b/ext/mbstring/tests/mb_ereg_replace_kname_unterminated_nul.phpt @@ -0,0 +1,18 @@ +--TEST-- +mb_ereg_replace() with unterminated \k backref must not embed a NUL byte +--EXTENSIONS-- +mbstring +--FILE-- + +--EXPECT-- +string(12) "5c6b3c6e756d" +string(12) "5c6b276e756d" +string(10) "615c6b3c6e" +string(8) "615c6bf0" +string(10) "5c5c6be282"