Handle incorrect break/continue statements at compile-time

This commit is contained in:
Dmitry Stogov 2015-04-01 15:52:26 +03:00
parent 4fd93a4da6
commit 8c031a3f95
4 changed files with 44 additions and 26 deletions

View File

@ -78,14 +78,16 @@ assert(0 && ($a = function &(array &$a, X $b = null) use ($c,&$d) : X {
return 9;
}
L0:
switch ($x) {
case 4: break;
case 5: continue;
case 6: break 2;
case 7: continue 2;
case 8: goto L0;
default: return;
}
do {
switch ($x) {
case 4: break;
case 5: continue;
case 6: break 2;
case 7: continue 2;
case 8: goto L0;
default: return;
}
} while (0);
}
}
}
@ -222,20 +224,22 @@ Warning: assert(): assert(0 && ($a = function &(array &$a, X $b = null) use($c,
return 9;
}
L0:
switch ($x) {
case 4:
break;
case 5:
continue;
case 6:
break 2;
case 7:
continue 2;
case 8:
goto L0;
default:
return;
}
do {
switch ($x) {
case 4:
break;
case 5:
continue;
case 6:
break 2;
case 7:
continue 2;
case 8:
goto L0;
default:
return;
}
} while (0);
}
}

View File

@ -12,4 +12,4 @@ function foo () {
foo();
?>
--EXPECTF--
Fatal error: Cannot break/continue 1 level in %stry_finally_011.php on line %d
Fatal error: 'break' not in the 'loop' or 'switch' context in %stry_finally_011.php on line %d

View File

@ -3495,6 +3495,22 @@ void zend_compile_break_continue(zend_ast *ast) /* {{{ */
ZVAL_LONG(&depth_node.u.constant, 1);
}
if (CG(context).current_brk_cont == -1) {
zend_error_noreturn(E_COMPILE_ERROR, "'%s' not in the 'loop' or 'switch' context",
ast->kind == ZEND_AST_BREAK ? "break" : "continue");
} else {
int array_offset = CG(context).current_brk_cont;
zend_long nest_level = Z_LVAL(depth_node.u.constant);
do {
if (array_offset == -1) {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot '%s' %d level%s",
ast->kind == ZEND_AST_BREAK ? "break" : "continue",
Z_LVAL(depth_node.u.constant), (Z_LVAL(depth_node.u.constant) == 1) ? "" : "s");
}
array_offset = CG(active_op_array)->brk_cont_array[array_offset].parent;
} while (--nest_level > 0);
}
opline = zend_emit_op(NULL, ast->kind == ZEND_AST_BREAK ? ZEND_BRK : ZEND_CONT,
NULL, &depth_node);
opline->op1.opline_num = CG(context).current_brk_cont;

View File

@ -1731,9 +1731,7 @@ static inline zend_brk_cont_element* zend_brk_cont(int nest_levels, int array_of
zend_brk_cont_element *jmp_to;
do {
if (array_offset==-1) {
zend_error_noreturn(E_ERROR, "Cannot break/continue %d level%s", original_nest_levels, (original_nest_levels == 1) ? "" : "s");
}
ZEND_ASSERT(array_offset != -1);
jmp_to = &op_array->brk_cont_array[array_offset];
if (nest_levels>1) {
zend_op *brk_opline = &op_array->opcodes[jmp_to->brk];