summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Zend/tests/temporary_cleaning_007.phpt22
-rw-r--r--Zend/zend_compile.c23
-rw-r--r--Zend/zend_compile.h4
-rw-r--r--Zend/zend_opcode.c8
4 files changed, 46 insertions, 11 deletions
diff --git a/Zend/tests/temporary_cleaning_007.phpt b/Zend/tests/temporary_cleaning_007.phpt
new file mode 100644
index 0000000000..0e29ed6c33
--- /dev/null
+++ b/Zend/tests/temporary_cleaning_007.phpt
@@ -0,0 +1,22 @@
+--TEST--
+Exception inside a foreach loop with return
+--FILE--
+<?php
+class saboteurTestController {
+ public function isConsistent() { throw new \Exception(); }
+}
+
+$controllers = array(new saboteurTestController(),new saboteurTestController());
+foreach ($controllers as $controller) {
+ try {
+ if ($controller->isConsistent()) {
+ return $controller;
+ }
+ } catch (\Exception $e) {
+ echo "Exception\n";
+ }
+}
+?>
+--EXPECT--
+Exception
+Exception
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c
index 51eb0bc754..53ff1ae651 100644
--- a/Zend/zend_compile.c
+++ b/Zend/zend_compile.c
@@ -872,7 +872,7 @@ static void str_dtor(zval *zv) /* {{{ */ {
static zend_bool zend_is_call(zend_ast *ast);
-static void generate_free_loop_var(znode *var) /* {{{ */
+static void generate_free_loop_var_ex(znode *var, uint32_t flags) /* {{{ */
{
if (var->op_type != IS_UNUSED) {
zend_op *opline = get_next_op(CG(active_op_array));
@@ -880,10 +880,16 @@ static void generate_free_loop_var(znode *var) /* {{{ */
opline->opcode = var->flag ? ZEND_FE_FREE : ZEND_FREE;
SET_NODE(opline->op1, var);
SET_UNUSED(opline->op2);
+ opline->extended_value = flags;
}
}
/* }}} */
+static void generate_free_loop_var(znode *var) /* {{{ */
+{
+ generate_free_loop_var_ex(var, 0);
+}
+
static uint32_t zend_add_try_element(uint32_t try_op) /* {{{ */
{
zend_op_array *op_array = CG(active_op_array);
@@ -3441,12 +3447,12 @@ void zend_compile_unset(zend_ast *ast) /* {{{ */
}
/* }}} */
-static void zend_free_foreach_and_switch_variables(void) /* {{{ */
+static void zend_free_foreach_and_switch_variables(uint32_t flags) /* {{{ */
{
int array_offset = CG(context).current_brk_cont;
while (array_offset != -1) {
zend_brk_cont_element *brk_cont = &CG(context).brk_cont_array[array_offset];
- generate_free_loop_var(&brk_cont->loop_var);
+ generate_free_loop_var_ex(&brk_cont->loop_var, flags);
array_offset = brk_cont->parent;
}
}
@@ -3470,7 +3476,12 @@ void zend_compile_return(zend_ast *ast) /* {{{ */
zend_compile_expr(&expr_node, expr_ast);
}
- zend_free_foreach_and_switch_variables();
+ /* Generator return types are handled separately */
+ if (!(CG(active_op_array)->fn_flags & ZEND_ACC_GENERATOR) && CG(active_op_array)->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
+ 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_RETURN);
if (CG(context).in_finally) {
opline = zend_emit_op(NULL, ZEND_DISCARD_EXCEPTION, NULL, NULL);
@@ -3478,10 +3489,6 @@ void zend_compile_return(zend_ast *ast) /* {{{ */
opline->op1.var = CG(context).fast_call_var;
}
- /* Generator return types are handled separately */
- if (!(CG(active_op_array)->fn_flags & ZEND_ACC_GENERATOR) && CG(active_op_array)->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
- zend_emit_return_type_check(expr_ast ? &expr_node : NULL, CG(active_op_array)->arg_info - 1);
- }
opline = zend_emit_op(NULL, by_ref ? ZEND_RETURN_BY_REF : ZEND_RETURN,
&expr_node, NULL);
diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h
index 3f9c091061..b07f70ea78 100644
--- a/Zend/zend_compile.h
+++ b/Zend/zend_compile.h
@@ -882,7 +882,9 @@ ZEND_API void zend_assert_valid_class_name(const zend_string *const_name);
#define ZEND_FETCH_ARG_MASK 0x000fffff
-#define ZEND_MEMBER_FUNC_CALL 1<<0
+#define ZEND_FREE_ON_RETURN (1<<0)
+
+#define ZEND_MEMBER_FUNC_CALL (1<<0)
#define ZEND_ARG_SEND_BY_REF (1<<0)
#define ZEND_ARG_COMPILE_TIME_BOUND (1<<1)
diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c
index ae2b4bf353..64ba6562ff 100644
--- a/Zend/zend_opcode.c
+++ b/Zend/zend_opcode.c
@@ -991,7 +991,11 @@ static zend_always_inline uint32_t *generate_var_liveliness_info_ex(zend_op_arra
&& opline->opcode != ZEND_FETCH_LIST
&& opline->opcode != ZEND_CASE
&& opline->opcode != ZEND_FE_FETCH_R
- && opline->opcode != ZEND_FE_FETCH_RW) {
+ && opline->opcode != ZEND_FE_FETCH_RW
+ /* the following opcodes are not the "final" */
+ && (opline->opcode != ZEND_FREE || !(opline->extended_value & ZEND_FREE_ON_RETURN))
+ && (opline->opcode != ZEND_FE_FREE || !(opline->extended_value & ZEND_FREE_ON_RETURN))
+ ) {
op_live_total += liveliness_kill_var(op_array, opline, var, Tstart, opTs);
}
}
@@ -1007,7 +1011,7 @@ static zend_always_inline uint32_t *generate_var_liveliness_info_ex(zend_op_arra
}
} while (++opline != end);
-#if ZEND_DEBUG
+#if 0
/* Check that all TMP variable live-ranges are closed */
for (i = 0; i < op_array->T; i++) {
ZEND_ASSERT(Tstart[i] == (uint32_t)-1);