Merge branch 'PHP-8.3' into PHP-8.4

* PHP-8.3:
  Fix GH-19303: Unpacking empty packed array into uninitialized array causes assertion failure
This commit is contained in:
Niels Dossche 2025-07-30 22:48:59 +02:00
commit a08df32f18
No known key found for this signature in database
GPG key ID: B8A8AD166DF0E2E5
4 changed files with 45 additions and 22 deletions

2
NEWS
View file

@ -15,6 +15,8 @@ PHP NEWS
binary const expr). (ilutov)
. Fixed bug GH-19305 (Operands may be being released during comparison).
(Arnaud)
. Fixed bug GH-19303 (Unpacking empty packed array into uninitialized array
causes assertion failure). (nielsdos)
- FTP:
. Fix theoretical issues with hrtime() not being available. (nielsdos)

View file

@ -0,0 +1,11 @@
--TEST--
GH-19303 (Unpacking empty packed array into uninitialized array causes assertion failure)
--FILE--
<?php
$a = [0];
unset($a[0]);
var_dump([...$a]);
?>
--EXPECT--
array(0) {
}

View file

@ -6262,17 +6262,22 @@ ZEND_VM_C_LABEL(add_unpack_again):
zval *val;
if (HT_IS_PACKED(ht) && (zend_hash_num_elements(result_ht) == 0 || HT_IS_PACKED(result_ht))) {
zend_hash_extend(result_ht, result_ht->nNumUsed + zend_hash_num_elements(ht), 1);
ZEND_HASH_FILL_PACKED(result_ht) {
ZEND_HASH_PACKED_FOREACH_VAL(ht, val) {
if (UNEXPECTED(Z_ISREF_P(val)) &&
UNEXPECTED(Z_REFCOUNT_P(val) == 1)) {
val = Z_REFVAL_P(val);
}
Z_TRY_ADDREF_P(val);
ZEND_HASH_FILL_ADD(val);
} ZEND_HASH_FOREACH_END();
} ZEND_HASH_FILL_END();
/* zend_hash_extend() skips initialization when the number of elements is 0,
* but the code below expects that result_ht is initialized as packed.
* We can just skip the work in that case. */
if (result_ht->nNumUsed + zend_hash_num_elements(ht) > 0) {
zend_hash_extend(result_ht, result_ht->nNumUsed + zend_hash_num_elements(ht), 1);
ZEND_HASH_FILL_PACKED(result_ht) {
ZEND_HASH_PACKED_FOREACH_VAL(ht, val) {
if (UNEXPECTED(Z_ISREF_P(val)) &&
UNEXPECTED(Z_REFCOUNT_P(val) == 1)) {
val = Z_REFVAL_P(val);
}
Z_TRY_ADDREF_P(val);
ZEND_HASH_FILL_ADD(val);
} ZEND_HASH_FOREACH_END();
} ZEND_HASH_FILL_END();
}
} else {
zend_string *key;

27
Zend/zend_vm_execute.h generated
View file

@ -2721,17 +2721,22 @@ add_unpack_again:
zval *val;
if (HT_IS_PACKED(ht) && (zend_hash_num_elements(result_ht) == 0 || HT_IS_PACKED(result_ht))) {
zend_hash_extend(result_ht, result_ht->nNumUsed + zend_hash_num_elements(ht), 1);
ZEND_HASH_FILL_PACKED(result_ht) {
ZEND_HASH_PACKED_FOREACH_VAL(ht, val) {
if (UNEXPECTED(Z_ISREF_P(val)) &&
UNEXPECTED(Z_REFCOUNT_P(val) == 1)) {
val = Z_REFVAL_P(val);
}
Z_TRY_ADDREF_P(val);
ZEND_HASH_FILL_ADD(val);
} ZEND_HASH_FOREACH_END();
} ZEND_HASH_FILL_END();
/* zend_hash_extend() skips initialization when the number of elements is 0,
* but the code below expects that result_ht is initialized as packed.
* We can just skip the work in that case. */
if (result_ht->nNumUsed + zend_hash_num_elements(ht) > 0) {
zend_hash_extend(result_ht, result_ht->nNumUsed + zend_hash_num_elements(ht), 1);
ZEND_HASH_FILL_PACKED(result_ht) {
ZEND_HASH_PACKED_FOREACH_VAL(ht, val) {
if (UNEXPECTED(Z_ISREF_P(val)) &&
UNEXPECTED(Z_REFCOUNT_P(val) == 1)) {
val = Z_REFVAL_P(val);
}
Z_TRY_ADDREF_P(val);
ZEND_HASH_FILL_ADD(val);
} ZEND_HASH_FOREACH_END();
} ZEND_HASH_FILL_END();
}
} else {
zend_string *key;