1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00

Fix GH-19926: reset internal pointer earlier while splicing array while COW violation flag is still set (#19929)

This commit is contained in:
Alexandre Daubois
2025-10-06 16:51:23 +02:00
committed by GitHub
parent 7e7d6d6380
commit 64c1d43b68
4 changed files with 47 additions and 2 deletions

2
NEWS
View File

@@ -62,6 +62,8 @@ PHP NEWS
(alexandre-daubois)
. Fixed bug GH-20043 (array_unique assertion failure with RC1 array
causing an exception on sort). (nielsdos)
. Fixed bug GH-19926 (reset internal pointer earlier while splicing array
while COW violation flag is still set). (alexandre-daubois)
- Streams:
. Fixed bug GH-19248 (Use strerror_r instead of strerror in main).

View File

@@ -3376,6 +3376,12 @@ static void php_splice(HashTable *in_hash, zend_long offset, zend_long length, H
HT_SET_ITERATORS_COUNT(in_hash, 0);
in_hash->pDestructor = NULL;
/* Set internal pointer to 0 directly instead of calling zend_hash_internal_pointer_reset().
* This avoids the COW violation assertion and delays advancing to the first valid position
* until after we've switched to the new array structure (out_hash). The iterator will be
* advanced when actually accessed, at which point it will find valid indexes in the new array. */
in_hash->nInternalPointer = 0;
if (UNEXPECTED(GC_DELREF(in_hash) == 0)) {
/* Array was completely deallocated during the operation */
zend_array_destroy(in_hash);
@@ -3394,8 +3400,6 @@ static void php_splice(HashTable *in_hash, zend_long offset, zend_long length, H
in_hash->nNextFreeElement = out_hash.nNextFreeElement;
in_hash->arData = out_hash.arData;
in_hash->pDestructor = out_hash.pDestructor;
zend_hash_internal_pointer_reset(in_hash);
}
/* }}} */

View File

@@ -0,0 +1,20 @@
--TEST--
GH-19926 (Assertion failure zend_hash_internal_pointer_reset_ex)
--FILE--
<?php
class ThrowingDestructor {
function __destruct() {
throw new Exception();
}
}
$arr = [new ThrowingDestructor(), new ThrowingDestructor()];
try {
array_splice($arr, 0, 2);
} catch (Exception $e) {
echo "Exception caught, no assertion failure\n";
}
?>
--EXPECT--
Exception caught, no assertion failure

View File

@@ -0,0 +1,19 @@
--TEST--
GH-19926 (internal pointer behavior after array_splice)
--FILE--
<?php
$a = [1, 2, 3];
unset($a[0]);
next($a);
echo "Before array_splice: ";
var_dump(current($a));
array_splice($a, 0, 0, [999]);
echo "After array_splice: ";
var_dump(current($a));
?>
--EXPECT--
Before array_splice: int(3)
After array_splice: int(999)