diff options
-rw-r--r-- | compiler.c | 10 | ||||
-rw-r--r-- | tests/03_bugs/10_break_stack_mismatch | 38 |
2 files changed, 43 insertions, 5 deletions
@@ -2128,9 +2128,6 @@ uc_compiler_compile_for_in(uc_compiler *compiler, bool local, uc_token *kvar, uc /* back patch conditional jump */ uc_compiler_set_jmpaddr(compiler, test_jmp, chunk->count); - /* patch up break/continue */ - uc_compiler_backpatch(compiler, chunk->count, skip_jmp + 5); - /* pop loop variables */ uc_compiler_emit_insn(compiler, 0, I_POP); @@ -2138,6 +2135,9 @@ uc_compiler_compile_for_in(uc_compiler *compiler, bool local, uc_token *kvar, uc uc_compiler_emit_insn(compiler, 0, I_POP); uc_compiler_leave_scope(compiler); + + /* patch up break/continue */ + uc_compiler_backpatch(compiler, chunk->count, skip_jmp + 5); } static void @@ -2232,10 +2232,10 @@ uc_compiler_compile_for_count(uc_compiler *compiler, bool local, uc_token *var) if (test_off) uc_compiler_set_jmpaddr(compiler, test_off, chunk->count); + uc_compiler_leave_scope(compiler); + /* patch up break/continue */ uc_compiler_backpatch(compiler, chunk->count, incr_off); - - uc_compiler_leave_scope(compiler); } static void diff --git a/tests/03_bugs/10_break_stack_mismatch b/tests/03_bugs/10_break_stack_mismatch new file mode 100644 index 0000000..ae16dac --- /dev/null +++ b/tests/03_bugs/10_break_stack_mismatch @@ -0,0 +1,38 @@ +When emitting jump instructions for breaking out of for-loops, the compiler +incorrectly set the jump target before the pop instruction clearing the +intermediate loop variables. Since the break instruction itself already +compiles to a series of pop instructions reverting the stack to it's the +pre-loop state, intermediate values got popped twice, leading to a stack +layout mismatch between compiler and VM, resulting in wrong local variable +values or segmentation faults at runtime. + +-- Testcase -- +{% + let x = 1; + + for (let y in [2]) + break; + + print(x, "\n"); +%} +-- End -- + +-- Expect stdout -- +1 +-- End -- + + +-- Testcase -- +{% + let x = 1; + + for (let y = 0; y < 1; y++) + break; + + print(x, "\n"); +%} +-- End -- + +-- Expect stdout -- +1 +-- End -- |