[PATCH v5 0/2] MR10818: Draft: vbscript/tests: Cover non-literal numeric vs whitespace-only BSTR.
Native VBScript treats a whitespace-only BSTR (e.g. Space(N)) as larger than any numeric in BSTR-vs-numeric comparison, regardless of binary lex order. Wine's CStr-coerce path goes through VarCmp's binary order and gets the opposite result for single-digit numerics, breaking the practical Left(str, n) guard pattern Len(str) > Space(n). continuation of !10775 -- v5: vbscript: Treat all-whitespace BSTR as greater than numeric in non-literal compare. https://gitlab.winehq.org/wine/wine/-/merge_requests/10818
From: Francis De Brabandere <francisdb@gmail.com> Native VBScript treats a whitespace-only BSTR (e.g. Space(N)) as larger than any numeric in BSTR-vs-numeric comparison, regardless of binary lex order. Wine's CStr-coerce path goes through VarCmp's binary order and gets the opposite result for single-digit numerics, breaking the practical Left(str, n) guard pattern Len(str) > Space(n). --- dlls/vbscript/tests/lang.vbs | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/dlls/vbscript/tests/lang.vbs b/dlls/vbscript/tests/lang.vbs index cc33d6951af..c80f45c1bdd 100644 --- a/dlls/vbscript/tests/lang.vbs +++ b/dlls/vbscript/tests/lang.vbs @@ -317,6 +317,37 @@ Call ok(not ("10" > CDbl(5)), """10"" > CDbl(5) should be false (lex)") Call ok(not ("10" > CSng(5)), """10"" > CSng(5) should be false (lex)") Call ok(not ("9" < CDbl(10)), """9"" < CDbl(10) should be false (lex)") +Dim ws_space : ws_space = Space(3) +Dim ws_tab : ws_tab = Chr(9) +Dim ws_lf : ws_lf = Chr(10) +Dim ws_cr : ws_cr = Chr(13) +Dim ws_nbsp : ws_nbsp = Chr(160) +Call todo_wine_ok(not (Len("ab") > ws_space), "Len(""ab"") > Space(3) should be false") +Call todo_wine_ok((Len("ab") < ws_space), "Len(""ab"") < Space(3) should be true") +Call ok(not (Len("ab") = ws_space), "Len(""ab"") = Space(3) should be false") +Call todo_wine_ok(not (Len("ab") > ws_tab), "Len(""ab"") > Chr(9) should be false") +Call todo_wine_ok((Len("ab") < ws_tab), "Len(""ab"") < Chr(9) should be true") +Call todo_wine_ok(not (Len("ab") > ws_lf), "Len(""ab"") > Chr(10) should be false") +Call todo_wine_ok((Len("ab") < ws_lf), "Len(""ab"") < Chr(10) should be true") +Call todo_wine_ok(not (Len("ab") > ws_cr), "Len(""ab"") > Chr(13) should be false") +Call todo_wine_ok((Len("ab") < ws_cr), "Len(""ab"") < Chr(13) should be true") +Call ok(not (Len("ab") > ws_nbsp), "Len(""ab"") > Chr(160) should be false") +Call ok((Len("ab") < ws_nbsp), "Len(""ab"") < Chr(160) should be true") + +Call ok((Len("ab") > ""), "Len(""ab"") > """" should be true") + +Dim guard_str : guard_str = "ab" +Dim guard_err, guard_r +On Error Resume Next +Err.Clear +If Len(guard_str) > Space(3) Then + guard_r = Left(guard_str, Space(3)) +End If +guard_err = Err.number +Err.Clear +On Error Goto 0 +Call todo_wine_ok(guard_err = 0, "Len(""ab"") > Space(3) guard should not raise (got " & guard_err & ")") + ' --- VT_DATE from CDate is non-literal: string compare, no error. --- Dim cdt : cdt = CDate("2024-01-15") Call ok(not ("abc" = cdt), "CDate: ""abc"" = CDate(...) should be false") -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10818
From: Francis De Brabandere <francisdb@gmail.com> Native VBScript sorts a non-empty all-whitespace BSTR (Space, tab, LF, CR, ...) higher than any numeric or boolean operand, regardless of the binary lex order their CStr forms would produce. Add an early-out in var_cmp before the CStr-coerce path; empty BSTR keeps falling through to the regular lex compare. --- dlls/vbscript/interp.c | 10 ++++++++++ dlls/vbscript/tests/lang.vbs | 20 ++++++++++---------- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/dlls/vbscript/interp.c b/dlls/vbscript/interp.c index 7ff3baecce8..defeb894c22 100644 --- a/dlls/vbscript/interp.c +++ b/dlls/vbscript/interp.c @@ -2168,9 +2168,19 @@ static HRESULT var_cmp(exec_ctx_t *ctx, VARIANT *l, VARIANT *r, unsigned flags) (rvt == VT_BSTR && (is_numeric_vt(lvt) || lvt == VT_BOOL))) { VARIANT *num = lvt == VT_BSTR ? r : l; VARIANT *str = lvt == VT_BSTR ? l : r; + BSTR str_bstr = V_BSTR(str); VARIANT num_str; HRESULT hres; + /* Native treats a non-empty all-whitespace BSTR as greater than + * any numeric or boolean, regardless of binary lex order. */ + if(str_bstr && *str_bstr) { + const WCHAR *p; + for(p = str_bstr; *p && iswspace(*p); p++); + if(!*p) + return lvt == VT_BSTR ? VARCMP_GT : VARCMP_LT; + } + VariantInit(&num_str); if((V_VT(num) & VT_TYPEMASK) == VT_BOOL) { V_VT(&num_str) = VT_BSTR; diff --git a/dlls/vbscript/tests/lang.vbs b/dlls/vbscript/tests/lang.vbs index c80f45c1bdd..c7f03e96180 100644 --- a/dlls/vbscript/tests/lang.vbs +++ b/dlls/vbscript/tests/lang.vbs @@ -322,15 +322,15 @@ Dim ws_tab : ws_tab = Chr(9) Dim ws_lf : ws_lf = Chr(10) Dim ws_cr : ws_cr = Chr(13) Dim ws_nbsp : ws_nbsp = Chr(160) -Call todo_wine_ok(not (Len("ab") > ws_space), "Len(""ab"") > Space(3) should be false") -Call todo_wine_ok((Len("ab") < ws_space), "Len(""ab"") < Space(3) should be true") -Call ok(not (Len("ab") = ws_space), "Len(""ab"") = Space(3) should be false") -Call todo_wine_ok(not (Len("ab") > ws_tab), "Len(""ab"") > Chr(9) should be false") -Call todo_wine_ok((Len("ab") < ws_tab), "Len(""ab"") < Chr(9) should be true") -Call todo_wine_ok(not (Len("ab") > ws_lf), "Len(""ab"") > Chr(10) should be false") -Call todo_wine_ok((Len("ab") < ws_lf), "Len(""ab"") < Chr(10) should be true") -Call todo_wine_ok(not (Len("ab") > ws_cr), "Len(""ab"") > Chr(13) should be false") -Call todo_wine_ok((Len("ab") < ws_cr), "Len(""ab"") < Chr(13) should be true") +Call ok(not (Len("ab") > ws_space), "Len(""ab"") > Space(3) should be false") +Call ok((Len("ab") < ws_space), "Len(""ab"") < Space(3) should be true") +Call ok(not (Len("ab") = ws_space), "Len(""ab"") = Space(3) should be false") +Call ok(not (Len("ab") > ws_tab), "Len(""ab"") > Chr(9) should be false") +Call ok((Len("ab") < ws_tab), "Len(""ab"") < Chr(9) should be true") +Call ok(not (Len("ab") > ws_lf), "Len(""ab"") > Chr(10) should be false") +Call ok((Len("ab") < ws_lf), "Len(""ab"") < Chr(10) should be true") +Call ok(not (Len("ab") > ws_cr), "Len(""ab"") > Chr(13) should be false") +Call ok((Len("ab") < ws_cr), "Len(""ab"") < Chr(13) should be true") Call ok(not (Len("ab") > ws_nbsp), "Len(""ab"") > Chr(160) should be false") Call ok((Len("ab") < ws_nbsp), "Len(""ab"") < Chr(160) should be true") @@ -346,7 +346,7 @@ End If guard_err = Err.number Err.Clear On Error Goto 0 -Call todo_wine_ok(guard_err = 0, "Len(""ab"") > Space(3) guard should not raise (got " & guard_err & ")") +Call ok(guard_err = 0, "Len(""ab"") > Space(3) guard should not raise (got " & guard_err & ")") ' --- VT_DATE from CDate is non-literal: string compare, no error. --- Dim cdt : cdt = CDate("2024-01-15") -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10818
participants (2)
-
Francis De Brabandere -
Francis De Brabandere (@francisdb)