diff options
| -rw-r--r-- | Zend/zend.c | 21 | ||||
| -rw-r--r-- | Zend/zend_exceptions.c | 44 | ||||
| -rw-r--r-- | Zend/zend_exceptions.h | 4 | ||||
| -rw-r--r-- | Zend/zend_execute_API.c | 10 | ||||
| -rw-r--r-- | Zend/zend_globals.h | 2 | ||||
| -rw-r--r-- | Zend/zend_objects.c | 9 | ||||
| -rw-r--r-- | Zend/zend_vm_def.h | 3 | ||||
| -rw-r--r-- | Zend/zend_vm_execute.h | 9 | ||||
| -rwxr-xr-x | ext/spl/php_spl.c | 10 |
9 files changed, 73 insertions, 39 deletions
diff --git a/Zend/zend.c b/Zend/zend.c index c2cd2450e3..ee1090dcf0 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -1197,31 +1197,28 @@ ZEND_API int zend_execute_scripts(int type TSRMLS_DC, zval **retval, int file_co 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); } diff --git a/Zend/zend_exceptions.c b/Zend/zend_exceptions.c index 90b00d76d4..aeab6e6421 100644 --- a/Zend/zend_exceptions.c +++ b/Zend/zend_exceptions.c @@ -33,21 +33,17 @@ zend_class_entry *error_exception_ce; 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) { @@ -59,12 +55,40 @@ void zend_exception_set_previous(zval *add_previous TSRMLS_DC) } } +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"); @@ -86,6 +110,10 @@ void zend_throw_exception_internal(zval *exception TSRMLS_DC) /* {{{ */ 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; } diff --git a/Zend/zend_exceptions.h b/Zend/zend_exceptions.h index 0b057c6979..3cfcaf6d2d 100644 --- a/Zend/zend_exceptions.h +++ b/Zend/zend_exceptions.h @@ -26,7 +26,9 @@ 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); diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 4b094e29a5..82c6619f0f 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -186,6 +186,7 @@ void init_executor(TSRMLS_D) /* {{{ */ #endif EG(exception) = NULL; + EG(prev_exception) = NULL; EG(scope) = NULL; EG(called_scope) = NULL; @@ -1029,7 +1030,7 @@ ZEND_API int zend_lookup_class_ex(const char *name, int name_length, int use_aut 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; @@ -1038,19 +1039,18 @@ ZEND_API int zend_lookup_class_ex(const char *name, int name_length, int use_aut 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); } diff --git a/Zend/zend_globals.h b/Zend/zend_globals.h index fb27175525..88fe44e083 100644 --- a/Zend/zend_globals.h +++ b/Zend/zend_globals.h @@ -239,7 +239,7 @@ struct _zend_executor_globals { 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]; diff --git a/Zend/zend_objects.c b/Zend/zend_objects.c index 3e88eeefef..12aebc7c56 100644 --- a/Zend/zend_objects.c +++ b/Zend/zend_objects.c @@ -53,7 +53,6 @@ ZEND_API void zend_objects_destroy_object(zend_object *object, zend_object_handl 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) { @@ -96,10 +95,12 @@ ZEND_API void zend_objects_destroy_object(zend_object *object, zend_object_handl * 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); } } diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 9b0a4369f0..c07b49741d 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -2515,6 +2515,7 @@ ZEND_VM_HANDLER(108, ZEND_THROW, CONST|TMP|VAR|CV, ANY) 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); @@ -2523,6 +2524,7 @@ ZEND_VM_HANDLER(108, ZEND_THROW, CONST|TMP|VAR|CV, ANY) } zend_throw_exception_object(exception TSRMLS_CC); + zend_exception_restore(TSRMLS_C); FREE_OP1_IF_VAR(); ZEND_VM_NEXT_OPCODE(); } @@ -2533,6 +2535,7 @@ ZEND_VM_HANDLER(107, ZEND_CATCH, ANY, CV) 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 */ diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index c7da5e3e0b..80151b35e5 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -1228,6 +1228,7 @@ static int ZEND_FASTCALL ZEND_CATCH_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) 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 */ @@ -1655,6 +1656,7 @@ static int ZEND_FASTCALL ZEND_THROW_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS 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); @@ -1663,6 +1665,7 @@ static int ZEND_FASTCALL ZEND_THROW_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS } zend_throw_exception_object(exception TSRMLS_CC); + zend_exception_restore(TSRMLS_C); ZEND_VM_NEXT_OPCODE(); } @@ -4936,6 +4939,7 @@ static int ZEND_FASTCALL ZEND_THROW_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) 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); @@ -4944,6 +4948,7 @@ static int ZEND_FASTCALL ZEND_THROW_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } zend_throw_exception_object(exception TSRMLS_CC); + zend_exception_restore(TSRMLS_C); ZEND_VM_NEXT_OPCODE(); } @@ -8121,6 +8126,7 @@ static int ZEND_FASTCALL ZEND_THROW_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) 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); @@ -8129,6 +8135,7 @@ static int ZEND_FASTCALL ZEND_THROW_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } 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(); } @@ -22193,6 +22200,7 @@ static int ZEND_FASTCALL ZEND_THROW_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) 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); @@ -22201,6 +22209,7 @@ static int ZEND_FASTCALL ZEND_THROW_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } zend_throw_exception_object(exception TSRMLS_CC); + zend_exception_restore(TSRMLS_C); ZEND_VM_NEXT_OPCODE(); } diff --git a/ext/spl/php_spl.c b/ext/spl/php_spl.c index 522cda68f5..22a264bde7 100755 --- a/ext/spl/php_spl.c +++ b/ext/spl/php_spl.c @@ -381,7 +381,6 @@ PHP_FUNCTION(spl_autoload_call) 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); @@ -390,12 +389,7 @@ PHP_FUNCTION(spl_autoload_call) 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); } @@ -404,7 +398,7 @@ PHP_FUNCTION(spl_autoload_call) } 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 { |
