diff --git a/Zend/tests/gh13446_1.phpt b/Zend/tests/gh13446_1.phpt new file mode 100644 index 0000000000000..cb51d041c969f --- /dev/null +++ b/Zend/tests/gh13446_1.phpt @@ -0,0 +1,19 @@ +--TEST-- +GH-13446: Exception handler is restored after is has finished +--FILE-- +getMessage(), "\n"; +} +set_exception_handler('exception_handler'); + +register_shutdown_function(function () { + echo set_exception_handler(null), "\n"; + restore_exception_handler(); +}); + +throw new Exception('Test'); +?> +--EXPECT-- +Exception caught: Test +exception_handler diff --git a/Zend/tests/gh13446_2.phpt b/Zend/tests/gh13446_2.phpt new file mode 100644 index 0000000000000..c1bab44ce80bf --- /dev/null +++ b/Zend/tests/gh13446_2.phpt @@ -0,0 +1,16 @@ +--TEST-- +GH-13446: Exception handler attempting to free itself +--FILE-- + +--EXPECT-- +object(stdClass)#1 (0) { +} diff --git a/Zend/tests/gh13446_3.phpt b/Zend/tests/gh13446_3.phpt new file mode 100644 index 0000000000000..eb56eb1b32d89 --- /dev/null +++ b/Zend/tests/gh13446_3.phpt @@ -0,0 +1,25 @@ +--TEST-- +GH-13446: Exception handler isn't restored if it is previously modified +--FILE-- + +--EXPECT-- +Handler 1 +exception_handler_2 diff --git a/Zend/tests/gh13446_4.phpt b/Zend/tests/gh13446_4.phpt new file mode 100644 index 0000000000000..634d16f38a0a3 --- /dev/null +++ b/Zend/tests/gh13446_4.phpt @@ -0,0 +1,21 @@ +--TEST-- +GH-13446: Exception handler isn't restored if stack is empty +--FILE-- + +--EXPECT-- +Handler +NULL diff --git a/Zend/zend.c b/Zend/zend.c index d154c67382a72..28922647bba1d 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -1839,7 +1839,9 @@ ZEND_API ZEND_COLD void zend_user_exception_handler(void) /* {{{ */ old_exception = EG(exception); EG(exception) = NULL; ZVAL_OBJ(¶ms[0], old_exception); + ZVAL_COPY_VALUE(&orig_user_exception_handler, &EG(user_exception_handler)); + zend_stack_push(&EG(user_exception_handlers), &orig_user_exception_handler); ZVAL_UNDEF(&EG(user_exception_handler)); if (call_user_function(CG(function_table), NULL, &orig_user_exception_handler, &retval2, 1, params) == SUCCESS) { @@ -1853,7 +1855,13 @@ ZEND_API ZEND_COLD void zend_user_exception_handler(void) /* {{{ */ EG(exception) = old_exception; } - zval_ptr_dtor(&orig_user_exception_handler); + if (Z_TYPE(EG(user_exception_handler)) == IS_UNDEF) { + zval *tmp = zend_stack_top(&EG(user_exception_handlers)); + if (tmp) { + ZVAL_COPY_VALUE(&EG(user_exception_handler), tmp); + zend_stack_del_top(&EG(user_exception_handlers)); + } + } } /* }}} */ ZEND_API zend_result zend_execute_scripts(int type, zval *retval, int file_count, ...) /* {{{ */