diff options
author | Dmitry Stogov <dmitry@zend.com> | 2015-07-09 17:38:29 +0300 |
---|---|---|
committer | Anatol Belski <ab@php.net> | 2015-07-09 17:26:01 +0200 |
commit | 724e98498a3f2954e9ce2457f1c989be0ab3b552 (patch) | |
tree | e1490741580a84c48e1bdfbbccbce18538bd3f45 | |
parent | 62062dcd0e3228830c7a6af5c689747151828f11 (diff) | |
download | php-git-724e98498a3f2954e9ce2457f1c989be0ab3b552.tar.gz |
Fixed invalid live-range detection
-rw-r--r-- | Zend/tests/temporary_cleaning_007.phpt | 22 | ||||
-rw-r--r-- | Zend/zend_compile.c | 23 | ||||
-rw-r--r-- | Zend/zend_compile.h | 4 | ||||
-rw-r--r-- | Zend/zend_opcode.c | 8 |
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); |