if (EG(active_op_array)) {
EG(return_value_ptr_ptr) = retval ? retval : NULL;
zend_execute(EG(active_op_array) TSRMLS_CC);
+ zend_exception_restore(TSRMLS_C);
if (EG(exception)) {
if (EG(user_exception_handler)) {
zval *orig_user_exception_handler;
- zval ***params, *retval2, *old_exception;
- params = (zval ***)emalloc(sizeof(zval **));
+ zval **params[1], *retval2, *old_exception;
old_exception = EG(exception);
- EG(exception) = NULL;
+ zend_exception_save(TSRMLS_C);
params[0] = &old_exception;
orig_user_exception_handler = EG(user_exception_handler);
if (call_user_function_ex(CG(function_table), NULL, orig_user_exception_handler, &retval2, 1, params, 1, NULL TSRMLS_CC) == SUCCESS) {
if (retval2 != NULL) {
zval_ptr_dtor(&retval2);
}
- } else {
- if (!EG(exception)) {
- EG(exception) = old_exception;
+ zend_exception_restore(TSRMLS_C);
+ if (EG(exception)) {
+ zval_ptr_dtor(&EG(exception));
+ EG(exception) = NULL;
}
+ } else {
+ zend_exception_restore(TSRMLS_C);
zend_exception_error(EG(exception) TSRMLS_CC);
}
- efree(params);
- zval_ptr_dtor(&old_exception);
- if (EG(exception)) {
- zval_ptr_dtor(&EG(exception));
- EG(exception) = NULL;
- }
} else {
zend_exception_error(EG(exception) TSRMLS_CC);
}
static zend_object_handlers default_exception_handlers;
ZEND_API void (*zend_throw_exception_hook)(zval *ex TSRMLS_DC);
-void zend_exception_set_previous(zval *add_previous TSRMLS_DC)
+void zend_exception_set_previous(zval *exception, zval *add_previous TSRMLS_DC)
{
- zval *exception = EG(exception), *previous;
+ zval *previous;
- if (exception == add_previous || !add_previous) {
+ if (exception == add_previous || !add_previous || !exception) {
return;
}
if (Z_TYPE_P(add_previous) != IS_OBJECT && !instanceof_function(Z_OBJCE_P(add_previous), default_exception_ce TSRMLS_CC)) {
zend_error(E_ERROR, "Cannot set non exception as previous exception");
return;
}
- if (!exception) {
- EG(exception) = add_previous;
- return;
- }
while (exception && exception != add_previous && Z_OBJ_HANDLE_P(exception) != Z_OBJ_HANDLE_P(add_previous)) {
previous = zend_read_property(default_exception_ce, exception, "previous", sizeof("previous")-1, 1 TSRMLS_CC);
if (Z_TYPE_P(previous) == IS_NULL) {
}
}
+void zend_exception_save(TSRMLS_D) /* {{{ */
+{
+ if (EG(prev_exception)) {
+ zend_exception_set_previous(EG(exception), EG(prev_exception) TSRMLS_CC);
+ }
+ if (EG(exception)) {
+ EG(prev_exception) = EG(exception);
+ }
+ EG(exception) = NULL;
+}
+/* }}} */
+
+void zend_exception_restore(TSRMLS_D) /* {{{ */
+{
+ if (EG(prev_exception)) {
+ if (EG(exception)) {
+ zend_exception_set_previous(EG(exception), EG(prev_exception) TSRMLS_CC);
+ } else {
+ EG(exception) = EG(prev_exception);
+ }
+ EG(prev_exception) = NULL;
+ }
+}
+/* }}} */
+
void zend_throw_exception_internal(zval *exception TSRMLS_DC) /* {{{ */
{
if (exception != NULL) {
zval *previous = EG(exception);
+ zend_exception_set_previous(exception, EG(exception) TSRMLS_CC);
EG(exception) = exception;
- zend_exception_set_previous(previous TSRMLS_CC);
+ if (previous) {
+ return;
+ }
}
if (!EG(current_execute_data)) {
zend_error(E_ERROR, "Exception thrown without a stack frame");
ZEND_API void zend_clear_exception(TSRMLS_D) /* {{{ */
{
+ if (EG(prev_exception)) {
+ zval_ptr_dtor(&EG(prev_exception));
+ EG(prev_exception) = NULL;
+ }
if (!EG(exception)) {
return;
}
BEGIN_EXTERN_C()
-ZEND_API void zend_exception_set_previous(zval *add_previous TSRMLS_DC);
+ZEND_API void zend_exception_set_previous(zval *exception, zval *add_previous TSRMLS_DC);
+ZEND_API void zend_exception_save(TSRMLS_D);
+ZEND_API void zend_exception_restore(TSRMLS_D);
void zend_throw_exception_internal(zval *exception TSRMLS_DC);
#endif
EG(exception) = NULL;
+ EG(prev_exception) = NULL;
EG(scope) = NULL;
EG(called_scope) = NULL;
fcall_cache.object_pp = NULL;
exception = EG(exception);
- EG(exception) = NULL;
+ zend_exception_save(TSRMLS_C);
retval = zend_call_function(&fcall_info, &fcall_cache TSRMLS_CC);
EG(autoload_func) = fcall_cache.function_handler;
zend_hash_del(EG(in_autoload), lc_name, name_length + 1);
if (retval == FAILURE) {
- EG(exception) = exception;
+ zend_exception_restore(TSRMLS_C);
free_alloca(lc_free, use_heap);
return FAILURE;
}
if (EG(exception) && exception) {
+ zend_exception_restore(TSRMLS_C);
free_alloca(lc_free, use_heap);
zend_error(E_ERROR, "Function %s(%s) threw an exception of type '%s'", ZEND_AUTOLOAD_FUNC_NAME, name, Z_OBJCE_P(EG(exception))->name);
return FAILURE;
}
- if (!EG(exception)) {
- EG(exception) = exception;
- }
+ zend_exception_restore(TSRMLS_C);
if (retval_ptr) {
zval_ptr_dtor(&retval_ptr);
}
HashTable *modified_ini_directives;
zend_objects_store objects_store;
- zval *exception;
+ zval *exception, *prev_exception;
zend_op *opline_before_exception;
zend_op exception_op[3];
if (destructor) {
zval *obj;
- zval *old_exception;
if (destructor->op_array.fn_flags & (ZEND_ACC_PRIVATE|ZEND_ACC_PROTECTED)) {
if (destructor->op_array.fn_flags & ZEND_ACC_PRIVATE) {
* For example, if an exception was thrown in a function and when the function's
* local variable destruction results in a destructor being called.
*/
- old_exception = EG(exception);
- EG(exception) = NULL;
+ if (EG(exception) && Z_OBJ_HANDLE_P(EG(exception)) == handle) {
+ zend_error(E_ERROR, "Attempt to destruct pending exception");
+ }
+ zend_exception_save(TSRMLS_C);
zend_call_method_with_0_params(&obj, object->ce, &destructor, ZEND_DESTRUCTOR_FUNC_NAME, NULL);
- zend_exception_set_previous(old_exception TSRMLS_CC);
+ zend_exception_restore(TSRMLS_C);
zval_ptr_dtor(&obj);
}
}
if (Z_TYPE_P(value) != IS_OBJECT) {
zend_error_noreturn(E_ERROR, "Can only throw objects");
}
+ zend_exception_save(TSRMLS_C);
/* Not sure if a complete copy is what we want here */
ALLOC_ZVAL(exception);
INIT_PZVAL_COPY(exception, value);
}
zend_throw_exception_object(exception TSRMLS_CC);
+ zend_exception_restore(TSRMLS_C);
FREE_OP1_IF_VAR();
ZEND_VM_NEXT_OPCODE();
}
zend_class_entry *ce;
/* Check whether an exception has been thrown, if not, jump over code */
+ zend_exception_restore(TSRMLS_C);
if (EG(exception) == NULL) {
ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[opline->extended_value]);
ZEND_VM_CONTINUE(); /* CHECK_ME */
zend_class_entry *ce;
/* Check whether an exception has been thrown, if not, jump over code */
+ zend_exception_restore(TSRMLS_C);
if (EG(exception) == NULL) {
ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[opline->extended_value]);
ZEND_VM_CONTINUE(); /* CHECK_ME */
if (Z_TYPE_P(value) != IS_OBJECT) {
zend_error_noreturn(E_ERROR, "Can only throw objects");
}
+ zend_exception_save(TSRMLS_C);
/* Not sure if a complete copy is what we want here */
ALLOC_ZVAL(exception);
INIT_PZVAL_COPY(exception, value);
}
zend_throw_exception_object(exception TSRMLS_CC);
+ zend_exception_restore(TSRMLS_C);
ZEND_VM_NEXT_OPCODE();
}
if (Z_TYPE_P(value) != IS_OBJECT) {
zend_error_noreturn(E_ERROR, "Can only throw objects");
}
+ zend_exception_save(TSRMLS_C);
/* Not sure if a complete copy is what we want here */
ALLOC_ZVAL(exception);
INIT_PZVAL_COPY(exception, value);
}
zend_throw_exception_object(exception TSRMLS_CC);
+ zend_exception_restore(TSRMLS_C);
ZEND_VM_NEXT_OPCODE();
}
if (Z_TYPE_P(value) != IS_OBJECT) {
zend_error_noreturn(E_ERROR, "Can only throw objects");
}
+ zend_exception_save(TSRMLS_C);
/* Not sure if a complete copy is what we want here */
ALLOC_ZVAL(exception);
INIT_PZVAL_COPY(exception, value);
}
zend_throw_exception_object(exception TSRMLS_CC);
+ zend_exception_restore(TSRMLS_C);
if (free_op1.var) {zval_ptr_dtor(&free_op1.var);};
ZEND_VM_NEXT_OPCODE();
}
if (Z_TYPE_P(value) != IS_OBJECT) {
zend_error_noreturn(E_ERROR, "Can only throw objects");
}
+ zend_exception_save(TSRMLS_C);
/* Not sure if a complete copy is what we want here */
ALLOC_ZVAL(exception);
INIT_PZVAL_COPY(exception, value);
}
zend_throw_exception_object(exception TSRMLS_CC);
+ zend_exception_restore(TSRMLS_C);
ZEND_VM_NEXT_OPCODE();
}
if (SPL_G(autoload_functions)) {
int l_autoload_running = SPL_G(autoload_running);
- zval *exception = NULL;
SPL_G(autoload_running) = 1;
class_name_len = Z_STRLEN_P(class_name);
lc_name = zend_str_tolower_dup(Z_STRVAL_P(class_name), class_name_len);
zend_hash_get_current_key_ex(SPL_G(autoload_functions), &func_name, &func_name_len, &dummy, 0, &function_pos);
zend_hash_get_current_data_ex(SPL_G(autoload_functions), (void **) &alfi, &function_pos);
zend_call_method(alfi->obj ? &alfi->obj : NULL, alfi->ce, &alfi->func_ptr, func_name, func_name_len, &retval, 1, class_name, NULL TSRMLS_CC);
- zend_exception_set_previous(exception TSRMLS_CC);
- if (EG(exception)) {
- zend_exception_set_previous(exception TSRMLS_CC);
- exception = EG(exception);
- EG(exception) = NULL;
- }
+ zend_exception_save(TSRMLS_C);
if (retval) {
zval_ptr_dtor(&retval);
}
}
zend_hash_move_forward_ex(SPL_G(autoload_functions), &function_pos);
}
- EG(exception) = exception;
+ zend_exception_restore(TSRMLS_C);
efree(lc_name);
SPL_G(autoload_running) = l_autoload_running;
} else {