Skip to content

Commit 9412d5a

Browse files
committed
Prevent targetting match expr with break
1 parent 7d9ddd2 commit 9412d5a

File tree

3 files changed

+40
-18
lines changed

3 files changed

+40
-18
lines changed

Zend/tests/match/bugs/010.phpt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
--TEST--
2+
WIP
3+
--FILE--
4+
<?php
5+
6+
var_dump(match (1) {
7+
1 => { break; }
8+
});
9+
10+
?>
11+
--EXPECTF--
12+
Fatal error: break must not target match expression whose result is used in %s on line %d

Zend/zend_compile.c

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -710,7 +710,7 @@ void zend_stop_lexing(void)
710710
}
711711

712712
static inline void zend_begin_loop(
713-
uint8_t free_opcode, const znode *loop_var, bool is_switch) /* {{{ */
713+
uint8_t free_opcode, const znode *loop_var, zend_brk_ctrl_kind kind) /* {{{ */
714714
{
715715
zend_brk_cont_element *brk_cont_element;
716716
int parent = CG(context).current_brk_cont;
@@ -719,7 +719,7 @@ static inline void zend_begin_loop(
719719
CG(context).current_brk_cont = CG(context).last_brk_cont;
720720
brk_cont_element = get_next_brk_cont_element();
721721
brk_cont_element->parent = parent;
722-
brk_cont_element->is_switch = is_switch;
722+
brk_cont_element->kind = kind;
723723

724724
uint32_t start = get_next_op_number();
725725
info.opcode_start = start;
@@ -5821,16 +5821,17 @@ static void zend_compile_break_continue(zend_ast *ast) /* {{{ */
58215821
}
58225822
}
58235823

5824-
if (ast->kind == ZEND_AST_CONTINUE) {
5825-
int d, cur = CG(context).current_brk_cont;
5826-
for (d = depth - 1; d > 0; d--) {
5827-
cur = CG(context).brk_cont_array[cur].parent;
5828-
ZEND_ASSERT(cur != -1);
5829-
}
5824+
int d, cur = CG(context).current_brk_cont;
5825+
for (d = depth - 1; d > 0; d--) {
5826+
cur = CG(context).brk_cont_array[cur].parent;
5827+
ZEND_ASSERT(cur != -1);
5828+
}
5829+
zend_brk_cont_element *current_brk_ctrl = &CG(context).brk_cont_array[cur];
58305830

5831-
if (CG(context).brk_cont_array[cur].is_switch) {
5831+
if (ast->kind == ZEND_AST_CONTINUE) {
5832+
if (current_brk_ctrl->kind == ZEND_BRK_CTRL_KIND_SWITCH_MATCH_STMT) {
58325833
if (depth == 1) {
5833-
if (CG(context).brk_cont_array[cur].parent == -1) {
5834+
if (current_brk_ctrl->parent == -1) {
58345835
zend_error(E_WARNING,
58355836
"\"continue\" targeting switch is equivalent to \"break\"");
58365837
} else {
@@ -5840,7 +5841,7 @@ static void zend_compile_break_continue(zend_ast *ast) /* {{{ */
58405841
depth + 1);
58415842
}
58425843
} else {
5843-
if (CG(context).brk_cont_array[cur].parent == -1) {
5844+
if (current_brk_ctrl->parent == -1) {
58445845
zend_error(E_WARNING,
58455846
"\"continue " ZEND_LONG_FMT "\" targeting switch is equivalent to \"break " ZEND_LONG_FMT "\"",
58465847
depth, depth);
@@ -5853,6 +5854,10 @@ static void zend_compile_break_continue(zend_ast *ast) /* {{{ */
58535854
}
58545855
}
58555856
}
5857+
if (current_brk_ctrl->kind == ZEND_BRK_CTRL_KIND_MATCH_EXPR) {
5858+
zend_error_noreturn(E_COMPILE_ERROR, "%s must not target match expression whose result is used",
5859+
ast->kind == ZEND_AST_BREAK ? "break" : "continue");
5860+
}
58565861

58575862
opline = zend_emit_op(NULL, ast->kind == ZEND_AST_BREAK ? ZEND_BRK : ZEND_CONT, NULL, NULL);
58585863
opline->op1.num = CG(context).current_brk_cont;
@@ -5966,7 +5971,7 @@ static void zend_compile_while(zend_ast *ast) /* {{{ */
59665971

59675972
opnum_jmp = zend_emit_jump(0);
59685973

5969-
zend_begin_loop(ZEND_NOP, NULL, 0);
5974+
zend_begin_loop(ZEND_NOP, NULL, ZEND_BRK_CTRL_KIND_LOOP);
59705975

59715976
opnum_start = get_next_op_number();
59725977
zend_compile_stmt(stmt_ast);
@@ -5989,7 +5994,7 @@ static void zend_compile_do_while(zend_ast *ast) /* {{{ */
59895994
znode cond_node;
59905995
uint32_t opnum_start, opnum_cond;
59915996

5992-
zend_begin_loop(ZEND_NOP, NULL, 0);
5997+
zend_begin_loop(ZEND_NOP, NULL, ZEND_BRK_CTRL_KIND_LOOP);
59935998

59945999
opnum_start = get_next_op_number();
59956000
zend_compile_stmt(stmt_ast);
@@ -6040,7 +6045,7 @@ static void zend_compile_for(zend_ast *ast) /* {{{ */
60406045

60416046
opnum_jmp = zend_emit_jump(0);
60426047

6043-
zend_begin_loop(ZEND_NOP, NULL, 0);
6048+
zend_begin_loop(ZEND_NOP, NULL, ZEND_BRK_CTRL_KIND_LOOP);
60446049

60456050
opnum_start = get_next_op_number();
60466051
zend_compile_stmt(stmt_ast);
@@ -6102,7 +6107,7 @@ static void zend_compile_foreach(zend_ast *ast) /* {{{ */
61026107
opnum_reset = get_next_op_number();
61036108
opline = zend_emit_op(&reset_node, by_ref ? ZEND_FE_RESET_RW : ZEND_FE_RESET_R, &expr_node, NULL);
61046109

6105-
zend_begin_loop(ZEND_FE_FREE, &reset_node, 0);
6110+
zend_begin_loop(ZEND_FE_FREE, &reset_node, ZEND_BRK_CTRL_KIND_LOOP);
61066111

61076112
opnum_fetch = get_next_op_number();
61086113
opline = zend_emit_op(NULL, by_ref ? ZEND_FE_FETCH_RW : ZEND_FE_FETCH_R, &reset_node, NULL);
@@ -6275,7 +6280,7 @@ static void zend_compile_switch(zend_ast *ast) /* {{{ */
62756280

62766281
zend_compile_expr(&expr_node, expr_ast);
62776282

6278-
zend_begin_loop(ZEND_FREE, &expr_node, 1);
6283+
zend_begin_loop(ZEND_FREE, &expr_node, ZEND_BRK_CTRL_KIND_SWITCH_MATCH_STMT);
62796284

62806285
case_node.op_type = IS_TMP_VAR;
62816286
case_node.u.op.var = get_temporary_variable();
@@ -6460,7 +6465,7 @@ static void zend_compile_match(znode *result, zend_ast *ast)
64606465
zend_stack_push(&CG(loop_var_stack), &info);
64616466
}
64626467

6463-
zend_begin_loop(ZEND_FREE, &expr_node, /* is_switch */ true);
6468+
zend_begin_loop(ZEND_FREE, &expr_node, result ? ZEND_BRK_CTRL_KIND_MATCH_EXPR : ZEND_BRK_CTRL_KIND_SWITCH_MATCH_STMT);
64646469

64656470
znode case_node;
64666471
case_node.op_type = IS_TMP_VAR;

Zend/zend_compile.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,13 +155,18 @@ struct _zend_op {
155155
#endif
156156
};
157157

158+
typedef enum {
159+
ZEND_BRK_CTRL_KIND_LOOP,
160+
ZEND_BRK_CTRL_KIND_SWITCH_MATCH_STMT,
161+
ZEND_BRK_CTRL_KIND_MATCH_EXPR,
162+
} zend_brk_ctrl_kind;
158163

159164
typedef struct _zend_brk_cont_element {
160165
int start;
161166
int cont;
162167
int brk;
163168
int parent;
164-
bool is_switch;
169+
zend_brk_ctrl_kind kind;
165170
} zend_brk_cont_element;
166171

167172
typedef struct _zend_label {

0 commit comments

Comments
 (0)