Skip to content

Commit f7222bd

Browse files
committed
Also fix same issue in ArrayObject::exchangeArray()
1 parent 8910ac8 commit f7222bd

File tree

2 files changed

+33
-3
lines changed

2 files changed

+33
-3
lines changed

ext/spl/spl_array.c

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1054,8 +1054,10 @@ static HashTable *spl_array_it_get_gc(zend_object_iterator *iter, zval **table,
10541054
static void spl_array_set_array(zval *object, spl_array_object *intern, zval *array, zend_long ar_flags, bool just_array) {
10551055
/* Handled by ZPP prior to this, or for __unserialize() before passing to here */
10561056
ZEND_ASSERT(Z_TYPE_P(array) == IS_ARRAY || Z_TYPE_P(array) == IS_OBJECT);
1057+
zval garbage;
1058+
ZVAL_UNDEF(&garbage);
10571059
if (Z_TYPE_P(array) == IS_ARRAY) {
1058-
zval_ptr_dtor(&intern->array);
1060+
ZVAL_COPY_VALUE(&garbage, &intern->array);
10591061
if (Z_REFCOUNT_P(array) == 1) {
10601062
ZVAL_COPY(&intern->array, array);
10611063
} else {
@@ -1073,7 +1075,7 @@ static void spl_array_set_array(zval *object, spl_array_object *intern, zval *ar
10731075
}
10741076
} else {
10751077
if (Z_OBJ_HT_P(array) == &spl_handler_ArrayObject || Z_OBJ_HT_P(array) == &spl_handler_ArrayIterator) {
1076-
zval_ptr_dtor(&intern->array);
1078+
ZVAL_COPY_VALUE(&garbage, &intern->array);
10771079
if (just_array) {
10781080
spl_array_object *other = Z_SPLARRAY_P(array);
10791081
ar_flags = other->ar_flags & ~SPL_ARRAY_INT_MASK;
@@ -1091,9 +1093,10 @@ static void spl_array_set_array(zval *object, spl_array_object *intern, zval *ar
10911093
zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0,
10921094
"Overloaded object of type %s is not compatible with %s",
10931095
ZSTR_VAL(Z_OBJCE_P(array)->name), ZSTR_VAL(intern->std.ce->name));
1096+
ZEND_ASSERT(Z_TYPE(garbage) == IS_UNDEF);
10941097
return;
10951098
}
1096-
zval_ptr_dtor(&intern->array);
1099+
ZVAL_COPY_VALUE(&garbage, &intern->array);
10971100
ZVAL_COPY(&intern->array, array);
10981101
}
10991102
}
@@ -1104,6 +1107,8 @@ static void spl_array_set_array(zval *object, spl_array_object *intern, zval *ar
11041107
zend_hash_iterator_del(intern->ht_iter);
11051108
intern->ht_iter = (uint32_t)-1;
11061109
}
1110+
1111+
zval_ptr_dtor(&garbage);
11071112
}
11081113
/* }}} */
11091114

ext/spl/tests/gh16646_2.phpt

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
--TEST--
2+
GH-16646: Use-after-free in ArrayObject::exchangeArray() with destructor
3+
--FILE--
4+
<?php
5+
6+
class C {
7+
function __destruct() {
8+
global $arr;
9+
echo __METHOD__, "\n";
10+
$arr->exchangeArray([]);
11+
}
12+
}
13+
14+
$arr = new ArrayObject(new C);
15+
$arr->exchangeArray([]);
16+
var_dump($arr);
17+
18+
?>
19+
--EXPECT--
20+
C::__destruct
21+
object(ArrayObject)#1 (1) {
22+
["storage":"ArrayObject":private]=>
23+
array(0) {
24+
}
25+
}

0 commit comments

Comments
 (0)