diff options
author | Dmitry Stogov <dmitry@zend.com> | 2015-11-10 10:10:39 +0300 |
---|---|---|
committer | Dmitry Stogov <dmitry@zend.com> | 2015-11-10 10:10:39 +0300 |
commit | d66d1b97aa5c30e4222d1d57d3d2e0f7522c998f (patch) | |
tree | 20e18ad1210a46ae9a8760c8a8d1f097c8d1cb92 /Zend | |
parent | 795af791b09112e9c522665320ee0b5b426d9073 (diff) | |
download | php-git-d66d1b97aa5c30e4222d1d57d3d2e0f7522c998f.tar.gz |
Fixed incorrect order of free/finally on exception
Diffstat (limited to 'Zend')
-rw-r--r-- | Zend/tests/try/try_finally_020.phpt | 2 | ||||
-rw-r--r-- | Zend/zend_execute.c | 11 | ||||
-rw-r--r-- | Zend/zend_vm_def.h | 19 | ||||
-rw-r--r-- | Zend/zend_vm_execute.h | 19 |
4 files changed, 35 insertions, 16 deletions
diff --git a/Zend/tests/try/try_finally_020.phpt b/Zend/tests/try/try_finally_020.phpt index 17756812fe..cfb72d0c55 100644 --- a/Zend/tests/try/try_finally_020.phpt +++ b/Zend/tests/try/try_finally_020.phpt @@ -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 { diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index bbeab75175..0e2431199f 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -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 diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 1fc343b5cb..8fae72b2f6 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -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); + } } } } diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index dcf0f071f7..5f02d4357e 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -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)); + } } } } |