[php-src] PR #23527: Fix bounds check in multibyte UTF detection
| From: | ydah | Date: | Tue, 01 Sep 2026 13:12:26 +0000 |
| Subject: | [php-src] PR #23527: Fix bounds check in multibyte UTF detection | ||
| Groups: | php.git-pulls | ||
| Request: | Send a blank email to git-pulls+get-38243@lists.php.net to get a copy of this message | ||
Pull Request: https://github.com/php/php-src/pull/23527
Author: ydah
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:
```php
$filename = __DIR__ . '/utf16le.php';
file_put_contents($filename, "<\0?\0p\0h\0p\0");
include $filename;
echo "Done\n";
```
#### Expected
```text
Done
```
The 10-byte BOM-less UTF-16LE script is detected as UTF-16LE.
#### Actual
```text
???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.