Fix use-after-free in ArrayObject::unset() with destructor

Fixes GH-16646
Closes GH-16653
This commit is contained in:
Ilija Tovilo 2024-10-30 23:50:55 +01:00
parent 845cdbce67
commit 8910ac800d
No known key found for this signature in database
GPG Key ID: 5050C66BFCD1015A
2 changed files with 35 additions and 1 deletions

View File

@ -555,13 +555,15 @@ static void spl_array_unset_dimension_ex(int check_inherited, zend_object *objec
if (Z_TYPE_P(data) == IS_INDIRECT) {
data = Z_INDIRECT_P(data);
if (Z_TYPE_P(data) != IS_UNDEF) {
zval_ptr_dtor(data);
zval garbage;
ZVAL_COPY_VALUE(&garbage, data);
ZVAL_UNDEF(data);
HT_FLAGS(ht) |= HASH_FLAG_HAS_EMPTY_IND;
zend_hash_move_forward_ex(ht, spl_array_get_pos_ptr(ht, intern));
if (spl_array_is_object(intern)) {
spl_array_skip_protected(intern, ht);
}
zval_ptr_dtor(&garbage);
}
} else {
zend_hash_del(ht, key.key);

View File

@ -0,0 +1,32 @@
--TEST--
GH-16646: Use-after-free in ArrayObject::unset() with destructor
--FILE--
<?php
class B {
public $b;
function __construct($arg) {
$this->b = $arg;
}
}
class C {
function __destruct() {
global $arr;
echo __METHOD__, "\n";
$arr->exchangeArray([]);
}
}
$arr = new ArrayObject(new B(new C));
unset($arr["b"]);
var_dump($arr);
?>
--EXPECT--
C::__destruct
object(ArrayObject)#1 (1) {
["storage":"ArrayObject":private]=>
array(0) {
}
}