Skip to content

GH-15911: prevent appending an AppendIterator to itself #16492

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: PHP-8.2
Choose a base branch
from
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
2 changes: 2 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ PHP NEWS
(ilutov)
. Fixed bug GH-16479 (Use-after-free in SplObjectStorage::setInfo()). (ilutov)
. Fixed bug GH-16478 (Use-after-free in SplFixedArray::unset()). (ilutov)
. Fixed bug GH-15911 (Infinite recursion in AppendIterator::append()).
(DanielEScherzer)

- Standard:
. Fixed bug GH-16293 (Failed assertion when throwing in assert() callback with
Expand Down
14 changes: 14 additions & 0 deletions ext/spl/spl_array.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,20 @@ static inline HashTable *spl_array_get_hash_table(spl_array_object* intern) { /*
}
/* }}} */

bool spl_array_iterator_contains(zval *object, zval *to_find) {
zend_object *obj_to_find = Z_OBJ_P(to_find);
spl_array_object *intern = Z_SPLARRAY_P(object);
// call spl_array_get_hash_table($40)
HashTable *ht = spl_array_get_hash_table(intern);
zval *iter = NULL;
ZEND_HASH_FOREACH_VAL(ht, iter) {
if (Z_OBJ_P(iter) == obj_to_find) {
return true;
}
} ZEND_HASH_FOREACH_END();
return false;
}

static inline bool spl_array_is_object(spl_array_object *intern) /* {{{ */
{
while (intern->ar_flags & SPL_ARRAY_USE_OTHER) {
Expand Down
1 change: 1 addition & 0 deletions ext/spl/spl_array.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,6 @@ PHP_MINIT_FUNCTION(spl_array);

extern void spl_array_iterator_append(zval *object, zval *append_value);
extern void spl_array_iterator_key(zval *object, zval *return_value);
extern bool spl_array_iterator_contains(zval *object, zval *to_find);

#endif /* SPL_ARRAY_H */
16 changes: 16 additions & 0 deletions ext/spl/spl_iterators.c
Original file line number Diff line number Diff line change
Expand Up @@ -2961,6 +2961,22 @@ PHP_METHOD(AppendIterator, append)

SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);

if (Z_OBJ_P(ZEND_THIS) == Z_OBJ_P(it)) {
zend_argument_value_error(1, "must be different than the iterator being appended to");
RETURN_THROWS();
}
if (instanceof_function(Z_OBJCE_P(it), spl_ce_AppendIterator)) {
// Make sure that the iterator being appended doesn't contain the
// iterator being appended to, GH-15911
// call spl_dual_it_from_obj(it.value.obj)
spl_dual_it_object *other_iterator = Z_SPLDUAL_IT_P(it);
ZEND_ASSERT(other_iterator->dit_type == DIT_AppendIterator);
if (spl_array_iterator_contains(&other_iterator->u.append.zarrayit, ZEND_THIS)) {
zend_argument_value_error(1, "must not contain the iterator being appended to");
RETURN_THROWS();
}
}

if (intern->u.append.iterator->funcs->valid(intern->u.append.iterator) == SUCCESS && spl_dual_it_valid(intern) != SUCCESS) {
spl_array_iterator_append(&intern->u.append.zarrayit, it);
intern->u.append.iterator->funcs->move_forward(intern->u.append.iterator);
Expand Down
17 changes: 17 additions & 0 deletions ext/spl/tests/gh15911_included.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
--TEST--
GH-15911 (Appending AppendIterator containing AppendIterator to the contained AppendIterator)
--FILE--
<?php

$iterator = new AppendIterator();
$other = new AppendIterator();
$other->append( $iterator );
$iterator->append( $other );

?>
--EXPECTF--
Fatal error: Uncaught ValueError: AppendIterator::append(): Argument #1 ($iterator) must not contain the iterator being appended to in %s:%d
Stack trace:
#0 %s(%d): AppendIterator->append(Object(AppendIterator))
#1 {main}
thrown in %s on line %d
15 changes: 15 additions & 0 deletions ext/spl/tests/gh15911_self.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
--TEST--
GH-15911 (Infinite recursion when appending AppendIterator to itself)
--FILE--
<?php

$iterator = new AppendIterator();

$iterator->append($iterator);
?>
--EXPECTF--
Fatal error: Uncaught ValueError: AppendIterator::append(): Argument #1 ($iterator) must be different than the iterator being appended to in %s:%d
Stack trace:
#0 %s(%d): AppendIterator->append(Object(AppendIterator))
#1 {main}
thrown in %s on line %d
Loading