Browse Source

Merge branch 'PHP-8.5'

* PHP-8.5:
  Fix GH-19926: reset internal pointer earlier while splicing array while COW violation flag is still set (#19929)
pull/20083/head
Alexandre Daubois 2 days ago
parent
commit
4858cfa9ca
No known key found for this signature in database GPG Key ID: DB5EB2A5B2556441
  1. 4
      NEWS
  2. 8
      ext/standard/array.c
  3. 20
      ext/standard/tests/array/gh19926.phpt
  4. 19
      ext/standard/tests/array/gh19926_pointer.phpt

4
NEWS

@ -11,4 +11,8 @@ PHP NEWS
with a given skeleton, locale, collapse type and identity fallback.
(BogdanUngureanu)
- Standard:
. Fixed bug GH-19926 (reset internal pointer earlier while splicing array
while COW violation flag is still set). (alexandre-daubois)
<<< NOTE: Insert NEWS from last stable release here prior to actual release! >>>

8
ext/standard/array.c

@ -3489,6 +3489,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);
@ -3507,8 +3513,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

@ -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

@ -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)
Loading…
Cancel
Save