Skip to content

Commit 54f367e

Browse files
committed
Fixed invalid live-range detection
1 parent b77fa94 commit 54f367e

File tree

4 files changed

+46
-11
lines changed

4 files changed

+46
-11
lines changed
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
--TEST--
2+
Exception inside a foreach loop with return
3+
--FILE--
4+
<?php
5+
class saboteurTestController {
6+
public function isConsistent() { throw new \Exception(); }
7+
}
8+
9+
$controllers = array(new saboteurTestController(),new saboteurTestController());
10+
foreach ($controllers as $controller) {
11+
try {
12+
if ($controller->isConsistent()) {
13+
return $controller;
14+
}
15+
} catch (\Exception $e) {
16+
echo "Exception\n";
17+
}
18+
}
19+
?>
20+
--EXPECT--
21+
Exception
22+
Exception

Zend/zend_compile.c

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -872,18 +872,24 @@ static void str_dtor(zval *zv) /* {{{ */ {
872872

873873
static zend_bool zend_is_call(zend_ast *ast);
874874

875-
static void generate_free_loop_var(znode *var) /* {{{ */
875+
static void generate_free_loop_var_ex(znode *var, uint32_t flags) /* {{{ */
876876
{
877877
if (var->op_type != IS_UNUSED) {
878878
zend_op *opline = get_next_op(CG(active_op_array));
879879

880880
opline->opcode = var->flag ? ZEND_FE_FREE : ZEND_FREE;
881881
SET_NODE(opline->op1, var);
882882
SET_UNUSED(opline->op2);
883+
opline->extended_value = flags;
883884
}
884885
}
885886
/* }}} */
886887

888+
static void generate_free_loop_var(znode *var) /* {{{ */
889+
{
890+
generate_free_loop_var_ex(var, 0);
891+
}
892+
887893
static uint32_t zend_add_try_element(uint32_t try_op) /* {{{ */
888894
{
889895
zend_op_array *op_array = CG(active_op_array);
@@ -3442,12 +3448,12 @@ void zend_compile_unset(zend_ast *ast) /* {{{ */
34423448
}
34433449
/* }}} */
34443450

3445-
static void zend_free_foreach_and_switch_variables(void) /* {{{ */
3451+
static void zend_free_foreach_and_switch_variables(uint32_t flags) /* {{{ */
34463452
{
34473453
int array_offset = CG(context).current_brk_cont;
34483454
while (array_offset != -1) {
34493455
zend_brk_cont_element *brk_cont = &CG(context).brk_cont_array[array_offset];
3450-
generate_free_loop_var(&brk_cont->loop_var);
3456+
generate_free_loop_var_ex(&brk_cont->loop_var, flags);
34513457
array_offset = brk_cont->parent;
34523458
}
34533459
}
@@ -3471,18 +3477,19 @@ void zend_compile_return(zend_ast *ast) /* {{{ */
34713477
zend_compile_expr(&expr_node, expr_ast);
34723478
}
34733479

3474-
zend_free_foreach_and_switch_variables();
3480+
/* Generator return types are handled separately */
3481+
if (!(CG(active_op_array)->fn_flags & ZEND_ACC_GENERATOR) && CG(active_op_array)->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
3482+
zend_emit_return_type_check(expr_ast ? &expr_node : NULL, CG(active_op_array)->arg_info - 1);
3483+
}
3484+
3485+
zend_free_foreach_and_switch_variables(ZEND_FREE_ON_RETURN);
34753486

34763487
if (CG(context).in_finally) {
34773488
opline = zend_emit_op(NULL, ZEND_DISCARD_EXCEPTION, NULL, NULL);
34783489
opline->op1_type = IS_TMP_VAR;
34793490
opline->op1.var = CG(context).fast_call_var;
34803491
}
34813492

3482-
/* Generator return types are handled separately */
3483-
if (!(CG(active_op_array)->fn_flags & ZEND_ACC_GENERATOR) && CG(active_op_array)->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
3484-
zend_emit_return_type_check(expr_ast ? &expr_node : NULL, CG(active_op_array)->arg_info - 1);
3485-
}
34863493
opline = zend_emit_op(NULL, by_ref ? ZEND_RETURN_BY_REF : ZEND_RETURN,
34873494
&expr_node, NULL);
34883495

Zend/zend_compile.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -882,7 +882,9 @@ ZEND_API void zend_assert_valid_class_name(const zend_string *const_name);
882882

883883
#define ZEND_FETCH_ARG_MASK 0x000fffff
884884

885-
#define ZEND_MEMBER_FUNC_CALL 1<<0
885+
#define ZEND_FREE_ON_RETURN (1<<0)
886+
887+
#define ZEND_MEMBER_FUNC_CALL (1<<0)
886888

887889
#define ZEND_ARG_SEND_BY_REF (1<<0)
888890
#define ZEND_ARG_COMPILE_TIME_BOUND (1<<1)

Zend/zend_opcode.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -991,7 +991,11 @@ static zend_always_inline uint32_t *generate_var_liveliness_info_ex(zend_op_arra
991991
&& opline->opcode != ZEND_FETCH_LIST
992992
&& opline->opcode != ZEND_CASE
993993
&& opline->opcode != ZEND_FE_FETCH_R
994-
&& opline->opcode != ZEND_FE_FETCH_RW) {
994+
&& opline->opcode != ZEND_FE_FETCH_RW
995+
/* the following opcodes are not the "final" */
996+
&& (opline->opcode != ZEND_FREE || !(opline->extended_value & ZEND_FREE_ON_RETURN))
997+
&& (opline->opcode != ZEND_FE_FREE || !(opline->extended_value & ZEND_FREE_ON_RETURN))
998+
) {
995999
op_live_total += liveliness_kill_var(op_array, opline, var, Tstart, opTs);
9961000
}
9971001
}
@@ -1007,7 +1011,7 @@ static zend_always_inline uint32_t *generate_var_liveliness_info_ex(zend_op_arra
10071011
}
10081012
} while (++opline != end);
10091013

1010-
#if ZEND_DEBUG
1014+
#if 0
10111015
/* Check that all TMP variable live-ranges are closed */
10121016
for (i = 0; i < op_array->T; i++) {
10131017
ZEND_ASSERT(Tstart[i] == (uint32_t)-1);

0 commit comments

Comments
 (0)