Skip to content

Fix bounds check in multibyte UTF detection - #23527

Open
ydah wants to merge 1 commit into
php:PHP-8.4from
ydah:fix/multibyte-utf-detection-bounds
Open

Fix bounds check in multibyte UTF detection#23527
ydah wants to merge 1 commit into
php:PHP-8.4from
ydah:fix/multibyte-utf-detection-bounds

Conversation

@ydah

@ydah ydah commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

zend_multibyte_detect_utf_encoding() advances the search position by four bytes after each NUL while looking for UTF-32-specific byte orders. When fewer than three bytes remain, script_size - (p - script) - 2 underflows and passes a huge size_t value to memchr().

Scripts are normally backed by a buffer with ZEND_MMAP_AHEAD zero padding, so this generally does not crash. Instead, memchr() may find a NUL in the padding and misdetect a BOM-less UTF-16 script as UTF-32, corrupting the script during conversion when zend.multibyte is enabled.

Track the search position as an offset and call memchr() only while at least three bytes remain. This also avoids advancing a pointer beyond the script buffer.

For example, with zend.multibyte=1 and internal_encoding=UTF-8:

$filename = __DIR__ . '/utf16le.php';
file_put_contents($filename, "<\0?\0p\0h\0p\0");
include $filename;
echo "Done\n";

Expected

Done

The 10-byte BOM-less UTF-16LE script is detected as UTF-16LE.

Actual

???Done

After the search reaches offset 9, the length calculation underflows. memchr() finds a NUL in the trailing padding, causing the script to be misdetected as UTF-32LE.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice follow-up you can do in this PR: p+wchar_size-1 is not certainly the correct place to read.

Also, please target this PR to 8.4. Otherwise looks good.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you! I updated the endianness detection loop to ensure that a full wide character remains before reading p + wchar_size - 1. I also rebased the branch onto PHP 8.4 and retargeted the PR accordingly.

@ydah
ydah changed the base branch from master to PHP-8.4 September 1, 2026 14:21
@ydah
ydah force-pushed the fix/multibyte-utf-detection-bounds branch from 90dc964 to 52a113c Compare September 1, 2026 14:27
@kocsismate
kocsismate removed their request for review September 1, 2026 18:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants