[PATCH 6/7] msvcrt: Make UCRT _beginthread[ex]() hold the DLL reference.

Arkadiusz Hiler ahiler at codeweavers.com
Tue May 4 06:49:40 CDT 2021


MSVCRT's _beginthread[ex]() doesn't exhibit the same behavior and using
ThreadExit() does leak the reference.

FreeLibraryAndExit() has to be used because the DLL may be the only user
of the given CRT.

This fixes Baldur's Gate 3 crashing shortly after launch.

Signed-off-by: Arkadiusz Hiler <ahiler at codeweavers.com>
---
 dlls/msvcrt/msvcrt.h |  1 +
 dlls/msvcrt/thread.c | 39 ++++++++++++++++++++++++++++++++++++---
 2 files changed, 37 insertions(+), 3 deletions(-)

diff --git a/dlls/msvcrt/msvcrt.h b/dlls/msvcrt/msvcrt.h
index 8f6ee08ef2a..c84e0a0a638 100644
--- a/dlls/msvcrt/msvcrt.h
+++ b/dlls/msvcrt/msvcrt.h
@@ -167,6 +167,7 @@ struct __thread_data {
     void                           *unk10[100];
 #if _MSVCR_VER >= 140
     _invalid_parameter_handler      invalid_parameter_handler;
+    HMODULE                         module;
 #endif
 };
 
diff --git a/dlls/msvcrt/thread.c b/dlls/msvcrt/thread.c
index 9c0a5e414ad..c106548adc1 100644
--- a/dlls/msvcrt/thread.c
+++ b/dlls/msvcrt/thread.c
@@ -54,6 +54,9 @@ thread_data_t *CDECL msvcrt_get_thread_data(void)
         ptr->random_seed = 1;
         ptr->locinfo = MSVCRT_locale->locinfo;
         ptr->mbcinfo = MSVCRT_locale->mbcinfo;
+#if _MSVCR_VER >= 140
+        ptr->module = NULL;
+#endif
     }
     SetLastError( err );
     return ptr;
@@ -76,8 +79,7 @@ void CDECL _endthread(void)
   } else
       WARN("tls=%p tls->handle=%p\n", tls, tls ? tls->handle : INVALID_HANDLE_VALUE);
 
-  /* FIXME */
-  ExitThread(0);
+  _endthreadex(0);
 }
 
 /*********************************************************************
@@ -88,7 +90,17 @@ void CDECL _endthreadex(
 {
   TRACE("(%d)\n", retval);
 
-  /* FIXME */
+#if _MSVCR_VER >= 140
+  {
+      thread_data_t *tls = TlsGetValue(msvcrt_tls_index);
+
+      if (tls && tls->module != NULL)
+          FreeLibraryAndExitThread(tls->module, retval);
+      else
+          WARN("tls=%p tls->module=%p\n", tls, tls ? tls->module : NULL);
+  }
+#endif
+
   ExitThread(retval);
 }
 
@@ -104,6 +116,15 @@ static DWORD CALLBACK _beginthread_trampoline(LPVOID arg)
     data->handle = local_trampoline.thread;
     free(arg);
 
+#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());
+    }
+#endif
+
     local_trampoline.start_address(local_trampoline.arglist);
     _endthread();
 }
@@ -166,6 +187,18 @@ static DWORD CALLBACK _beginthreadex_trampoline(LPVOID arg)
     data->handle = local_trampoline.thread;
     free(arg);
 
+#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());
+        }
+    }
+#endif
+
     retval = local_trampoline.start_address_ex(local_trampoline.arglist);
     _endthreadex(retval);
 }
-- 
2.31.1




More information about the wine-devel mailing list