[PATCH v5 0/1] MR10592: vbscript: Add call depth limit to prevent stack overflow on infinite recursion.
Track call depth in script_ctx_t and return error 28 "Out of stack space" when it exceeds 572, matching Windows behavior. Previously Wine would crash with a native stack overflow. -- v5: vbscript: Add call depth limit to prevent stack overflow on infinite recursion. https://gitlab.winehq.org/wine/wine/-/merge_requests/10592
From: Francis De Brabandere <francisdb@gmail.com> Track call depth in script_ctx_t and return error 28 "Out of stack space" when it exceeds 572, matching Windows behavior. Previously Wine would crash with a native stack overflow. --- dlls/vbscript/interp.c | 8 +++++++ dlls/vbscript/tests/lang.vbs | 40 +++++++++++++++++++++++++++++++++++ dlls/vbscript/vbscript.h | 1 + dlls/vbscript/vbscript.rc | 1 + dlls/vbscript/vbscript_defs.h | 1 + 5 files changed, 51 insertions(+) diff --git a/dlls/vbscript/interp.c b/dlls/vbscript/interp.c index 4bbdad181e0..27dac97e636 100644 --- a/dlls/vbscript/interp.c +++ b/dlls/vbscript/interp.c @@ -25,6 +25,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(vbscript); static DISPID propput_dispid = DISPID_PROPERTYPUT; +static const unsigned max_call_depth = 572; typedef struct _exec_ctx_t { vbscode_t *code; @@ -2657,6 +2658,11 @@ HRESULT exec_script(script_ctx_t *ctx, BOOL extern_caller, function_t *func, vbd vbsop_t op; HRESULT hres = S_OK; + if(!extern_caller && ctx->call_depth++ >= max_call_depth) { + ctx->call_depth--; + return MAKE_VBSERROR(VBSE_OUT_OF_STACK); + } + exec.code = func->code_ctx; exec.caller = ctx->caller_exec; ctx->caller_exec = NULL; @@ -2815,6 +2821,8 @@ HRESULT exec_script(script_ctx_t *ctx, BOOL extern_caller, function_t *func, vbd } ctx->current_named_item = prev_named_item; + if(!extern_caller) + ctx->call_depth--; release_exec(&exec); return hres; } diff --git a/dlls/vbscript/tests/lang.vbs b/dlls/vbscript/tests/lang.vbs index cce5b02e9cb..46d72ac3435 100644 --- a/dlls/vbscript/tests/lang.vbs +++ b/dlls/vbscript/tests/lang.vbs @@ -2730,6 +2730,46 @@ function recursingfunction2 end function call ok(recursingfunction2() = 1, "unexpected return value " & recursingfunction2()) +' Recursion depth: verify recursion works up to 572 levels +Dim recursionDepth +recursionDepth = 0 +Sub RecurseN(n) + recursionDepth = recursionDepth + 1 + If n > 1 Then RecurseN n - 1 +End Sub +RecurseN 572 +Call ok(recursionDepth = 572, "recursion depth: " & recursionDepth & " expected 572") + +' Error 28: Out of stack space (infinite recursion) +Sub RecurseForever() + RecurseForever +End Sub + +' Error 28: Out of stack space (mutual recursion) +' Depth varies on Windows (572 on Win10 64-bit VM, 1197 on Win10 64-bit CI, +' 3122 on Win10 32-bit CI). The exact limit is not well understood. +Dim mutualDepth +mutualDepth = 0 +Sub MutualA() + mutualDepth = mutualDepth + 1 + MutualB +End Sub +Sub MutualB() + mutualDepth = mutualDepth + 1 + MutualA +End Sub + +On Error Resume Next +Err.Clear +MutualA +Call ok(Err.Number = 28, "mutual recursion: err.number = " & Err.Number) + +' Error 28: Out of stack space (infinite recursion) +Err.Clear +RecurseForever +Call ok(Err.Number = 28, "infinite recursion: err.number = " & Err.Number) +On Error GoTo 0 + function f2(x,y) end function diff --git a/dlls/vbscript/vbscript.h b/dlls/vbscript/vbscript.h index 19c9260a342..edcc3865dcd 100644 --- a/dlls/vbscript/vbscript.h +++ b/dlls/vbscript/vbscript.h @@ -211,6 +211,7 @@ struct _script_ctx_t { exec_ctx_t *current_exec; exec_ctx_t *caller_exec; + unsigned call_depth; EXCEPINFO ei; vbscode_t *error_loc_code; diff --git a/dlls/vbscript/vbscript.rc b/dlls/vbscript/vbscript.rc index 5e3adddc789..60843e1fb71 100644 --- a/dlls/vbscript/vbscript.rc +++ b/dlls/vbscript/vbscript.rc @@ -32,6 +32,7 @@ STRINGTABLE VBSE_ARRAY_LOCKED "This array is fixed or temporarily locked" VBSE_DIVISION_BY_ZERO "Division by zero" VBSE_TYPE_MISMATCH "Type mismatch" + VBSE_OUT_OF_STACK "Out of stack space" VBSE_FILE_NOT_FOUND "File not found" VBSE_IO_ERROR "Device I/O error" VBSE_FILE_ALREADY_EXISTS "File already exists" diff --git a/dlls/vbscript/vbscript_defs.h b/dlls/vbscript/vbscript_defs.h index 0dc7b677517..cc015514df0 100644 --- a/dlls/vbscript/vbscript_defs.h +++ b/dlls/vbscript/vbscript_defs.h @@ -243,6 +243,7 @@ #define VBSE_ARRAY_LOCKED 10 #define VBSE_DIVISION_BY_ZERO 11 #define VBSE_TYPE_MISMATCH 13 +#define VBSE_OUT_OF_STACK 28 #define VBSE_FILE_NOT_FOUND 53 #define VBSE_IO_ERROR 57 #define VBSE_FILE_ALREADY_EXISTS 58 -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10592
participants (2)
-
Francis De Brabandere -
Francis De Brabandere (@francisdb)