Skip to content

Commit c2b2930

Browse files
committed
Merge branch 'PHP-8.0'
* PHP-8.0: Fix RecursiveIteratorIterator segfault for invalid aggregate
2 parents 6dc20e1 + b9ae73e commit c2b2930

File tree

2 files changed

+47
-15
lines changed

2 files changed

+47
-15
lines changed

ext/spl/spl_iterators.c

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,24 @@ static zend_object_iterator *spl_recursive_it_get_iterator(zend_class_entry *ce,
481481
return (zend_object_iterator*)iterator;
482482
}
483483

484+
static int spl_get_iterator_from_aggregate(zval *retval, zend_class_entry *ce, zend_object *obj) {
485+
zend_function **getiterator_cache =
486+
ce->iterator_funcs_ptr ? &ce->iterator_funcs_ptr->zf_new_iterator : NULL;
487+
zend_call_method_with_0_params(obj, ce, getiterator_cache, "getiterator", retval);
488+
if (EG(exception)) {
489+
return FAILURE;
490+
}
491+
if (Z_TYPE_P(retval) != IS_OBJECT
492+
|| !instanceof_function(Z_OBJCE_P(retval), zend_ce_traversable)) {
493+
zend_throw_exception_ex(spl_ce_LogicException, 0,
494+
"%s::getIterator() must return an object that implements Traversable",
495+
ZSTR_VAL(ce->name));
496+
zval_ptr_dtor(retval);
497+
return FAILURE;
498+
}
499+
return SUCCESS;
500+
}
501+
484502
static void spl_recursive_it_it_construct(INTERNAL_FUNCTION_PARAMETERS, zend_class_entry *ce_base, zend_class_entry *ce_inner, recursive_it_it_type rit_type)
485503
{
486504
zval *object = ZEND_THIS;
@@ -502,9 +520,10 @@ static void spl_recursive_it_it_construct(INTERNAL_FUNCTION_PARAMETERS, zend_cla
502520
}
503521

504522
if (instanceof_function(Z_OBJCE_P(iterator), zend_ce_aggregate)) {
505-
zend_function **getiterator_cache = Z_OBJCE_P(iterator)->iterator_funcs_ptr
506-
? &Z_OBJCE_P(iterator)->iterator_funcs_ptr->zf_new_iterator : NULL;
507-
zend_call_method_with_0_params(Z_OBJ_P(iterator), Z_OBJCE_P(iterator), getiterator_cache, "getiterator", &aggregate_retval);
523+
if (spl_get_iterator_from_aggregate(
524+
&aggregate_retval, Z_OBJCE_P(iterator), Z_OBJ_P(iterator)) == FAILURE) {
525+
RETURN_THROWS();
526+
}
508527
iterator = &aggregate_retval;
509528
} else {
510529
Z_ADDREF_P(iterator);
@@ -526,9 +545,10 @@ static void spl_recursive_it_it_construct(INTERNAL_FUNCTION_PARAMETERS, zend_cla
526545
}
527546

528547
if (instanceof_function(Z_OBJCE_P(iterator), zend_ce_aggregate)) {
529-
zend_function **getiterator_cache = Z_OBJCE_P(iterator)->iterator_funcs_ptr
530-
? &Z_OBJCE_P(iterator)->iterator_funcs_ptr->zf_new_iterator : NULL;
531-
zend_call_method_with_0_params(Z_OBJ_P(iterator), Z_OBJCE_P(iterator), getiterator_cache, "getiterator", &aggregate_retval);
548+
if (spl_get_iterator_from_aggregate(
549+
&aggregate_retval, Z_OBJCE_P(iterator), Z_OBJ_P(iterator)) == FAILURE) {
550+
RETURN_THROWS();
551+
}
532552
iterator = &aggregate_retval;
533553
} else {
534554
Z_ADDREF_P(iterator);
@@ -1332,15 +1352,7 @@ static spl_dual_it_object* spl_dual_it_construct(INTERNAL_FUNCTION_PARAMETERS, z
13321352
ce = ce_cast;
13331353
}
13341354
if (instanceof_function(ce, zend_ce_aggregate)) {
1335-
zend_function **getiterator_cache =
1336-
ce->iterator_funcs_ptr ? &ce->iterator_funcs_ptr->zf_new_iterator : NULL;
1337-
zend_call_method_with_0_params(Z_OBJ_P(zobject), ce, getiterator_cache, "getiterator", &retval);
1338-
if (EG(exception)) {
1339-
zval_ptr_dtor(&retval);
1340-
return NULL;
1341-
}
1342-
if (Z_TYPE(retval) != IS_OBJECT || !instanceof_function(Z_OBJCE(retval), zend_ce_traversable)) {
1343-
zend_throw_exception_ex(spl_ce_LogicException, 0, "%s::getIterator() must return an object that implements Traversable", ZSTR_VAL(ce->name));
1355+
if (spl_get_iterator_from_aggregate(&retval, ce, Z_OBJ_P(zobject)) == FAILURE) {
13441356
return NULL;
13451357
}
13461358
zobject = &retval;
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
--TEST--
2+
RecursiveIteratorIterator constructor should thrown if IteratorAggregate does not return Iterator
3+
--FILE--
4+
<?php
5+
6+
class MyIteratorAggregate implements IteratorAggregate {
7+
function getIterator() {
8+
return null;
9+
}
10+
}
11+
12+
try {
13+
new RecursiveIteratorIterator(new MyIteratorAggregate);
14+
} catch (LogicException $e) {
15+
echo $e->getMessage(), "\n";
16+
}
17+
18+
?>
19+
--EXPECT--
20+
MyIteratorAggregate::getIterator() must return an object that implements Traversable

0 commit comments

Comments
 (0)