Jacek Caban : ole32: Lock spies list when iterating it.

Alexandre Julliard julliard at winehq.org
Tue Sep 24 16:04:45 CDT 2019


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

Author: Jacek Caban <jacek at codeweavers.com>
Date:   Tue Sep 24 15:56:38 2019 +0200

ole32: Lock spies list when iterating it.

Signed-off-by: Jacek Caban <jacek at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/ole32/compobj.c         | 65 +++++++++++++++++++++++++++++++++-----------
 dlls/ole32/compobj_private.h |  1 +
 2 files changed, 50 insertions(+), 16 deletions(-)

diff --git a/dlls/ole32/compobj.c b/dlls/ole32/compobj.c
index a3e84929bd..c5a36059b9 100644
--- a/dlls/ole32/compobj.c
+++ b/dlls/ole32/compobj.c
@@ -1744,7 +1744,7 @@ static void COM_TlsDestroy(void)
         LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, &info->spies, struct init_spy, entry)
         {
             list_remove(&cursor->entry);
-            IInitializeSpy_Release(cursor->spy);
+            if (cursor->spy) IInitializeSpy_Release(cursor->spy);
             heap_free(cursor);
         }
 
@@ -1777,13 +1777,36 @@ static struct init_spy *get_spy_entry(struct oletls *info, unsigned int id)
 
     LIST_FOR_EACH_ENTRY(spy, &info->spies, struct init_spy, entry)
     {
-        if (id == spy->id)
+        if (id == spy->id && spy->spy)
             return spy;
     }
 
     return NULL;
 }
 
+/*
+ * When locked, don't modify list (unless we add a new head), so that it's
+ * safe to iterate it. Freeing of list entries is delayed and done on unlock.
+ */
+static inline void lock_init_spies(struct oletls *info)
+{
+    info->spies_lock++;
+}
+
+static void unlock_init_spies(struct oletls *info)
+{
+    struct init_spy *spy, *next;
+
+    if (--info->spies_lock) return;
+
+    LIST_FOR_EACH_ENTRY_SAFE(spy, next, &info->spies, struct init_spy, entry)
+    {
+        if (spy->spy) continue;
+        list_remove(&spy->entry);
+        heap_free(spy);
+    }
+}
+
 /******************************************************************************
  *              CoRegisterInitializeSpy [OLE32.@]
  *
@@ -1869,16 +1892,16 @@ HRESULT WINAPI CoRevokeInitializeSpy(ULARGE_INTEGER cookie)
     if (!info || cookie.HighPart != GetCurrentThreadId())
         return E_INVALIDARG;
 
-    if ((spy = get_spy_entry(info, cookie.LowPart)))
+    if (!(spy = get_spy_entry(info, cookie.LowPart))) return E_INVALIDARG;
+
+    IInitializeSpy_Release(spy->spy);
+    spy->spy = NULL;
+    if (!info->spies_lock)
     {
-        IInitializeSpy_Release(spy->spy);
         list_remove(&spy->entry);
         heap_free(spy);
-
-        return S_OK;
     }
-
-    return E_INVALIDARG;
+    return S_OK;
 }
 
 HRESULT enter_apartment( struct oletls *info, DWORD model )
@@ -2000,17 +2023,21 @@ HRESULT WINAPI DECLSPEC_HOTPATCH CoInitializeEx(LPVOID lpReserved, DWORD dwCoIni
     RunningObjectTableImpl_Initialize();
   }
 
+  lock_init_spies(info);
   LIST_FOR_EACH_ENTRY(cursor, &info->spies, struct init_spy, entry)
   {
-      IInitializeSpy_PreInitialize(cursor->spy, dwCoInit, info->inits);
+      if (cursor->spy) IInitializeSpy_PreInitialize(cursor->spy, dwCoInit, info->inits);
   }
+  unlock_init_spies(info);
 
   hr = enter_apartment( info, dwCoInit );
 
+  lock_init_spies(info);
   LIST_FOR_EACH_ENTRY(cursor, &info->spies, struct init_spy, entry)
   {
-      hr = IInitializeSpy_PostInitialize(cursor->spy, hr, dwCoInit, info->inits);
+      if (cursor->spy) hr = IInitializeSpy_PostInitialize(cursor->spy, hr, dwCoInit, info->inits);
   }
+  unlock_init_spies(info);
 
   return hr;
 }
@@ -2034,7 +2061,7 @@ HRESULT WINAPI DECLSPEC_HOTPATCH CoInitializeEx(LPVOID lpReserved, DWORD dwCoIni
 void WINAPI DECLSPEC_HOTPATCH CoUninitialize(void)
 {
   struct oletls * info = COM_CurrentInfo();
-  struct init_spy *cursor;
+  struct init_spy *cursor, *next;
   LONG lCOMRefCnt;
 
   TRACE("()\n");
@@ -2042,20 +2069,24 @@ void WINAPI DECLSPEC_HOTPATCH CoUninitialize(void)
   /* will only happen on OOM */
   if (!info) return;
 
-  LIST_FOR_EACH_ENTRY(cursor, &info->spies, struct init_spy, entry)
+  lock_init_spies(info);
+  LIST_FOR_EACH_ENTRY_SAFE(cursor, next, &info->spies, struct init_spy, entry)
   {
-      IInitializeSpy_PreUninitialize(cursor->spy, info->inits);
+      if (cursor->spy) IInitializeSpy_PreUninitialize(cursor->spy, info->inits);
   }
+  unlock_init_spies(info);
 
   /* sanity check */
   if (!info->inits)
   {
       ERR("Mismatched CoUninitialize\n");
 
-      LIST_FOR_EACH_ENTRY(cursor, &info->spies, struct init_spy, entry)
+      lock_init_spies(info);
+      LIST_FOR_EACH_ENTRY_SAFE(cursor, next, &info->spies, struct init_spy, entry)
       {
-          IInitializeSpy_PostUninitialize(cursor->spy, info->inits);
+          if (cursor->spy) IInitializeSpy_PostUninitialize(cursor->spy, info->inits);
       }
+      unlock_init_spies(info);
 
       return;
   }
@@ -2080,10 +2111,12 @@ void WINAPI DECLSPEC_HOTPATCH CoUninitialize(void)
     InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
   }
 
+  lock_init_spies(info);
   LIST_FOR_EACH_ENTRY(cursor, &info->spies, struct init_spy, entry)
   {
-      IInitializeSpy_PostUninitialize(cursor->spy, info->inits);
+      if (cursor->spy) IInitializeSpy_PostUninitialize(cursor->spy, info->inits);
   }
+  unlock_init_spies(info);
 }
 
 /******************************************************************************
diff --git a/dlls/ole32/compobj_private.h b/dlls/ole32/compobj_private.h
index 8bf3d6fc81..bda1c6bff2 100644
--- a/dlls/ole32/compobj_private.h
+++ b/dlls/ole32/compobj_private.h
@@ -179,6 +179,7 @@ struct oletls
     DWORD            unknown2[46];
     IUnknown        *cancel_object; /* cancel object set by CoSetCancelObject (+F8h on x86) */
     struct list      spies;         /* Spies installed with CoRegisterInitializeSpy */
+    DWORD            spies_lock;
 };
 
 




More information about the wine-cvs mailing list