[php-src] PR #25215: Fix unpack() "h*" and "H*" not advancing the input position
| From: | b84330808 | Date: | Thu, 05 Nov 2026 16:00:31 +0000 |
| Subject: | [php-src] PR #25215: Fix unpack() "h*" and "H*" not advancing the input position | ||
| Groups: | php.git-pulls | ||
| Request: | Send a blank email to git-pulls+get-40327@lists.php.net to get a copy of this message | ||
Pull Request: https://github.com/php/php-src/pull/25215
Author: b84330808
This change and the description below were written by an LLM (Claude Code).
With the
* repeater, the h/H case in unpack() leaves size at
-1. The a/A/Z cases set size to the number of bytes they consumed, but the hex case
never does, so inputpos += size moves the position one byte backwards instead of to the
end of the input. Any format code after h* or H* then re-reads data that
was already consumed:
```php
unpack("H*a/H*b", "\xab\xcd");
// ["a" => "abcd", "b" => "abcd"], expected
"b" => "" like "a*a/a*b"
unpack("H*a/Cb", "\xab\xcd");
// ["a" => "abcd", "b" => 171], expected the "Type C: not
enough input values" warning and false, like "a*a/Cb"
unpack("Ca/H*b/X/Cc", "\x01\xab\xcd");
// "c" => 1 (re-reads byte 0), expected 205 (the last byte)
```
The fix sets size to the number of input bytes the nibbles came from, (len + 1) /
2. For explicit counts that's the value it already had, so only the * case
changes.
The new phpt fails without the fix, and ext/standard/tests/strings passes with it.
Targeting PHP-8.4 as the lowest branch that still gets bug fixes. PHP-8.5 and up have the same bug,
but the surrounding lines differ, so the merge-up needs the same line added by hand.