@@ -41,6 +41,9 @@ ZEND_API zend_class_entry *zend_ce_value_error;
4141ZEND_API zend_class_entry * zend_ce_arithmetic_error ;
4242ZEND_API zend_class_entry * zend_ce_division_by_zero_error ;
4343
44+ /* Internal pseudo-exception that is not exposed to userland. */
45+ static zend_class_entry zend_ce_unwind_exit ;
46+
4447ZEND_API void (* zend_throw_exception_hook )(zval * ex );
4548
4649static zend_object_handlers default_exception_handlers ;
@@ -81,6 +84,12 @@ void zend_exception_set_previous(zend_object *exception, zend_object *add_previo
8184 if (exception == add_previous || !add_previous || !exception ) {
8285 return ;
8386 }
87+
88+ if (zend_is_unwind_exit (add_previous )) {
89+ OBJ_RELEASE (add_previous );
90+ return ;
91+ }
92+
8493 ZVAL_OBJ (& pv , add_previous );
8594 if (!instanceof_function (Z_OBJCE (pv ), zend_ce_throwable )) {
8695 zend_error_noreturn (E_CORE_ERROR , "Previous exception must implement Throwable" );
@@ -803,6 +812,8 @@ void zend_register_default_exception(void) /* {{{ */
803812 INIT_CLASS_ENTRY (ce , "DivisionByZeroError" , class_DivisionByZeroError_methods );
804813 zend_ce_division_by_zero_error = zend_register_internal_class_ex (& ce , zend_ce_arithmetic_error );
805814 zend_ce_division_by_zero_error -> create_object = zend_default_exception_new ;
815+
816+ INIT_CLASS_ENTRY (zend_ce_unwind_exit , "UnwindExit" , NULL );
806817}
807818/* }}} */
808819
@@ -898,10 +909,11 @@ static void zend_error_va(int type, const char *file, uint32_t lineno, const cha
898909/* }}} */
899910
900911/* This function doesn't return if it uses E_ERROR */
901- ZEND_API ZEND_COLD void zend_exception_error (zend_object * ex , int severity ) /* {{{ */
912+ ZEND_API ZEND_COLD int zend_exception_error (zend_object * ex , int severity ) /* {{{ */
902913{
903914 zval exception , rv ;
904915 zend_class_entry * ce_exception ;
916+ int result = FAILURE ;
905917
906918 ZVAL_OBJ (& exception , ex );
907919 ce_exception = ex -> ce ;
@@ -961,11 +973,15 @@ ZEND_API ZEND_COLD void zend_exception_error(zend_object *ex, int severity) /* {
961973
962974 zend_string_release_ex (str , 0 );
963975 zend_string_release_ex (file , 0 );
976+ } else if (ce_exception == & zend_ce_unwind_exit ) {
977+ /* We successfully unwound, nothing more to do */
978+ result = SUCCESS ;
964979 } else {
965980 zend_error (severity , "Uncaught exception '%s'" , ZSTR_VAL (ce_exception -> name ));
966981 }
967982
968983 OBJ_RELEASE (ex );
984+ return result ;
969985}
970986/* }}} */
971987
@@ -987,3 +1003,16 @@ ZEND_API ZEND_COLD void zend_throw_exception_object(zval *exception) /* {{{ */
9871003 zend_throw_exception_internal (exception );
9881004}
9891005/* }}} */
1006+
1007+ ZEND_API ZEND_COLD void zend_throw_unwind_exit ()
1008+ {
1009+ ZEND_ASSERT (!EG (exception ));
1010+ EG (exception ) = zend_objects_new (& zend_ce_unwind_exit );
1011+ EG (opline_before_exception ) = EG (current_execute_data )-> opline ;
1012+ EG (current_execute_data )-> opline = EG (exception_op );
1013+ }
1014+
1015+ ZEND_API zend_bool zend_is_unwind_exit (zend_object * ex )
1016+ {
1017+ return ex -> ce == & zend_ce_unwind_exit ;
1018+ }
0 commit comments