From 4c5f108321a8fd3f67f597ca918427eda813c12e Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 22 Jun 2017 13:50:33 +1000 Subject: [PATCH] py/compile: Fix bug with break/continue in else of optimised for-range. This patch fixes a bug whereby the Python stack was not correctly reset if there was a break/continue statement in the else black of an optimised for-range loop. For example, in the following code the "j" variable from the inner for loop was not being popped off the Python stack: for i in range(4): for j in range(4): pass else: continue This is now fixed with this patch. --- py/compile.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/py/compile.c b/py/compile.c index 86ec4d3a3c..1511786ae9 100644 --- a/py/compile.c +++ b/py/compile.c @@ -1406,7 +1406,20 @@ STATIC void compile_for_stmt_optimised_range(compiler_t *comp, mp_parse_node_t p // break/continue apply to outer loop (if any) in the else block END_BREAK_CONTINUE_BLOCK - compile_node(comp, pn_else); + // Compile the else block. We must pop the iterator variables before + // executing the else code because it may contain break/continue statements. + uint end_label = 0; + if (!MP_PARSE_NODE_IS_NULL(pn_else)) { + // discard final value of "var", and possible "end" value + EMIT(pop_top); + if (end_on_stack) { + EMIT(pop_top); + } + compile_node(comp, pn_else); + end_label = comp_next_label(comp); + EMIT_ARG(jump, end_label); + EMIT_ARG(adjust_stack_size, 1 + end_on_stack); + } EMIT_ARG(label_assign, break_label); @@ -1417,6 +1430,10 @@ STATIC void compile_for_stmt_optimised_range(compiler_t *comp, mp_parse_node_t p if (end_on_stack) { EMIT(pop_top); } + + if (!MP_PARSE_NODE_IS_NULL(pn_else)) { + EMIT_ARG(label_assign, end_label); + } } STATIC void compile_for_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { @@ -1496,7 +1513,7 @@ STATIC void compile_for_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { // break/continue apply to outer loop (if any) in the else block END_BREAK_CONTINUE_BLOCK - compile_node(comp, pns->nodes[3]); // else (not tested) + compile_node(comp, pns->nodes[3]); // else (may be empty) EMIT_ARG(label_assign, break_label); }