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:
committed by
GitHub
parent
7e7d6d6380
commit
64c1d43b68
2
NEWS
2
NEWS
@@ -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).
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
|
||||
20
ext/standard/tests/array/gh19926.phpt
Normal file
20
ext/standard/tests/array/gh19926.phpt
Normal 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
|
||||
19
ext/standard/tests/array/gh19926_pointer.phpt
Normal file
19
ext/standard/tests/array/gh19926_pointer.phpt
Normal 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)
|
||||
Reference in New Issue
Block a user