]> granicus.if.org Git - php/commitdiff
- MFH Improve exception linking
authorMarcus Boerger <helly@php.net>
Thu, 14 Aug 2008 10:24:52 +0000 (10:24 +0000)
committerMarcus Boerger <helly@php.net>
Thu, 14 Aug 2008 10:24:52 +0000 (10:24 +0000)
Zend/zend.c
Zend/zend_exceptions.c
Zend/zend_exceptions.h
Zend/zend_execute_API.c
Zend/zend_globals.h
Zend/zend_objects.c
Zend/zend_vm_def.h
Zend/zend_vm_execute.h
ext/spl/php_spl.c

index c2cd2450e393dc9faf0ebef8ca0b6e3d34a2baad..ee1090dcf0505b6949bcfa88394491e7c1c7d21f 100644 (file)
@@ -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);
                                }
index 90b00d76d41092924068423c8c9c87e8cdbb4b67..aeab6e6421c60564eac91b8702817da487583397 100644 (file)
@@ -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;
        }
index 0b057c697900c35e6c1d99f46c1fc13a772d84ec..3cfcaf6d2df3171923ca2a2e583d0bad85330d50 100644 (file)
@@ -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);
 
index 4b094e29a5b0fbc2ca0e8f5844d9c7782eabe003..82c6619f0f2cc2acb355daefbdc45d8b95581e56 100644 (file)
@@ -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);
        }
index fb2717552507e65d0e3722166c2e031216e726f0..88fe44e08315a929a4ee0efa84c24282c2a6335f 100644 (file)
@@ -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];
 
index 3e88eeefef98f2d9a6d61ae48e693be79af6732e..12aebc7c5609cbfae95bc9d929ea298f9e6d8b8d 100644 (file)
@@ -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);
        }
 }
index 9b0a4369f0b2f5e2531bd836949fb35a2d943b91..c07b49741d0f3f1d34e159ee8f724ab056406d17 100644 (file)
@@ -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 */
index c7da5e3e0b7b06b6e8394d2b965f03b811927319..80151b35e5ac80ad4fc66d82490c9478fb682894 100644 (file)
@@ -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();
 }
index 522cda68f56d66d6b99ef36fd5e08db706720cc8..22a264bde7f749293b4d5b2b512e2bb4c71129b3 100755 (executable)
@@ -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 {