]> granicus.if.org Git - php/commitdiff
Improve fix for #66608
authorXinchen Hui <laruence@php.net>
Sat, 19 Jul 2014 09:19:01 +0000 (17:19 +0800)
committerXinchen Hui <laruence@php.net>
Sat, 19 Jul 2014 09:19:01 +0000 (17:19 +0800)
Zend/tests/bug66608.phpt
Zend/zend_compile.h
Zend/zend_opcode.c
Zend/zend_vm_def.h
Zend/zend_vm_execute.h

index 6329506d0662e6137f05247d6ec6765994b8b452..5a499a1dab15efb99fe31f7f507dd6588fd43255 100644 (file)
@@ -5,28 +5,56 @@ Bug #66608 (Incorrect behavior with nested "finally" blocks)
 function bar() {
        try {
                echo "1\n";
+               try {
+               } finally {
+                       try {
+                       } finally {
+                       }
+                       echo "2\n";
+               }
        } finally {
                try {
                        throw new Exception ("");
                } catch (Exception $ab) {
-                       echo "2\n";
+                       echo "3\n";
                } finally {
                        try {
                        } finally {
-                               echo "3\n";
+                               echo "4\n";
                                try  {
                                } finally {
                                }
-                               echo "4\n";
+                               echo "5\n";
                        }
                }
-               echo "5\n";
+               echo "6\n";
                try {
                } finally {
-                       echo "6\n";
+                       while (1) {
+                               try {
+                                       echo "7\n";
+                                       break;
+                               } finally {
+                                       echo "8\n";
+                               }
+                               echo "bad";
+                       }
+                       echo "9\n";
+                       while (1) {
+                               try {
+                                       throw new Exception("");
+                               } catch(Exception $e) {
+                                       echo "10\n";
+                                       break;
+                               } finally {
+                                       echo "11\n";
+                               }
+                               echo "bak\n";
+                       }
                }
+               echo "12\n";
        }
-       echo "7\n";
+       echo "13\n";
 }
 bar();
 --EXPECT--
@@ -37,3 +65,9 @@ bar();
 5
 6
 7
+8
+9
+10
+11
+12
+13
index e6e30f37b7d889137dee2489c7b9d485385bb331..f6b1be96fa61c67cd1fbfbcb5872b7f313afd6c9 100644 (file)
@@ -843,8 +843,8 @@ 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
+#define ZEND_FAST_CALL_FROM_CATCH      1
+#define ZEND_FAST_CALL_FROM_FINALLY    2
 
 END_EXTERN_C()
 
index b3fb11f00f63e4085e1c5e19033093aa91dfc78e..5c032d94bd37fbd78722df7610599665bd6db4bb 100644 (file)
@@ -509,6 +509,49 @@ static void zend_check_finally_breakout(zend_op_array *op_array, zend_uint op_nu
        } 
 }
 
+static void zend_adjust_fast_call(zend_op_array *op_array, zend_uint fast_call, zend_uint start, zend_uint end TSRMLS_DC)
+{
+       int i;
+       zend_uint op_num = 0;
+
+       for (i = 0; i < op_array->last_try_catch; i++) {
+               if (op_array->try_catch_array[i].finally_op > start 
+                               && op_array->try_catch_array[i].finally_end < end) {
+                       op_num = op_array->try_catch_array[i].finally_op;
+                       start = op_array->try_catch_array[i].finally_end;
+               }
+       }
+
+       if (op_num) {
+               /* Must be ZEND_FAST_CALL */
+               ZEND_ASSERT(op_array->opcodes[op_num - 2].opcode == ZEND_FAST_CALL);
+               op_array->opcodes[op_num - 2].extended_value = ZEND_FAST_CALL_FROM_FINALLY;
+               op_array->opcodes[op_num - 2].op2.opline_num = fast_call;
+       }
+}
+
+static void zend_resolve_fast_call(zend_op_array *op_array, zend_uint fast_call, 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_num >= op_array->try_catch_array[i].finally_op
+                               && 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) {
+               /* Must be ZEND_FAST_CALL */
+               ZEND_ASSERT(op_array->opcodes[finally_op_num - 2].opcode == ZEND_FAST_CALL);
+               if (op_array->opcodes[fast_call].extended_value == 0) {
+                       op_array->opcodes[fast_call].extended_value = ZEND_FAST_CALL_FROM_FINALLY;
+                       op_array->opcodes[fast_call].op2.opline_num = finally_op_num - 2;
+               }
+       } 
+}
+
 static void zend_resolve_finally_call(zend_op_array *op_array, zend_uint op_num, zend_uint dst_num TSRMLS_DC)
 {
        zend_uint start_op;
@@ -536,11 +579,23 @@ static void zend_resolve_finally_call(zend_op_array *op_array, zend_uint op_num,
                        opline->opcode = ZEND_FAST_CALL;
                        SET_UNUSED(opline->op1);
                        SET_UNUSED(opline->op2);
-                       opline->op1.opline_num = op_array->try_catch_array[i].finally_op;
+                       zend_adjust_fast_call(op_array, start_op,
+                                       op_array->try_catch_array[i].finally_op,
+                                       op_array->try_catch_array[i].finally_end TSRMLS_CC);
                        if (op_array->try_catch_array[i].catch_op) {
-                               opline->extended_value = ZEND_FAST_CALL_FOR_CATCH;
+                               opline->extended_value = ZEND_FAST_CALL_FROM_CATCH;
                                opline->op2.opline_num = op_array->try_catch_array[i].catch_op;
+                               opline->op1.opline_num = get_next_op_number(op_array);
+                               /* generate a FAST_CALL to hole CALL_FROM_FINALLY */
+                               opline = get_next_op(op_array TSRMLS_CC);
+                               opline->opcode = ZEND_FAST_CALL;
+                               SET_UNUSED(opline->op1);
+                               SET_UNUSED(opline->op2);
+                               zend_resolve_fast_call(op_array, start_op + 1, op_array->try_catch_array[i].finally_op - 2 TSRMLS_CC);
+                       } else {
+                               zend_resolve_fast_call(op_array, start_op, op_array->try_catch_array[i].finally_op - 2 TSRMLS_CC);
                        }
+                       opline->op1.opline_num = op_array->try_catch_array[i].finally_op;
 
                        /* generate a sequence of FAST_CALL to upward finally block */
                        while (i > 0) {
@@ -603,26 +658,6 @@ 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, j;
@@ -666,7 +701,7 @@ static void zend_resolve_finally_calls(zend_op_array *op_array TSRMLS_DC)
                                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);
+                               zend_resolve_fast_call(op_array, i, i TSRMLS_CC);
                                break;
                        case ZEND_FAST_RET:
                                zend_resolve_finally_ret(op_array, i TSRMLS_CC);
index 161dd7744246ceb3122640284d59e116296bb00f..79453f13b333f9c8d1e935db8b7070778fc05f53 100644 (file)
@@ -5396,7 +5396,7 @@ ZEND_VM_HANDLER(162, ZEND_FAST_CALL, ANY, ANY)
 {
        USE_OPLINE
 
-       if ((opline->extended_value & ZEND_FAST_CALL_FOR_CATCH) &&
+       if ((opline->extended_value & ZEND_FAST_CALL_FROM_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]);
@@ -5411,7 +5411,7 @@ ZEND_VM_HANDLER(163, ZEND_FAST_RET, ANY, ANY)
 {
        if (EX(fast_ret)) {
                ZEND_VM_SET_OPCODE(EX(fast_ret) + 1);
-               if ((EX(fast_ret)->extended_value & ZEND_FAST_CALL_FOR_FINALLY)) {
+               if ((EX(fast_ret)->extended_value & ZEND_FAST_CALL_FROM_FINALLY)) {
                        EX(fast_ret) = &EX(op_array)->opcodes[EX(fast_ret)->op2.opline_num];
                }
                ZEND_VM_CONTINUE();
index c94c2d755b3895c81ae9ca55ef77ba6f42cce391..4d2b6f266c67d91bee6a6442882bf960e40eb731 100644 (file)
@@ -1137,7 +1137,7 @@ static int ZEND_FASTCALL  ZEND_FAST_CALL_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
 {
        USE_OPLINE
 
-       if ((opline->extended_value & ZEND_FAST_CALL_FOR_CATCH) &&
+       if ((opline->extended_value & ZEND_FAST_CALL_FROM_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]);
@@ -1152,7 +1152,7 @@ static int ZEND_FASTCALL  ZEND_FAST_RET_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
 {
        if (EX(fast_ret)) {
                ZEND_VM_SET_OPCODE(EX(fast_ret) + 1);
-               if ((EX(fast_ret)->extended_value & ZEND_FAST_CALL_FOR_FINALLY)) {
+               if ((EX(fast_ret)->extended_value & ZEND_FAST_CALL_FROM_FINALLY)) {
                        EX(fast_ret) = &EX(op_array)->opcodes[EX(fast_ret)->op2.opline_num];
                }
                ZEND_VM_CONTINUE();