Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions ext/spl/spl_array.c
Original file line number Diff line number Diff line change
Expand Up @@ -943,6 +943,19 @@ static void spl_array_set_array(zval *object, spl_array_object *intern, zval *ar
}
} else {
if (Z_OBJ_HT_P(array) == &spl_handler_ArrayObject) {
if (Z_OBJ_P(object) != Z_OBJ_P(array)) {
/* Reject storage that (indirectly) uses this object as its storage. */
spl_array_object *other = Z_SPLARRAY_P(array);
while (other->ar_flags & SPL_ARRAY_USE_OTHER) {
if (Z_OBJ(other->array) == Z_OBJ_P(object)) {
zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0,
"Cannot use %s as storage of %s, as it would create a cycle",
ZSTR_VAL(Z_OBJCE_P(array)->name), ZSTR_VAL(intern->std.ce->name));
return;
}
other = Z_SPLARRAY_P(&other->array);
}
}
ZVAL_COPY_VALUE(&garbage, &intern->array);
if (just_array) {
spl_array_object *other = Z_SPLARRAY_P(array);
Expand Down
57 changes: 57 additions & 0 deletions ext/spl/tests/gh24615.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
--TEST--
GH-24615 (ArrayObject backing storage cycle causes unbounded recursion)
--FILE--
<?php
$a = new ArrayObject([1]);
$b = new ArrayObject($a);
try {
$a->exchangeArray($b);
} catch (InvalidArgumentException $e) {
echo $e->getMessage(), "\n";
}
var_dump(count($a), count($b));

/* Longer cycle, through an ArrayIterator */
$c = new ArrayIterator($b);
try {
$a->exchangeArray($c);
} catch (InvalidArgumentException $e) {
echo $e->getMessage(), "\n";
}
try {
$a->__construct($c);
} catch (InvalidArgumentException $e) {
echo $e->getMessage(), "\n";
}
var_dump(count($a), count($b), count($c));

/* Cycle built by __unserialize() */
$d = new ArrayObject([2]);
try {
$a->__unserialize([0, $d, []]);
$d->__unserialize([0, $a, []]);
} catch (InvalidArgumentException $e) {
echo $e->getMessage(), "\n";
}
var_dump(count($a), count($d));

/* Using an object as its own storage and sharing storage are still allowed */
$e = new ArrayObject([3]);
$e->exchangeArray($e);
$f = new ArrayObject($b);
var_dump(count($e), count($f));
?>
--EXPECT--
Cannot use ArrayObject as storage of ArrayObject, as it would create a cycle
int(1)
int(1)
Cannot use ArrayIterator as storage of ArrayObject, as it would create a cycle
Cannot use ArrayIterator as storage of ArrayObject, as it would create a cycle
int(1)
int(1)
int(1)
Cannot use ArrayObject as storage of ArrayObject, as it would create a cycle
int(1)
int(1)
int(0)
int(1)
Loading