From: Tim Clem tclem@codeweavers.com
If multiple threads are creating and releasing the factory, these accesses are racy and can result in callers of DXCoreCreateAdapterFactory getting a null pointer or a pointer to freed memory. --- dlls/dxcore/dxcore.c | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-)
diff --git a/dlls/dxcore/dxcore.c b/dlls/dxcore/dxcore.c index 71cdca9412a..3de9ce99220 100644 --- a/dlls/dxcore/dxcore.c +++ b/dlls/dxcore/dxcore.c @@ -29,6 +29,15 @@ WINE_DEFAULT_DEBUG_CHANNEL(dxcore);
static struct dxcore_adapter_factory *dxcore_adapter_factory;
+static CRITICAL_SECTION factory_section; +static CRITICAL_SECTION_DEBUG critsect_debug = +{ + 0, 0, &factory_section, + { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": factory_section") } +}; +static CRITICAL_SECTION factory_section = { &critsect_debug, -1, 0, 0, 0, 0 }; + struct dxcore_adapter { IDXCoreAdapter IDXCoreAdapter_iface; @@ -428,18 +437,26 @@ static HRESULT STDMETHODCALLTYPE dxcore_adapter_factory_QueryInterface(IDXCoreAd static ULONG STDMETHODCALLTYPE dxcore_adapter_factory_AddRef(IDXCoreAdapterFactory *iface) { struct dxcore_adapter_factory *factory = impl_from_IDXCoreAdapterFactory(iface); - ULONG refcount = InterlockedIncrement(&factory->refcount); + ULONG refcount; + + EnterCriticalSection(&factory_section);
+ refcount = InterlockedIncrement(&factory->refcount); TRACE("%p increasing refcount to %lu.\n", iface, refcount);
+ LeaveCriticalSection(&factory_section); + return refcount; }
static ULONG STDMETHODCALLTYPE dxcore_adapter_factory_Release(IDXCoreAdapterFactory *iface) { struct dxcore_adapter_factory *factory = impl_from_IDXCoreAdapterFactory(iface); - ULONG refcount = InterlockedDecrement(&factory->refcount); + ULONG refcount; + + EnterCriticalSection(&factory_section);
+ refcount = InterlockedDecrement(&factory->refcount); TRACE("%p decreasing refcount to %lu.\n", iface, refcount);
if (!refcount) @@ -448,6 +465,8 @@ static ULONG STDMETHODCALLTYPE dxcore_adapter_factory_Release(IDXCoreAdapterFact dxcore_adapter_factory = NULL; }
+ LeaveCriticalSection(&factory_section); + return refcount; }
@@ -614,15 +633,20 @@ static const struct IDXCoreAdapterFactoryVtbl dxcore_adapter_factory_vtbl =
HRESULT STDMETHODCALLTYPE DXCoreCreateAdapterFactory(REFIID riid, void **out) { + HRESULT hr; + TRACE("riid %s, out %p\n", debugstr_guid(riid), out);
if (!out) return E_POINTER;
+ EnterCriticalSection(&factory_section); + if (!dxcore_adapter_factory) { if (!(dxcore_adapter_factory = calloc(1, sizeof(*dxcore_adapter_factory)))) { + LeaveCriticalSection(&factory_section); *out = NULL; return E_OUTOFMEMORY; } @@ -631,6 +655,10 @@ HRESULT STDMETHODCALLTYPE DXCoreCreateAdapterFactory(REFIID riid, void **out) dxcore_adapter_factory->refcount = 0; }
+ hr = IDXCoreAdapterFactory_QueryInterface(&dxcore_adapter_factory->IDXCoreAdapterFactory_iface, riid, out); + + LeaveCriticalSection(&factory_section); + TRACE("created IDXCoreAdapterFactory %p.\n", *out); - return IDXCoreAdapterFactory_QueryInterface(&dxcore_adapter_factory->IDXCoreAdapterFactory_iface, riid, out); + return hr; }