summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@nbd.name>2024-02-08 20:46:02 +0100
committerJo-Philipp Wich <jo@mein.io>2024-02-13 17:03:55 +0100
commit3f9811d2f7b730f1f1d030872ae1def7e8349be6 (patch)
tree649af4c5bac5512ee0223d8fa4dd31dae5dd6cee
parentdce19b7cce0bef3ec13166bcd85766cc8c0ecdba (diff)
compiler: close upvalues on loop control statements
When removing locals from all scopes, upvalues need to be considered like in uc_compiler_leave_scope(). Closing them is required to avoid leaving lingering references to stack values that went out of scope, which would lead to invalid memory accesses in subsequent code when such upvalues are used by closures. Fixes: #187 Signed-off-by: Felix Fietkau <nbd@nbd.name> [add testcase, reword commit message] Signed-off-by: Jo-Philipp Wich <jo@mein.io>
-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 --