1
0
mirror of https://github.com/php/php-src.git synced 2026-03-31 04:32:19 +02:00

Merge branch 'PHP-8.0'

* PHP-8.0:
  Fix RecursiveIteratorIterator segfault for invalid aggregate
This commit is contained in:
Nikita Popov
2021-07-15 13:11:39 +02:00
2 changed files with 47 additions and 15 deletions

View File

@@ -481,6 +481,24 @@ static zend_object_iterator *spl_recursive_it_get_iterator(zend_class_entry *ce,
return (zend_object_iterator*)iterator;
}
static int spl_get_iterator_from_aggregate(zval *retval, zend_class_entry *ce, zend_object *obj) {
zend_function **getiterator_cache =
ce->iterator_funcs_ptr ? &ce->iterator_funcs_ptr->zf_new_iterator : NULL;
zend_call_method_with_0_params(obj, ce, getiterator_cache, "getiterator", retval);
if (EG(exception)) {
return FAILURE;
}
if (Z_TYPE_P(retval) != IS_OBJECT
|| !instanceof_function(Z_OBJCE_P(retval), zend_ce_traversable)) {
zend_throw_exception_ex(spl_ce_LogicException, 0,
"%s::getIterator() must return an object that implements Traversable",
ZSTR_VAL(ce->name));
zval_ptr_dtor(retval);
return FAILURE;
}
return SUCCESS;
}
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)
{
zval *object = ZEND_THIS;
@@ -502,9 +520,10 @@ static void spl_recursive_it_it_construct(INTERNAL_FUNCTION_PARAMETERS, zend_cla
}
if (instanceof_function(Z_OBJCE_P(iterator), zend_ce_aggregate)) {
zend_function **getiterator_cache = Z_OBJCE_P(iterator)->iterator_funcs_ptr
? &Z_OBJCE_P(iterator)->iterator_funcs_ptr->zf_new_iterator : NULL;
zend_call_method_with_0_params(Z_OBJ_P(iterator), Z_OBJCE_P(iterator), getiterator_cache, "getiterator", &aggregate_retval);
if (spl_get_iterator_from_aggregate(
&aggregate_retval, Z_OBJCE_P(iterator), Z_OBJ_P(iterator)) == FAILURE) {
RETURN_THROWS();
}
iterator = &aggregate_retval;
} else {
Z_ADDREF_P(iterator);
@@ -526,9 +545,10 @@ static void spl_recursive_it_it_construct(INTERNAL_FUNCTION_PARAMETERS, zend_cla
}
if (instanceof_function(Z_OBJCE_P(iterator), zend_ce_aggregate)) {
zend_function **getiterator_cache = Z_OBJCE_P(iterator)->iterator_funcs_ptr
? &Z_OBJCE_P(iterator)->iterator_funcs_ptr->zf_new_iterator : NULL;
zend_call_method_with_0_params(Z_OBJ_P(iterator), Z_OBJCE_P(iterator), getiterator_cache, "getiterator", &aggregate_retval);
if (spl_get_iterator_from_aggregate(
&aggregate_retval, Z_OBJCE_P(iterator), Z_OBJ_P(iterator)) == FAILURE) {
RETURN_THROWS();
}
iterator = &aggregate_retval;
} else {
Z_ADDREF_P(iterator);
@@ -1332,15 +1352,7 @@ static spl_dual_it_object* spl_dual_it_construct(INTERNAL_FUNCTION_PARAMETERS, z
ce = ce_cast;
}
if (instanceof_function(ce, zend_ce_aggregate)) {
zend_function **getiterator_cache =
ce->iterator_funcs_ptr ? &ce->iterator_funcs_ptr->zf_new_iterator : NULL;
zend_call_method_with_0_params(Z_OBJ_P(zobject), ce, getiterator_cache, "getiterator", &retval);
if (EG(exception)) {
zval_ptr_dtor(&retval);
return NULL;
}
if (Z_TYPE(retval) != IS_OBJECT || !instanceof_function(Z_OBJCE(retval), zend_ce_traversable)) {
zend_throw_exception_ex(spl_ce_LogicException, 0, "%s::getIterator() must return an object that implements Traversable", ZSTR_VAL(ce->name));
if (spl_get_iterator_from_aggregate(&retval, ce, Z_OBJ_P(zobject)) == FAILURE) {
return NULL;
}
zobject = &retval;

View File

@@ -0,0 +1,20 @@
--TEST--
RecursiveIteratorIterator constructor should thrown if IteratorAggregate does not return Iterator
--FILE--
<?php
class MyIteratorAggregate implements IteratorAggregate {
function getIterator() {
return null;
}
}
try {
new RecursiveIteratorIterator(new MyIteratorAggregate);
} catch (LogicException $e) {
echo $e->getMessage(), "\n";
}
?>
--EXPECT--
MyIteratorAggregate::getIterator() must return an object that implements Traversable