[PATCH v2 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 -- v2: 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 | 22 +++++++++++++++------- dlls/vbscript/tests/lang.vbs | 13 +++++++++++++ dlls/vbscript/vbscript.rc | 1 + dlls/vbscript/vbscript_defs.h | 1 + 4 files changed, 30 insertions(+), 7 deletions(-) diff --git a/dlls/vbscript/interp.c b/dlls/vbscript/interp.c index 6be173f75d0..cf6816a61b8 100644 --- a/dlls/vbscript/interp.c +++ b/dlls/vbscript/interp.c @@ -1453,7 +1453,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; @@ -1468,7 +1468,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++; @@ -1477,6 +1477,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) @@ -2399,11 +2408,10 @@ static HRESULT interp_incc(exec_ctx_t *ctx) } hres = VarAdd(stack_top(ctx, 0), ref.u.v, &v); - if(FAILED(hres)) - return hres; - - VariantClear(ref.u.v); - *ref.u.v = v; + if(SUCCEEDED(hres)) { + VariantClear(ref.u.v); + *ref.u.v = v; + } return S_OK; } diff --git a/dlls/vbscript/tests/lang.vbs b/dlls/vbscript/tests/lang.vbs index 055a63047c0..9eaecd27612 100644 --- a/dlls/vbscript/tests/lang.vbs +++ b/dlls/vbscript/tests/lang.vbs @@ -828,6 +828,19 @@ do while true next loop +On Error Resume Next +x = Empty +y = 0 +z = 99 +For z = 1 To UBound(x) + y = y + 1 +Next +call ok(Err.Number = 92, "for to UBound(Empty): Err.Number = " & Err.Number) +call ok(y = 1, "for to UBound(Empty): y = " & y) +call todo_wine_ok(z = 99, "for to UBound(Empty): z = " & z) +Err.Clear +On Error GoTo 0 + if null then call ok(false, "if null evaluated") while null diff --git a/dlls/vbscript/vbscript.rc b/dlls/vbscript/vbscript.rc index a0f7381bcf0..6bac38bd756 100644 --- a/dlls/vbscript/vbscript.rc +++ b/dlls/vbscript/vbscript.rc @@ -41,6 +41,7 @@ STRINGTABLE VBSE_PATH_FILE_ACCESS "Path/File access error" VBSE_PATH_NOT_FOUND "Path not found" VBSE_OBJECT_VARIABLE_NOT_SET "Object variable not set" + VBSE_FOR_LOOP_NOT_INITIALIZED "For loop not initialized" VBSE_ILLEGAL_NULL_USE "Invalid use of Null" VBSE_CANT_CREATE_TMP_FILE "Can't create necessary temporary file" VBSE_OBJECT_REQUIRED "Object required" diff --git a/dlls/vbscript/vbscript_defs.h b/dlls/vbscript/vbscript_defs.h index 06d3b8990fb..e5c896f9158 100644 --- a/dlls/vbscript/vbscript_defs.h +++ b/dlls/vbscript/vbscript_defs.h @@ -252,6 +252,7 @@ #define VBSE_PATH_FILE_ACCESS 75 #define VBSE_PATH_NOT_FOUND 76 #define VBSE_OBJECT_VARIABLE_NOT_SET 91 +#define VBSE_FOR_LOOP_NOT_INITIALIZED 92 #define VBSE_ILLEGAL_NULL_USE 94 #define VBSE_CANT_CREATE_TMP_FILE 322 #define VBSE_OBJECT_REQUIRED 424 -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10366
participants (2)
-
Francis De Brabandere -
Francis De Brabandere (@francisdb)