]> granicus.if.org Git - php/commitdiff
Fixed bug #72188 (Nested try/finally blocks losing return value)
authorDmitry Stogov <dmitry@zend.com>
Fri, 13 May 2016 11:38:43 +0000 (14:38 +0300)
committerDmitry Stogov <dmitry@zend.com>
Fri, 13 May 2016 11:38:43 +0000 (14:38 +0300)
NEWS
Zend/tests/bug72188.phpt [new file with mode: 0644]
Zend/zend_compile.c
Zend/zend_opcode.c
Zend/zend_vm_def.h
Zend/zend_vm_execute.h
Zend/zend_vm_opcodes.c
sapi/phpdbg/tests/stepping_001.phpt

diff --git a/NEWS b/NEWS
index 9b26cdbda968cf6fc3367304d10a6548bac248c7..0553dc9029e23287a132b90af6a3ad7400eddcf7 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -14,6 +14,7 @@ PHP                                                                        NEWS
     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)
diff --git a/Zend/tests/bug72188.phpt b/Zend/tests/bug72188.phpt
new file mode 100644 (file)
index 0000000..0deab6b
--- /dev/null
@@ -0,0 +1,27 @@
+--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
index c534088b58ae77b91140270e21d37291615f1973..7ae54da5bbda3173c34a0012acd8fccde42e9ae5 100644 (file)
@@ -4532,6 +4532,7 @@ void zend_compile_try(zend_ast *ast) /* {{{ */
        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");
@@ -4554,8 +4555,8 @@ void zend_compile_try(zend_ast *ast) /* {{{ */
                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;
@@ -4665,6 +4666,8 @@ void zend_compile_try(zend_ast *ast) /* {{{ */
                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);
index 27c04e3a76df0215d6be768fcea1c86c0a2c6319..34e060fa4aebd740bd0f24bfb88fa3547d0f9593 100644 (file)
@@ -550,7 +550,6 @@ static void zend_resolve_fast_call(zend_op_array *op_array, uint32_t op_num)
                /* 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;
        }
 }
 
index b65075830c43e5677db85316149f61eff008b620..2750d8e60a4e853a2eec856007b64beb670ffcc8 100644 (file)
@@ -7531,7 +7531,7 @@ ZEND_VM_HANDLER(159, ZEND_DISCARD_EXCEPTION, ANY, ANY)
        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);
@@ -7554,9 +7554,6 @@ ZEND_VM_HANDLER(163, ZEND_FAST_RET, ANY, TRY_CATCH, FAST_RET)
 
        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 {
@@ -7565,7 +7562,11 @@ ZEND_VM_HANDLER(163, ZEND_FAST_RET, ANY, TRY_CATCH, FAST_RET)
 
                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();
index 9eaff4624dd4b762e8680af9af88c27196d4e77d..5b09255f30c0332636df2895fff5ba94083fd2e3 100644 (file)
@@ -1845,9 +1845,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_RET_SPEC_HANDLER(ZEND_OPC
 
        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 {
@@ -1856,7 +1853,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_RET_SPEC_HANDLER(ZEND_OPC
 
                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();
index 3edde60853a9348472b6eff5e0eef4c23a871f27..180b745fb25797433094315ca43f37b26bf1d041 100644 (file)
@@ -371,7 +371,7 @@ static uint32_t zend_vm_opcodes_flags[184] = {
        0x00000000,
        0x0b000303,
        0x00000003,
-       0x09003020,
+       0x09000020,
        0x0a003000,
        0x00000010,
        0x00000000,
index ec9def278ffe2d2a7277969a37369ce1aea937c6..9366550f5663401fce00a1957255645e6948f6fc 100644 (file)
@@ -34,7 +34,7 @@ prompt> [L10 %s ECHO                    "ok"
  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: }