[PATCH v4 0/1] MR10366: vbscript: Fix For loop getting stuck when expression evaluation fails with On Error Resume Next.
When a For..To loop's bound expression fails (e.g. UBound on Empty) and On Error Resume Next is active, the error handler fills the step/to stack slots with VT_EMPTY. On the next iteration, VarCmp fails on these values and the error propagates back into the loop, causing an infinite loop. Fix this by handling VarCmp failures in interp_step: exit the loop and report error 92 (For loop not initialized). Also make interp_incc ignore VarAdd failures so execution reaches interp_step for proper cleanup. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=54291 -- v4: vbscript: Fix For loop getting stuck when expression evaluation fails with On Error Resume Next. https://gitlab.winehq.org/wine/wine/-/merge_requests/10366
From: Francis De Brabandere <francisdb@gmail.com> When a For..To loop's bound expression fails (e.g. UBound on Empty) and On Error Resume Next is active, the error handler fills the step/to stack slots with VT_EMPTY. On the next iteration, VarCmp fails on these values and the error propagates back into the loop, causing an infinite loop. Fix this by handling VarCmp failures in interp_step: exit the loop and report error 92 (For loop not initialized). Also make interp_incc ignore VarAdd failures so execution reaches interp_step for proper cleanup. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=54291 --- dlls/vbscript/interp.c | 13 +++++++++++-- dlls/vbscript/tests/lang.vbs | 12 ++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/dlls/vbscript/interp.c b/dlls/vbscript/interp.c index 4bbdad181e0..74f19941b56 100644 --- a/dlls/vbscript/interp.c +++ b/dlls/vbscript/interp.c @@ -1569,7 +1569,7 @@ static HRESULT interp_step(exec_ctx_t *ctx) V_I2(&zero) = 0; hres = VarCmp(stack_top(ctx, 0), &zero, ctx->script->lcid, 0); if(FAILED(hres)) - return hres; + goto loop_not_initialized; gteq_zero = hres == VARCMP_GT || hres == VARCMP_EQ; @@ -1584,7 +1584,7 @@ static HRESULT interp_step(exec_ctx_t *ctx) hres = VarCmp(ref.u.v, stack_top(ctx, 1), ctx->script->lcid, 0); if(FAILED(hres)) - return hres; + goto loop_not_initialized; if(hres == VARCMP_EQ || hres == (gteq_zero ? VARCMP_LT : VARCMP_GT)) { ctx->instr++; @@ -1593,6 +1593,15 @@ static HRESULT interp_step(exec_ctx_t *ctx) instr_jmp(ctx, ctx->instr->arg1.uint); } return S_OK; + +loop_not_initialized: + WARN("For loop not initialized\n"); + stack_popn(ctx, 2); + instr_jmp(ctx, ctx->instr->arg1.uint); + clear_ei(&ctx->script->ei); + ctx->script->ei.scode = MAKE_VBSERROR(VBSE_FOR_LOOP_NOT_INITIALIZED); + map_vbs_exception(&ctx->script->ei); + return S_OK; } static HRESULT interp_newenum(exec_ctx_t *ctx) diff --git a/dlls/vbscript/tests/lang.vbs b/dlls/vbscript/tests/lang.vbs index cce5b02e9cb..61b8ec2101c 100644 --- a/dlls/vbscript/tests/lang.vbs +++ b/dlls/vbscript/tests/lang.vbs @@ -894,6 +894,18 @@ next call ok(err.number = 92, "for (UBound(empty)): err.number = " & err.number) call ok(z = 99, "for (UBound(empty)): z = " & z) +' For loop variable set to incompatible type during iteration +x = 0 +y = 0 +err.clear +for x = 1 to 5 + y = y + 1 + if x = 3 then x = "not a number" +next +call ok(y = 3, "for (type change): y = " & y) +call ok(x = "not a number", "for (type change): x = " & x) +call todo_wine_ok(err.number = 13, "for (type change): err.number = " & err.number) + on error goto 0 ' For loop expression evaluation order: from, to, step -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10366
participants (2)
-
Francis De Brabandere -
Francis De Brabandere (@francisdb)