mirror of
https://gitlab.winehq.org/wine/wine-staging.git
synced 2024-09-13 09:17:20 -07:00
Added patch to implement proper refcounting and locking for HGLOBAL based IStream.
This commit is contained in:
parent
8e6776a691
commit
74ac55e7d9
@ -0,0 +1,279 @@
|
||||
From 267315dd040ccfa527f8ba48038a268236ca1d29 Mon Sep 17 00:00:00 2001
|
||||
From: Dmitry Timoshkov <dmitry@baikal.ru>
|
||||
Date: Tue, 2 Feb 2016 12:49:16 +0800
|
||||
Subject: ole32/tests: Add a bunch of tests for HGLOBAL based IStream::Clone.
|
||||
|
||||
---
|
||||
dlls/ole32/tests/hglobalstream.c | 244 +++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 244 insertions(+)
|
||||
|
||||
diff --git a/dlls/ole32/tests/hglobalstream.c b/dlls/ole32/tests/hglobalstream.c
|
||||
index e20d81b..0dc3c52 100644
|
||||
--- a/dlls/ole32/tests/hglobalstream.c
|
||||
+++ b/dlls/ole32/tests/hglobalstream.c
|
||||
@@ -2,6 +2,7 @@
|
||||
* Stream on HGLOBAL Tests
|
||||
*
|
||||
* Copyright 2006 Robert Shearman (for CodeWeavers)
|
||||
+ * Copyright 2016 Dmitry Timoshkov
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -508,11 +509,254 @@ static void test_freed_hglobal(void)
|
||||
IStream_Release(pStream);
|
||||
}
|
||||
|
||||
+static void stream_info(IStream *stream, HGLOBAL *hmem, int *size, int *pos)
|
||||
+{
|
||||
+ HRESULT hr;
|
||||
+ STATSTG stat;
|
||||
+ LARGE_INTEGER offset;
|
||||
+ ULARGE_INTEGER newpos;
|
||||
+
|
||||
+ *hmem = 0;
|
||||
+ *size = *pos = -1;
|
||||
+
|
||||
+ hr = GetHGlobalFromStream(stream, hmem);
|
||||
+ ok(hr == S_OK, "unexpected %#x\n", hr);
|
||||
+
|
||||
+ memset(&stat, 0x55, sizeof(stat));
|
||||
+ hr = IStream_Stat(stream, &stat, STATFLAG_DEFAULT);
|
||||
+ ok(hr == S_OK, "unexpected %#x\n", hr);
|
||||
+ ok(stat.type == STGTY_STREAM, "unexpected %#x\n", stat.type);
|
||||
+ ok(!stat.pwcsName, "unexpected %p\n", stat.pwcsName);
|
||||
+ ok(IsEqualIID(&stat.clsid, &GUID_NULL), "unexpected %s\n", wine_dbgstr_guid(&stat.clsid));
|
||||
+ ok(!stat.cbSize.HighPart, "unexpected %#x\n", stat.cbSize.HighPart);
|
||||
+ *size = stat.cbSize.LowPart;
|
||||
+
|
||||
+ offset.QuadPart = 0;
|
||||
+ hr = IStream_Seek(stream, offset, STREAM_SEEK_CUR, &newpos);
|
||||
+ ok(hr == S_OK, "unexpected %#x\n", hr);
|
||||
+ ok(!newpos.HighPart, "unexpected %#x\n", newpos.HighPart);
|
||||
+ *pos = newpos.LowPart;
|
||||
+}
|
||||
+
|
||||
+static void test_IStream_Clone(void)
|
||||
+{
|
||||
+ static const char hello[] = "Hello World!";
|
||||
+ char buf[32];
|
||||
+ HRESULT hr;
|
||||
+ IStream *stream, *clone;
|
||||
+ HGLOBAL orig_hmem, hmem, hmem_clone;
|
||||
+ ULARGE_INTEGER newsize;
|
||||
+ LARGE_INTEGER offset;
|
||||
+ int size, pos, ret;
|
||||
+
|
||||
+ /* test simple case for Clone */
|
||||
+ orig_hmem = GlobalAlloc(GMEM_MOVEABLE, 0);
|
||||
+ ok(orig_hmem != 0, "unexpected %p\n", orig_hmem);
|
||||
+ hr = CreateStreamOnHGlobal(orig_hmem, TRUE, &stream);
|
||||
+ ok(hr == S_OK, "unexpected %#x\n", hr);
|
||||
+
|
||||
+ stream_info(stream, &hmem, &size, &pos);
|
||||
+ ok(hmem == orig_hmem, "handles should match\n");
|
||||
+ ok(size == 0, "unexpected %d\n", size);
|
||||
+ ok(pos == 0, "unexpected %d\n", pos);
|
||||
+
|
||||
+ hr = IStream_Clone(stream, &clone);
|
||||
+ ok(hr == S_OK, "unexpected %#x\n", hr);
|
||||
+
|
||||
+ hr = IStream_Write(stream, hello, sizeof(hello), NULL);
|
||||
+ ok(hr == S_OK, "unexpected %#x\n", hr);
|
||||
+
|
||||
+ stream_info(stream, &hmem, &size, &pos);
|
||||
+ ok(hmem != 0, "unexpected %p\n", hmem);
|
||||
+ ok(size == 13, "unexpected %d\n", size);
|
||||
+ ok(pos == 13, "unexpected %d\n", pos);
|
||||
+
|
||||
+ stream_info(clone, &hmem_clone, &size, &pos);
|
||||
+ ok(hmem_clone == hmem, "handles should match\n");
|
||||
+todo_wine
|
||||
+ ok(size == 13, "unexpected %d\n", size);
|
||||
+ ok(pos == 0, "unexpected %d\n", pos);
|
||||
+
|
||||
+ buf[0] = 0;
|
||||
+ hr = IStream_Read(clone, buf, sizeof(buf), NULL);
|
||||
+ ok(hr == S_OK, "unexpected %#x\n", hr);
|
||||
+todo_wine
|
||||
+ ok(!strcmp(buf, hello), "wrong stream contents\n");
|
||||
+
|
||||
+ newsize.QuadPart = 0x8000;
|
||||
+ hr = IStream_SetSize(stream, newsize);
|
||||
+ ok(hr == S_OK, "unexpected %#x\n", hr);
|
||||
+
|
||||
+ stream_info(stream, &hmem, &size, &pos);
|
||||
+ ok(hmem != 0, "unexpected %p\n", hmem);
|
||||
+ ok(hmem == orig_hmem, "unexpected %p\n", hmem);
|
||||
+ ok(size == 0x8000, "unexpected %#x\n", size);
|
||||
+ ok(pos == 13, "unexpected %d\n", pos);
|
||||
+
|
||||
+ stream_info(clone, &hmem_clone, &size, &pos);
|
||||
+ ok(hmem_clone == hmem, "handles should match\n");
|
||||
+todo_wine
|
||||
+ ok(size == 0x8000, "unexpected %#x\n", size);
|
||||
+todo_wine
|
||||
+ ok(pos == 13, "unexpected %d\n", pos);
|
||||
+
|
||||
+ IStream_Release(clone);
|
||||
+ IStream_Release(stream);
|
||||
+
|
||||
+ /* exploit GMEM_FIXED forced move for the same base streams */
|
||||
+ orig_hmem = GlobalAlloc(GMEM_FIXED, 1);
|
||||
+ ok(orig_hmem != 0, "unexpected %p\n", orig_hmem);
|
||||
+ hr = CreateStreamOnHGlobal(orig_hmem, TRUE, &stream);
|
||||
+ ok(hr == S_OK, "unexpected %#x\n", hr);
|
||||
+
|
||||
+ hr = IStream_Clone(stream, &clone);
|
||||
+ ok(hr == S_OK, "unexpected %#x\n", hr);
|
||||
+
|
||||
+ stream_info(stream, &hmem, &size, &pos);
|
||||
+ ok(hmem != 0, "unexpected %p\n", hmem);
|
||||
+ ok(size == 1, "unexpected %d\n", size);
|
||||
+ ok(pos == 0, "unexpected %d\n", pos);
|
||||
+
|
||||
+ stream_info(clone, &hmem_clone, &size, &pos);
|
||||
+ ok(hmem_clone == hmem, "handles should match\n");
|
||||
+ ok(size == 1, "unexpected %d\n", size);
|
||||
+ ok(pos == 0, "unexpected %d\n", pos);
|
||||
+
|
||||
+ newsize.QuadPart = 0x8000;
|
||||
+ hr = IStream_SetSize(stream, newsize);
|
||||
+todo_wine
|
||||
+ ok(hr == S_OK, "unexpected %#x\n", hr);
|
||||
+
|
||||
+ stream_info(stream, &hmem, &size, &pos);
|
||||
+ ok(hmem != 0, "unexpected %p\n", hmem);
|
||||
+todo_wine
|
||||
+ ok(hmem != orig_hmem, "unexpected %p\n", hmem);
|
||||
+todo_wine
|
||||
+ ok(size == 0x8000, "unexpected %#x\n", size);
|
||||
+ ok(pos == 0, "unexpected %d\n", pos);
|
||||
+
|
||||
+ stream_info(clone, &hmem_clone, &size, &pos);
|
||||
+ ok(hmem_clone == hmem, "handles should match\n");
|
||||
+todo_wine
|
||||
+ ok(size == 0x8000, "unexpected %#x\n", size);
|
||||
+ ok(pos == 0, "unexpected %d\n", pos);
|
||||
+
|
||||
+ IStream_Release(stream);
|
||||
+ IStream_Release(clone);
|
||||
+
|
||||
+ /* exploit GMEM_FIXED forced move for different base streams */
|
||||
+ orig_hmem = GlobalAlloc(GMEM_FIXED, 1);
|
||||
+ ok(orig_hmem != 0, "unexpected %p\n", orig_hmem);
|
||||
+ hr = CreateStreamOnHGlobal(orig_hmem, TRUE, &stream);
|
||||
+ ok(hr == S_OK, "unexpected %#x\n", hr);
|
||||
+
|
||||
+ hr = CreateStreamOnHGlobal(orig_hmem, TRUE, &clone);
|
||||
+ ok(hr == S_OK, "unexpected %#x\n", hr);
|
||||
+
|
||||
+ stream_info(stream, &hmem, &size, &pos);
|
||||
+ ok(hmem != 0, "unexpected %p\n", hmem);
|
||||
+ ok(size == 1, "unexpected %d\n", size);
|
||||
+ ok(pos == 0, "unexpected %d\n", pos);
|
||||
+
|
||||
+ stream_info(clone, &hmem_clone, &size, &pos);
|
||||
+ ok(hmem_clone == hmem, "handles should match\n");
|
||||
+ ok(size == 1, "unexpected %d\n", size);
|
||||
+ ok(pos == 0, "unexpected %d\n", pos);
|
||||
+
|
||||
+ newsize.QuadPart = 0x8000;
|
||||
+ hr = IStream_SetSize(stream, newsize);
|
||||
+todo_wine
|
||||
+ ok(hr == S_OK, "unexpected %#x\n", hr);
|
||||
+
|
||||
+ stream_info(stream, &hmem, &size, &pos);
|
||||
+ ok(hmem != 0, "unexpected %p\n", hmem);
|
||||
+todo_wine
|
||||
+ ok(hmem != orig_hmem, "unexpected %p\n", hmem);
|
||||
+todo_wine
|
||||
+ ok(size == 0x8000, "unexpected %#x\n", size);
|
||||
+ ok(pos == 0, "unexpected %d\n", pos);
|
||||
+
|
||||
+ stream_info(clone, &hmem_clone, &size, &pos);
|
||||
+todo_wine
|
||||
+ ok(hmem_clone != hmem, "handles should not match\n");
|
||||
+ ok(size == 1, "unexpected %#x\n", size);
|
||||
+ ok(pos == 0, "unexpected %d\n", pos);
|
||||
+
|
||||
+ IStream_Release(stream);
|
||||
+ /* releasing clone leads to test termination under windows
|
||||
+ IStream_Release(clone);
|
||||
+ */
|
||||
+
|
||||
+ /* test Release for a being cloned stream */
|
||||
+ hr = CreateStreamOnHGlobal(0, TRUE, &stream);
|
||||
+ ok(hr == S_OK, "unexpected %#x\n", hr);
|
||||
+
|
||||
+ hr = IStream_Clone(stream, &clone);
|
||||
+ ok(hr == S_OK, "unexpected %#x\n", hr);
|
||||
+
|
||||
+ stream_info(stream, &hmem, &size, &pos);
|
||||
+ ok(hmem != 0, "unexpected %p\n", hmem);
|
||||
+ ok(size == 0, "unexpected %d\n", size);
|
||||
+ ok(pos == 0, "unexpected %d\n", pos);
|
||||
+
|
||||
+ stream_info(clone, &hmem_clone, &size, &pos);
|
||||
+ ok(hmem_clone == hmem, "handles should match\n");
|
||||
+ ok(size == 0, "unexpected %#x\n", size);
|
||||
+ ok(pos == 0, "unexpected %d\n", pos);
|
||||
+
|
||||
+ ret = IStream_Release(stream);
|
||||
+ ok(ret == 0, "unexpected %d\n", ret);
|
||||
+
|
||||
+ newsize.QuadPart = 0x8000;
|
||||
+ hr = IStream_SetSize(clone, newsize);
|
||||
+todo_wine
|
||||
+ ok(hr == S_OK, "unexpected %#x\n", hr);
|
||||
+
|
||||
+ stream_info(clone, &hmem_clone, &size, &pos);
|
||||
+ ok(hmem_clone == hmem, "handles should match\n");
|
||||
+todo_wine
|
||||
+ ok(size == 0x8000, "unexpected %#x\n", size);
|
||||
+ ok(pos == 0, "unexpected %d\n", pos);
|
||||
+
|
||||
+ hr = IStream_Write(clone, hello, sizeof(hello), NULL);
|
||||
+todo_wine
|
||||
+ ok(hr == S_OK, "unexpected %#x\n", hr);
|
||||
+
|
||||
+ stream_info(clone, &hmem_clone, &size, &pos);
|
||||
+ ok(hmem_clone == hmem, "handles should match\n");
|
||||
+todo_wine
|
||||
+ ok(size == 0x8000, "unexpected %#x\n", size);
|
||||
+todo_wine
|
||||
+ ok(pos == 13, "unexpected %d\n", pos);
|
||||
+
|
||||
+ offset.QuadPart = 0;
|
||||
+ hr = IStream_Seek(clone, offset, STREAM_SEEK_SET, NULL);
|
||||
+ ok(hr == S_OK, "unexpected %#x\n", hr);
|
||||
+
|
||||
+ buf[0] = 0;
|
||||
+ hr = IStream_Read(clone, buf, sizeof(buf), NULL);
|
||||
+ ok(hr == S_OK, "unexpected %#x\n", hr);
|
||||
+todo_wine
|
||||
+ ok(!strcmp(buf, hello), "wrong stream contents\n");
|
||||
+
|
||||
+ stream_info(clone, &hmem_clone, &size, &pos);
|
||||
+ ok(hmem_clone == hmem, "handles should match\n");
|
||||
+todo_wine
|
||||
+ ok(size == 0x8000, "unexpected %#x\n", size);
|
||||
+todo_wine
|
||||
+ ok(pos == 32, "unexpected %d\n", pos);
|
||||
+
|
||||
+ ret = IStream_Release(clone);
|
||||
+ ok(ret == 0, "unexpected %d\n", ret);
|
||||
+}
|
||||
+
|
||||
START_TEST(hglobalstream)
|
||||
{
|
||||
HRESULT hr;
|
||||
IStream *pStream;
|
||||
|
||||
+ test_IStream_Clone();
|
||||
+
|
||||
hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
|
||||
ok_ole_success(hr, "CreateStreamOnHGlobal");
|
||||
|
||||
--
|
||||
2.7.0
|
||||
|
@ -0,0 +1,47 @@
|
||||
From a26bfabac3940176f412896241ffab5c7f92baaa Mon Sep 17 00:00:00 2001
|
||||
From: Dmitry Timoshkov <dmitry@baikal.ru>
|
||||
Date: Tue, 2 Feb 2016 12:53:47 +0800
|
||||
Subject: ole32: Add a check for hglobal pointer to GetHGlobalFromStream.
|
||||
|
||||
---
|
||||
dlls/ole32/hglobalstream.c | 4 ++--
|
||||
dlls/ole32/tests/hglobalstream.c | 6 ++++++
|
||||
2 files changed, 8 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/dlls/ole32/hglobalstream.c b/dlls/ole32/hglobalstream.c
|
||||
index 655e380..b86de56 100644
|
||||
--- a/dlls/ole32/hglobalstream.c
|
||||
+++ b/dlls/ole32/hglobalstream.c
|
||||
@@ -621,10 +621,10 @@ HRESULT WINAPI GetHGlobalFromStream(IStream* pstm, HGLOBAL* phglobal)
|
||||
{
|
||||
HGLOBALStreamImpl* pStream;
|
||||
|
||||
- if (pstm == NULL)
|
||||
+ if (!pstm || !phglobal)
|
||||
return E_INVALIDARG;
|
||||
|
||||
- pStream = (HGLOBALStreamImpl*) pstm;
|
||||
+ pStream = impl_from_IStream(pstm);
|
||||
|
||||
/*
|
||||
* Verify that the stream object was created with CreateStreamOnHGlobal.
|
||||
diff --git a/dlls/ole32/tests/hglobalstream.c b/dlls/ole32/tests/hglobalstream.c
|
||||
index 0dc3c52..0453e54 100644
|
||||
--- a/dlls/ole32/tests/hglobalstream.c
|
||||
+++ b/dlls/ole32/tests/hglobalstream.c
|
||||
@@ -555,6 +555,12 @@ static void test_IStream_Clone(void)
|
||||
hr = CreateStreamOnHGlobal(orig_hmem, TRUE, &stream);
|
||||
ok(hr == S_OK, "unexpected %#x\n", hr);
|
||||
|
||||
+ hr = GetHGlobalFromStream(stream, NULL);
|
||||
+ ok(hr == E_INVALIDARG, "unexpected %#x\n", hr);
|
||||
+
|
||||
+ hr = GetHGlobalFromStream(NULL, &hmem);
|
||||
+ ok(hr == E_INVALIDARG, "unexpected %#x\n", hr);
|
||||
+
|
||||
stream_info(stream, &hmem, &size, &pos);
|
||||
ok(hmem == orig_hmem, "handles should match\n");
|
||||
ok(size == 0, "unexpected %d\n", size);
|
||||
--
|
||||
2.7.0
|
||||
|
@ -0,0 +1,422 @@
|
||||
From 3c9954c3838d7504fad0213ade7363747e7a6805 Mon Sep 17 00:00:00 2001
|
||||
From: Dmitry Timoshkov <dmitry@baikal.ru>
|
||||
Date: Tue, 2 Feb 2016 13:03:58 +0800
|
||||
Subject: ole32: Add a wrapper for memory block managed by HGLOBAL based
|
||||
IStream.
|
||||
|
||||
Based on a suggestion of Sebastian Lackner <sebastian@fds-team.de>.
|
||||
---
|
||||
dlls/ole32/hglobalstream.c | 202 +++++++++++++++++++++++++++------------
|
||||
dlls/ole32/tests/hglobalstream.c | 12 ---
|
||||
2 files changed, 140 insertions(+), 74 deletions(-)
|
||||
|
||||
diff --git a/dlls/ole32/hglobalstream.c b/dlls/ole32/hglobalstream.c
|
||||
index b86de56..5eb6320 100644
|
||||
--- a/dlls/ole32/hglobalstream.c
|
||||
+++ b/dlls/ole32/hglobalstream.c
|
||||
@@ -5,6 +5,7 @@
|
||||
* for streams contained supported by an HGLOBAL pointer.
|
||||
*
|
||||
* Copyright 1999 Francis Beaudet
|
||||
+ * Copyright 2016 Dmitry Timoshkov
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -42,7 +43,96 @@
|
||||
|
||||
#include "wine/debug.h"
|
||||
|
||||
-WINE_DEFAULT_DEBUG_CHANNEL(storage);
|
||||
+WINE_DEFAULT_DEBUG_CHANNEL(hglobalstream);
|
||||
+
|
||||
+struct handle_wrapper
|
||||
+{
|
||||
+ LONG ref;
|
||||
+ HGLOBAL hglobal;
|
||||
+ ULONG size;
|
||||
+ BOOL delete_on_release;
|
||||
+ CRITICAL_SECTION lock;
|
||||
+};
|
||||
+
|
||||
+static void handle_addref(struct handle_wrapper *handle)
|
||||
+{
|
||||
+ InterlockedIncrement(&handle->ref);
|
||||
+}
|
||||
+
|
||||
+static void handle_release(struct handle_wrapper *handle)
|
||||
+{
|
||||
+ ULONG ref = InterlockedDecrement(&handle->ref);
|
||||
+
|
||||
+ if (!ref)
|
||||
+ {
|
||||
+ if (handle->delete_on_release)
|
||||
+ {
|
||||
+ GlobalFree(handle->hglobal);
|
||||
+ handle->hglobal = NULL;
|
||||
+ }
|
||||
+
|
||||
+ DeleteCriticalSection(&handle->lock);
|
||||
+ HeapFree(GetProcessHeap(), 0, handle);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void *handle_lock(struct handle_wrapper *handle)
|
||||
+{
|
||||
+ return GlobalLock(handle->hglobal);
|
||||
+}
|
||||
+
|
||||
+static void handle_unlock(struct handle_wrapper *handle)
|
||||
+{
|
||||
+ GlobalUnlock(handle->hglobal);
|
||||
+}
|
||||
+
|
||||
+static HGLOBAL handle_gethglobal(struct handle_wrapper *handle)
|
||||
+{
|
||||
+ return handle->hglobal;
|
||||
+}
|
||||
+
|
||||
+static HRESULT handle_setsize(struct handle_wrapper *handle, ULONG size)
|
||||
+{
|
||||
+ HRESULT hr = S_OK;
|
||||
+
|
||||
+ EnterCriticalSection(&handle->lock);
|
||||
+
|
||||
+ if (handle->size != size)
|
||||
+ {
|
||||
+ HGLOBAL hglobal = GlobalReAlloc(handle->hglobal, size, 0);
|
||||
+ if (hglobal)
|
||||
+ {
|
||||
+ handle->hglobal = hglobal;
|
||||
+ handle->size = size;
|
||||
+ }
|
||||
+ else
|
||||
+ hr = E_OUTOFMEMORY;
|
||||
+ }
|
||||
+
|
||||
+ LeaveCriticalSection(&handle->lock);
|
||||
+ return hr;
|
||||
+}
|
||||
+
|
||||
+static ULONG handle_getsize(struct handle_wrapper *handle)
|
||||
+{
|
||||
+ return handle->size;
|
||||
+}
|
||||
+
|
||||
+static struct handle_wrapper *handle_create(HGLOBAL hglobal, BOOL delete_on_release)
|
||||
+{
|
||||
+ struct handle_wrapper *handle;
|
||||
+
|
||||
+ handle = HeapAlloc(GetProcessHeap(), 0, sizeof(*handle));
|
||||
+ if (handle)
|
||||
+ {
|
||||
+ handle->ref = 1;
|
||||
+ handle->hglobal = hglobal;
|
||||
+ handle->size = GlobalSize(hglobal);
|
||||
+ handle->delete_on_release = delete_on_release;
|
||||
+ InitializeCriticalSection(&handle->lock);
|
||||
+ }
|
||||
+ return handle;
|
||||
+}
|
||||
|
||||
/****************************************************************************
|
||||
* HGLOBALStreamImpl definition.
|
||||
@@ -55,14 +145,7 @@ typedef struct
|
||||
IStream IStream_iface;
|
||||
LONG ref;
|
||||
|
||||
- /* support for the stream */
|
||||
- HGLOBAL supportHandle;
|
||||
-
|
||||
- /* if TRUE the HGLOBAL is destroyed when the stream is finally released */
|
||||
- BOOL deleteOnRelease;
|
||||
-
|
||||
- /* size of the stream */
|
||||
- ULARGE_INTEGER streamSize;
|
||||
+ struct handle_wrapper *handle;
|
||||
|
||||
/* current position of the cursor */
|
||||
ULARGE_INTEGER currentPosition;
|
||||
@@ -114,12 +197,7 @@ static ULONG WINAPI HGLOBALStreamImpl_Release(
|
||||
|
||||
if (!ref)
|
||||
{
|
||||
- if (This->deleteOnRelease)
|
||||
- {
|
||||
- GlobalFree(This->supportHandle);
|
||||
- This->supportHandle = NULL;
|
||||
- }
|
||||
-
|
||||
+ handle_release(This->handle);
|
||||
HeapFree(GetProcessHeap(), 0, This);
|
||||
}
|
||||
|
||||
@@ -161,15 +239,15 @@ static HRESULT WINAPI HGLOBALStreamImpl_Read(
|
||||
* Using the known size of the stream, calculate the number of bytes
|
||||
* to read from the block chain
|
||||
*/
|
||||
- bytesToReadFromBuffer = min( This->streamSize.u.LowPart - This->currentPosition.u.LowPart, cb);
|
||||
+ bytesToReadFromBuffer = min( handle_getsize(This->handle) - This->currentPosition.u.LowPart, cb);
|
||||
|
||||
/*
|
||||
* Lock the buffer in position and copy the data.
|
||||
*/
|
||||
- supportBuffer = GlobalLock(This->supportHandle);
|
||||
+ supportBuffer = handle_lock(This->handle);
|
||||
if (!supportBuffer)
|
||||
{
|
||||
- WARN("read from invalid hglobal %p\n", This->supportHandle);
|
||||
+ WARN("read from invalid hglobal %p\n", handle_gethglobal(This->handle));
|
||||
*pcbRead = 0;
|
||||
return S_OK;
|
||||
}
|
||||
@@ -189,7 +267,7 @@ static HRESULT WINAPI HGLOBALStreamImpl_Read(
|
||||
/*
|
||||
* Cleanup
|
||||
*/
|
||||
- GlobalUnlock(This->supportHandle);
|
||||
+ handle_unlock(This->handle);
|
||||
|
||||
/*
|
||||
* Always returns S_OK even if the end of the stream is reached before the
|
||||
@@ -241,7 +319,7 @@ static HRESULT WINAPI HGLOBALStreamImpl_Write(
|
||||
/*
|
||||
* Verify if we need to grow the stream
|
||||
*/
|
||||
- if (newSize.u.LowPart > This->streamSize.u.LowPart)
|
||||
+ if (newSize.u.LowPart > handle_getsize(This->handle))
|
||||
{
|
||||
/* grow stream */
|
||||
HRESULT hr = IStream_SetSize(iface, newSize);
|
||||
@@ -255,10 +333,10 @@ static HRESULT WINAPI HGLOBALStreamImpl_Write(
|
||||
/*
|
||||
* Lock the buffer in position and copy the data.
|
||||
*/
|
||||
- supportBuffer = GlobalLock(This->supportHandle);
|
||||
+ supportBuffer = handle_lock(This->handle);
|
||||
if (!supportBuffer)
|
||||
{
|
||||
- WARN("write to invalid hglobal %p\n", This->supportHandle);
|
||||
+ WARN("write to invalid hglobal %p\n", handle_gethglobal(This->handle));
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
@@ -272,7 +350,7 @@ static HRESULT WINAPI HGLOBALStreamImpl_Write(
|
||||
/*
|
||||
* Cleanup
|
||||
*/
|
||||
- GlobalUnlock(This->supportHandle);
|
||||
+ handle_unlock(This->handle);
|
||||
|
||||
out:
|
||||
/*
|
||||
@@ -318,7 +396,7 @@ static HRESULT WINAPI HGLOBALStreamImpl_Seek(
|
||||
case STREAM_SEEK_CUR:
|
||||
break;
|
||||
case STREAM_SEEK_END:
|
||||
- newPosition = This->streamSize;
|
||||
+ newPosition.QuadPart = handle_getsize(This->handle);
|
||||
break;
|
||||
default:
|
||||
hr = STG_E_SEEKERROR;
|
||||
@@ -363,29 +441,13 @@ static HRESULT WINAPI HGLOBALStreamImpl_SetSize(
|
||||
ULARGE_INTEGER libNewSize) /* [in] */
|
||||
{
|
||||
HGLOBALStreamImpl* This = impl_from_IStream(iface);
|
||||
- HGLOBAL supportHandle;
|
||||
|
||||
TRACE("(%p, %d)\n", iface, libNewSize.u.LowPart);
|
||||
|
||||
/*
|
||||
* HighPart is ignored as shown in tests
|
||||
*/
|
||||
-
|
||||
- if (This->streamSize.u.LowPart == libNewSize.u.LowPart)
|
||||
- return S_OK;
|
||||
-
|
||||
- /*
|
||||
- * Re allocate the HGlobal to fit the new size of the stream.
|
||||
- */
|
||||
- supportHandle = GlobalReAlloc(This->supportHandle, libNewSize.u.LowPart, 0);
|
||||
-
|
||||
- if (supportHandle == 0)
|
||||
- return E_OUTOFMEMORY;
|
||||
-
|
||||
- This->supportHandle = supportHandle;
|
||||
- This->streamSize.u.LowPart = libNewSize.u.LowPart;
|
||||
-
|
||||
- return S_OK;
|
||||
+ return handle_setsize(This->handle, libNewSize.u.LowPart);
|
||||
}
|
||||
|
||||
/***
|
||||
@@ -533,24 +595,49 @@ static HRESULT WINAPI HGLOBALStreamImpl_Stat(
|
||||
|
||||
pstatstg->pwcsName = NULL;
|
||||
pstatstg->type = STGTY_STREAM;
|
||||
- pstatstg->cbSize = This->streamSize;
|
||||
+ pstatstg->cbSize.QuadPart = handle_getsize(This->handle);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
+static const IStreamVtbl HGLOBALStreamImplVtbl;
|
||||
+
|
||||
+static HGLOBALStreamImpl *HGLOBALStreamImpl_Create(void)
|
||||
+{
|
||||
+ HGLOBALStreamImpl *This;
|
||||
+
|
||||
+ This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
|
||||
+ if (This)
|
||||
+ {
|
||||
+ This->IStream_iface.lpVtbl = &HGLOBALStreamImplVtbl;
|
||||
+ This->ref = 1;
|
||||
+ }
|
||||
+ return This;
|
||||
+}
|
||||
+
|
||||
static HRESULT WINAPI HGLOBALStreamImpl_Clone(
|
||||
IStream* iface,
|
||||
IStream** ppstm) /* [out] */
|
||||
{
|
||||
HGLOBALStreamImpl* This = impl_from_IStream(iface);
|
||||
+ HGLOBALStreamImpl* clone;
|
||||
ULARGE_INTEGER dummy;
|
||||
LARGE_INTEGER offset;
|
||||
- HRESULT hr;
|
||||
|
||||
- TRACE(" Cloning %p (deleteOnRelease=%d seek position=%ld)\n",iface,This->deleteOnRelease,(long)This->currentPosition.QuadPart);
|
||||
- hr = CreateStreamOnHGlobal(This->supportHandle, FALSE, ppstm);
|
||||
- if(FAILED(hr))
|
||||
- return hr;
|
||||
+ if (!ppstm) return E_INVALIDARG;
|
||||
+
|
||||
+ *ppstm = NULL;
|
||||
+
|
||||
+ TRACE(" Cloning %p (seek position=%d)\n", iface, This->currentPosition.u.LowPart);
|
||||
+
|
||||
+ clone = HGLOBALStreamImpl_Create();
|
||||
+ if (!clone) return E_OUTOFMEMORY;
|
||||
+
|
||||
+ *ppstm = &clone->IStream_iface;
|
||||
+
|
||||
+ handle_addref(This->handle);
|
||||
+ clone->handle = This->handle;
|
||||
+
|
||||
offset.QuadPart = (LONGLONG)This->currentPosition.QuadPart;
|
||||
IStream_Seek(*ppstm, offset, STREAM_SEEK_SET, &dummy);
|
||||
return S_OK;
|
||||
@@ -587,28 +674,19 @@ HRESULT WINAPI CreateStreamOnHGlobal(
|
||||
if (!ppstm)
|
||||
return E_INVALIDARG;
|
||||
|
||||
- This = HeapAlloc(GetProcessHeap(), 0, sizeof(HGLOBALStreamImpl));
|
||||
+ This = HGLOBALStreamImpl_Create();
|
||||
if (!This) return E_OUTOFMEMORY;
|
||||
|
||||
- This->IStream_iface.lpVtbl = &HGLOBALStreamImplVtbl;
|
||||
- This->ref = 1;
|
||||
-
|
||||
- /* initialize the support */
|
||||
- This->supportHandle = hGlobal;
|
||||
- This->deleteOnRelease = fDeleteOnRelease;
|
||||
-
|
||||
/* allocate a handle if one is not supplied */
|
||||
- if (!This->supportHandle)
|
||||
- This->supportHandle = GlobalAlloc(GMEM_MOVEABLE|GMEM_NODISCARD|GMEM_SHARE, 0);
|
||||
+ if (!hGlobal)
|
||||
+ hGlobal = GlobalAlloc(GMEM_MOVEABLE|GMEM_NODISCARD|GMEM_SHARE, 0);
|
||||
+
|
||||
+ This->handle = handle_create(hGlobal, fDeleteOnRelease);
|
||||
|
||||
/* start at the beginning */
|
||||
This->currentPosition.u.HighPart = 0;
|
||||
This->currentPosition.u.LowPart = 0;
|
||||
|
||||
- /* initialize the size of the stream to the size of the handle */
|
||||
- This->streamSize.u.HighPart = 0;
|
||||
- This->streamSize.u.LowPart = GlobalSize(This->supportHandle);
|
||||
-
|
||||
*ppstm = &This->IStream_iface;
|
||||
|
||||
return S_OK;
|
||||
@@ -630,7 +708,7 @@ HRESULT WINAPI GetHGlobalFromStream(IStream* pstm, HGLOBAL* phglobal)
|
||||
* Verify that the stream object was created with CreateStreamOnHGlobal.
|
||||
*/
|
||||
if (pStream->IStream_iface.lpVtbl == &HGLOBALStreamImplVtbl)
|
||||
- *phglobal = pStream->supportHandle;
|
||||
+ *phglobal = handle_gethglobal(pStream->handle);
|
||||
else
|
||||
{
|
||||
*phglobal = 0;
|
||||
diff --git a/dlls/ole32/tests/hglobalstream.c b/dlls/ole32/tests/hglobalstream.c
|
||||
index 0453e54..afda4e6 100644
|
||||
--- a/dlls/ole32/tests/hglobalstream.c
|
||||
+++ b/dlls/ole32/tests/hglobalstream.c
|
||||
@@ -579,14 +579,12 @@ static void test_IStream_Clone(void)
|
||||
|
||||
stream_info(clone, &hmem_clone, &size, &pos);
|
||||
ok(hmem_clone == hmem, "handles should match\n");
|
||||
-todo_wine
|
||||
ok(size == 13, "unexpected %d\n", size);
|
||||
ok(pos == 0, "unexpected %d\n", pos);
|
||||
|
||||
buf[0] = 0;
|
||||
hr = IStream_Read(clone, buf, sizeof(buf), NULL);
|
||||
ok(hr == S_OK, "unexpected %#x\n", hr);
|
||||
-todo_wine
|
||||
ok(!strcmp(buf, hello), "wrong stream contents\n");
|
||||
|
||||
newsize.QuadPart = 0x8000;
|
||||
@@ -601,9 +599,7 @@ todo_wine
|
||||
|
||||
stream_info(clone, &hmem_clone, &size, &pos);
|
||||
ok(hmem_clone == hmem, "handles should match\n");
|
||||
-todo_wine
|
||||
ok(size == 0x8000, "unexpected %#x\n", size);
|
||||
-todo_wine
|
||||
ok(pos == 13, "unexpected %d\n", pos);
|
||||
|
||||
IStream_Release(clone);
|
||||
@@ -715,24 +711,19 @@ todo_wine
|
||||
|
||||
newsize.QuadPart = 0x8000;
|
||||
hr = IStream_SetSize(clone, newsize);
|
||||
-todo_wine
|
||||
ok(hr == S_OK, "unexpected %#x\n", hr);
|
||||
|
||||
stream_info(clone, &hmem_clone, &size, &pos);
|
||||
ok(hmem_clone == hmem, "handles should match\n");
|
||||
-todo_wine
|
||||
ok(size == 0x8000, "unexpected %#x\n", size);
|
||||
ok(pos == 0, "unexpected %d\n", pos);
|
||||
|
||||
hr = IStream_Write(clone, hello, sizeof(hello), NULL);
|
||||
-todo_wine
|
||||
ok(hr == S_OK, "unexpected %#x\n", hr);
|
||||
|
||||
stream_info(clone, &hmem_clone, &size, &pos);
|
||||
ok(hmem_clone == hmem, "handles should match\n");
|
||||
-todo_wine
|
||||
ok(size == 0x8000, "unexpected %#x\n", size);
|
||||
-todo_wine
|
||||
ok(pos == 13, "unexpected %d\n", pos);
|
||||
|
||||
offset.QuadPart = 0;
|
||||
@@ -742,14 +733,11 @@ todo_wine
|
||||
buf[0] = 0;
|
||||
hr = IStream_Read(clone, buf, sizeof(buf), NULL);
|
||||
ok(hr == S_OK, "unexpected %#x\n", hr);
|
||||
-todo_wine
|
||||
ok(!strcmp(buf, hello), "wrong stream contents\n");
|
||||
|
||||
stream_info(clone, &hmem_clone, &size, &pos);
|
||||
ok(hmem_clone == hmem, "handles should match\n");
|
||||
-todo_wine
|
||||
ok(size == 0x8000, "unexpected %#x\n", size);
|
||||
-todo_wine
|
||||
ok(pos == 32, "unexpected %d\n", pos);
|
||||
|
||||
ret = IStream_Release(clone);
|
||||
--
|
||||
2.7.0
|
||||
|
@ -0,0 +1,32 @@
|
||||
From e6b772e0000dac0c50a8070b46413352e9c86174 Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Lackner <sebastian@fds-team.de>
|
||||
Date: Sat, 6 Feb 2016 03:26:10 +0100
|
||||
Subject: ole32: Set DebugInfo->Spare[0] for handle_wrapper lock.
|
||||
|
||||
---
|
||||
dlls/ole32/hglobalstream.c | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/dlls/ole32/hglobalstream.c b/dlls/ole32/hglobalstream.c
|
||||
index 5eb6320..8b7e960 100644
|
||||
--- a/dlls/ole32/hglobalstream.c
|
||||
+++ b/dlls/ole32/hglobalstream.c
|
||||
@@ -71,6 +71,7 @@ static void handle_release(struct handle_wrapper *handle)
|
||||
handle->hglobal = NULL;
|
||||
}
|
||||
|
||||
+ handle->lock.DebugInfo->Spare[0] = 0;
|
||||
DeleteCriticalSection(&handle->lock);
|
||||
HeapFree(GetProcessHeap(), 0, handle);
|
||||
}
|
||||
@@ -130,6 +131,7 @@ static struct handle_wrapper *handle_create(HGLOBAL hglobal, BOOL delete_on_rele
|
||||
handle->size = GlobalSize(hglobal);
|
||||
handle->delete_on_release = delete_on_release;
|
||||
InitializeCriticalSection(&handle->lock);
|
||||
+ handle->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": handle_wrapper.lock");
|
||||
}
|
||||
return handle;
|
||||
}
|
||||
--
|
||||
2.7.0
|
||||
|
@ -0,0 +1,72 @@
|
||||
From b7849b3a81d2e55ccfc3d61a8a14bbacf878438b Mon Sep 17 00:00:00 2001
|
||||
From: Dmitry Timoshkov <dmitry@baikal.ru>
|
||||
Date: Tue, 2 Feb 2016 15:35:59 +0800
|
||||
Subject: ole32: Allow moving a being reallocated block of memory managed by
|
||||
HGLOBAL based IStream.
|
||||
|
||||
---
|
||||
dlls/ole32/hglobalstream.c | 2 +-
|
||||
dlls/ole32/tests/hglobalstream.c | 8 --------
|
||||
2 files changed, 1 insertion(+), 9 deletions(-)
|
||||
|
||||
diff --git a/dlls/ole32/hglobalstream.c b/dlls/ole32/hglobalstream.c
|
||||
index 8b7e960..3e7f67b 100644
|
||||
--- a/dlls/ole32/hglobalstream.c
|
||||
+++ b/dlls/ole32/hglobalstream.c
|
||||
@@ -100,7 +100,7 @@ static HRESULT handle_setsize(struct handle_wrapper *handle, ULONG size)
|
||||
|
||||
if (handle->size != size)
|
||||
{
|
||||
- HGLOBAL hglobal = GlobalReAlloc(handle->hglobal, size, 0);
|
||||
+ HGLOBAL hglobal = GlobalReAlloc(handle->hglobal, size, GMEM_MOVEABLE);
|
||||
if (hglobal)
|
||||
{
|
||||
handle->hglobal = hglobal;
|
||||
diff --git a/dlls/ole32/tests/hglobalstream.c b/dlls/ole32/tests/hglobalstream.c
|
||||
index afda4e6..9aa3b6c 100644
|
||||
--- a/dlls/ole32/tests/hglobalstream.c
|
||||
+++ b/dlls/ole32/tests/hglobalstream.c
|
||||
@@ -626,20 +626,16 @@ static void test_IStream_Clone(void)
|
||||
|
||||
newsize.QuadPart = 0x8000;
|
||||
hr = IStream_SetSize(stream, newsize);
|
||||
-todo_wine
|
||||
ok(hr == S_OK, "unexpected %#x\n", hr);
|
||||
|
||||
stream_info(stream, &hmem, &size, &pos);
|
||||
ok(hmem != 0, "unexpected %p\n", hmem);
|
||||
-todo_wine
|
||||
ok(hmem != orig_hmem, "unexpected %p\n", hmem);
|
||||
-todo_wine
|
||||
ok(size == 0x8000, "unexpected %#x\n", size);
|
||||
ok(pos == 0, "unexpected %d\n", pos);
|
||||
|
||||
stream_info(clone, &hmem_clone, &size, &pos);
|
||||
ok(hmem_clone == hmem, "handles should match\n");
|
||||
-todo_wine
|
||||
ok(size == 0x8000, "unexpected %#x\n", size);
|
||||
ok(pos == 0, "unexpected %d\n", pos);
|
||||
|
||||
@@ -667,19 +663,15 @@ todo_wine
|
||||
|
||||
newsize.QuadPart = 0x8000;
|
||||
hr = IStream_SetSize(stream, newsize);
|
||||
-todo_wine
|
||||
ok(hr == S_OK, "unexpected %#x\n", hr);
|
||||
|
||||
stream_info(stream, &hmem, &size, &pos);
|
||||
ok(hmem != 0, "unexpected %p\n", hmem);
|
||||
-todo_wine
|
||||
ok(hmem != orig_hmem, "unexpected %p\n", hmem);
|
||||
-todo_wine
|
||||
ok(size == 0x8000, "unexpected %#x\n", size);
|
||||
ok(pos == 0, "unexpected %d\n", pos);
|
||||
|
||||
stream_info(clone, &hmem_clone, &size, &pos);
|
||||
-todo_wine
|
||||
ok(hmem_clone != hmem, "handles should not match\n");
|
||||
ok(size == 1, "unexpected %#x\n", size);
|
||||
ok(pos == 0, "unexpected %d\n", pos);
|
||||
--
|
||||
2.7.0
|
||||
|
@ -0,0 +1,115 @@
|
||||
From f5c31437019892510e36f603cbde72d9204a4155 Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Lackner <sebastian@fds-team.de>
|
||||
Date: Sat, 6 Feb 2016 03:50:55 +0100
|
||||
Subject: ole32: Improve thread-safety of HGLOBALStreamImpl_Read.
|
||||
|
||||
---
|
||||
dlls/ole32/hglobalstream.c | 83 ++++++++++++++++++----------------------------
|
||||
1 file changed, 32 insertions(+), 51 deletions(-)
|
||||
|
||||
diff --git a/dlls/ole32/hglobalstream.c b/dlls/ole32/hglobalstream.c
|
||||
index 3e7f67b..27ac706 100644
|
||||
--- a/dlls/ole32/hglobalstream.c
|
||||
+++ b/dlls/ole32/hglobalstream.c
|
||||
@@ -87,6 +87,34 @@ static void handle_unlock(struct handle_wrapper *handle)
|
||||
GlobalUnlock(handle->hglobal);
|
||||
}
|
||||
|
||||
+static ULONG handle_read(struct handle_wrapper *handle, ULONG *pos, void *dest, ULONG len)
|
||||
+{
|
||||
+ void *source;
|
||||
+
|
||||
+ EnterCriticalSection(&handle->lock);
|
||||
+
|
||||
+ if (*pos < handle->size)
|
||||
+ len = min(handle->size - *pos, len);
|
||||
+ else
|
||||
+ len = 0;
|
||||
+
|
||||
+ source = GlobalLock(handle->hglobal);
|
||||
+ if (source)
|
||||
+ {
|
||||
+ memcpy(dest, (char *)source + *pos, len);
|
||||
+ *pos += len;
|
||||
+ GlobalUnlock(handle->hglobal);
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ WARN("read from invalid hglobal %p\n", handle->hglobal);
|
||||
+ len = 0;
|
||||
+ }
|
||||
+
|
||||
+ LeaveCriticalSection(&handle->lock);
|
||||
+ return len;
|
||||
+}
|
||||
+
|
||||
static HGLOBAL handle_gethglobal(struct handle_wrapper *handle)
|
||||
{
|
||||
return handle->hglobal;
|
||||
@@ -222,59 +250,12 @@ static HRESULT WINAPI HGLOBALStreamImpl_Read(
|
||||
ULONG* pcbRead) /* [out] */
|
||||
{
|
||||
HGLOBALStreamImpl* This = impl_from_IStream(iface);
|
||||
+ ULONG num_bytes;
|
||||
|
||||
- void* supportBuffer;
|
||||
- ULONG bytesReadBuffer;
|
||||
- ULONG bytesToReadFromBuffer;
|
||||
-
|
||||
- TRACE("(%p, %p, %d, %p)\n", iface,
|
||||
- pv, cb, pcbRead);
|
||||
-
|
||||
- /*
|
||||
- * If the caller is not interested in the number of bytes read,
|
||||
- * we use another buffer to avoid "if" statements in the code.
|
||||
- */
|
||||
- if (pcbRead==0)
|
||||
- pcbRead = &bytesReadBuffer;
|
||||
-
|
||||
- /*
|
||||
- * Using the known size of the stream, calculate the number of bytes
|
||||
- * to read from the block chain
|
||||
- */
|
||||
- bytesToReadFromBuffer = min( handle_getsize(This->handle) - This->currentPosition.u.LowPart, cb);
|
||||
-
|
||||
- /*
|
||||
- * Lock the buffer in position and copy the data.
|
||||
- */
|
||||
- supportBuffer = handle_lock(This->handle);
|
||||
- if (!supportBuffer)
|
||||
- {
|
||||
- WARN("read from invalid hglobal %p\n", handle_gethglobal(This->handle));
|
||||
- *pcbRead = 0;
|
||||
- return S_OK;
|
||||
- }
|
||||
-
|
||||
- memcpy(pv, (char *) supportBuffer+This->currentPosition.u.LowPart, bytesToReadFromBuffer);
|
||||
-
|
||||
- /*
|
||||
- * Move the current position to the new position
|
||||
- */
|
||||
- This->currentPosition.u.LowPart+=bytesToReadFromBuffer;
|
||||
-
|
||||
- /*
|
||||
- * Return the number of bytes read.
|
||||
- */
|
||||
- *pcbRead = bytesToReadFromBuffer;
|
||||
-
|
||||
- /*
|
||||
- * Cleanup
|
||||
- */
|
||||
- handle_unlock(This->handle);
|
||||
+ TRACE("(%p, %p, %d, %p)\n", iface, pv, cb, pcbRead);
|
||||
|
||||
- /*
|
||||
- * Always returns S_OK even if the end of the stream is reached before the
|
||||
- * buffer is filled
|
||||
- */
|
||||
+ num_bytes = handle_read(This->handle, &This->currentPosition.u.LowPart, pv, cb);
|
||||
+ if (pcbRead) *pcbRead = num_bytes;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
--
|
||||
2.7.0
|
||||
|
@ -0,0 +1,158 @@
|
||||
From 8656639654762bd3151593fe00a0c47080a085d8 Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Lackner <sebastian@fds-team.de>
|
||||
Date: Sat, 6 Feb 2016 04:09:45 +0100
|
||||
Subject: ole32: Improve thread-safety of HGLOBALStreamImpl_Write.
|
||||
|
||||
---
|
||||
dlls/ole32/hglobalstream.c | 117 ++++++++++++++++++---------------------------
|
||||
1 file changed, 46 insertions(+), 71 deletions(-)
|
||||
|
||||
diff --git a/dlls/ole32/hglobalstream.c b/dlls/ole32/hglobalstream.c
|
||||
index 27ac706..2c08710 100644
|
||||
--- a/dlls/ole32/hglobalstream.c
|
||||
+++ b/dlls/ole32/hglobalstream.c
|
||||
@@ -77,16 +77,6 @@ static void handle_release(struct handle_wrapper *handle)
|
||||
}
|
||||
}
|
||||
|
||||
-static void *handle_lock(struct handle_wrapper *handle)
|
||||
-{
|
||||
- return GlobalLock(handle->hglobal);
|
||||
-}
|
||||
-
|
||||
-static void handle_unlock(struct handle_wrapper *handle)
|
||||
-{
|
||||
- GlobalUnlock(handle->hglobal);
|
||||
-}
|
||||
-
|
||||
static ULONG handle_read(struct handle_wrapper *handle, ULONG *pos, void *dest, ULONG len)
|
||||
{
|
||||
void *source;
|
||||
@@ -115,6 +105,48 @@ static ULONG handle_read(struct handle_wrapper *handle, ULONG *pos, void *dest,
|
||||
return len;
|
||||
}
|
||||
|
||||
+static ULONG handle_write(struct handle_wrapper *handle, ULONG *pos, const void *source, ULONG len)
|
||||
+{
|
||||
+ void *dest;
|
||||
+
|
||||
+ if (!len)
|
||||
+ return 0;
|
||||
+
|
||||
+ EnterCriticalSection(&handle->lock);
|
||||
+
|
||||
+ if (*pos + len > handle->size)
|
||||
+ {
|
||||
+ HGLOBAL hglobal = GlobalReAlloc(handle->hglobal, *pos + len, GMEM_MOVEABLE);
|
||||
+ if (hglobal)
|
||||
+ {
|
||||
+ handle->hglobal = hglobal;
|
||||
+ handle->size = *pos + len;
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ len = 0;
|
||||
+ goto done;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ dest = GlobalLock(handle->hglobal);
|
||||
+ if (dest)
|
||||
+ {
|
||||
+ memcpy((char *)dest + *pos, source, len);
|
||||
+ *pos += len;
|
||||
+ GlobalUnlock(handle->hglobal);
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ WARN("write to invalid hglobal %p\n", handle->hglobal);
|
||||
+ /* len = 0; */
|
||||
+ }
|
||||
+
|
||||
+done:
|
||||
+ LeaveCriticalSection(&handle->lock);
|
||||
+ return len;
|
||||
+}
|
||||
+
|
||||
static HGLOBAL handle_gethglobal(struct handle_wrapper *handle)
|
||||
{
|
||||
return handle->hglobal;
|
||||
@@ -277,71 +309,14 @@ static HRESULT WINAPI HGLOBALStreamImpl_Write(
|
||||
ULONG* pcbWritten) /* [out] */
|
||||
{
|
||||
HGLOBALStreamImpl* This = impl_from_IStream(iface);
|
||||
-
|
||||
- void* supportBuffer;
|
||||
- ULARGE_INTEGER newSize;
|
||||
- ULONG bytesWritten = 0;
|
||||
+ ULONG num_bytes;
|
||||
|
||||
TRACE("(%p, %p, %d, %p)\n", iface, pv, cb, pcbWritten);
|
||||
|
||||
- /*
|
||||
- * If the caller is not interested in the number of bytes written,
|
||||
- * we use another buffer to avoid "if" statements in the code.
|
||||
- */
|
||||
- if (pcbWritten == 0)
|
||||
- pcbWritten = &bytesWritten;
|
||||
-
|
||||
- if (cb == 0)
|
||||
- goto out;
|
||||
-
|
||||
- *pcbWritten = 0;
|
||||
-
|
||||
- newSize.u.HighPart = 0;
|
||||
- newSize.u.LowPart = This->currentPosition.u.LowPart + cb;
|
||||
-
|
||||
- /*
|
||||
- * Verify if we need to grow the stream
|
||||
- */
|
||||
- if (newSize.u.LowPart > handle_getsize(This->handle))
|
||||
- {
|
||||
- /* grow stream */
|
||||
- HRESULT hr = IStream_SetSize(iface, newSize);
|
||||
- if (FAILED(hr))
|
||||
- {
|
||||
- ERR("IStream_SetSize failed with error 0x%08x\n", hr);
|
||||
- return hr;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- /*
|
||||
- * Lock the buffer in position and copy the data.
|
||||
- */
|
||||
- supportBuffer = handle_lock(This->handle);
|
||||
- if (!supportBuffer)
|
||||
- {
|
||||
- WARN("write to invalid hglobal %p\n", handle_gethglobal(This->handle));
|
||||
- return S_OK;
|
||||
- }
|
||||
-
|
||||
- memcpy((char *) supportBuffer+This->currentPosition.u.LowPart, pv, cb);
|
||||
-
|
||||
- /*
|
||||
- * Move the current position to the new position
|
||||
- */
|
||||
- This->currentPosition.u.LowPart+=cb;
|
||||
-
|
||||
- /*
|
||||
- * Cleanup
|
||||
- */
|
||||
- handle_unlock(This->handle);
|
||||
-
|
||||
-out:
|
||||
- /*
|
||||
- * Return the number of bytes read.
|
||||
- */
|
||||
- *pcbWritten = cb;
|
||||
+ num_bytes = handle_write(This->handle, &This->currentPosition.u.LowPart, pv, cb);
|
||||
+ if (pcbWritten) *pcbWritten = num_bytes;
|
||||
|
||||
- return S_OK;
|
||||
+ return (num_bytes < cb) ? E_OUTOFMEMORY : S_OK;
|
||||
}
|
||||
|
||||
/***
|
||||
--
|
||||
2.7.0
|
||||
|
1
patches/ole32-HGLOBALStream/definition
Normal file
1
patches/ole32-HGLOBALStream/definition
Normal file
@ -0,0 +1 @@
|
||||
Fixes: Implement proper refcounting and locking for HGLOBAL based IStream
|
@ -238,6 +238,7 @@ patch_enable_all ()
|
||||
enable_nvcuvid_CUDA_Video_Support="$1"
|
||||
enable_nvencodeapi_Video_Encoder="$1"
|
||||
enable_ole32_CoGetApartmentType="$1"
|
||||
enable_ole32_HGLOBALStream="$1"
|
||||
enable_oleaut32_CreateTypeLib="$1"
|
||||
enable_oleaut32_TKIND_COCLASS="$1"
|
||||
enable_oleaut32_x86_64_Marshaller="$1"
|
||||
@ -853,6 +854,9 @@ patch_enable ()
|
||||
ole32-CoGetApartmentType)
|
||||
enable_ole32_CoGetApartmentType="$2"
|
||||
;;
|
||||
ole32-HGLOBALStream)
|
||||
enable_ole32_HGLOBALStream="$2"
|
||||
;;
|
||||
oleaut32-CreateTypeLib)
|
||||
enable_oleaut32_CreateTypeLib="$2"
|
||||
;;
|
||||
@ -5202,6 +5206,30 @@ if test "$enable_nvencodeapi_Video_Encoder" -eq 1; then
|
||||
) >> "$patchlist"
|
||||
fi
|
||||
|
||||
# Patchset ole32-HGLOBALStream
|
||||
# |
|
||||
# | Modified files:
|
||||
# | * dlls/ole32/hglobalstream.c, dlls/ole32/tests/hglobalstream.c
|
||||
# |
|
||||
if test "$enable_ole32_HGLOBALStream" -eq 1; then
|
||||
patch_apply ole32-HGLOBALStream/0001-ole32-tests-Add-a-bunch-of-tests-for-HGLOBAL-based-I.patch
|
||||
patch_apply ole32-HGLOBALStream/0002-ole32-Add-a-check-for-hglobal-pointer-to-GetHGlobalF.patch
|
||||
patch_apply ole32-HGLOBALStream/0003-ole32-Add-a-wrapper-for-memory-block-managed-by-HGLO.patch
|
||||
patch_apply ole32-HGLOBALStream/0004-ole32-Set-DebugInfo-Spare-0-for-handle_wrapper-lock.patch
|
||||
patch_apply ole32-HGLOBALStream/0005-ole32-Allow-moving-a-being-reallocated-block-of-memo.patch
|
||||
patch_apply ole32-HGLOBALStream/0006-ole32-Improve-thread-safety-of-HGLOBALStreamImpl_Rea.patch
|
||||
patch_apply ole32-HGLOBALStream/0007-ole32-Improve-thread-safety-of-HGLOBALStreamImpl_Wri.patch
|
||||
(
|
||||
echo '+ { "Dmitry Timoshkov", "ole32/tests: Add a bunch of tests for HGLOBAL based IStream::Clone.", 1 },';
|
||||
echo '+ { "Dmitry Timoshkov", "ole32: Add a check for hglobal pointer to GetHGlobalFromStream.", 1 },';
|
||||
echo '+ { "Dmitry Timoshkov", "ole32: Add a wrapper for memory block managed by HGLOBAL based IStream.", 1 },';
|
||||
echo '+ { "Sebastian Lackner", "ole32: Set DebugInfo->Spare[0] for handle_wrapper lock.", 1 },';
|
||||
echo '+ { "Dmitry Timoshkov", "ole32: Allow moving a being reallocated block of memory managed by HGLOBAL based IStream.", 1 },';
|
||||
echo '+ { "Sebastian Lackner", "ole32: Improve thread-safety of HGLOBALStreamImpl_Read.", 1 },';
|
||||
echo '+ { "Sebastian Lackner", "ole32: Improve thread-safety of HGLOBALStreamImpl_Write.", 1 },';
|
||||
) >> "$patchlist"
|
||||
fi
|
||||
|
||||
# Patchset oleaut32-CreateTypeLib
|
||||
# |
|
||||
# | This patchset fixes the following Wine bugs:
|
||||
|
Loading…
Reference in New Issue
Block a user