Nikolay Sivov : oleaut32: Fix destination data release when copying FADF_RECORD arrays.
Alexandre Julliard
julliard at winehq.org
Tue Feb 18 14:11:02 CST 2014
Module: wine
Branch: master
Commit: f85644c6f9d8f350ce19954fcbe5bed9d88856a3
URL: http://source.winehq.org/git/wine.git/?a=commit;h=f85644c6f9d8f350ce19954fcbe5bed9d88856a3
Author: Nikolay Sivov <nsivov at codeweavers.com>
Date: Tue Feb 18 10:59:31 2014 +0400
oleaut32: Fix destination data release when copying FADF_RECORD arrays.
---
dlls/oleaut32/safearray.c | 102 ++++++++++++++++++++++-----------------
dlls/oleaut32/tests/safearray.c | 3 +-
2 files changed, 59 insertions(+), 46 deletions(-)
diff --git a/dlls/oleaut32/safearray.c b/dlls/oleaut32/safearray.c
index 71f8c69..436a2ca 100644
--- a/dlls/oleaut32/safearray.c
+++ b/dlls/oleaut32/safearray.c
@@ -306,7 +306,7 @@ static HRESULT SAFEARRAY_DestroyData(SAFEARRAY *psa, ULONG ulStartCell)
lpUnknown++;
}
}
- else if (psa->fFeatures & (FADF_RECORD))
+ else if (psa->fFeatures & FADF_RECORD)
{
IRecordInfo *lpRecInfo;
@@ -347,12 +347,15 @@ static HRESULT SAFEARRAY_DestroyData(SAFEARRAY *psa, ULONG ulStartCell)
return S_OK;
}
-/* Copy data items from one array to another */
+/* Copy data items from one array to another. Destination data is freed before copy. */
static HRESULT SAFEARRAY_CopyData(SAFEARRAY *psa, SAFEARRAY *dest)
{
+ HRESULT hr = S_OK;
+
if (!psa->pvData)
return S_OK;
- else if (!dest->pvData || psa->fFeatures & FADF_DATADELETED)
+
+ if (!dest->pvData || psa->fFeatures & FADF_DATADELETED)
return E_INVALIDARG;
else
{
@@ -362,70 +365,84 @@ static HRESULT SAFEARRAY_CopyData(SAFEARRAY *psa, SAFEARRAY *dest)
if (psa->fFeatures & FADF_VARIANT)
{
- VARIANT* lpVariant = psa->pvData;
- VARIANT* lpDest = dest->pvData;
+ VARIANT *src_var = psa->pvData;
+ VARIANT *dest_var = dest->pvData;
while(ulCellCount--)
{
HRESULT hRet;
- hRet = VariantCopy(lpDest, lpVariant);
- if (FAILED(hRet)) FIXME("VariantCopy failed with 0x%x\n", hRet);
- lpVariant++;
- lpDest++;
+ /* destination is cleared automatically */
+ hRet = VariantCopy(dest_var, src_var);
+ if (FAILED(hRet)) FIXME("VariantCopy failed with 0x%08x, element %u\n", hRet, ulCellCount);
+ src_var++;
+ dest_var++;
}
}
else if (psa->fFeatures & FADF_BSTR)
{
- BSTR* lpBstr = psa->pvData;
- BSTR* lpDest = dest->pvData;
+ BSTR *src_bstr = psa->pvData;
+ BSTR *dest_bstr = dest->pvData;
while(ulCellCount--)
{
- if (*lpBstr)
+ SysFreeString(*dest_bstr);
+ if (*src_bstr)
{
- *lpDest = SysAllocStringByteLen((char*)*lpBstr, SysStringByteLen(*lpBstr));
- if (!*lpDest)
+ *dest_bstr = SysAllocStringByteLen((char*)*src_bstr, SysStringByteLen(*src_bstr));
+ if (!*dest_bstr)
return E_OUTOFMEMORY;
}
else
- *lpDest = NULL;
- lpBstr++;
- lpDest++;
+ *dest_bstr = NULL;
+ src_bstr++;
+ dest_bstr++;
}
}
- else
+ else if (psa->fFeatures & FADF_RECORD)
{
- /* Copy the data over */
- memcpy(dest->pvData, psa->pvData, ulCellCount * psa->cbElements);
+ const SAFEARRAYBOUND* psab = psa->rgsabound;
+ BYTE *dest_data = dest->pvData;
+ BYTE *src_data = psa->pvData;
+ IRecordInfo *record;
- if (psa->fFeatures & (FADF_UNKNOWN|FADF_DISPATCH))
+ SafeArrayGetRecordInfo(psa, &record);
+ while (ulCellCount--)
{
- LPUNKNOWN *lpUnknown = dest->pvData;
-
- while(ulCellCount--)
- {
- if (*lpUnknown)
- IUnknown_AddRef(*lpUnknown);
- lpUnknown++;
- }
+ /* RecordCopy() clears destination record */
+ hr = IRecordInfo_RecordCopy(record, src_data, dest_data);
+ if (FAILED(hr)) break;
+ src_data += psab->cElements;
+ dest_data += psab->cElements;
}
- }
- if (psa->fFeatures & FADF_RECORD)
+ SafeArraySetRecordInfo(dest, record);
+ IRecordInfo_Release(record);
+ }
+ else if (psa->fFeatures & (FADF_UNKNOWN|FADF_DISPATCH))
{
- IRecordInfo* pRecInfo = NULL;
-
- SafeArrayGetRecordInfo(psa, &pRecInfo);
- SafeArraySetRecordInfo(dest, pRecInfo);
+ IUnknown **dest_unk = dest->pvData;
+ IUnknown **src_unk = psa->pvData;
- if (pRecInfo)
+ /* release old iface, addref new one */
+ while (ulCellCount--)
{
- /* Release because Get() adds a reference */
- IRecordInfo_Release(pRecInfo);
+ if (*dest_unk)
+ IUnknown_Release(*dest_unk);
+ *dest_unk = *src_unk;
+ if (*dest_unk)
+ IUnknown_AddRef(*dest_unk);
+ src_unk++;
+ dest_unk++;
}
}
- else if (psa->fFeatures & FADF_HAVEIID)
+ else
+ {
+ /* Copy the data over */
+ memcpy(dest->pvData, psa->pvData, ulCellCount * psa->cbElements);
+ }
+
+ if (psa->fFeatures & FADF_HAVEIID)
{
GUID guid;
SafeArrayGetIID(psa, &guid);
@@ -436,7 +453,8 @@ static HRESULT SAFEARRAY_CopyData(SAFEARRAY *psa, SAFEARRAY *dest)
SAFEARRAY_SetHiddenDWORD(dest, SAFEARRAY_GetHiddenDWORD(psa));
}
}
- return S_OK;
+
+ return hr;
}
/*************************************************************************
@@ -1281,7 +1299,6 @@ HRESULT WINAPI SafeArrayDestroyData(SAFEARRAY *psa)
*/
HRESULT WINAPI SafeArrayCopyData(SAFEARRAY *psaSource, SAFEARRAY *psaTarget)
{
- HRESULT hr;
int dim;
TRACE("(%p,%p)\n", psaSource, psaTarget);
@@ -1297,9 +1314,6 @@ HRESULT WINAPI SafeArrayCopyData(SAFEARRAY *psaSource, SAFEARRAY *psaTarget)
psaTarget->rgsabound[dim].cElements)
return E_INVALIDARG;
- hr = SAFEARRAY_DestroyData(psaTarget, 0);
- if (FAILED(hr)) return hr;
-
return SAFEARRAY_CopyData(psaSource, psaTarget);
}
diff --git a/dlls/oleaut32/tests/safearray.c b/dlls/oleaut32/tests/safearray.c
index 2ab9ad3..915d0ca 100644
--- a/dlls/oleaut32/tests/safearray.c
+++ b/dlls/oleaut32/tests/safearray.c
@@ -1636,10 +1636,9 @@ static void test_SafeArrayCreateEx(void)
/* array copy code doesn't explicitely clear a record */
hres = SafeArrayCopyData(sa, sacopy);
ok(hres == S_OK, "got 0x%08x\n", hres);
-todo_wine {
ok(iRec->recordcopy == sab[0].cElements, "got %d\n", iRec->recordcopy);
ok(iRec->clearCalled == 0, "got %d\n", iRec->clearCalled);
-}
+
hres = SafeArrayDestroy(sacopy);
ok(hres == S_OK, "got 0x%08x\n", hres);
More information about the wine-cvs
mailing list