From 413bd72d0fb3f994f0b948529c5672ab5c060a30 Mon Sep 17 00:00:00 2001 From: b84330808 Date: Wed, 4 Nov 2026 16:10:17 +0000 Subject: [PATCH] Fix unpack() "h*" and "H*" not advancing the input position For the '*' repeater, the h/H case leaves size at -1. Unlike the a/A/Z cases, which set size to the number of bytes they consumed, the hex case never updates it, so "inputpos += size" moved the position one byte backwards instead of to the end of the input. Any code following h* or H* therefore re-read input that had already been consumed: unpack("H*a/H*b", "\xab\xcd"); // b => "abcd" instead of "" unpack("H*a/Cb", "\xab\xcd"); // b => 171 instead of a warning Set size to the number of input bytes consumed by the nibbles that were read. This is what was already used for explicit counts, so only the '*' case changes. --- ext/standard/pack.c | 3 ++ .../strings/unpack_hex_star_position.phpt | 42 +++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 ext/standard/tests/strings/unpack_hex_star_position.phpt diff --git a/ext/standard/pack.c b/ext/standard/pack.c index fa401e9828be..105de796f381 100644 --- a/ext/standard/pack.c +++ b/ext/standard/pack.c @@ -1020,6 +1020,9 @@ PHP_FUNCTION(unpack) ZSTR_VAL(buf)[len] = '\0'; + /* Advance by the number of bytes consumed, also for '*' */ + size = (len + 1) / 2; + ZVAL_STR(&val, buf); zend_symtable_update(Z_ARRVAL_P(return_value), real_name, &val); break; diff --git a/ext/standard/tests/strings/unpack_hex_star_position.phpt b/ext/standard/tests/strings/unpack_hex_star_position.phpt new file mode 100644 index 000000000000..52448348bae7 --- /dev/null +++ b/ext/standard/tests/strings/unpack_hex_star_position.phpt @@ -0,0 +1,42 @@ +--TEST-- +unpack() with "h*" and "H*" advances the position to the end of the input +--FILE-- + +--EXPECTF-- +array(3) { + ["a"]=> + int(1) + ["b"]=> + string(4) "abcd" + ["c"]=> + int(205) +} +array(3) { + ["a"]=> + int(1) + ["b"]=> + string(4) "badc" + ["c"]=> + int(205) +} +array(2) { + ["a"]=> + string(4) "abcd" + ["b"]=> + string(0) "" +} + +Warning: unpack(): Type C: not enough input values, need 1 values but only 0 were provided in %s on line %d +bool(false) +array(2) { + ["a"]=> + string(3) "abc" + ["b"]=> + int(239) +}