]> granicus.if.org Git - php/commitdiff
Fixed bug #66608 (Incorrect behavior with nested "finally" blocks)
authorXinchen Hui <laruence@php.net>
Fri, 18 Jul 2014 07:45:31 +0000 (15:45 +0800)
committerXinchen Hui <laruence@php.net>
Fri, 18 Jul 2014 07:45:31 +0000 (15:45 +0800)
NEWS
Zend/tests/bug66608.phpt [new file with mode: 0644]
Zend/zend_compile.h
Zend/zend_opcode.c
Zend/zend_vm_def.h
Zend/zend_vm_execute.h

diff --git a/NEWS b/NEWS
index cea00519e28eedd32903f9b8377b1bcf43cd8060..44c09d0d7d5ac788a1cb9d1df10f6609e986f663 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -17,6 +17,8 @@ PHP                                                                        NEWS
   . Fixed bug #67151 (strtr with empty array crashes). (Nikita)
   . Fixed bug #67407 (Windows 8.1/Server 2012 R2 reported as Windows 8/Server
     2012). (Christian Wenz)
+  . Fixed bug #66608 (Incorrect behavior with nested "finally" blocks).
+    (Laruence, Dmitry)
   . Implemented FR #34407 (ucwords and Title Case). (Tjerk)
 
 - CLI server:
diff --git a/Zend/tests/bug66608.phpt b/Zend/tests/bug66608.phpt
new file mode 100644 (file)
index 0000000..6329506
--- /dev/null
@@ -0,0 +1,39 @@
+--TEST--
+Bug #66608 (Incorrect behavior with nested "finally" blocks)
+--FILE--
+<?php
+function bar() {
+       try {
+               echo "1\n";
+       } finally {
+               try {
+                       throw new Exception ("");
+               } catch (Exception $ab) {
+                       echo "2\n";
+               } finally {
+                       try {
+                       } finally {
+                               echo "3\n";
+                               try  {
+                               } finally {
+                               }
+                               echo "4\n";
+                       }
+               }
+               echo "5\n";
+               try {
+               } finally {
+                       echo "6\n";
+               }
+       }
+       echo "7\n";
+}
+bar();
+--EXPECT--
+1
+2
+3
+4
+5
+6
+7
index 2a3d58e490c7a3b3348c26d520876af4c5abab51..e6e30f37b7d889137dee2489c7b9d485385bb331 100644 (file)
@@ -843,6 +843,9 @@ int zend_add_literal(zend_op_array *op_array, const zval *zv TSRMLS_DC);
 #define ZEND_FAST_RET_TO_CATCH         1
 #define ZEND_FAST_RET_TO_FINALLY       2
 
+#define ZEND_FAST_CALL_FOR_CATCH       1
+#define ZEND_FAST_CALL_FOR_FINALLY     2
+
 END_EXTERN_C()
 
 #define ZEND_CLONE_FUNC_NAME           "__clone"
index 025e8faa3c29cc5af637259e524e6cbb896b0b59..cd810ec36f7aef0204910b89f6a3f2adbe5d0c85 100644 (file)
@@ -538,7 +538,7 @@ static void zend_resolve_finally_call(zend_op_array *op_array, zend_uint op_num,
                        SET_UNUSED(opline->op2);
                        opline->op1.opline_num = op_array->try_catch_array[i].finally_op;
                        if (op_array->try_catch_array[i].catch_op) {
-                               opline->extended_value = 1;
+                               opline->extended_value = ZEND_FAST_CALL_FOR_CATCH;
                                opline->op2.opline_num = op_array->try_catch_array[i].catch_op;
                        }
 
@@ -603,6 +603,26 @@ static void zend_resolve_finally_ret(zend_op_array *op_array, zend_uint op_num T
        }
 }
 
+static void zend_resolve_fast_call(zend_op_array *op_array, zend_uint op_num TSRMLS_DC)
+{
+       int i;
+       zend_uint finally_op_num = 0;
+
+       for (i = 0; i < op_array->last_try_catch; i++) {
+               if (op_array->try_catch_array[i].finally_op > op_num) {
+                       break;
+               }
+               if (op_num < op_array->try_catch_array[i].finally_end) {
+                       finally_op_num = op_array->try_catch_array[i].finally_op;
+               }
+       }
+
+       if (finally_op_num) {
+               op_array->opcodes[op_num].extended_value = ZEND_FAST_CALL_FOR_FINALLY;
+               op_array->opcodes[op_num].op2.opline_num = finally_op_num - 2; /* it must be ZEND_FAST_CALL */
+       } 
+}
+
 static void zend_resolve_finally_calls(zend_op_array *op_array TSRMLS_DC)
 {
        zend_uint i;
@@ -644,6 +664,9 @@ static void zend_resolve_finally_calls(zend_op_array *op_array TSRMLS_DC)
                        case ZEND_JMP:
                                zend_resolve_finally_call(op_array, i, opline->op1.opline_num TSRMLS_CC);
                                break;
+                       case ZEND_FAST_CALL:
+                               zend_resolve_fast_call(op_array, i TSRMLS_CC);
+                               break;
                        case ZEND_FAST_RET:
                                zend_resolve_finally_ret(op_array, i TSRMLS_CC);
                                break;
index f76e52961ae0d0143c2b781cf97e44a0ea4c52f4..161dd7744246ceb3122640284d59e116296bb00f 100644 (file)
@@ -5396,13 +5396,13 @@ ZEND_VM_HANDLER(162, ZEND_FAST_CALL, ANY, ANY)
 {
        USE_OPLINE
 
-       if (opline->extended_value &&
+       if ((opline->extended_value & ZEND_FAST_CALL_FOR_CATCH) &&
            UNEXPECTED(EG(prev_exception) != NULL)) {
            /* in case of unhandled exception jump to catch block instead of finally */
                ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[opline->op2.opline_num]);
                ZEND_VM_CONTINUE();
        }
-       EX(fast_ret) = opline + 1;
+       EX(fast_ret) = opline;
        ZEND_VM_SET_OPCODE(opline->op1.jmp_addr);
        ZEND_VM_CONTINUE();
 }
@@ -5410,7 +5410,10 @@ ZEND_VM_HANDLER(162, ZEND_FAST_CALL, ANY, ANY)
 ZEND_VM_HANDLER(163, ZEND_FAST_RET, ANY, ANY)
 {
        if (EX(fast_ret)) {
-               ZEND_VM_SET_OPCODE(EX(fast_ret));
+               ZEND_VM_SET_OPCODE(EX(fast_ret) + 1);
+               if ((EX(fast_ret)->extended_value & ZEND_FAST_CALL_FOR_FINALLY)) {
+                       EX(fast_ret) = &EX(op_array)->opcodes[EX(fast_ret)->op2.opline_num];
+               }
                ZEND_VM_CONTINUE();
        } else {
                /* special case for unhandled exceptions */
index 94026a08efccf4a111727fb98acee6ae71cbe6a2..c94c2d755b3895c81ae9ca55ef77ba6f42cce391 100644 (file)
@@ -1137,13 +1137,13 @@ static int ZEND_FASTCALL  ZEND_FAST_CALL_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
 {
        USE_OPLINE
 
-       if (opline->extended_value &&
+       if ((opline->extended_value & ZEND_FAST_CALL_FOR_CATCH) &&
            UNEXPECTED(EG(prev_exception) != NULL)) {
            /* in case of unhandled exception jump to catch block instead of finally */
                ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[opline->op2.opline_num]);
                ZEND_VM_CONTINUE();
        }
-       EX(fast_ret) = opline + 1;
+       EX(fast_ret) = opline;
        ZEND_VM_SET_OPCODE(opline->op1.jmp_addr);
        ZEND_VM_CONTINUE();
 }
@@ -1151,7 +1151,10 @@ static int ZEND_FASTCALL  ZEND_FAST_CALL_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
 static int ZEND_FASTCALL  ZEND_FAST_RET_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
 {
        if (EX(fast_ret)) {
-               ZEND_VM_SET_OPCODE(EX(fast_ret));
+               ZEND_VM_SET_OPCODE(EX(fast_ret) + 1);
+               if ((EX(fast_ret)->extended_value & ZEND_FAST_CALL_FOR_FINALLY)) {
+                       EX(fast_ret) = &EX(op_array)->opcodes[EX(fast_ret)->op2.opline_num];
+               }
                ZEND_VM_CONTINUE();
        } else {
                /* special case for unhandled exceptions */