summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Stogov <dmitry@zend.com>2015-07-09 23:20:50 +0300
committerDmitry Stogov <dmitry@zend.com>2015-07-09 23:20:50 +0300
commit8c3f701eebfa92d761bb368cfa8c2d1ccf821b9d (patch)
tree27b4b3a7e25b4f8785ff5205ea7c3c91ebe16330
parent788c4c852d0b0523eb918039e4ac3247f5c8a6d0 (diff)
downloadphp-git-8c3f701eebfa92d761bb368cfa8c2d1ccf821b9d.tar.gz
Fixed exception catching on break/continue
Fixed "finaly" handling on exception in "return" statement
-rw-r--r--Zend/tests/return_types/031.phpt43
-rw-r--r--Zend/zend_compile.c6
-rw-r--r--Zend/zend_compile.h3
-rw-r--r--Zend/zend_opcode.c4
-rw-r--r--Zend/zend_vm_def.h8
-rw-r--r--Zend/zend_vm_execute.h8
6 files changed, 58 insertions, 14 deletions
diff --git a/Zend/tests/return_types/031.phpt b/Zend/tests/return_types/031.phpt
new file mode 100644
index 0000000000..7240274804
--- /dev/null
+++ b/Zend/tests/return_types/031.phpt
@@ -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
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c
index 4f21769e12..4ae27e5a3f 100644
--- a/Zend/zend_compile.c
+++ b/Zend/zend_compile.c
@@ -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;
diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h
index 5560b7e86d..52456a79e9 100644
--- a/Zend/zend_compile.h
+++ b/Zend/zend_compile.h
@@ -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)
diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c
index 6a89a54712..5fe5ae7f33 100644
--- a/Zend/zend_opcode.c
+++ b/Zend/zend_opcode.c
@@ -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);
}
diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h
index 57c8a94867..98f6be671a 100644
--- a/Zend/zend_vm_def.h
+++ b/Zend/zend_vm_def.h
@@ -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;
}
}
diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h
index bdfce50cf1..95c1b5dfaa 100644
--- a/Zend/zend_vm_execute.h
+++ b/Zend/zend_vm_execute.h
@@ -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;
}
}