summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--compiler.c3
-rw-r--r--tests/custom/99_bugs/45_compiler_loop_ctrl_unclosed_upvals22
2 files changed, 24 insertions, 1 deletions
diff --git a/compiler.c b/compiler.c
index 17c0249..1ea0c65 100644
--- a/compiler.c
+++ b/compiler.c
@@ -2969,7 +2969,8 @@ uc_compiler_compile_control(uc_compiler_t *compiler)
/* pop locals in all scopes covered by the target patchlist */
for (i = locals->count; i > 0 && (size_t)locals->entries[i - 1].depth > p->depth; i--)
- uc_compiler_emit_insn(compiler, 0, I_POP);
+ uc_compiler_emit_insn(compiler, 0,
+ locals->entries[i - 1].captured ? I_CUPV : I_POP);
uc_vector_grow(p);
diff --git a/tests/custom/99_bugs/45_compiler_loop_ctrl_unclosed_upvals b/tests/custom/99_bugs/45_compiler_loop_ctrl_unclosed_upvals
new file mode 100644
index 0000000..d4b7ed8
--- /dev/null
+++ b/tests/custom/99_bugs/45_compiler_loop_ctrl_unclosed_upvals
@@ -0,0 +1,22 @@
+When compiling loop control statements, the compiler incorrectly emitted an
+I_POP instead of an I_CUPV instruction for open upvalues, causing closures to
+reference unclosed upvalues that went out of scope, potentially leading to
+invalid stack accesses in subsequent code.
+
+-- Testcase --
+{%
+ let dest;
+
+ for (let i in [ 1 ]) {
+ let foo = i;
+ dest = () => print(foo, '\n');
+ continue;
+ }
+
+ dest();
+%}
+-- End --
+
+-- Expect stdout --
+1
+-- End --