Skip to content

Commit c02f35a

Browse files
Fix GH-19926: preserve COW violation flags when copying a hashtable while splicing
1 parent 266cb7d commit c02f35a

File tree

2 files changed

+35
-1
lines changed

2 files changed

+35
-1
lines changed

ext/standard/array.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3395,7 +3395,14 @@ static void php_splice(HashTable *in_hash, zend_long offset, zend_long length, H
33953395
in_hash->arData = out_hash.arData;
33963396
in_hash->pDestructor = out_hash.pDestructor;
33973397

3398-
zend_hash_internal_pointer_reset(in_hash);
3398+
/* Temporarily allow COW violation for pointer reset when refcount > 1 */
3399+
if (GC_REFCOUNT(in_hash) > 1) {
3400+
HT_ALLOW_COW_VIOLATION(in_hash);
3401+
zend_hash_internal_pointer_reset(in_hash);
3402+
HT_FLAGS(in_hash) &= ~HASH_FLAG_ALLOW_COW_VIOLATION;
3403+
} else {
3404+
zend_hash_internal_pointer_reset(in_hash);
3405+
}
33993406
}
34003407
/* }}} */
34013408

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
--TEST--
2+
GH-19926 (Assertion failure zend_hash_internal_pointer_reset_ex)
3+
--FILE--
4+
<?php
5+
function exception_error_handler() {
6+
throw new Exception();
7+
}
8+
9+
set_error_handler("exception_error_handler");
10+
11+
class MultiDestructor {
12+
function __destruct() {
13+
if ($this->id == 2) {
14+
}
15+
}
16+
}
17+
18+
$arr = ["start", new MultiDestructor(1), new MultiDestructor(2), "end"];
19+
20+
try {
21+
array_splice($arr, 1, 2);
22+
} catch (Exception $e) {
23+
echo "Exception caught, no assertion failure\n";
24+
}
25+
?>
26+
--EXPECT--
27+
Exception caught, no assertion failure

0 commit comments

Comments
 (0)