]> granicus.if.org Git - php/commitdiff
- Improved exception linking
authorMarcus Boerger <helly@php.net>
Thu, 14 Aug 2008 10:06:39 +0000 (10:06 +0000)
committerMarcus Boerger <helly@php.net>
Thu, 14 Aug 2008 10:06:39 +0000 (10:06 +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 9362f5a8f7e7b1ce2a868472eb1ae5f0562ee9e1..3d1b6f48814bfb37db8f4e6ae75072e82a6c3d08 100644 (file)
@@ -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);
                                }
index 2696d66091c46ef92552a464617c1065f2b25a8e..71dedf576496b6010a2cd7d6d6d086510a84216b 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 d8fa3938f062579648437b0765ca93dc611483b3..1705861e215fa130483130a6651ef1b65d1647ef 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 7abf272872c9189c8380f5e71ec0fb83bee5de70..030e102e2ea0d47eec5169a827fcb4c5f6d1c6b2 100644 (file)
@@ -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);
        }
index d075af337b65f34f5500480935ff3f2920a42984..ea26e3f210e07741fdf6237bf20666692fb032e7 100644 (file)
@@ -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];
 
index 654efe0b107ce79aec52c64c57b215f0a6e8dd49..afedb57199c2cdc8a632bffba0409a2afd20f44d 100644 (file)
@@ -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);
        }
 }
index cef9d961ab7c51d6a70af914a3cda69d8352604f..19c8b87e42b56617cd7d940fd65bdefd12504000 100644 (file)
@@ -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 */
index e8649a43c92b2adcf92b00a0210e8acf5e77ae5a..4c884f2d8ec54311c50057c7ad161bc5a2bfca24 100644 (file)
@@ -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();
 }
index f8fa3a5a60fa0ee0a69c6ab87f957af1526e5863..64bf651694d84c3b36d1632b969ec4f6b2ab61c3 100755 (executable)
@@ -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 {