Brendan Shanks : sechost: Fix hang when a device notification callback tries to register/unregister a notify.

Alexandre Julliard julliard at winehq.org
Tue Nov 9 15:55:06 CST 2021


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

Author: Brendan Shanks <bshanks at codeweavers.com>
Date:   Mon Nov  8 14:38:57 2021 -0800

sechost: Fix hang when a device notification callback tries to register/unregister a notify.

Fixes 4 second hang in Yooka-Laylee and the Impossible Lair when a
controller is connected.

Signed-off-by: Brendan Shanks <bshanks at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/sechost/service.c | 25 +++++++++++++++++++++++--
 1 file changed, 23 insertions(+), 2 deletions(-)

diff --git a/dlls/sechost/service.c b/dlls/sechost/service.c
index c447263bd0f..e6f4eb75db0 100644
--- a/dlls/sechost/service.c
+++ b/dlls/sechost/service.c
@@ -1992,9 +1992,11 @@ static DWORD WINAPI device_notify_proc( void *arg )
     RPC_WSTR binding_str;
     DWORD err = ERROR_SUCCESS;
     struct device_notify_registration *registration;
+    struct device_notification_details *details_copy;
+    unsigned int details_copy_nelems, details_copy_size;
     plugplay_rpc_handle handle = NULL;
     DWORD code = 0;
-    unsigned int size;
+    unsigned int i, size;
     BYTE *buf;
 
     if ((err = RpcStringBindingComposeW( NULL, protseq, NULL, endpoint, NULL, &binding_str )))
@@ -2026,6 +2028,9 @@ static DWORD WINAPI device_notify_proc( void *arg )
         return 1;
     }
 
+    details_copy_size = 8;
+    details_copy = heap_alloc( details_copy_size * sizeof(*details_copy) );
+
     for (;;)
     {
         buf = NULL;
@@ -2046,15 +2051,31 @@ static DWORD WINAPI device_notify_proc( void *arg )
             break;
         }
 
+        /* Make a copy to avoid a hang if a callback tries to register or unregister for notifications. */
+        i = 0;
+        details_copy_nelems = 0;
         EnterCriticalSection( &service_cs );
         LIST_FOR_EACH_ENTRY(registration, &device_notify_list, struct device_notify_registration, entry)
         {
-            registration->details.cb( registration->details.handle, code, (DEV_BROADCAST_HDR *)buf );
+            details_copy[i++] = registration->details;
+            details_copy_nelems++;
+            if (i == details_copy_size)
+            {
+                details_copy_size *= 2;
+                details_copy = heap_realloc( details_copy, details_copy_size * sizeof(*details_copy) );
+            }
         }
         LeaveCriticalSection(&service_cs);
+
+        for (i = 0; i < details_copy_nelems; i++)
+        {
+            details_copy[i].cb( details_copy[i].handle, code, (DEV_BROADCAST_HDR *)buf );
+        }
         MIDL_user_free(buf);
     }
 
+    heap_free( details_copy );
+
     __TRY
     {
         plugplay_unregister_listener( handle );




More information about the wine-cvs mailing list