[PATCH v12 0/2] MR8635: oleaut32: Convert VT_BSTR numeric strings to VT_I4 in VarAnd
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=56280 -- v12: oleaut32: Convert VT_BSTR numeric strings to VT_I4 in VarAnd. oleaut32/tests: Add more test cases for VarAnd https://gitlab.winehq.org/wine/wine/-/merge_requests/8635
From: Maotong Zhang <zmtong1988@gmail.com> --- dlls/oleaut32/tests/vartest.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/dlls/oleaut32/tests/vartest.c b/dlls/oleaut32/tests/vartest.c index e5bbecbdd3f..158857e5863 100644 --- a/dlls/oleaut32/tests/vartest.c +++ b/dlls/oleaut32/tests/vartest.c @@ -6814,7 +6814,7 @@ static void test_VarAnd(void) static const WCHAR szFalse[] = { '#','F','A','L','S','E','#','\0' }; static const WCHAR szTrue[] = { '#','T','R','U','E','#','\0' }; VARIANT left, right, exp, result; - BSTR false_str, true_str; + BSTR false_str, true_str, bstrmaxi4, bstrmini4; VARTYPE i; HRESULT hres; @@ -6822,6 +6822,9 @@ static void test_VarAnd(void) true_str = SysAllocString(szTrue); false_str = SysAllocString(szFalse); + bstrmaxi4 = SysAllocString(L"2147483647"); + bstrmini4 = SysAllocString(L"-2147483648"); + /* Test all possible flag/vt combinations & the resulting vt type */ for (i = 0; i < ARRAY_SIZE(ExtraFlags); i++) @@ -7154,6 +7157,8 @@ static void test_VarAnd(void) VARAND(UI1,255,BSTR,false_str,I2,0); VARAND(UI1,0,BSTR,true_str,I2,0); VARAND(UI1,255,BSTR,true_str,I2,255); + VARAND(UI1, 1, BSTR, bstrmaxi4, I4, 1); + VARAND(UI1, 1, BSTR, bstrmini4, I4, 0); VARANDCY(UI1,255,10000,I4,1); VARANDCY(UI1,255,0,I4,0); VARANDCY(UI1,0,0,I4,0); @@ -7197,6 +7202,8 @@ static void test_VarAnd(void) VARAND(I2,-1,BSTR,false_str,I2,0); VARAND(I2,0,BSTR,true_str,I2,0); VARAND(I2,-1,BSTR,true_str,I2,-1); + VARAND(I2,1,BSTR,bstrmaxi4,I4,1); + VARAND(I2,1,BSTR,bstrmini4,I4,0); VARANDCY(I2,-1,10000,I4,1); VARANDCY(I2,-1,0,I4,0); VARANDCY(I2,0,0,I4,0); @@ -7463,6 +7470,8 @@ static void test_VarAnd(void) SysFreeString(true_str); SysFreeString(false_str); + SysFreeString(bstrmaxi4); + SysFreeString(bstrmini4); } static void test_cmp( int line, LCID lcid, UINT flags, VARIANT *left, VARIANT *right, HRESULT result ) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/8635
From: Maotong Zhang <zmtong1988@gmail.com> --- dlls/oleaut32/variant.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/dlls/oleaut32/variant.c b/dlls/oleaut32/variant.c index 8b5e41ec66d..2c94231227b 100644 --- a/dlls/oleaut32/variant.c +++ b/dlls/oleaut32/variant.c @@ -3132,7 +3132,13 @@ HRESULT WINAPI VarAnd(LPVARIANT left, LPVARIANT right, LPVARIANT result) hres = VariantChangeType(&varLeft,&varLeft, VARIANT_LOCALBOOL, VT_BOOL); if (SUCCEEDED(hres) && V_VT(&varLeft) != resvt) + { + if (V_VT(&varLeft) == VT_BSTR) + { + if (d >= I4_MIN && d <= I4_MAX) resvt = VT_I4; + } hres = VariantChangeType(&varLeft,&varLeft,0,resvt); + } if (FAILED(hres)) goto VarAnd_Exit; } @@ -3148,10 +3154,28 @@ HRESULT WINAPI VarAnd(LPVARIANT left, LPVARIANT right, LPVARIANT result) hres = VariantChangeType(&varRight, &varRight, VARIANT_LOCALBOOL, VT_BOOL); if (SUCCEEDED(hres) && V_VT(&varRight) != resvt) + { + if (V_VT(&varRight) == VT_BSTR) + { + if (d >= I4_MIN && d <= I4_MAX) resvt = VT_I4; + } hres = VariantChangeType(&varRight, &varRight, 0, resvt); + } if (FAILED(hres)) goto VarAnd_Exit; } + if (V_VT(&varLeft) != resvt) + { + hres = VariantChangeType(&varLeft, &varLeft, 0, resvt); + if (FAILED(hres)) goto VarAnd_Exit; + } + + if (V_VT(&varRight) != resvt) + { + hres = VariantChangeType(&varRight, &varRight, 0, resvt); + if (FAILED(hres)) goto VarAnd_Exit; + } + V_VT(result) = resvt; switch(resvt) { -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/8635
The probe table you have looks good for the I4-fit cases. Native + Wine-with-this-patch diverge on three classes I'd suggest covering: 1. `(BSTR_numeric_over_I4, BSTR_anything_numeric)` — native errors with `DISP_E_OVERFLOW`, current patch silently returns wrong results because the BOOL fallback fires when the BSTR is too big to widen and the other side later bumps `resvt` to `I4`. E.g. `"9999999998" AND "3"` returns 3 here, native overflows. 2. Fractional BSTRs use truncation toward zero on native, not banker's rounding: `"1.99" AND 1 = 1` and `"-1.99" AND 1 = 1` natively. Could compute the I4 directly from the parsed `d` (e.g. `(LONG)d` after the `VarR8FromStr` succeeds, when `d` fits I4) instead of round-tripping through `VariantChangeType(BSTR -> I4)`. 3. Hex BSTRs with the sign bit set: native treats `"&HFFFFFFFF"` as signed `I4(-1)` and computes `-1 & 1 = 1`. Currently `VarR8FromStr` returns the unsigned value `4294967295`, the fits-in-I4 check fails, and the conversion overflows. Maybe special-case `"&H..."` via `VarI4FromStr`. Test cases that would pin all three: ```c BSTR bstr9999999998 = SysAllocString(L"9999999998"); BSTR bstr3 = SysAllocString(L"3"); BSTR bstrfloat1p99 = SysAllocString(L"1.99"); BSTR bstrfloatm1p99 = SysAllocString(L"-1.99"); BSTR bstrhexFFFFFFFF = SysAllocString(L"&HFFFFFFFF"); /* (BSTR, BSTR) numeric-but-outside-I4: native overflows */ hres = pVarAnd_with(BSTR, bstr9999999998, BSTR, bstr3, &result); ok(hres == DISP_E_OVERFLOW, "expected DISP_E_OVERFLOW, got %08lx\n", hres); /* float-BSTR: truncation toward zero (not banker's rounding) */ VARAND(BSTR, bstrfloat1p99, I2, 1, I4, 1); VARAND(BSTR, bstrfloatm1p99, I2, 1, I4, 1); /* hex with sign bit: signed I4 interpretation */ VARAND(BSTR, bstrhexFFFFFFFF, I2, 1, I4, 1); ``` -- https://gitlab.winehq.org/wine/wine/-/merge_requests/8635#note_139186
participants (3)
-
Francis De Brabandere (@francisdb) -
Maotong Zhang -
Maotong Zhang (@xiaotong)