null byte). (Francois)
. Fixed bug #71897 (ASCII 0x7F Delete control character permitted in
identifiers). (Andrea)
+ . Fixed bug #72188 (Nested try/finally blocks losing return value). (Dmitry)
. Implemented the RFC `Support Class Constant Visibility`. (Sean DuBois,
Reeze Xia, Dmitry)
. Added void return type. (Andrea)
--- /dev/null
+--TEST--
+Bug #72188 (Nested try/finally blocks losing return value)
+--FILE--
+<?php
+function test() {
+ try {
+ return 5;
+ } finally {
+ try {
+ echo 1;
+ } finally {
+ echo 2;
+ }
+ }
+}
+
+
+
+$a = test();
+if($a !== 5) {
+ echo "FAILED: expected 5, received ", var_export($a), PHP_EOL;
+} else {
+ echo "Passed", PHP_EOL;
+}
+?>
+--EXPECT--
+12Passed
zend_op *opline;
uint32_t try_catch_offset;
uint32_t *jmp_opnums = safe_emalloc(sizeof(uint32_t), catches->children, 0);
+ uint32_t orig_fast_call_var = CG(context).fast_call_var;
if (catches->children == 0 && !finally_ast) {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot use try without catch or finally");
zend_loop_var fast_call;
if (!(CG(active_op_array)->fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK)) {
CG(active_op_array)->fn_flags |= ZEND_ACC_HAS_FINALLY_BLOCK;
- CG(context).fast_call_var = get_temporary_variable(CG(active_op_array));
}
+ CG(context).fast_call_var = get_temporary_variable(CG(active_op_array));
/* Push FAST_CALL on unwind stack */
fast_call.opcode = ZEND_FAST_CALL;
opline->op1.var = CG(context).fast_call_var;
zend_update_jump_target_to_next(opnum_jmp);
+
+ CG(context).fast_call_var = orig_fast_call_var;
}
efree(jmp_opnums);
/* Must be ZEND_FAST_CALL */
ZEND_ASSERT(op_array->opcodes[op_array->try_catch_array[finally_num].finally_op - 2].opcode == ZEND_FAST_CALL);
op_array->opcodes[op_num].extended_value = ZEND_FAST_CALL_FROM_FINALLY;
- op_array->opcodes[op_num].op2.num = finally_num;
}
}
ZEND_VM_NEXT_OPCODE();
}
-ZEND_VM_HANDLER(162, ZEND_FAST_CALL, JMP_ADDR, TRY_CATCH, FAST_CALL)
+ZEND_VM_HANDLER(162, ZEND_FAST_CALL, JMP_ADDR, ANY, FAST_CALL)
{
USE_OPLINE
zval *fast_call = EX_VAR(opline->result.var);
if (fast_call->u2.lineno != (uint32_t)-1) {
const zend_op *fast_ret = EX(func)->op_array.opcodes + fast_call->u2.lineno;
- if (fast_ret->extended_value & ZEND_FAST_CALL_FROM_FINALLY) {
- fast_call->u2.lineno = EX(func)->op_array.try_catch_array[fast_ret->op2.num].finally_op - 2;
- }
ZEND_VM_SET_OPCODE(fast_ret + 1);
ZEND_VM_CONTINUE();
} else {
if (opline->extended_value == ZEND_FAST_RET_TO_FINALLY) {
uint32_t finally_op = EX(func)->op_array.try_catch_array[opline->op2.num].finally_op;
+ uint32_t finally_end = EX(func)->op_array.try_catch_array[opline->op2.num].finally_end;
+ zval *next_fast_call = EX_VAR(EX(func)->op_array.opcodes[finally_end].op1.var);
+ Z_OBJ_P(next_fast_call) = Z_OBJ_P(fast_call);
+ next_fast_call->u2.lineno = (uint32_t)-1;
cleanup_live_vars(execute_data, opline - EX(func)->op_array.opcodes, finally_op);
ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[finally_op]);
ZEND_VM_CONTINUE();
if (fast_call->u2.lineno != (uint32_t)-1) {
const zend_op *fast_ret = EX(func)->op_array.opcodes + fast_call->u2.lineno;
- if (fast_ret->extended_value & ZEND_FAST_CALL_FROM_FINALLY) {
- fast_call->u2.lineno = EX(func)->op_array.try_catch_array[fast_ret->op2.num].finally_op - 2;
- }
ZEND_VM_SET_OPCODE(fast_ret + 1);
ZEND_VM_CONTINUE();
} else {
if (opline->extended_value == ZEND_FAST_RET_TO_FINALLY) {
uint32_t finally_op = EX(func)->op_array.try_catch_array[opline->op2.num].finally_op;
+ uint32_t finally_end = EX(func)->op_array.try_catch_array[opline->op2.num].finally_end;
+ zval *next_fast_call = EX_VAR(EX(func)->op_array.opcodes[finally_end].op1.var);
+ Z_OBJ_P(next_fast_call) = Z_OBJ_P(fast_call);
+ next_fast_call->u2.lineno = (uint32_t)-1;
cleanup_live_vars(execute_data, opline - EX(func)->op_array.opcodes, finally_op);
ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[finally_op]);
ZEND_VM_CONTINUE();
0x00000000,
0x0b000303,
0x00000003,
- 0x09003020,
+ 0x09000020,
0x0a003000,
0x00000010,
0x00000000,
00011: } finally {
00012: echo " ... ok";
prompt> ok
-[L11 %s FAST_CALL J8 try-catch(0) ~%d %s]
+[L11 %s FAST_CALL J8 ~%d %s]
>00011: } finally {
00012: echo " ... ok";
00013: }