]> granicus.if.org Git - php/commitdiff
Fixed incorrect order of free/finally on exception
authorDmitry Stogov <dmitry@zend.com>
Tue, 10 Nov 2015 07:10:39 +0000 (10:10 +0300)
committerDmitry Stogov <dmitry@zend.com>
Tue, 10 Nov 2015 07:10:39 +0000 (10:10 +0300)
Zend/tests/try/try_finally_020.phpt
Zend/zend_execute.c
Zend/zend_vm_def.h
Zend/zend_vm_execute.h

index 17756812fefeed7703eb44a91d5e3f58f7f6c01f..cfb72d0c5545472ffbca6a592a99b9d91b459f1f 100644 (file)
@@ -1,7 +1,5 @@
 --TEST--
 Combination of foreach, finally and exception (call order)
---XFAIL--
-See Bug #62210 and attempt to fix it in "tmp_liveliness" branch
 --FILE--
 <?php
 class A {
index bbeab75175f61f79fc3955f1e1a1e07ecbf1c76f..0e2431199fe7186a1841b2b8cdb8d9a1296dae59 100644 (file)
@@ -2418,7 +2418,7 @@ static zend_always_inline zend_generator *zend_get_running_generator(zend_execut
 }
 /* }}} */
 
-static zend_always_inline void i_cleanup_unfinished_execution(zend_execute_data *execute_data, uint32_t op_num, uint32_t catch_op_num) /* {{{ */
+static void cleanup_unfinished_calls(zend_execute_data *execute_data, uint32_t op_num) /* {{{ */
 {
        int i;
        if (UNEXPECTED(EX(call))) {
@@ -2543,6 +2543,12 @@ static zend_always_inline void i_cleanup_unfinished_execution(zend_execute_data
                        call = EX(call);
                } while (call);
        }
+}
+/* }}} */
+
+static void cleanup_live_vars(zend_execute_data *execute_data, uint32_t op_num, uint32_t catch_op_num) /* {{{ */
+{
+       int i;
 
        for (i = 0; i < EX(func)->op_array.last_brk_cont; i++) {
                const zend_brk_cont_element *brk_cont = &EX(func)->op_array.brk_cont_array[i];
@@ -2592,7 +2598,8 @@ static zend_always_inline void i_cleanup_unfinished_execution(zend_execute_data
 /* }}} */
 
 void zend_cleanup_unfinished_execution(zend_execute_data *execute_data, uint32_t op_num, uint32_t catch_op_num) {
-       i_cleanup_unfinished_execution(execute_data, op_num, catch_op_num);
+       cleanup_unfinished_calls(execute_data, op_num);
+       cleanup_live_vars(execute_data, op_num, catch_op_num);
 }
 
 #ifdef HAVE_GCC_GLOBAL_REGS
index 1fc343b5cb2e514e426c4c5f913366091d30b62a..8fae72b2f66e062714d90d722e99c81261eb8e3c 100644 (file)
@@ -7124,11 +7124,12 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY)
                }
        }
 
-       i_cleanup_unfinished_execution(execute_data, op_num, catch_op_num);
+       cleanup_unfinished_calls(execute_data, op_num);
 
        if (finally_op_num && (!catch_op_num || catch_op_num >= finally_op_num)) {
                zval *fast_call = EX_VAR(EX(func)->op_array.opcodes[finally_op_end].op1.var);
 
+               cleanup_live_vars(execute_data, op_num, finally_op_num);
                if (in_finally && Z_OBJ_P(fast_call)) {
                        zend_exception_set_previous(EG(exception), Z_OBJ_P(fast_call));
                }
@@ -7138,6 +7139,7 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY)
                ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[finally_op_num]);
                ZEND_VM_CONTINUE();
        } else {
+               cleanup_live_vars(execute_data, op_num, catch_op_num);
                if (in_finally) {
                        /* we are going out of current finally scope */
                        zval *fast_call = EX_VAR(EX(func)->op_array.opcodes[finally_op_end].op1.var);
@@ -7557,20 +7559,25 @@ ZEND_VM_HANDLER(163, ZEND_FAST_RET, ANY, ANY)
                USE_OPLINE
 
                if (opline->extended_value == ZEND_FAST_RET_TO_FINALLY) {
+                       cleanup_live_vars(execute_data, opline - EX(func)->op_array.opcodes, opline->op2.opline_num);
                        ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[opline->op2.opline_num]);
                        ZEND_VM_CONTINUE();
                } else {
                        EG(exception) = Z_OBJ_P(fast_call);
                        Z_OBJ_P(fast_call) = NULL;
                        if (opline->extended_value == ZEND_FAST_RET_TO_CATCH) {
+                               cleanup_live_vars(execute_data, opline - EX(func)->op_array.opcodes, opline->op2.opline_num);
                                ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[opline->op2.opline_num]);
                                ZEND_VM_CONTINUE();
-                       } else if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_GENERATOR) != 0)) {
-                               zend_generator *generator = zend_get_running_generator(execute_data);
-                               zend_generator_close(generator, 1);
-                               ZEND_VM_RETURN();
                        } else {
-                               ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper);
+                               cleanup_live_vars(execute_data, opline - EX(func)->op_array.opcodes, 0);
+                               if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_GENERATOR) != 0)) {
+                                       zend_generator *generator = zend_get_running_generator(execute_data);
+                                       zend_generator_close(generator, 1);
+                                       ZEND_VM_RETURN();
+                               } else {
+                                       ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper);
+                               }
                        }
                }
        }
index dcf0f071f7a6adcb0232049347a65c37d0a64c24..5f02d4357e4bbef7a3daed9f4ab854b509a8d45c 100644 (file)
@@ -1514,11 +1514,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(
                }
        }
 
-       i_cleanup_unfinished_execution(execute_data, op_num, catch_op_num);
+       cleanup_unfinished_calls(execute_data, op_num);
 
        if (finally_op_num && (!catch_op_num || catch_op_num >= finally_op_num)) {
                zval *fast_call = EX_VAR(EX(func)->op_array.opcodes[finally_op_end].op1.var);
 
+               cleanup_live_vars(execute_data, op_num, finally_op_num);
                if (in_finally && Z_OBJ_P(fast_call)) {
                        zend_exception_set_previous(EG(exception), Z_OBJ_P(fast_call));
                }
@@ -1528,6 +1529,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(
                ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[finally_op_num]);
                ZEND_VM_CONTINUE();
        } else {
+               cleanup_live_vars(execute_data, op_num, catch_op_num);
                if (in_finally) {
                        /* we are going out of current finally scope */
                        zval *fast_call = EX_VAR(EX(func)->op_array.opcodes[finally_op_end].op1.var);
@@ -1639,20 +1641,25 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_RET_SPEC_HANDLER(ZEND_OPC
                USE_OPLINE
 
                if (opline->extended_value == ZEND_FAST_RET_TO_FINALLY) {
+                       cleanup_live_vars(execute_data, opline - EX(func)->op_array.opcodes, opline->op2.opline_num);
                        ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[opline->op2.opline_num]);
                        ZEND_VM_CONTINUE();
                } else {
                        EG(exception) = Z_OBJ_P(fast_call);
                        Z_OBJ_P(fast_call) = NULL;
                        if (opline->extended_value == ZEND_FAST_RET_TO_CATCH) {
+                               cleanup_live_vars(execute_data, opline - EX(func)->op_array.opcodes, opline->op2.opline_num);
                                ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[opline->op2.opline_num]);
                                ZEND_VM_CONTINUE();
-                       } else if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_GENERATOR) != 0)) {
-                               zend_generator *generator = zend_get_running_generator(execute_data);
-                               zend_generator_close(generator, 1);
-                               ZEND_VM_RETURN();
                        } else {
-                               ZEND_VM_TAIL_CALL(zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU));
+                               cleanup_live_vars(execute_data, opline - EX(func)->op_array.opcodes, 0);
+                               if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_GENERATOR) != 0)) {
+                                       zend_generator *generator = zend_get_running_generator(execute_data);
+                                       zend_generator_close(generator, 1);
+                                       ZEND_VM_RETURN();
+                               } else {
+                                       ZEND_VM_TAIL_CALL(zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU));
+                               }
                        }
                }
        }