]> granicus.if.org Git - php/commitdiff
Refactor examing of jumping out of finally block
authorXinchen Hui <laruence@php.net>
Fri, 17 Aug 2012 16:16:34 +0000 (00:16 +0800)
committerXinchen Hui <laruence@php.net>
Fri, 17 Aug 2012 16:16:34 +0000 (00:16 +0800)
Zend/tests/try_finally_005.phpt
Zend/tests/try_finally_006.phpt
Zend/tests/try_finally_007.phpt [new file with mode: 0644]
Zend/tests/try_finally_008.phpt [new file with mode: 0644]
Zend/zend_compile.c
Zend/zend_compile.h
Zend/zend_opcode.c

index e0937f1b16b5a91fad765205199e3ec5700c78da..2c6c2c9e6ce4559bc0155e78bef8dd7e0088bab9 100644 (file)
@@ -14,4 +14,4 @@ label:
 foo();
 ?>
 --EXPECTF--
-Fatal error: 'goto' out of a finally block is disallowed in %stry_finally_005.php on line %d
+Fatal error: jump out of a finally block is disallowed in %stry_finally_005.php on line %d
index ba1c183eb4b3beff4ebfd7b6eae08f8c95a4ce7e..2bfa4caea9c39c355b8e8701d92370c3aa867531 100644 (file)
@@ -3,12 +3,19 @@ Finally with near goto
 --FILE--
 <?php
 function foo () {
+   $jmp = 1;
    try {
    } finally {
-      goto label;
-      echo "dummy";
+previous:
+       if ($jmp) {
+           goto label;
+           echo "dummy";
 label:
-      echo "label";
+           echo "label\n";
+           $jmp = 0;
+           goto previous;
+       }
+       echo "okey";
    }
 }
 
@@ -16,3 +23,4 @@ foo();
 ?>
 --EXPECTF--
 label
+okey
diff --git a/Zend/tests/try_finally_007.phpt b/Zend/tests/try_finally_007.phpt
new file mode 100644 (file)
index 0000000..b13bd59
--- /dev/null
@@ -0,0 +1,22 @@
+--TEST--
+Finally with goto previous label
+--FILE--
+<?php
+function foo () {
+    try {
+label:
+        echo "label"; 
+        try {
+        } finally {
+            goto label;
+            echo "dummy";
+        }
+    } catch (Exception $e) {
+    } finally {
+    }
+}
+
+foo();
+?>
+--EXPECTF--
+Fatal error: jump out of a finally block is disallowed in %stry_finally_007.php on line %d
diff --git a/Zend/tests/try_finally_008.phpt b/Zend/tests/try_finally_008.phpt
new file mode 100644 (file)
index 0000000..77ecf4f
--- /dev/null
@@ -0,0 +1,24 @@
+--TEST--
+Finally with jmp (do while)
+--FILE--
+<?php
+function foo () {
+    do {
+        try {
+            try {
+            } finally {
+                goto label;
+                echo "dummy";
+            }
+        } catch (Exception $e) {
+        } finally {
+        }
+    } while (0);
+label:
+        echo "label"; 
+}
+
+foo();
+?>
+--EXPECTF--
+Fatal error: jump out of a finally block is disallowed in %stry_finally_008.php on line %d
index bad9411a2f46fb42da8181c57d259a316a0c9f9b..6a501f78a5df5563067bd2b28be1dc7ceaff8fac 100644 (file)
@@ -2277,30 +2277,6 @@ void zend_resolve_goto_label(zend_op_array *op_array, zend_op *opline, int pass2
        zval_dtor(label);
        Z_TYPE_P(label) = IS_NULL;
 
-       if (op_array->last_try_catch) {
-               zend_uint i, op_num = opline - op_array->opcodes;
-               for (i=0; i<op_array->last_try_catch; i++) {
-                       if (op_array->try_catch_array[i].try_op > op_num) {
-                               break;
-                       }
-                       if (op_num >= op_array->try_catch_array[i].finally_op) {
-                               zend_op *p, *end; 
-                               p = opline;
-                               end = op_array->opcodes + opline->op1.opline_num;
-                               while (++p < end) {
-                                       if (p->opcode == ZEND_LEAVE) {
-                                               if (pass2) {
-                                                       CG(in_compilation) = 1;
-                                                       CG(active_op_array) = op_array;
-                                                       CG(zend_lineno) = opline->lineno;
-                                               }
-                                               zend_error(E_COMPILE_ERROR, "'goto' out of a finally block is disallowed");
-                                       }
-                               }
-                       }
-               }
-       }
-
        /* Check that we are not moving into loop or switch */
        current = opline->extended_value;
        for (distance = 0; current != dest->brk_cont; distance++) {
@@ -2686,6 +2662,7 @@ static int zend_add_try_element(zend_uint try_op TSRMLS_DC) /* {{{ */
        CG(active_op_array)->try_catch_array = erealloc(CG(active_op_array)->try_catch_array, sizeof(zend_try_catch_element)*CG(active_op_array)->last_try_catch);
        CG(active_op_array)->try_catch_array[try_catch_offset].try_op = try_op;
        CG(active_op_array)->try_catch_array[try_catch_offset].finally_op = 0;
+       CG(active_op_array)->try_catch_array[try_catch_offset].finally_end = 0;
        return try_catch_offset;
 }
 /* }}} */
@@ -2808,14 +2785,13 @@ void zend_do_bind_catch(znode *try_token, znode *catch_token TSRMLS_DC) /* {{{ *
 
 void zend_do_end_finally(znode *try_token, znode* catch_token, znode *finally_token TSRMLS_DC) /* {{{ */
 {
-       zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
-
        if (catch_token->op_type == IS_UNUSED && finally_token->op_type == IS_UNUSED) {
                zend_error(E_COMPILE_ERROR, "Cannot use try without catch or finally");
        } 
        if (finally_token->op_type != IS_UNUSED) {
+               zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
                CG(active_op_array)->try_catch_array[try_token->u.op.opline_num].finally_op = finally_token->u.op.opline_num;
-               //try_token->u.op.opline_num = catch_token->u.op.opline_num;
+               CG(active_op_array)->try_catch_array[try_token->u.op.opline_num].finally_end = get_next_op_number(CG(active_op_array));
 
                opline->opcode = ZEND_LEAVE;
                SET_UNUSED(opline->op1);
index 550fb0e9318dc4bd9403bcac06de6497b690119b..a06c985a97901b52fc80b692a1505310e98afbc9 100644 (file)
@@ -132,7 +132,8 @@ typedef struct _zend_label {
 typedef struct _zend_try_catch_element {
        zend_uint try_op;
        zend_uint catch_op;  /* ketchup! */
-    zend_uint finally_op;
+       zend_uint finally_op;
+       zend_uint finally_end;
 } zend_try_catch_element;
 
 #if SIZEOF_LONG == 8
index 19fd71e763d090e7974fe5311d62cbed7d4ac821..8cccfe637684cd0053507859f2a4adc62d7caa4e 100644 (file)
@@ -528,6 +528,23 @@ ZEND_API int pass_two(zend_op_array *op_array TSRMLS_DC)
                                }
                                /* break omitted intentionally */
                        case ZEND_JMP:
+                               if (op_array->last_try_catch) {
+                                       zend_uint i, op_num = opline - op_array->opcodes;
+                                       for (i=0; i < op_array->last_try_catch; i++) {
+                                               if (op_array->try_catch_array[i].try_op > op_num) {
+                                                       break;
+                                               }
+                                               if ((op_num >= op_array->try_catch_array[i].finally_op 
+                                                                       && op_num < op_array->try_catch_array[i].finally_end)
+                                                               && (opline->op1.opline_num >= op_array->try_catch_array[i].finally_end 
+                                                                       || opline->op1.opline_num < op_array->try_catch_array[i].finally_op)) {
+                                                       CG(in_compilation) = 1;
+                                                       CG(active_op_array) = op_array;
+                                                       CG(zend_lineno) = opline->lineno;
+                                                       zend_error(E_COMPILE_ERROR, "jump out of a finally block is disallowed");
+                                               }
+                                       } 
+                               }
                                opline->op1.jmp_addr = &op_array->opcodes[opline->op1.opline_num];
                                break;
                        case ZEND_JMPZ: