Skip to content

Commit 6fe457f

Browse files
committed
Merge branch 'PHP-7.0'
* PHP-7.0: Fixed incorrect order of free/finally on exception
2 parents 7bc6361 + d66d1b9 commit 6fe457f

File tree

4 files changed

+35
-16
lines changed

4 files changed

+35
-16
lines changed

Zend/tests/try/try_finally_020.phpt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
--TEST--
22
Combination of foreach, finally and exception (call order)
3-
--XFAIL--
4-
See Bug #62210 and attempt to fix it in "tmp_liveliness" branch
53
--FILE--
64
<?php
75
class A {

Zend/zend_execute.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2418,7 +2418,7 @@ static zend_always_inline zend_generator *zend_get_running_generator(zend_execut
24182418
}
24192419
/* }}} */
24202420

2421-
static zend_always_inline void i_cleanup_unfinished_execution(zend_execute_data *execute_data, uint32_t op_num, uint32_t catch_op_num) /* {{{ */
2421+
static void cleanup_unfinished_calls(zend_execute_data *execute_data, uint32_t op_num) /* {{{ */
24222422
{
24232423
int i;
24242424
if (UNEXPECTED(EX(call))) {
@@ -2543,6 +2543,12 @@ static zend_always_inline void i_cleanup_unfinished_execution(zend_execute_data
25432543
call = EX(call);
25442544
} while (call);
25452545
}
2546+
}
2547+
/* }}} */
2548+
2549+
static void cleanup_live_vars(zend_execute_data *execute_data, uint32_t op_num, uint32_t catch_op_num) /* {{{ */
2550+
{
2551+
int i;
25462552

25472553
for (i = 0; i < EX(func)->op_array.last_brk_cont; i++) {
25482554
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
25922598
/* }}} */
25932599

25942600
void zend_cleanup_unfinished_execution(zend_execute_data *execute_data, uint32_t op_num, uint32_t catch_op_num) {
2595-
i_cleanup_unfinished_execution(execute_data, op_num, catch_op_num);
2601+
cleanup_unfinished_calls(execute_data, op_num);
2602+
cleanup_live_vars(execute_data, op_num, catch_op_num);
25962603
}
25972604

25982605
#ifdef HAVE_GCC_GLOBAL_REGS

Zend/zend_vm_def.h

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7277,11 +7277,12 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY)
72777277
}
72787278
}
72797279

7280-
i_cleanup_unfinished_execution(execute_data, op_num, catch_op_num);
7280+
cleanup_unfinished_calls(execute_data, op_num);
72817281

72827282
if (finally_op_num && (!catch_op_num || catch_op_num >= finally_op_num)) {
72837283
zval *fast_call = EX_VAR(EX(func)->op_array.opcodes[finally_op_end].op1.var);
72847284

7285+
cleanup_live_vars(execute_data, op_num, finally_op_num);
72857286
if (in_finally && Z_OBJ_P(fast_call)) {
72867287
zend_exception_set_previous(EG(exception), Z_OBJ_P(fast_call));
72877288
}
@@ -7291,6 +7292,7 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY)
72917292
ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[finally_op_num]);
72927293
ZEND_VM_CONTINUE();
72937294
} else {
7295+
cleanup_live_vars(execute_data, op_num, catch_op_num);
72947296
if (in_finally) {
72957297
/* we are going out of current finally scope */
72967298
zval *fast_call = EX_VAR(EX(func)->op_array.opcodes[finally_op_end].op1.var);
@@ -7710,20 +7712,25 @@ ZEND_VM_HANDLER(163, ZEND_FAST_RET, ANY, JMP_ABS, FAST_RET)
77107712
USE_OPLINE
77117713

77127714
if (opline->extended_value == ZEND_FAST_RET_TO_FINALLY) {
7715+
cleanup_live_vars(execute_data, opline - EX(func)->op_array.opcodes, opline->op2.opline_num);
77137716
ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[opline->op2.opline_num]);
77147717
ZEND_VM_CONTINUE();
77157718
} else {
77167719
EG(exception) = Z_OBJ_P(fast_call);
77177720
Z_OBJ_P(fast_call) = NULL;
77187721
if (opline->extended_value == ZEND_FAST_RET_TO_CATCH) {
7722+
cleanup_live_vars(execute_data, opline - EX(func)->op_array.opcodes, opline->op2.opline_num);
77197723
ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[opline->op2.opline_num]);
77207724
ZEND_VM_CONTINUE();
7721-
} else if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_GENERATOR) != 0)) {
7722-
zend_generator *generator = zend_get_running_generator(execute_data);
7723-
zend_generator_close(generator, 1);
7724-
ZEND_VM_RETURN();
77257725
} else {
7726-
ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper);
7726+
cleanup_live_vars(execute_data, opline - EX(func)->op_array.opcodes, 0);
7727+
if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_GENERATOR) != 0)) {
7728+
zend_generator *generator = zend_get_running_generator(execute_data);
7729+
zend_generator_close(generator, 1);
7730+
ZEND_VM_RETURN();
7731+
} else {
7732+
ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper);
7733+
}
77277734
}
77287735
}
77297736
}

Zend/zend_vm_execute.h

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1514,11 +1514,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(
15141514
}
15151515
}
15161516

1517-
i_cleanup_unfinished_execution(execute_data, op_num, catch_op_num);
1517+
cleanup_unfinished_calls(execute_data, op_num);
15181518

15191519
if (finally_op_num && (!catch_op_num || catch_op_num >= finally_op_num)) {
15201520
zval *fast_call = EX_VAR(EX(func)->op_array.opcodes[finally_op_end].op1.var);
15211521

1522+
cleanup_live_vars(execute_data, op_num, finally_op_num);
15221523
if (in_finally && Z_OBJ_P(fast_call)) {
15231524
zend_exception_set_previous(EG(exception), Z_OBJ_P(fast_call));
15241525
}
@@ -1528,6 +1529,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(
15281529
ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[finally_op_num]);
15291530
ZEND_VM_CONTINUE();
15301531
} else {
1532+
cleanup_live_vars(execute_data, op_num, catch_op_num);
15311533
if (in_finally) {
15321534
/* we are going out of current finally scope */
15331535
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
16391641
USE_OPLINE
16401642

16411643
if (opline->extended_value == ZEND_FAST_RET_TO_FINALLY) {
1644+
cleanup_live_vars(execute_data, opline - EX(func)->op_array.opcodes, opline->op2.opline_num);
16421645
ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[opline->op2.opline_num]);
16431646
ZEND_VM_CONTINUE();
16441647
} else {
16451648
EG(exception) = Z_OBJ_P(fast_call);
16461649
Z_OBJ_P(fast_call) = NULL;
16471650
if (opline->extended_value == ZEND_FAST_RET_TO_CATCH) {
1651+
cleanup_live_vars(execute_data, opline - EX(func)->op_array.opcodes, opline->op2.opline_num);
16481652
ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[opline->op2.opline_num]);
16491653
ZEND_VM_CONTINUE();
1650-
} else if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_GENERATOR) != 0)) {
1651-
zend_generator *generator = zend_get_running_generator(execute_data);
1652-
zend_generator_close(generator, 1);
1653-
ZEND_VM_RETURN();
16541654
} else {
1655-
ZEND_VM_TAIL_CALL(zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU));
1655+
cleanup_live_vars(execute_data, opline - EX(func)->op_array.opcodes, 0);
1656+
if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_GENERATOR) != 0)) {
1657+
zend_generator *generator = zend_get_running_generator(execute_data);
1658+
zend_generator_close(generator, 1);
1659+
ZEND_VM_RETURN();
1660+
} else {
1661+
ZEND_VM_TAIL_CALL(zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU));
1662+
}
16561663
}
16571664
}
16581665
}

0 commit comments

Comments
 (0)