From dd57d12404ec74406ce9ba882577977ab402d63d Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Mon, 5 Oct 2026 20:14:57 +0100 Subject: [PATCH] compiler: do not drop the loop condition at chunk offset 0 uc_compiler_compile_for_count() records where the condition starts in cond_off and treats 0 as "no condition". A counting for loop without an initializer that opens a function body puts its condition at offset 0, so the jump from the incrementer back to the condition is never emitted and the loop keeps running after the condition turned false: function f(n) { for (; n > 0; n--) print(n); } never returns. Test for the conditional jump instead, which is always emitted after at least one instruction of the condition. Fixes: 37568066a7d9 ("treewide: rewrite ucode interpreter") Signed-off-by: Daniel Golle --- compiler.c | 2 +- .../58_for_loop_condition_at_function_start | 38 +++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 tests/custom/99_bugs/58_for_loop_condition_at_function_start diff --git a/compiler.c b/compiler.c index 3b2d585e..73e5f5b9 100644 --- a/compiler.c +++ b/compiler.c @@ -2990,7 +2990,7 @@ uc_compiler_compile_for_count(uc_compiler_t *compiler, bool local, uc_token_t *p uc_compiler_parse_consume(compiler, TK_RPAREN); /* if we have a condition, jump back to it, else continue to the loop body */ - if (cond_off) + if (test_off) uc_compiler_emit_jmp_dest(compiler, 0, cond_off); /* back patch skip address */ diff --git a/tests/custom/99_bugs/58_for_loop_condition_at_function_start b/tests/custom/99_bugs/58_for_loop_condition_at_function_start new file mode 100644 index 00000000..91ec3b42 --- /dev/null +++ b/tests/custom/99_bugs/58_for_loop_condition_at_function_start @@ -0,0 +1,38 @@ +A counting for loop without an initializer that opened a function body +placed its condition at bytecode offset 0, which the compiler mistook +for an absent condition. The loop then never jumped back to the test +and kept running after the condition had turned false. + +-- Testcase -- +{% + function count_down(n) { + for (; n > 0; n--) { + if (n < -2) + return "runaway"; + + print(n, "\n"); + } + + return "done"; + } + + function walk(n) { + for (; n > 1; n = int(n / 2)) + if (n == 0) + return "runaway"; + + return n; + } + + print(count_down(3), "\n"); + print(walk(8), "\n"); +%} +-- End -- + +-- Expect stdout -- +3 +2 +1 +done +1 +-- End --