[PATCH v5 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 -- v5: 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 | 12 +++++++++--- dlls/vbscript/tests/lang.vbs | 12 ++++++++++++ 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/dlls/vbscript/interp.c b/dlls/vbscript/interp.c index 4bbdad181e0..fe7fa9eaf70 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,12 @@ 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); + return hres; } static HRESULT interp_newenum(exec_ctx_t *ctx) @@ -2516,7 +2522,7 @@ static HRESULT interp_incc(exec_ctx_t *ctx) hres = VarAdd(stack_top(ctx, 0), ref.u.v, &v); if(FAILED(hres)) - return MAKE_VBSERROR(VBSE_FOR_LOOP_NOT_INITIALIZED); + return hres; VariantClear(ref.u.v); *ref.u.v = v; diff --git a/dlls/vbscript/tests/lang.vbs b/dlls/vbscript/tests/lang.vbs index cce5b02e9cb..02f23f7faf8 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 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
This merge request was approved by Jacek Caban. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10366
participants (3)
-
Francis De Brabandere -
Francis De Brabandere (@francisdb) -
Jacek Caban (@jacek)