[PATCH v2 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 -- v2: 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 | 23 ++++++++++++++++++++++- dlls/vbscript/tests/lang.vbs | 16 ++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/dlls/vbscript/interp.c b/dlls/vbscript/interp.c index 127fcc2c05e..5ba3988ec4e 100644 --- a/dlls/vbscript/interp.c +++ b/dlls/vbscript/interp.c @@ -1941,11 +1941,32 @@ 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_BOOL || 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); + }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 VarCmp(l, r, ctx->script->lcid, 0); } diff --git a/dlls/vbscript/tests/lang.vbs b/dlls/vbscript/tests/lang.vbs index 0025bfeddcf..1cff45443c7 100644 --- a/dlls/vbscript/tests/lang.vbs +++ b/dlls/vbscript/tests/lang.vbs @@ -92,6 +92,22 @@ Call ok(not(false = true = ""), "false = true = """" is true") Call ok(not (false = false <> false = false), "false = false <> false = false is true") Call ok(not ("" <> false = false), """"" <> false = false is true") +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(getVT(false) = "VT_BOOL", "getVT(false) is not VT_BOOL") Call ok(getVT(true) = "VT_BOOL", "getVT(true) is not VT_BOOL") Call ok(getVT("") = "VT_BSTR", "getVT("""") is not VT_BSTR") -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10314
I added tests for doubles -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10314#note_132051
On Thu Mar 12 15:20:50 2026 +0000, Francis De Brabandere wrote:
Not convinced this should be pushed down to `VarCmp`. I expect the OLE api to be more tested / covered / used than the vbscript dll? I added tests for doubles
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10314#note_132053
participants (2)
-
Francis De Brabandere -
Francis De Brabandere (@francisdb)