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
No known key found for this signature in database
GPG Key ID: DB5EB2A5B2556441
4 changed files with
49 additions and
2 deletions
-
NEWS
-
ext/standard/array.c
-
ext/standard/tests/array/gh19926.phpt
-
ext/standard/tests/array/gh19926_pointer.phpt
|
|
@ -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! >>> |
|
|
@ -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); |
|
|
|
} |
|
|
|
/* }}} */ |
|
|
|
|
|
|
|
|
|
@ -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 |
|
|
@ -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) |