MSVCRT _beginthread[ex]() doesn't exhibit the same behavior.
Using ThreadExit() does leak the reference.
FreeLibraryAndExit() has to be used because the DLL may be the only user of the given CRT.
Signed-off-by: Arkadiusz Hiler ahiler@codeweavers.com --- dlls/msvcrt/msvcrt.h | 1 + dlls/msvcrt/thread.c | 44 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 43 insertions(+), 2 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 523e463d695..b796f7ac852 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,7 +79,13 @@ void CDECL _endthread(void) } else WARN("tls=%p tls->handle=%p\n", tls, tls ? tls->handle : INVALID_HANDLE_VALUE);
- /* FIXME */ +#if _MSVCR_VER >= 140 + if (tls && tls->module != NULL) + FreeLibraryAndExitThread(tls->module, 0); + else + WARN("tls=%p tls->module=%p\n", tls, tls ? tls->module : NULL); +#endif + ExitThread(0); }
@@ -88,7 +97,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 +123,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(); return 0; @@ -160,6 +188,18 @@ static DWORD CALLBACK _beginthreadex_trampoline(LPVOID arg) memcpy(&local_trampoline,arg,sizeof(local_trampoline)); 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);