]> granicus.if.org Git - php/commitdiff
Fixed exception catching on break/continue
authorDmitry Stogov <dmitry@zend.com>
Thu, 9 Jul 2015 20:20:50 +0000 (23:20 +0300)
committerDmitry Stogov <dmitry@zend.com>
Thu, 9 Jul 2015 20:20:50 +0000 (23:20 +0300)
Fixed "finaly" handling on exception in "return" statement

Zend/tests/return_types/031.phpt [new file with mode: 0644]
Zend/zend_compile.c
Zend/zend_compile.h
Zend/zend_opcode.c
Zend/zend_vm_def.h
Zend/zend_vm_execute.h

diff --git a/Zend/tests/return_types/031.phpt b/Zend/tests/return_types/031.phpt
new file mode 100644 (file)
index 0000000..7240274
--- /dev/null
@@ -0,0 +1,43 @@
+--TEST--
+Excepton on return types mismutch shouldn't execute "catch" code but should execute "finally" code.
+--FILE--
+<?php
+
+function foo(): string {
+       $a = "OK\n";
+       try {
+               return $a; // invalid return type
+       } catch (TypeError $e) {
+               echo "BAG!\n";
+               return "ops!\n";
+       } finally {
+               echo "finally1\n";
+       }
+}
+function bar(): string {
+       $a = [];
+       try {
+               return $a; // invalid return type
+       } catch (TypeError $e) {
+               echo "BAG!\n";
+               return "ops!\n";
+       } finally {
+               echo "finally2\n";
+       }
+}
+try {
+       echo foo();
+} catch (TypeError $e) {
+       echo "BAG\n";
+}
+try {
+       echo bar();
+} catch (TypeError $e) {
+       echo "OK\n";
+}
+?>
+--EXPECT--
+finally1
+OK
+finally2
+OK
index 4f21769e12e3c07db1a4438f12aee8c5177c9b1c..4ae27e5a3ff9d8d071a1ee724332bd7534bdd998 100644 (file)
@@ -3482,7 +3482,7 @@ void zend_compile_return(zend_ast *ast) /* {{{ */
                zend_emit_return_type_check(expr_ast ? &expr_node : NULL, CG(active_op_array)->arg_info - 1);
        }
 
-       zend_free_foreach_and_switch_variables(ZEND_FREE_ON_JUMP);
+       zend_free_foreach_and_switch_variables(ZEND_FREE_ON_RETURN);
 
        if (CG(context).in_finally) {
                opline = zend_emit_op(NULL, ZEND_DISCARD_EXCEPTION, NULL, NULL);
@@ -3567,7 +3567,7 @@ void zend_compile_break_continue(zend_ast *ast) /* {{{ */
                        }
 
                        if (nest_level > 1) {
-                               generate_free_loop_var_ex(&CG(context).brk_cont_array[array_offset].loop_var, ZEND_FREE_ON_JUMP);
+                               generate_free_loop_var_ex(&CG(context).brk_cont_array[array_offset].loop_var, ZEND_FREE_ON_BREAK);
                        }
 
                        array_offset = CG(context).brk_cont_array[array_offset].parent;
@@ -3637,7 +3637,7 @@ void zend_resolve_goto_label(zend_op_array *op_array, znode *label_node, zend_op
                        if (pass2_opline) {
                                free_vars++;
                        } else {
-                               generate_free_loop_var_ex(&CG(context).brk_cont_array[current].loop_var, ZEND_FREE_ON_JUMP);
+                               generate_free_loop_var_ex(&CG(context).brk_cont_array[current].loop_var, ZEND_FREE_ON_BREAK);
                        }
                }
                current = CG(context).brk_cont_array[current].parent;
index 5560b7e86df7abf68ab90899252a105874eae7df..52456a79e97b21c2e26155f94af9f51c5d8fbe47 100644 (file)
@@ -882,7 +882,8 @@ ZEND_API void zend_assert_valid_class_name(const zend_string *const_name);
 
 #define ZEND_FETCH_ARG_MASK         0x000fffff
 
-#define ZEND_FREE_ON_JUMP       (1<<0)
+#define ZEND_FREE_ON_RETURN     (1<<0)
+#define ZEND_FREE_ON_BREAK      (1<<1)
 
 #define ZEND_MEMBER_FUNC_CALL  (1<<0)
 
index 6a89a54712ce55ed03fe641eb41fd9470037cce1..5fe5ae7f33041cb8395bf875c3e1480c1da221c6 100644 (file)
@@ -994,8 +994,8 @@ static zend_always_inline uint32_t *generate_var_liveliness_info_ex(zend_op_arra
                                && opline->opcode != ZEND_FE_FETCH_RW
                                /* the following opcodes are parts of "return" statement */
                                && opline->opcode != ZEND_VERIFY_RETURN_TYPE
-                               && (opline->opcode != ZEND_FREE || !(opline->extended_value & ZEND_FREE_ON_JUMP))
-                               && (opline->opcode != ZEND_FE_FREE || !(opline->extended_value & ZEND_FREE_ON_JUMP))
+                               && (opline->opcode != ZEND_FREE || !(opline->extended_value & (ZEND_FREE_ON_RETURN|ZEND_FREE_ON_BREAK)))
+                               && (opline->opcode != ZEND_FE_FREE || !(opline->extended_value & (ZEND_FREE_ON_RETURN|ZEND_FREE_ON_BREAK)))
                        ) {
                                op_live_total += liveliness_kill_var(op_array, opline, var, Tstart, opTs);
                        }
index 57c8a9486723c9211d9fd2b7f790f87a44c66308..98f6be671aee8438e0a4a455f0a33811060a15fd 100644 (file)
@@ -7082,12 +7082,12 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY)
                }
        }
 
-       if (catch_op_num || finally_op_num) {
+       if (catch_op_num) {
                if (EX(func)->op_array.opcodes[op_num].opcode == ZEND_VERIFY_RETURN_TYPE
-                || (EX(func)->op_array.opcodes[op_num].opcode == ZEND_FREE && (EX(func)->op_array.opcodes[op_num].extended_value & ZEND_FREE_ON_JUMP))
-                || (EX(func)->op_array.opcodes[op_num].opcode == ZEND_FE_FREE && (EX(func)->op_array.opcodes[op_num].extended_value & ZEND_FREE_ON_JUMP))
+                || (EX(func)->op_array.opcodes[op_num].opcode == ZEND_FREE && (EX(func)->op_array.opcodes[op_num].extended_value & ZEND_FREE_ON_RETURN))
+                || (EX(func)->op_array.opcodes[op_num].opcode == ZEND_FE_FREE && (EX(func)->op_array.opcodes[op_num].extended_value & ZEND_FREE_ON_RETURN))
                ) {
-                       catch_op_num = finally_op_num = 0;
+                       catch_op_num = 0;
                }
        }
 
index bdfce50cf14923f0891db478503707d74e4fd057..95c1b5dfaa1905602987b32875eba5b5ed2fa485 100644 (file)
@@ -1500,12 +1500,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(
                }
        }
 
-       if (catch_op_num || finally_op_num) {
+       if (catch_op_num) {
                if (EX(func)->op_array.opcodes[op_num].opcode == ZEND_VERIFY_RETURN_TYPE
-                || (EX(func)->op_array.opcodes[op_num].opcode == ZEND_FREE && (EX(func)->op_array.opcodes[op_num].extended_value & ZEND_FREE_ON_JUMP))
-                || (EX(func)->op_array.opcodes[op_num].opcode == ZEND_FE_FREE && (EX(func)->op_array.opcodes[op_num].extended_value & ZEND_FREE_ON_JUMP))
+                || (EX(func)->op_array.opcodes[op_num].opcode == ZEND_FREE && (EX(func)->op_array.opcodes[op_num].extended_value & ZEND_FREE_ON_RETURN))
+                || (EX(func)->op_array.opcodes[op_num].opcode == ZEND_FE_FREE && (EX(func)->op_array.opcodes[op_num].extended_value & ZEND_FREE_ON_RETURN))
                ) {
-                       catch_op_num = finally_op_num = 0;
+                       catch_op_num = 0;
                }
        }