From: Francis De Brabandere <francisdb@gmail.com> Store a reference to vbscode_t in VBScriptError and compute the source line text on demand in GetSourceLineText. Only store the source reference for compile errors, not runtime errors, matching native behavior. Also fix a memory leak in VBScriptError_Release by using clear_ei to free EXCEPINFO BSTRs. --- dlls/vbscript/compile.c | 2 +- dlls/vbscript/interp.c | 2 +- dlls/vbscript/tests/run.c | 76 ++++++++++++++++++++++++++++----------- dlls/vbscript/vbscript.c | 43 +++++++++++++++++++--- dlls/vbscript/vbscript.h | 2 +- 5 files changed, 98 insertions(+), 27 deletions(-) diff --git a/dlls/vbscript/compile.c b/dlls/vbscript/compile.c index a3fedc950a1..345e3b5291b 100644 --- a/dlls/vbscript/compile.c +++ b/dlls/vbscript/compile.c @@ -402,7 +402,7 @@ static HRESULT compile_error(script_ctx_t *ctx, compile_ctx_t *compiler, HRESULT ctx->ei.scode = error; ctx->ei.bstrSource = get_vbscript_string(VBS_COMPILE_ERROR); map_vbs_exception(&ctx->ei); - return report_script_error(ctx, compiler->code, compiler->loc); + return report_script_error(ctx, compiler->code, compiler->loc, TRUE); } static expression_t *lookup_const_decls(compile_ctx_t *ctx, const WCHAR *name, BOOL lookup_global) diff --git a/dlls/vbscript/interp.c b/dlls/vbscript/interp.c index 79225af27b9..439521a7a39 100644 --- a/dlls/vbscript/interp.c +++ b/dlls/vbscript/interp.c @@ -2593,7 +2593,7 @@ HRESULT exec_script(script_ctx_t *ctx, BOOL extern_caller, function_t *func, vbd if(FAILED(hres)) { if(!ctx->ei.scode) ctx->ei.scode = hres; - hres = report_script_error(ctx, ctx->error_loc_code, ctx->error_loc_offset); + hres = report_script_error(ctx, ctx->error_loc_code, ctx->error_loc_offset, FALSE); clear_error_loc(ctx); } IActiveScriptSite_OnLeaveScript(ctx->site); diff --git a/dlls/vbscript/tests/run.c b/dlls/vbscript/tests/run.c index 80cd3a34bd2..1b46cd49393 100644 --- a/dlls/vbscript/tests/run.c +++ b/dlls/vbscript/tests/run.c @@ -2007,6 +2007,8 @@ static HRESULT WINAPI ActiveScriptSite_OnStateChange(IActiveScriptSite *iface, S static IActiveScriptError **store_script_error; static ULONG error_line; static LONG error_char; +static BSTR error_source_line; +static HRESULT error_source_line_hres; static HRESULT WINAPI ActiveScriptSite_OnScriptError(IActiveScriptSite *iface, IActiveScriptError *pscripterror) { @@ -2015,6 +2017,10 @@ static HRESULT WINAPI ActiveScriptSite_OnScriptError(IActiveScriptSite *iface, I hres = IActiveScriptError_GetSourcePosition(pscripterror, NULL, &error_line, &error_char); ok(hres == S_OK, "GetSourcePosition failed: %08lx\n", hres); + SysFreeString(error_source_line); + error_source_line = NULL; + error_source_line_hres = IActiveScriptError_GetSourceLineText(pscripterror, &error_source_line); + if(!expect_OnScriptError) { EXCEPINFO info; @@ -2696,6 +2702,8 @@ static void test_parse_errors(void) const WCHAR *src; unsigned error_line; int error_char; + const WCHAR *source_line; + HRESULT source_line_hres; } invalid_scripts[] = { @@ -2703,7 +2711,8 @@ static void test_parse_errors(void) /* If...End If */ L"If 0 > 1 Then\n" " x = 0 End If\n", - 1, 10 + 1, 10, + L" x = 0 End If", S_OK }, { /* ElseIf...End If */ @@ -2711,50 +2720,58 @@ static void test_parse_errors(void) " x = 0\n" "ElseIf True Then\n" " x = 1 End If\n", - 3, 10 + 3, 10, + L" x = 1 End If", S_OK }, { /* Else End If (no separator) */ L"If False Then\n" " x = 0\n" "Else End If\n", - 2, 5 + 2, 5, + L"Else End If", S_OK }, { /* While...End While */ L"While False\n" " x = 0 End While\n", - 1, 10 + 1, 10, + L" x = 0 End While", S_OK }, { /* While...Wend */ L"While False\n" " x = 0 Wend\n", - 1, 10 + 1, 10, + L" x = 0 Wend", S_OK }, { /* Do While...Loop */ L"Do While False\n" " x = 0 Loop\n", - 1, 10 + 1, 10, + L" x = 0 Loop", S_OK }, { /* Do Until...Loop */ L"Do Until True\n" " x = 0 Loop\n", - 1, 10 + 1, 10, + L" x = 0 Loop", S_OK }, { /* Do...Loop While */ L"Do\n" " x = 0 Loop While False\n", - 1, 10 + 1, 10, + L" x = 0 Loop While False", S_OK }, { /* Do...Loop Until */ L"Do\n" " x = 0 Loop Until True\n", - 1, 10 + 1, 10, + L" x = 0 Loop Until True", S_OK }, { /* Select...End Select */ @@ -2765,36 +2782,43 @@ static void test_parse_errors(void) " Case 42\n" " x = True End Select\n" "Call ok(x, \"wrong case\")\n", - 5, 17 + 5, 17, + L" x = True End Select", S_OK }, { /* Class...End Class (empty) */ L"Class C End Class", - 0, 8 + 0, 8, + L"Class C End Class", S_OK }, { /* Class...End Class (empty) */ L"Class C _\nEnd Class", - 1, 0 + 1, 0, + L"End Class", S_OK }, { /* invalid use of parentheses for call statement */ L"strcomp(\"x\", \"y\")", - 0, 17 + 0, 17, + L"strcomp(\"x\", \"y\")", S_OK }, { L"\n\n\n cint _\n throwInt(&h80001234&)", - 3, 2 + 3, 2, + NULL, E_FAIL }, { L"dim x\n" "if true then throwInt(&h80001234&)", - 1, 13 + 1, 13, + NULL, E_FAIL }, { L"dim x\n" "if x = throwInt(&h80001234&) then x = 1", - 1, 0 + 1, 0, + NULL, E_FAIL }, { L"sub test\n" @@ -2802,14 +2826,16 @@ static void test_parse_errors(void) " if x = throwInt(&h80001234&) then x = 1\n" "end sub\n" "test\n", - 2, 4 + 2, 4, + NULL, E_FAIL }, { L"dim x\n" "do\n" " x = 1\n" "loop until throwInt(&h80001234&)\n", - 3, 0 + 3, 0, + NULL, E_FAIL }, { L"\n select case 3\n" @@ -2818,7 +2844,8 @@ static void test_parse_errors(void) " case throwInt(&h80001234&)\n" " throwInt &h87001234&\n" "end select\n", - 1, 2 + 1, 2, + NULL, E_FAIL }, { L"if false then\n" @@ -2828,7 +2855,8 @@ static void test_parse_errors(void) "else\n" " throwInt &h87001234&\n" "end if\n", - 2, 1 + 2, 1, + NULL, E_FAIL } }; HRESULT hres; @@ -2850,7 +2878,15 @@ static void test_parse_errors(void) todo_wine_if(invalid_scripts[i].error_char < 0) ok(error_char == abs(invalid_scripts[i].error_char), "[%u] error char %ld expected %d\n", i, error_char, invalid_scripts[i].error_char); + ok(error_source_line_hres == invalid_scripts[i].source_line_hres, + "[%u] GetSourceLineText returned: %08lx\n", i, error_source_line_hres); + if(error_source_line_hres == S_OK && invalid_scripts[i].source_line) + ok(!wcscmp(error_source_line, invalid_scripts[i].source_line), + "[%u] source line %s expected %s\n", i, + wine_dbgstr_w(error_source_line), wine_dbgstr_w(invalid_scripts[i].source_line)); } + SysFreeString(error_source_line); + error_source_line = NULL; } static void test_msgbox(void) diff --git a/dlls/vbscript/vbscript.c b/dlls/vbscript/vbscript.c index 715c98d32bb..bc5a4ea416c 100644 --- a/dlls/vbscript/vbscript.c +++ b/dlls/vbscript/vbscript.c @@ -64,6 +64,8 @@ typedef struct { DWORD_PTR cookie; unsigned line; unsigned character; + vbscode_t *code; + unsigned loc; } VBScriptError; static inline WCHAR *heap_pool_strdup(heap_pool_t *heap, const WCHAR *str) @@ -505,8 +507,12 @@ static ULONG WINAPI VBScriptError_Release(IActiveScriptError *iface) TRACE("(%p) ref=%ld\n", This, ref); - if(!ref) + if(!ref) { + clear_ei(&This->ei); + if(This->code) + release_vbscode(This->code); free(This); + } return ref; } @@ -542,8 +548,28 @@ static HRESULT WINAPI VBScriptError_GetSourcePosition(IActiveScriptError *iface, static HRESULT WINAPI VBScriptError_GetSourceLineText(IActiveScriptError *iface, BSTR *source) { VBScriptError *This = impl_from_IActiveScriptError(iface); - FIXME("(%p)->(%p)\n", This, source); - return E_NOTIMPL; + const WCHAR *nl, *line_end; + + TRACE("(%p)->(%p)\n", This, source); + + if(!source) + return E_POINTER; + + if(!This->code) { + *source = NULL; + return E_FAIL; + } + + nl = This->code->source + This->loc; + while(nl > This->code->source && nl[-1] != '\n') + nl--; + + line_end = This->code->source + This->loc; + while(*line_end && *line_end != '\n' && *line_end != '\r') + line_end++; + + *source = SysAllocStringLen(nl, line_end - nl); + return *source ? S_OK : E_OUTOFMEMORY; } static const IActiveScriptErrorVtbl VBScriptErrorVtbl = { @@ -555,7 +581,7 @@ static const IActiveScriptErrorVtbl VBScriptErrorVtbl = { VBScriptError_GetSourceLineText }; -HRESULT report_script_error(script_ctx_t *ctx, const vbscode_t *code, unsigned loc) +HRESULT report_script_error(script_ctx_t *ctx, vbscode_t *code, unsigned loc, BOOL store_source) { VBScriptError *error; const WCHAR *p, *nl; @@ -580,6 +606,15 @@ HRESULT report_script_error(script_ctx_t *ctx, const vbscode_t *code, unsigned l } error->character = code->source + loc - nl; + if(store_source) { + grab_vbscode(code); + error->code = code; + error->loc = loc; + }else { + error->code = NULL; + error->loc = 0; + } + hres = IActiveScriptSite_OnScriptError(ctx->site, &error->IActiveScriptError_iface); IActiveScriptError_Release(&error->IActiveScriptError_iface); return hres == S_OK ? SCRIPT_E_REPORTED : result; diff --git a/dlls/vbscript/vbscript.h b/dlls/vbscript/vbscript.h index 6b67c8b1bc5..a0c8b9f82e8 100644 --- a/dlls/vbscript/vbscript.h +++ b/dlls/vbscript/vbscript.h @@ -394,7 +394,7 @@ void release_dynamic_var(dynamic_var_t*); named_item_t *lookup_named_item(script_ctx_t*,const WCHAR*,unsigned); void release_named_item(named_item_t*); void clear_ei(EXCEPINFO*); -HRESULT report_script_error(script_ctx_t*,const vbscode_t*,unsigned); +HRESULT report_script_error(script_ctx_t*,vbscode_t*,unsigned,BOOL); void detach_global_objects(script_ctx_t*); HRESULT get_builtin_id(BuiltinDisp*,const WCHAR*,DISPID*); HRESULT array_access(SAFEARRAY *array, DISPPARAMS *dp, VARIANT **ret); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10396