Skip to content

Commit

Permalink
compiler: close upvalues on loop control statements
Browse files Browse the repository at this point in the history
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 <[email protected]>
[add testcase, reword commit message]
Signed-off-by: Jo-Philipp Wich <[email protected]>
  • Loading branch information
nbd168 authored and jow- committed Feb 13, 2024
1 parent dce19b7 commit 3f9811d
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 1 deletion.
3 changes: 2 additions & 1 deletion compiler.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
22 changes: 22 additions & 0 deletions tests/custom/99_bugs/45_compiler_loop_ctrl_unclosed_upvals
Original file line number Diff line number Diff line change
@@ -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 --

0 comments on commit 3f9811d

Please sign in to comment.