diff --git a/ext/spl/spl_iterators.c b/ext/spl/spl_iterators.c index 05bdfdb34ba3..a61195fb12d4 100644 --- a/ext/spl/spl_iterators.c +++ b/ext/spl/spl_iterators.c @@ -1541,7 +1541,8 @@ static inline void spl_dual_it_next(spl_dual_it_object *intern, int do_free) { if (do_free) { spl_dual_it_free(intern); - } else if (!intern->inner.iterator) { + } + if (!intern->inner.iterator) { zend_throw_error(NULL, "The inner constructor wasn't initialized with an iterator instance"); return; } @@ -2692,7 +2693,7 @@ PHP_METHOD(NoRewindIterator, valid) ZEND_PARSE_PARAMETERS_NONE(); SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS); - RETURN_BOOL(intern->inner.iterator->funcs->valid(intern->inner.iterator) == SUCCESS); + RETURN_BOOL(spl_dual_it_valid(intern) == SUCCESS); } /* }}} */ /* {{{ Return inner iterators key() */ @@ -2704,7 +2705,7 @@ PHP_METHOD(NoRewindIterator, key) SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS); - if (intern->inner.iterator->funcs->get_current_key) { + if (intern->inner.iterator && intern->inner.iterator->funcs->get_current_key) { intern->inner.iterator->funcs->get_current_key(intern->inner.iterator, return_value); } else { RETURN_NULL(); @@ -2720,6 +2721,9 @@ PHP_METHOD(NoRewindIterator, current) ZEND_PARSE_PARAMETERS_NONE(); SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS); + if (!intern->inner.iterator) { + RETURN_NULL(); + } data = intern->inner.iterator->funcs->get_current_data(intern->inner.iterator); if (data) { RETURN_COPY_DEREF(data); @@ -2734,6 +2738,10 @@ PHP_METHOD(NoRewindIterator, next) ZEND_PARSE_PARAMETERS_NONE(); SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS); + if (!intern->inner.iterator) { + zend_throw_error(NULL, "The inner constructor wasn't initialized with an iterator instance"); + RETURN_THROWS(); + } intern->inner.iterator->funcs->move_forward(intern->inner.iterator); } /* }}} */ diff --git a/ext/spl/tests/gh25415.phpt b/ext/spl/tests/gh25415.phpt new file mode 100644 index 000000000000..015e97ac8b12 --- /dev/null +++ b/ext/spl/tests/gh25415.phpt @@ -0,0 +1,69 @@ +--TEST-- +GH-25415 (Segfault in FilterIterator::next() after the subclass catches an exception from parent::__construct()) +--CREDITS-- +marinelay +--FILE-- +getMessage(), "\n"; + } + } + public function accept(): bool { return true; } + }, + new class($gen) extends IteratorIterator { + public function __construct(Iterator $it) { + try { + parent::__construct($it); + } catch (Exception $e) { + echo $e->getMessage(), "\n"; + } + } + }, + new class($gen) extends NoRewindIterator { + public function __construct(Iterator $it) { + try { + parent::__construct($it); + } catch (Exception $e) { + echo $e->getMessage(), "\n"; + } + } + }, +]; + +foreach ($iterators as $it) { + var_dump($it->valid(), $it->key(), $it->current()); + try { + $it->next(); + } catch (Error $e) { + echo $e->getMessage(), "\n"; + } +} + +?> +--EXPECT-- +Cannot traverse an already closed generator +Cannot traverse an already closed generator +Cannot traverse an already closed generator +bool(false) +NULL +NULL +The inner constructor wasn't initialized with an iterator instance +bool(false) +NULL +NULL +The inner constructor wasn't initialized with an iterator instance +bool(false) +NULL +NULL +The inner constructor wasn't initialized with an iterator instance