Skip to content

Commit be07170

Browse files
committed
Fixed bug #72188 (Nested try/finally blocks losing return value)
1 parent e9c3f9f commit be07170

8 files changed

Lines changed: 43 additions & 11 deletions

File tree

NEWS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ PHP NEWS
1414
null byte). (Francois)
1515
. Fixed bug #71897 (ASCII 0x7F Delete control character permitted in
1616
identifiers). (Andrea)
17+
. Fixed bug #72188 (Nested try/finally blocks losing return value). (Dmitry)
1718
. Implemented the RFC `Support Class Constant Visibility`. (Sean DuBois,
1819
Reeze Xia, Dmitry)
1920
. Added void return type. (Andrea)

Zend/tests/bug72188.phpt

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
--TEST--
2+
Bug #72188 (Nested try/finally blocks losing return value)
3+
--FILE--
4+
<?php
5+
function test() {
6+
try {
7+
return 5;
8+
} finally {
9+
try {
10+
echo 1;
11+
} finally {
12+
echo 2;
13+
}
14+
}
15+
}
16+
17+
18+
19+
$a = test();
20+
if($a !== 5) {
21+
echo "FAILED: expected 5, received ", var_export($a), PHP_EOL;
22+
} else {
23+
echo "Passed", PHP_EOL;
24+
}
25+
?>
26+
--EXPECT--
27+
12Passed

Zend/zend_compile.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4532,6 +4532,7 @@ void zend_compile_try(zend_ast *ast) /* {{{ */
45324532
zend_op *opline;
45334533
uint32_t try_catch_offset;
45344534
uint32_t *jmp_opnums = safe_emalloc(sizeof(uint32_t), catches->children, 0);
4535+
uint32_t orig_fast_call_var = CG(context).fast_call_var;
45354536

45364537
if (catches->children == 0 && !finally_ast) {
45374538
zend_error_noreturn(E_COMPILE_ERROR, "Cannot use try without catch or finally");
@@ -4554,8 +4555,8 @@ void zend_compile_try(zend_ast *ast) /* {{{ */
45544555
zend_loop_var fast_call;
45554556
if (!(CG(active_op_array)->fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK)) {
45564557
CG(active_op_array)->fn_flags |= ZEND_ACC_HAS_FINALLY_BLOCK;
4557-
CG(context).fast_call_var = get_temporary_variable(CG(active_op_array));
45584558
}
4559+
CG(context).fast_call_var = get_temporary_variable(CG(active_op_array));
45594560

45604561
/* Push FAST_CALL on unwind stack */
45614562
fast_call.opcode = ZEND_FAST_CALL;
@@ -4665,6 +4666,8 @@ void zend_compile_try(zend_ast *ast) /* {{{ */
46654666
opline->op1.var = CG(context).fast_call_var;
46664667

46674668
zend_update_jump_target_to_next(opnum_jmp);
4669+
4670+
CG(context).fast_call_var = orig_fast_call_var;
46684671
}
46694672

46704673
efree(jmp_opnums);

Zend/zend_opcode.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -550,7 +550,6 @@ static void zend_resolve_fast_call(zend_op_array *op_array, uint32_t op_num)
550550
/* Must be ZEND_FAST_CALL */
551551
ZEND_ASSERT(op_array->opcodes[op_array->try_catch_array[finally_num].finally_op - 2].opcode == ZEND_FAST_CALL);
552552
op_array->opcodes[op_num].extended_value = ZEND_FAST_CALL_FROM_FINALLY;
553-
op_array->opcodes[op_num].op2.num = finally_num;
554553
}
555554
}
556555

Zend/zend_vm_def.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7531,7 +7531,7 @@ ZEND_VM_HANDLER(159, ZEND_DISCARD_EXCEPTION, ANY, ANY)
75317531
ZEND_VM_NEXT_OPCODE();
75327532
}
75337533

7534-
ZEND_VM_HANDLER(162, ZEND_FAST_CALL, JMP_ADDR, TRY_CATCH, FAST_CALL)
7534+
ZEND_VM_HANDLER(162, ZEND_FAST_CALL, JMP_ADDR, ANY, FAST_CALL)
75357535
{
75367536
USE_OPLINE
75377537
zval *fast_call = EX_VAR(opline->result.var);
@@ -7554,9 +7554,6 @@ ZEND_VM_HANDLER(163, ZEND_FAST_RET, ANY, TRY_CATCH, FAST_RET)
75547554

75557555
if (fast_call->u2.lineno != (uint32_t)-1) {
75567556
const zend_op *fast_ret = EX(func)->op_array.opcodes + fast_call->u2.lineno;
7557-
if (fast_ret->extended_value & ZEND_FAST_CALL_FROM_FINALLY) {
7558-
fast_call->u2.lineno = EX(func)->op_array.try_catch_array[fast_ret->op2.num].finally_op - 2;
7559-
}
75607557
ZEND_VM_SET_OPCODE(fast_ret + 1);
75617558
ZEND_VM_CONTINUE();
75627559
} else {
@@ -7565,7 +7562,11 @@ ZEND_VM_HANDLER(163, ZEND_FAST_RET, ANY, TRY_CATCH, FAST_RET)
75657562

75667563
if (opline->extended_value == ZEND_FAST_RET_TO_FINALLY) {
75677564
uint32_t finally_op = EX(func)->op_array.try_catch_array[opline->op2.num].finally_op;
7565+
uint32_t finally_end = EX(func)->op_array.try_catch_array[opline->op2.num].finally_end;
7566+
zval *next_fast_call = EX_VAR(EX(func)->op_array.opcodes[finally_end].op1.var);
75687567

7568+
Z_OBJ_P(next_fast_call) = Z_OBJ_P(fast_call);
7569+
next_fast_call->u2.lineno = (uint32_t)-1;
75697570
cleanup_live_vars(execute_data, opline - EX(func)->op_array.opcodes, finally_op);
75707571
ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[finally_op]);
75717572
ZEND_VM_CONTINUE();

Zend/zend_vm_execute.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1845,9 +1845,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_RET_SPEC_HANDLER(ZEND_OPC
18451845

18461846
if (fast_call->u2.lineno != (uint32_t)-1) {
18471847
const zend_op *fast_ret = EX(func)->op_array.opcodes + fast_call->u2.lineno;
1848-
if (fast_ret->extended_value & ZEND_FAST_CALL_FROM_FINALLY) {
1849-
fast_call->u2.lineno = EX(func)->op_array.try_catch_array[fast_ret->op2.num].finally_op - 2;
1850-
}
18511848
ZEND_VM_SET_OPCODE(fast_ret + 1);
18521849
ZEND_VM_CONTINUE();
18531850
} else {
@@ -1856,7 +1853,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_RET_SPEC_HANDLER(ZEND_OPC
18561853

18571854
if (opline->extended_value == ZEND_FAST_RET_TO_FINALLY) {
18581855
uint32_t finally_op = EX(func)->op_array.try_catch_array[opline->op2.num].finally_op;
1856+
uint32_t finally_end = EX(func)->op_array.try_catch_array[opline->op2.num].finally_end;
1857+
zval *next_fast_call = EX_VAR(EX(func)->op_array.opcodes[finally_end].op1.var);
18591858

1859+
Z_OBJ_P(next_fast_call) = Z_OBJ_P(fast_call);
1860+
next_fast_call->u2.lineno = (uint32_t)-1;
18601861
cleanup_live_vars(execute_data, opline - EX(func)->op_array.opcodes, finally_op);
18611862
ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[finally_op]);
18621863
ZEND_VM_CONTINUE();

Zend/zend_vm_opcodes.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,7 @@ static uint32_t zend_vm_opcodes_flags[184] = {
371371
0x00000000,
372372
0x0b000303,
373373
0x00000003,
374-
0x09003020,
374+
0x09000020,
375375
0x0a003000,
376376
0x00000010,
377377
0x00000000,

sapi/phpdbg/tests/stepping_001.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ prompt> [L10 %s ECHO "ok"
3434
00011: } finally {
3535
00012: echo " ... ok";
3636
prompt> ok
37-
[L11 %s FAST_CALL J8 try-catch(0) ~%d %s]
37+
[L11 %s FAST_CALL J8 ~%d %s]
3838
>00011: } finally {
3939
00012: echo " ... ok";
4040
00013: }

0 commit comments

Comments
 (0)