Jan Sikorski : wined3d: Decrement reference count and take the lock atomically for cached objects.

Alexandre Julliard julliard at winehq.org
Thu Dec 9 15:34:28 CST 2021


Module: wine
Branch: master
Commit: 996728315afb01d4f9ed8a81a14d812d8e866081
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=996728315afb01d4f9ed8a81a14d812d8e866081

Author: Jan Sikorski <jsikorski at codeweavers.com>
Date:   Wed Dec  1 13:31:33 2021 +0100

wined3d: Decrement reference count and take the lock atomically for cached objects.

Samplers, blend states, rasterizer states and depth stencil states can
be retrieved from the cache in struct d3d_device even after the
reference count reaches zero, causing memory corruption.

Signed-off-by: Jan Sikorski <jsikorski at codeweavers.com>
Signed-off-by: Henri Verbeet <hverbeet at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/wined3d/sampler.c         |  3 +--
 dlls/wined3d/state.c           |  9 +++------
 dlls/wined3d/wined3d_private.h | 20 ++++++++++++++++++++
 3 files changed, 24 insertions(+), 8 deletions(-)

diff --git a/dlls/wined3d/sampler.c b/dlls/wined3d/sampler.c
index a6259bd3f82..600442ac6f3 100644
--- a/dlls/wined3d/sampler.c
+++ b/dlls/wined3d/sampler.c
@@ -34,13 +34,12 @@ ULONG CDECL wined3d_sampler_incref(struct wined3d_sampler *sampler)
 
 ULONG CDECL wined3d_sampler_decref(struct wined3d_sampler *sampler)
 {
-    ULONG refcount = InterlockedDecrement(&sampler->refcount);
+    ULONG refcount = wined3d_atomic_decrement_mutex_lock(&sampler->refcount);
 
     TRACE("%p decreasing refcount to %u.\n", sampler, refcount);
 
     if (!refcount)
     {
-        wined3d_mutex_lock();
         sampler->parent_ops->wined3d_object_destroyed(sampler->parent);
         sampler->device->adapter->adapter_ops->adapter_destroy_sampler(sampler);
         wined3d_mutex_unlock();
diff --git a/dlls/wined3d/state.c b/dlls/wined3d/state.c
index bc214f73b63..865c60d189e 100644
--- a/dlls/wined3d/state.c
+++ b/dlls/wined3d/state.c
@@ -51,14 +51,13 @@ static void wined3d_blend_state_destroy_object(void *object)
 
 ULONG CDECL wined3d_blend_state_decref(struct wined3d_blend_state *state)
 {
-    ULONG refcount = InterlockedDecrement(&state->refcount);
+    ULONG refcount = wined3d_atomic_decrement_mutex_lock(&state->refcount);
     struct wined3d_device *device = state->device;
 
     TRACE("%p decreasing refcount to %u.\n", state, refcount);
 
     if (!refcount)
     {
-        wined3d_mutex_lock();
         state->parent_ops->wined3d_object_destroyed(state->parent);
         wined3d_cs_destroy_object(device->cs, wined3d_blend_state_destroy_object, state);
         wined3d_mutex_unlock();
@@ -127,14 +126,13 @@ static void wined3d_depth_stencil_state_destroy_object(void *object)
 
 ULONG CDECL wined3d_depth_stencil_state_decref(struct wined3d_depth_stencil_state *state)
 {
-    ULONG refcount = InterlockedDecrement(&state->refcount);
+    ULONG refcount = wined3d_atomic_decrement_mutex_lock(&state->refcount);
     struct wined3d_device *device = state->device;
 
     TRACE("%p decreasing refcount to %u.\n", state, refcount);
 
     if (!refcount)
     {
-        wined3d_mutex_lock();
         state->parent_ops->wined3d_object_destroyed(state->parent);
         wined3d_cs_destroy_object(device->cs, wined3d_depth_stencil_state_destroy_object, state);
         wined3d_mutex_unlock();
@@ -192,14 +190,13 @@ static void wined3d_rasterizer_state_destroy_object(void *object)
 
 ULONG CDECL wined3d_rasterizer_state_decref(struct wined3d_rasterizer_state *state)
 {
-    ULONG refcount = InterlockedDecrement(&state->refcount);
+    ULONG refcount = wined3d_atomic_decrement_mutex_lock(&state->refcount);
     struct wined3d_device *device = state->device;
 
     TRACE("%p decreasing refcount to %u.\n", state, refcount);
 
     if (!refcount)
     {
-        wined3d_mutex_lock();
         state->parent_ops->wined3d_object_destroyed(state->parent);
         wined3d_cs_destroy_object(device->cs, wined3d_rasterizer_state_destroy_object, state);
         wined3d_mutex_unlock();
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index b30a4108b0b..369f69913a8 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -4155,6 +4155,26 @@ const char *wined3d_debug_view_desc(const struct wined3d_view_desc *d,
         const struct wined3d_resource *resource) DECLSPEC_HIDDEN;
 const char *wined3d_debug_vkresult(VkResult vr) DECLSPEC_HIDDEN;
 
+static inline ULONG wined3d_atomic_decrement_mutex_lock(volatile LONG *refcount)
+{
+    ULONG count, old_count = *refcount;
+    do
+    {
+        if ((count = old_count) == 1)
+        {
+            wined3d_mutex_lock();
+            count = InterlockedDecrement(refcount);
+            if (count) wined3d_mutex_unlock();
+            return count;
+        }
+
+        old_count = InterlockedCompareExchange(refcount, count - 1, count);
+    }
+    while (old_count != count);
+
+    return count - 1;
+}
+
 struct wined3d_client_resource
 {
     /* The resource's persistently mapped address, which we may use to perform




More information about the wine-cvs mailing list