From: Marcus Boerger Date: Thu, 14 Aug 2008 10:06:39 +0000 (+0000) Subject: - Improved exception linking X-Git-Tag: BEFORE_HEAD_NS_CHANGE~725 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=75b08f4adf57edf31d38718f4d85f30a4f637595;p=php - Improved exception linking --- diff --git a/Zend/zend.c b/Zend/zend.c index 9362f5a8f7..3d1b6f4881 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -1723,32 +1723,29 @@ 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)) { EG(opline_ptr) = NULL; 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); } + zend_exception_restore(TSRMLS_C); + if (EG(exception)) { + zval_ptr_dtor(&EG(exception)); + EG(exception) = NULL; + } } else { - if (!EG(exception)) { - EG(exception) = old_exception; - } + 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 2696d66091..71dedf5764 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 d8fa3938f0..1705861e21 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 7abf272872..030e102e2e 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -200,6 +200,7 @@ void init_executor(TSRMLS_D) /* {{{ */ #endif EG(exception) = NULL; + EG(prev_exception) = NULL; EG(scope) = NULL; EG(called_scope) = NULL; @@ -1110,7 +1111,7 @@ ZEND_API int zend_u_lookup_class_ex(zend_uchar type, zstr name, int name_length, 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; @@ -1123,7 +1124,7 @@ ZEND_API int zend_u_lookup_class_ex(zend_uchar type, zstr name, int name_length, zend_u_hash_del(EG(in_autoload), type, lc_name, lc_name_len + 1); if (retval == FAILURE) { - EG(exception) = exception; + zend_exception_restore(TSRMLS_C); if (do_normalize) { efree(lc_free.v); } @@ -1131,15 +1132,14 @@ ZEND_API int zend_u_lookup_class_ex(zend_uchar type, zstr name, int name_length, } if (EG(exception) && exception) { + zend_exception_restore(TSRMLS_C); if (do_normalize) { efree(lc_free.v); } zend_error(E_ERROR, "Function %s(%R) threw an exception of type '%v'", ZEND_AUTOLOAD_FUNC_NAME, type, 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 d075af337b..ea26e3f210 100644 --- a/Zend/zend_globals.h +++ b/Zend/zend_globals.h @@ -227,7 +227,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 654efe0b10..afedb57199 100644 --- a/Zend/zend_objects.c +++ b/Zend/zend_objects.c @@ -55,7 +55,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) { @@ -97,10 +96,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 cef9d961ab..19c8b87e42 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -2581,6 +2581,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); @@ -2589,6 +2590,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(); } @@ -2599,6 +2601,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 e8649a43c9..4c884f2d8e 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -1209,6 +1209,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 */ @@ -1649,6 +1650,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); @@ -1657,6 +1659,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(); } @@ -5073,6 +5076,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); @@ -5081,6 +5085,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(); } @@ -8402,6 +8407,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); @@ -8410,6 +8416,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(); } @@ -23099,6 +23106,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); @@ -23107,6 +23115,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 f8fa3a5a60..64bf651694 100755 --- a/ext/spl/php_spl.c +++ b/ext/spl/php_spl.c @@ -381,11 +381,7 @@ PHP_FUNCTION(spl_autoload_call) func_name_type = 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_u_call_method(alfi->obj ? &alfi->obj : NULL, alfi->ce, &alfi->func_ptr, func_name_type, func_name, func_name_len, &retval, 1, zclass_name, NULL 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); } @@ -394,7 +390,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.v); SPL_G(autoload_running) = l_autoload_running; } else {