Arkadiusz Hiler : msvcrt: Increase module's reference count before returning from _beginthread[ex]().

Alexandre Julliard julliard at winehq.org
Mon Nov 8 15:45:07 CST 2021


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

Author: Arkadiusz Hiler <ahiler at codeweavers.com>
Date:   Mon Nov  8 19:38:33 2021 +0200

msvcrt: Increase module's reference count before returning from _beginthread[ex]().

Increasing DLL's reference count from the trampoline function makes it
prone to race conditions. The thread can start executing after we have
already returned from _beginthread[ex]() and the DLL might have been
freed.

Fixes rare crash on launch with Baldur's Gate 3.

Signed-off-by: Arkadiusz Hiler <ahiler at codeweavers.com>
Signed-off-by: Piotr Caban <piotr at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/msvcrt/thread.c | 50 +++++++++++++++++++++++++++++++-------------------
 1 file changed, 31 insertions(+), 19 deletions(-)

diff --git a/dlls/msvcrt/thread.c b/dlls/msvcrt/thread.c
index 01500d93d91..173763d0eb1 100644
--- a/dlls/msvcrt/thread.c
+++ b/dlls/msvcrt/thread.c
@@ -32,6 +32,9 @@ typedef struct {
       _beginthreadex_start_routine_t start_address_ex;
   };
   void *arglist;
+#if _MSVCR_VER >= 140
+  HMODULE module;
+#endif
 } _beginthread_trampoline_t;
 
 /*********************************************************************
@@ -113,16 +116,10 @@ static DWORD CALLBACK _beginthread_trampoline(LPVOID arg)
     thread_data_t *data = msvcrt_get_thread_data();
 
     memcpy(&local_trampoline,arg,sizeof(local_trampoline));
-    data->handle = local_trampoline.thread;
     free(arg);
-
+    data->handle = local_trampoline.thread;
 #if _MSVCR_VER >= 140
-    if (!GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
-                (void*)local_trampoline.start_address, &data->module))
-    {
-        data->module = NULL;
-        WARN("failed to get module for the start_address: %d\n", GetLastError());
-    }
+    data->module = local_trampoline.module;
 #endif
 
     local_trampoline.start_address(local_trampoline.arglist);
@@ -162,7 +159,19 @@ uintptr_t CDECL _beginthread(
   trampoline->start_address = start_address;
   trampoline->arglist = arglist;
 
+#if _MSVCR_VER >= 140
+  if(!GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
+              (void*)start_address, &trampoline->module))
+  {
+      trampoline->module = NULL;
+      WARN("failed to get module for the start_address: %d\n", GetLastError());
+  }
+#endif
+
   if(ResumeThread(thread) == -1) {
+#if _MSVCR_VER >= 140
+      FreeLibrary(trampoline->module);
+#endif
       free(trampoline);
       *_errno() = EAGAIN;
       return -1;
@@ -181,19 +190,10 @@ static DWORD CALLBACK _beginthreadex_trampoline(LPVOID arg)
     thread_data_t *data = msvcrt_get_thread_data();
 
     memcpy(&local_trampoline, arg, sizeof(local_trampoline));
-    data->handle = local_trampoline.thread;
     free(arg);
-
+    data->handle = local_trampoline.thread;
 #if _MSVCR_VER >= 140
-    {
-        thread_data_t *data = msvcrt_get_thread_data();
-        if (!GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
-                    (void*)local_trampoline.start_address_ex, &data->module))
-        {
-            data->module = NULL;
-            WARN("failed to get module for the start_address: %d\n", GetLastError());
-        }
-    }
+    data->module = local_trampoline.module;
 #endif
 
     retval = local_trampoline.start_address_ex(local_trampoline.arglist);
@@ -225,9 +225,21 @@ uintptr_t CDECL _beginthreadex(
   trampoline->start_address_ex = start_address;
   trampoline->arglist = arglist;
 
+#if _MSVCR_VER >= 140
+  if(!GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
+              (void*)start_address, &trampoline->module))
+  {
+     trampoline->module = NULL;
+     WARN("failed to get module for the start_address: %d\n", GetLastError());
+  }
+#endif
+
   thread = CreateThread(security, stack_size, _beginthreadex_trampoline,
           trampoline, initflag, thrdaddr);
   if(!thread) {
+#if _MSVCR_VER >= 140
+      FreeLibrary(trampoline->module);
+#endif
       free(trampoline);
       msvcrt_set_errno(GetLastError());
       return 0;




More information about the wine-cvs mailing list