[PATCH v6 0/1] MR10314: vbscript: Convert string to number for comparison operators.
When one operand was a string and the other numeric, VBScript should have converted the string to a double before comparing. VarCmp did not do this automatically, resulting in incorrect string comparison. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=56281 -- v6: vbscript: Convert string to number for comparison operators. https://gitlab.winehq.org/wine/wine/-/merge_requests/10314
From: Francis De Brabandere <francisdb@gmail.com> When one operand was a string and the other numeric, VBScript should have converted the string to a double before comparing. VarCmp did not do this automatically, resulting in incorrect string comparison. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=56281 --- dlls/vbscript/interp.c | 32 ++++++++++++++++++++++++++++++-- dlls/vbscript/tests/lang.vbs | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 2 deletions(-) diff --git a/dlls/vbscript/interp.c b/dlls/vbscript/interp.c index d8f0f80dfaa..c917f62d143 100644 --- a/dlls/vbscript/interp.c +++ b/dlls/vbscript/interp.c @@ -1959,11 +1959,34 @@ static HRESULT interp_imp(exec_ctx_t *ctx) return stack_push(ctx, &v); } +static inline BOOL is_numeric_vt(VARTYPE vt) +{ + return vt == VT_I2 || vt == VT_I4 || vt == VT_R4 || vt == VT_R8 + || vt == VT_CY || vt == VT_DATE || vt == VT_UI1; +} + static HRESULT var_cmp(exec_ctx_t *ctx, VARIANT *l, VARIANT *r) { + VARIANT v; + HRESULT hres; + TRACE("%s %s\n", debugstr_variant(l), debugstr_variant(r)); - /* FIXME: Fix comparing string to number */ + /* VBScript compares string to number by converting the string to double, + * while VarCmp would use string comparison. */ + if(V_VT(l) == VT_BSTR && is_numeric_vt(V_VT(r))) { + V_VT(&v) = VT_EMPTY; + hres = VariantChangeType(&v, l, 0, VT_R8); + if(SUCCEEDED(hres)) + return VarCmp(&v, r, ctx->script->lcid, 0); + return hres; + }else if(V_VT(r) == VT_BSTR && is_numeric_vt(V_VT(l))) { + V_VT(&v) = VT_EMPTY; + hres = VariantChangeType(&v, r, 0, VT_R8); + if(SUCCEEDED(hres)) + return VarCmp(l, &v, ctx->script->lcid, 0); + return hres; + } return VarCmp(l, r, ctx->script->lcid, 0); } @@ -2109,8 +2132,13 @@ static HRESULT interp_case(exec_ctx_t *ctx) hres = var_cmp(ctx, stack_top(ctx, 0), v.v); release_val(&v); - if(FAILED(hres)) + if(FAILED(hres)) { + if(hres == DISP_E_TYPEMISMATCH) { + ctx->instr++; + return S_OK; + } return hres; + } if(hres == VARCMP_EQ) { stack_popn(ctx, 1); diff --git a/dlls/vbscript/tests/lang.vbs b/dlls/vbscript/tests/lang.vbs index c0d22606ba6..668cd175c92 100644 --- a/dlls/vbscript/tests/lang.vbs +++ b/dlls/vbscript/tests/lang.vbs @@ -117,6 +117,41 @@ Call ok(1 <> Not 0 = 0, "1 <> Not 0 = 0 should be true") Call ok(0 = Not 1 = 1, "0 = Not 1 = 1 should be true") Call ok(1 > Not 5 > 3, "1 > Not 5 > 3 should be true") Call ok(Not false And false = false, "Not false And false should be false") +x = "0" +Call ok(not (x > 30), """0"" > 30 should be false") +Call ok(x < 30, """0"" < 30 should be true") +Call ok(not ("0" > 30), """0"" > 30 literal should be false") +Call ok("0" < 30, """0"" < 30 literal should be true") +Call ok("10" > 9, """10"" > 9 should be true") +Call ok(not ("10" > 100), """10"" > 100 should be false") +Call ok("10" < 100, """10"" < 100 should be true") +Call ok("42" = 42, """42"" = 42 should be true") +Call ok(not ("42" = 43), """42"" = 43 should be false") +Call ok(doubleAsString(0.5) > 0, """0.5"" > 0 should be true") +Call ok(doubleAsString(0.5) < 1, """0.5"" < 1 should be true") +Call ok(doubleAsString(3.5) = 3.5, """3.5"" = 3.5 should be true") +Call ok(not (doubleAsString(1.5) > 2), """1.5"" > 2 should be false") +Call ok(doubleAsString(2.5) > 2, """2.5"" > 2 should be true") +Call ok(30 > "0", "30 > ""0"" should be true") +Call ok(9 < "10", "9 < ""10"" should be true") +Call ok(42 = "42", "42 = ""42"" should be true") +Call ok(not ("10" > "9"), """10"" > ""9"" should be false (string comparison)") +' String vs Boolean uses string comparison, not numeric conversion +Call ok(not ("1" = True), """1"" = True should be false") +Call ok(not ("-1" = True), """-1"" = True should be false") +Call ok(not ("0" = False), """0"" = False should be false") +' Non-numeric string compared to number should raise type mismatch +on error resume next +err.clear +x = ("abc" > 5) +Call ok(err.number = 13, """abc"" > 5 err.number = " & err.number) +err.clear +x = ("" > 0) +Call ok(err.number = 13, """"" > 0 err.number = " & err.number) +err.clear +x = (5 > "abc") +Call ok(err.number = 13, "5 > ""abc"" err.number = " & err.number) +on error goto 0 Call ok(getVT(false) = "VT_BOOL", "getVT(false) is not VT_BOOL") Call ok(getVT(true) = "VT_BOOL", "getVT(true) is not VT_BOOL") -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10314
Added some more test cases and fixed bool not being numeric in VBScript. (after more testing on windows) -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10314#note_134283
On Sun Mar 29 21:56:14 2026 +0000, Francis De Brabandere wrote:
I added tests for doubles Had another look and this is just VBScript specific.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10314#note_134284
participants (2)
-
Francis De Brabandere -
Francis De Brabandere (@francisdb)