While working in vbscript, I noticed abs on a `BSTR` value with a positive number would come back with an invalid value.
Given the following script:
``` Dim x x = "30000" Debug.Print "x" & "=" & abs(x) ```
Outputs:
``` Script.Print 'x=3.08221696253945E-314' ```
After debugging, `pVarIn` gets the R8 value but is never shallow copied into `pVarOut`.
In addition to a test case in `oleaut32`, I've included a test case in `vbscript`.
This fixes bug: https://bugs.winehq.org/show_bug.cgi?id=54489
-- v9: oleaut32: fix VarAbs function for BSTR with positive values
From: Jacek Caban jacek@codeweavers.com
--- dlls/oleaut32/tests/vartest.c | 2 ++ dlls/oleaut32/variant.c | 8 ++++++-- 2 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/dlls/oleaut32/tests/vartest.c b/dlls/oleaut32/tests/vartest.c index cdbb836b041..4e9c892e37e 100644 --- a/dlls/oleaut32/tests/vartest.c +++ b/dlls/oleaut32/tests/vartest.c @@ -3121,6 +3121,8 @@ static void test_VarAbs(void) VARABS(R4,-1,R4,1); VARABS(R8,1,R8,1); VARABS(R8,-1,R8,1); + VARABS(R4,1.40129846432481707e-45,R4,1.40129846432481707e-45); + VARABS(R8,4.94065645841246544e-324,R8,4.94065645841246544e-324); VARABS(DATE,1,DATE,1); VARABS(DATE,-1,DATE,1); V_VT(&v) = VT_CY; diff --git a/dlls/oleaut32/variant.c b/dlls/oleaut32/variant.c index 885082cc659..bbfc1b2d952 100644 --- a/dlls/oleaut32/variant.c +++ b/dlls/oleaut32/variant.c @@ -4369,7 +4369,9 @@ HRESULT WINAPI VarAbs(LPVARIANT pVarIn, LPVARIANT pVarOut) case VT_INT: ABS_CASE(I4,I4_MIN); ABS_CASE(I8,I8_MIN); - ABS_CASE(R4,R4_MIN); + case VT_R4: + if (V_R4(pVarOut) < 0.0) V_R4(pVarOut) = -V_R4(pVarOut); + break; case VT_BSTR: hRet = VarR8FromStr(V_BSTR(pVarIn), LOCALE_USER_DEFAULT, 0, &V_R8(&varIn)); if (FAILED(hRet)) @@ -4378,7 +4380,9 @@ HRESULT WINAPI VarAbs(LPVARIANT pVarIn, LPVARIANT pVarOut) pVarIn = &varIn; /* Fall through ... */ case VT_DATE: - ABS_CASE(R8,R8_MIN); + case VT_R8: + if (V_R8(pVarOut) < 0.0) V_R8(pVarOut) = -V_R8(pVarOut); + break; case VT_CY: hRet = VarCyAbs(V_CY(pVarIn), & V_CY(pVarOut)); break;
From: Jason Millard jsm174@gmail.com
--- dlls/oleaut32/tests/vartest.c | 8 ++++++++ dlls/oleaut32/variant.c | 4 +--- dlls/vbscript/tests/api.vbs | 1 + 3 files changed, 10 insertions(+), 3 deletions(-)
diff --git a/dlls/oleaut32/tests/vartest.c b/dlls/oleaut32/tests/vartest.c index 4e9c892e37e..d31df67d084 100644 --- a/dlls/oleaut32/tests/vartest.c +++ b/dlls/oleaut32/tests/vartest.c @@ -3145,6 +3145,14 @@ static void test_VarAbs(void) hres = pVarAbs(&v,&vDst); ok(hres == S_OK && V_VT(&vDst) == VT_R8 && V_R8(&vDst) == 1.1, "VarAbs: expected 0x0,%d,%g, got 0x%lX,%d,%g\n", VT_R8, 1.1, hres, V_VT(&vDst), V_R8(&vDst)); + + V_VT(&v) = VT_BSTR; + V_BSTR(&v) = SysAllocString(L"30000"); + memset(&vDst,0,sizeof(vDst)); + hres = pVarAbs(&v,&vDst); + ok(hres == S_OK && V_VT(&vDst) == VT_R8 && V_R8(&vDst) == 30000.0, + "VarAbs: expected 0x0,%d,%g, got 0x%lX,%d,%g\n", VT_R8, 30000.0, hres, V_VT(&vDst), V_R8(&vDst)); + SysFreeString(V_BSTR(&v)); }
static HRESULT (WINAPI *pVarNot)(LPVARIANT,LPVARIANT); diff --git a/dlls/oleaut32/variant.c b/dlls/oleaut32/variant.c index bbfc1b2d952..8c2aa3b729d 100644 --- a/dlls/oleaut32/variant.c +++ b/dlls/oleaut32/variant.c @@ -4329,7 +4329,6 @@ VarOr_Exit: */ HRESULT WINAPI VarAbs(LPVARIANT pVarIn, LPVARIANT pVarOut) { - VARIANT varIn; HRESULT hRet = S_OK; VARIANT temp;
@@ -4373,11 +4372,10 @@ HRESULT WINAPI VarAbs(LPVARIANT pVarIn, LPVARIANT pVarOut) if (V_R4(pVarOut) < 0.0) V_R4(pVarOut) = -V_R4(pVarOut); break; case VT_BSTR: - hRet = VarR8FromStr(V_BSTR(pVarIn), LOCALE_USER_DEFAULT, 0, &V_R8(&varIn)); + hRet = VarR8FromStr(V_BSTR(pVarIn), LOCALE_USER_DEFAULT, 0, &V_R8(pVarOut)); if (FAILED(hRet)) break; V_VT(pVarOut) = VT_R8; - pVarIn = &varIn; /* Fall through ... */ case VT_DATE: case VT_R8: diff --git a/dlls/vbscript/tests/api.vbs b/dlls/vbscript/tests/api.vbs index c0ac6c56cf5..842cce33f83 100644 --- a/dlls/vbscript/tests/api.vbs +++ b/dlls/vbscript/tests/api.vbs @@ -1672,6 +1672,7 @@ Call ok(Abs(True) = 1, "Abs(True) = " & Abs(True)) Call ok(getVT(Abs(True)) = "VT_I2", "getVT(Abs(True)) = " & getVT(Abs(True))) Call ok(Abs(CByte(1)) = 1, "Abs(CByte(1)) = " & Abs(CByte(1))) Call ok(getVT(Abs(CByte(1))) = "VT_UI1", "getVT(Abs(CByte(1))) = " & getVT(Abs(CByte(1)))) +Call ok(Abs("30000") = 30000, "Abs(""30000"") = " & Abs("30000"))
Sub testAbsError(strings, error_num1, error_num2) on error resume next
This merge request was approved by Jacek Caban.