ole32: Postpone removing a being destroyed apartment from the global list.

Dmitry Timoshkov dmitry at baikal.ru
Fri Jun 7 04:29:29 CDT 2013


StdMarshalImpl_ReleaseMarshalData called from apartment_release() needs to
access apartment data, but fails because an apartment has already been removed
from the global list. That leads to lost connections and memory leaks.

Found with a not yet accepted local server test.
---
 dlls/ole32/compobj.c | 21 ++++++++++-----------
 1 file changed, 10 insertions(+), 11 deletions(-)

diff --git a/dlls/ole32/compobj.c b/dlls/ole32/compobj.c
index 92ace8a..d025820 100644
--- a/dlls/ole32/compobj.c
+++ b/dlls/ole32/compobj.c
@@ -960,19 +960,8 @@ DWORD apartment_release(struct apartment *apt)
 {
     DWORD ret;
 
-    EnterCriticalSection(&csApartment);
-
     ret = InterlockedDecrement(&apt->refs);
     TRACE("%s: after = %d\n", wine_dbgstr_longlong(apt->oxid), ret);
-    /* destruction stuff that needs to happen under csApartment CS */
-    if (ret == 0)
-    {
-        if (apt == MTA) MTA = NULL;
-        else if (apt == MainApartment) MainApartment = NULL;
-        list_remove(&apt->entry);
-    }
-
-    LeaveCriticalSection(&csApartment);
 
     if (ret == 0)
     {
@@ -980,6 +969,9 @@ DWORD apartment_release(struct apartment *apt)
 
         TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
 
+        /* Pin the apartment reference, so it doesn't get recursively destroyed */
+        InterlockedIncrement(&apt->refs);
+
         if(apt->local_server) {
             LocalServer *local_server = apt->local_server;
             LARGE_INTEGER zero;
@@ -1006,6 +998,13 @@ DWORD apartment_release(struct apartment *apt)
         if (apt->win) DestroyWindow(apt->win);
         if (apt->host_apt_tid) PostThreadMessageW(apt->host_apt_tid, WM_QUIT, 0, 0);
 
+        /* destruction stuff that needs to happen under csApartment CS */
+        EnterCriticalSection(&csApartment);
+        if (apt == MTA) MTA = NULL;
+        else if (apt == MainApartment) MainApartment = NULL;
+        list_remove(&apt->entry);
+        LeaveCriticalSection(&csApartment);
+
         LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
         {
             struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
-- 
1.8.3




More information about the wine-patches mailing list