From: Francis De Brabandere <francisdb@gmail.com> Fix several interpreter code paths that returned wrong error codes when an object was expected but not provided: - stack_pop_disp: E_FAIL -> 424 for non-dispatch types. - do_mcall: E_FAIL -> 424 when calling a member on Nothing. - interp_assign_member: E_FAIL -> 424 for Nothing.Prop = value. - interp_set_member: E_FAIL -> 424 for Set Nothing.Child = obj. - interp_is: E_NOTIMPL -> 424 for non-object Is operands. Also add OP_with opcode to validate the With expression is a dispatch object at entry time, matching Windows behavior where With on non-object types (integers, strings, Empty, Null, booleans) raises error 424 immediately, while With Nothing succeeds. --- dlls/vbscript/compile.c | 3 ++ dlls/vbscript/interp.c | 42 +++++++++++------ dlls/vbscript/tests/error.vbs | 85 +++++++++++++++++++++++++++++++++++ dlls/vbscript/vbscript.h | 1 + 4 files changed, 117 insertions(+), 14 deletions(-) diff --git a/dlls/vbscript/compile.c b/dlls/vbscript/compile.c index 345e3b5291b..f1072252ff1 100644 --- a/dlls/vbscript/compile.c +++ b/dlls/vbscript/compile.c @@ -954,6 +954,9 @@ static HRESULT compile_with_statement(compile_ctx_t *ctx, with_statement_t *stat if(FAILED(hres)) return hres; + if(!push_instr(ctx, OP_with)) + return E_OUTOFMEMORY; + if(!emit_catch(ctx, 1)) return E_OUTOFMEMORY; diff --git a/dlls/vbscript/interp.c b/dlls/vbscript/interp.c index 00ef7d93eb6..088c23d0cf0 100644 --- a/dlls/vbscript/interp.c +++ b/dlls/vbscript/interp.c @@ -449,15 +449,15 @@ static HRESULT stack_pop_disp(exec_ctx_t *ctx, IDispatch **ret) } if(V_VT(v) != (VT_VARIANT|VT_BYREF)) { - FIXME("not supported type: %s\n", debugstr_variant(v)); + WARN("not supported type: %s\n", debugstr_variant(v)); VariantClear(v); - return E_FAIL; + return MAKE_VBSERROR(VBSE_OBJECT_REQUIRED); } v = V_BYREF(v); if(V_VT(v) != VT_DISPATCH) { - FIXME("not disp %s\n", debugstr_variant(v)); - return E_FAIL; + WARN("not disp %s\n", debugstr_variant(v)); + return MAKE_VBSERROR(VBSE_OBJECT_REQUIRED); } if(V_DISPATCH(v)) @@ -768,8 +768,8 @@ static HRESULT do_mcall(exec_ctx_t *ctx, VARIANT *res) return hres; if(!obj) { - FIXME("NULL obj\n"); - return E_FAIL; + WARN("NULL obj\n"); + return MAKE_VBSERROR(VBSE_OBJECT_REQUIRED); } vbstack_to_dp(ctx, arg_cnt, FALSE, &dp); @@ -997,8 +997,8 @@ static HRESULT interp_assign_member(exec_ctx_t *ctx) return hres; if(!obj) { - FIXME("NULL obj\n"); - return E_FAIL; + WARN("NULL obj\n"); + return MAKE_VBSERROR(VBSE_OBJECT_REQUIRED); } hres = disp_get_id(obj, identifier, VBDISP_LET, FALSE, &id); @@ -1029,8 +1029,8 @@ static HRESULT interp_set_member(exec_ctx_t *ctx) return hres; if(!obj) { - FIXME("NULL obj\n"); - return E_FAIL; + WARN("NULL obj\n"); + return MAKE_VBSERROR(VBSE_OBJECT_REQUIRED); } hres = stack_assume_disp(ctx, arg_cnt, NULL); @@ -2127,8 +2127,8 @@ static HRESULT interp_is(exec_ctx_t *ctx) stack_pop_deref(ctx, &v); if(V_VT(v.v) != VT_DISPATCH && V_VT(v.v) != VT_UNKNOWN) { - FIXME("Unhandled type %s\n", debugstr_variant(v.v)); - hres = E_NOTIMPL; + WARN("Unhandled type %s\n", debugstr_variant(v.v)); + hres = MAKE_VBSERROR(VBSE_OBJECT_REQUIRED); }else if(V_UNKNOWN(v.v)) { hres = IUnknown_QueryInterface(V_UNKNOWN(v.v), &IID_IUnknown, (void**)&r); } @@ -2138,8 +2138,8 @@ static HRESULT interp_is(exec_ctx_t *ctx) stack_pop_deref(ctx, &v); if(V_VT(v.v) != VT_DISPATCH && V_VT(v.v) != VT_UNKNOWN) { - FIXME("Unhandled type %s\n", debugstr_variant(v.v)); - hres = E_NOTIMPL; + WARN("Unhandled type %s\n", debugstr_variant(v.v)); + hres = MAKE_VBSERROR(VBSE_OBJECT_REQUIRED); }else if(V_UNKNOWN(v.v)) { hres = IUnknown_QueryInterface(V_UNKNOWN(v.v), &IID_IUnknown, (void**)&l); } @@ -2407,6 +2407,20 @@ static HRESULT interp_incc(exec_ctx_t *ctx) return S_OK; } +static HRESULT interp_with(exec_ctx_t *ctx) +{ + VARIANT *v; + + TRACE("\n"); + + v = stack_top(ctx, 0); + if(V_VT(v) == (VT_VARIANT|VT_BYREF)) + v = V_VARIANTREF(v); + if(V_VT(v) != VT_DISPATCH && V_VT(v) != VT_UNKNOWN) + return MAKE_VBSERROR(VBSE_OBJECT_REQUIRED); + return S_OK; +} + static HRESULT interp_catch(exec_ctx_t *ctx) { /* Nothing to do here, the OP is for unwinding only. */ diff --git a/dlls/vbscript/tests/error.vbs b/dlls/vbscript/tests/error.vbs index a9d4dc9c0be..1ffe88318e9 100644 --- a/dlls/vbscript/tests/error.vbs +++ b/dlls/vbscript/tests/error.vbs @@ -515,4 +515,89 @@ unused = undeclaredVar2 todo_wine_ok err.number = 500, "err.number = " & err.number on error goto 0 +sub testObjectRequired() + on error resume next + dim x, r + + ' Is operator with non-object operands + err.clear + r = "hello" Is Nothing + ok err.number = 424, "Is string: err.number = " & err.number + + err.clear + r = Nothing Is "hello" + ok err.number = 424, "Is string rhs: err.number = " & err.number + + err.clear + r = 42 Is 42 + ok err.number = 424, "Is int: err.number = " & err.number + + err.clear + r = Empty Is Empty + ok err.number = 424, "Is empty: err.number = " & err.number + + err.clear + r = Null Is Nothing + ok err.number = 424, "Is null: err.number = " & err.number + + ' Member call on Nothing + err.clear + set x = Nothing + x.Prop + ok err.number = 424, "Nothing.Prop: err.number = " & err.number + + ' Assign member on Nothing + err.clear + set x = Nothing + x.Prop = 1 + ok err.number = 424, "Nothing.Prop = 1: err.number = " & err.number + + ' Set member on Nothing + err.clear + set x = Nothing + set x.Child = Nothing + ok err.number = 424, "Set Nothing.Child: err.number = " & err.number + + ' With on non-object types (no member access) + err.clear + with 42 + end with + ok err.number = 424, "With 42: err.number = " & err.number + + err.clear + with "hello" + end with + ok err.number = 424, "With string: err.number = " & err.number + + err.clear + with empty + end with + ok err.number = 424, "With empty: err.number = " & err.number + + err.clear + with null + end with + ok err.number = 424, "With null: err.number = " & err.number + + err.clear + with true + end with + ok err.number = 424, "With true: err.number = " & err.number + + ' With Nothing should NOT raise 424 at entry + err.clear + with Nothing + end with + ok err.number = 0, "With Nothing: err.number = " & err.number + + ' With Nothing + member access should raise 424 + err.clear + with Nothing + .Prop = 1 + end with + ok err.number = 424, "With Nothing .Prop: err.number = " & err.number +end sub + +call testObjectRequired() + call reportSuccess() diff --git a/dlls/vbscript/vbscript.h b/dlls/vbscript/vbscript.h index a0c8b9f82e8..0f1bfc5fb11 100644 --- a/dlls/vbscript/vbscript.h +++ b/dlls/vbscript/vbscript.h @@ -296,6 +296,7 @@ typedef enum { X(val, 1, 0, 0) \ X(vcall, 1, ARG_UINT, 0) \ X(vcallv, 1, ARG_UINT, 0) \ + X(with, 1, 0, 0) \ X(xor, 1, 0, 0) typedef enum { -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10455