diff --git a/ext/spl/spl_iterators.c b/ext/spl/spl_iterators.c index d4e40bf6b684a..23eb95c4d7ea5 100644 --- a/ext/spl/spl_iterators.c +++ b/ext/spl/spl_iterators.c @@ -3059,10 +3059,9 @@ PHP_FUNCTION(iterator_count) /* }}} */ typedef struct { - zval *obj; - zend_long count; - zend_fcall_info fci; - zend_fcall_info_cache fcc; + zend_long count; + HashTable *params_ht; + zend_fcall_info_cache fcc; } spl_iterator_apply_info; static int spl_iterator_func_apply(zend_object_iterator *iter, void *puser) /* {{{ */ @@ -3072,7 +3071,7 @@ static int spl_iterator_func_apply(zend_object_iterator *iter, void *puser) /* { int result; apply_info->count++; - zend_call_function_with_return_value(&apply_info->fci, &apply_info->fcc, &retval); + zend_call_known_fcc(&apply_info->fcc, &retval, 0, NULL, apply_info->params_ht); result = zend_is_true(&retval) ? ZEND_HASH_APPLY_KEEP : ZEND_HASH_APPLY_STOP; zval_ptr_dtor(&retval); return result; @@ -3082,18 +3081,26 @@ static int spl_iterator_func_apply(zend_object_iterator *iter, void *puser) /* { /* {{{ Calls a function for every element in an iterator */ PHP_FUNCTION(iterator_apply) { - spl_iterator_apply_info apply_info; + zval *traversable; + zend_fcall_info dummy_fci; + spl_iterator_apply_info apply_info = { + .count = 0, + .params_ht = NULL, + .fcc = {}, + }; /* The HashTable is used to determine positional arguments */ - if (zend_parse_parameters(ZEND_NUM_ARGS(), "Of|h!", &apply_info.obj, zend_ce_traversable, - &apply_info.fci, &apply_info.fcc, &apply_info.fci.named_params) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "OF|h!", &traversable, zend_ce_traversable, + &dummy_fci, &apply_info.fcc, &apply_info.params_ht) == FAILURE) { + zend_release_fcall_info_cache(&apply_info.fcc); RETURN_THROWS(); } - apply_info.count = 0; - if (spl_iterator_apply(apply_info.obj, spl_iterator_func_apply, (void*)&apply_info) == FAILURE) { - return; + if (spl_iterator_apply(traversable, spl_iterator_func_apply, (void*)&apply_info) == FAILURE) { + zend_release_fcall_info_cache(&apply_info.fcc); + RETURN_THROWS(); } + zend_release_fcall_info_cache(&apply_info.fcc); RETURN_LONG(apply_info.count); } /* }}} */ diff --git a/ext/spl/tests/spl_iterator_apply_with_trampoline.phpt b/ext/spl/tests/spl_iterator_apply_with_trampoline.phpt new file mode 100644 index 0000000000000..7247506b85b13 --- /dev/null +++ b/ext/spl/tests/spl_iterator_apply_with_trampoline.phpt @@ -0,0 +1,48 @@ +--TEST-- +SPL: iterator_apply() with a trampoline +--FILE-- +getMessage(), PHP_EOL; +} +try { + iterator_apply($it, $callbackThrow); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} +try { + iterator_apply($it, $callback, 'not an array'); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} + +?> +--EXPECT-- +Trampoline for trampoline +array(0) { +} +int(1) +Trampoline for trampolineThrow +array(0) { +} +Exception: boo +TypeError: iterator_apply(): Argument #3 ($args) must be of type ?array, string given