diff --git a/ext/spl/spl_iterators.c b/ext/spl/spl_iterators.c index 425bd99f37c0..05bdfdb34ba3 100644 --- a/ext/spl/spl_iterators.c +++ b/ext/spl/spl_iterators.c @@ -251,6 +251,13 @@ static void spl_recursive_it_get_current_key(zend_object_iterator *iter, zval *k } } +static bool spl_can_catch_exception(zend_long flags) +{ + return (flags & CIT_CATCH_GET_CHILD) + && !zend_is_unwind_exit(EG(exception)) + && !zend_is_graceful_exit(EG(exception)); +} + static void spl_recursive_it_move_forward_ex(spl_recursive_it_object *object, zval *zthis) { zend_object_iterator *iterator; @@ -271,7 +278,7 @@ static void spl_recursive_it_move_forward_ex(spl_recursive_it_object *object, zv case RS_NEXT: iterator->funcs->move_forward(iterator); if (EG(exception)) { - if (!(object->flags & RIT_CATCH_GET_CHILD)) { + if (!spl_can_catch_exception(object->flags)) { return; } else { zend_clear_exception(); @@ -308,7 +315,7 @@ static void spl_recursive_it_move_forward_ex(spl_recursive_it_object *object, zv zend_call_method_with_0_params(obj, ce, cache, "haschildren", &retval); } if (EG(exception)) { - if (!(object->flags & RIT_CATCH_GET_CHILD)) { + if (!spl_can_catch_exception(object->flags)) { object->iterators[object->level].state = RS_NEXT; return; } else { @@ -344,7 +351,7 @@ static void spl_recursive_it_move_forward_ex(spl_recursive_it_object *object, zv } object->iterators[object->level].state = RS_NEXT; if (EG(exception)) { - if (!(object->flags & RIT_CATCH_GET_CHILD)) { + if (!spl_can_catch_exception(object->flags)) { return; } else { zend_clear_exception(); @@ -373,7 +380,7 @@ static void spl_recursive_it_move_forward_ex(spl_recursive_it_object *object, zv } if (EG(exception)) { - if (!(object->flags & RIT_CATCH_GET_CHILD)) { + if (!spl_can_catch_exception(object->flags)) { return; } else { zend_clear_exception(); @@ -417,7 +424,7 @@ static void spl_recursive_it_move_forward_ex(spl_recursive_it_object *object, zv if (object->beginChildren) { zend_call_method_with_0_params(Z_OBJ_P(zthis), object->ce, &object->beginChildren, "beginchildren", NULL); if (EG(exception)) { - if (!(object->flags & RIT_CATCH_GET_CHILD)) { + if (!spl_can_catch_exception(object->flags)) { return; } else { zend_clear_exception(); @@ -431,7 +438,7 @@ static void spl_recursive_it_move_forward_ex(spl_recursive_it_object *object, zv if (object->endChildren) { zend_call_method_with_0_params(Z_OBJ_P(zthis), object->ce, &object->endChildren, "endchildren", NULL); if (EG(exception)) { - if (!(object->flags & RIT_CATCH_GET_CHILD)) { + if (!spl_can_catch_exception(object->flags)) { return; } else { zend_clear_exception(); @@ -2300,7 +2307,7 @@ static inline void spl_caching_it_next(spl_dual_it_object *intern) zend_call_method_with_0_params(Z_OBJ(intern->inner.zobject), intern->inner.ce, NULL, "haschildren", &retval); if (EG(exception)) { zval_ptr_dtor(&retval); - if (intern->u.caching.flags & CIT_CATCH_GET_CHILD) { + if (spl_can_catch_exception(intern->u.caching.flags)) { zend_clear_exception(); } else { return; @@ -2316,7 +2323,7 @@ static inline void spl_caching_it_next(spl_dual_it_object *intern) zend_call_method_with_0_params(Z_OBJ(intern->inner.zobject), intern->inner.ce, NULL, "getchildren", &args[0]); if (EG(exception)) { zval_ptr_dtor(&args[0]); - if (intern->u.caching.flags & CIT_CATCH_GET_CHILD) { + if (spl_can_catch_exception(intern->u.caching.flags)) { zend_clear_exception(); } else { return; @@ -2333,7 +2340,7 @@ static inline void spl_caching_it_next(spl_dual_it_object *intern) ); zval_ptr_dtor(&args[0]); if (is_initialized == FAILURE) { - if (intern->u.caching.flags & CIT_CATCH_GET_CHILD) { + if (spl_can_catch_exception(intern->u.caching.flags)) { zend_clear_exception(); } else { return; diff --git a/ext/spl/tests/gh24264_1.phpt b/ext/spl/tests/gh24264_1.phpt new file mode 100644 index 000000000000..dd0005a81589 --- /dev/null +++ b/ext/spl/tests/gh24264_1.phpt @@ -0,0 +1,24 @@ +--TEST-- +GH-24264 (Unwind/GracefulExit discarded in spl_iterators.c): RecursiveIteratorIterator hasChildren() +--FILE-- + +--EXPECT-- +exit diff --git a/ext/spl/tests/gh24264_2.phpt b/ext/spl/tests/gh24264_2.phpt new file mode 100644 index 000000000000..d71c282a6410 --- /dev/null +++ b/ext/spl/tests/gh24264_2.phpt @@ -0,0 +1,23 @@ +--TEST-- +GH-24264 (Unwind/GracefulExit discarded in spl_iterators.c): RecursiveCachingIterator hasChildren() +--FILE-- + +--EXPECT-- +exit diff --git a/ext/spl/tests/gh24264_3.phpt b/ext/spl/tests/gh24264_3.phpt new file mode 100644 index 000000000000..985ef5399e14 --- /dev/null +++ b/ext/spl/tests/gh24264_3.phpt @@ -0,0 +1,24 @@ +--TEST-- +GH-24264 (Unwind/GracefulExit discarded in spl_iterators.c): RecursiveIteratorIterator getChildren() +--FILE-- + +--EXPECT-- +exit diff --git a/ext/spl/tests/gh24264_4.phpt b/ext/spl/tests/gh24264_4.phpt new file mode 100644 index 000000000000..b59950bc2a54 --- /dev/null +++ b/ext/spl/tests/gh24264_4.phpt @@ -0,0 +1,23 @@ +--TEST-- +GH-24264 (Unwind/GracefulExit discarded in spl_iterators.c): RecursiveCachingIterator getChildren() +--FILE-- + +--EXPECT-- +exit diff --git a/ext/spl/tests/gh24264_5.phpt b/ext/spl/tests/gh24264_5.phpt new file mode 100644 index 000000000000..620ee4a43403 --- /dev/null +++ b/ext/spl/tests/gh24264_5.phpt @@ -0,0 +1,35 @@ +--TEST-- +GH-24264 (Unwind/GracefulExit discarded in spl_iterators.c): destroyed fiber suspended in getChildren() +--FILE-- +start(); +unset($fiber); + +echo "Done\n"; +?> +--EXPECT-- +finally +Done