diff --git a/patches/ntdll-FLS_Callbacks/0001-kernelbase-Maintain-FLS-storage-list-in-PEB.patch b/patches/ntdll-FLS_Callbacks/0001-kernelbase-Maintain-FLS-storage-list-in-PEB.patch new file mode 100644 index 00000000..1d5434bf --- /dev/null +++ b/patches/ntdll-FLS_Callbacks/0001-kernelbase-Maintain-FLS-storage-list-in-PEB.patch @@ -0,0 +1,322 @@ +From 5c370d9f0be803d89302da7471ef0b93b45a0d75 Mon Sep 17 00:00:00 2001 +From: Paul Gofman +Date: Thu, 23 Apr 2020 14:32:23 +0300 +Subject: [PATCH] kernelbase: Maintain FLS storage list in PEB. + +--- + dlls/kernel32/tests/fiber.c | 35 ++++++++++++++++++++ + dlls/kernel32/tests/thread.c | 2 -- + dlls/kernelbase/thread.c | 63 +++++++++++++++++++++++++++--------- + dlls/ntdll/loader.c | 46 ++++++++++++++++++++++++++ + 4 files changed, 129 insertions(+), 17 deletions(-) + +diff --git a/dlls/kernel32/tests/fiber.c b/dlls/kernel32/tests/fiber.c +index 7501165dc87..2bcc3ee60c4 100644 +--- a/dlls/kernel32/tests/fiber.c ++++ b/dlls/kernel32/tests/fiber.c +@@ -19,6 +19,7 @@ + */ + + #include "wine/test.h" ++#include + + static LPVOID (WINAPI *pCreateFiber)(SIZE_T,LPFIBER_START_ROUTINE,LPVOID); + static LPVOID (WINAPI *pConvertThreadToFiber)(LPVOID); +@@ -171,8 +172,25 @@ static void test_FiberHandling(void) + if (pIsThreadAFiber) ok(!pIsThreadAFiber(), "IsThreadAFiber reported TRUE\n"); + } + ++static unsigned int list_size(const LIST_ENTRY *le) ++{ ++ unsigned int count = 0; ++ LIST_ENTRY *entry; ++ ++ for (entry = le->Flink; entry != le; entry = entry->Flink) ++ ++count; ++ ++ return count; ++} ++ ++#define FLS_TEST_INDEX_COUNT 2048 ++ + static void test_FiberLocalStorage(void) + { ++ static DWORD fls_indices[FLS_TEST_INDEX_COUNT]; ++ TEB *teb = NtCurrentTeb(); ++ unsigned int i, count; ++ PEB *peb = teb->Peb; + DWORD fls, fls_2; + BOOL ret; + void* val; +@@ -183,6 +201,23 @@ static void test_FiberLocalStorage(void) + return; + } + ++ ok(!!teb->FlsSlots, "Got NULL teb->FlsSlots.\n"); ++ ok(!!peb->FlsCallback, "Got NULL peb->FlsCallback.\n"); ++ ++ count = list_size(&peb->FlsListHead); ++ ok(count == 1, "Got unexpected FLS list size %u.\n", count); ++ ++ for (i = 0; i < FLS_TEST_INDEX_COUNT; ++i) ++ { ++ if ((fls_indices[i] = pFlsAlloc(NULL)) == FLS_OUT_OF_INDEXES) ++ break; ++ } ++ count = i; ++ ok(count <= 127, "Could allocate %u FLS indices.\n", count); ++ ++ for (i = 0; i < count; ++i) ++ pFlsFree(fls_indices[i]); ++ + /* Test an unallocated index + * FlsFree should fail + * FlsGetValue and FlsSetValue should succeed +diff --git a/dlls/kernel32/tests/thread.c b/dlls/kernel32/tests/thread.c +index a454bf118cc..dac30959734 100644 +--- a/dlls/kernel32/tests/thread.c ++++ b/dlls/kernel32/tests/thread.c +@@ -2435,7 +2435,6 @@ START_TEST(thread) + } + return; + } +- + test_thread_info(); + test_reserved_tls(); + test_CreateRemoteThread(); +@@ -2463,6 +2462,5 @@ START_TEST(thread) + test_thread_fpu_cw(); + test_thread_actctx(); + test_thread_description(); +- + test_threadpool(); + } +diff --git a/dlls/kernelbase/thread.c b/dlls/kernelbase/thread.c +index 03b16da95bb..4409f120491 100644 +--- a/dlls/kernelbase/thread.c ++++ b/dlls/kernelbase/thread.c +@@ -38,6 +38,10 @@ + + WINE_DEFAULT_DEBUG_CHANNEL(thread); + ++static inline void **fls_addr_from_index(void *fls_slots, DWORD index) ++{ ++ return (void **)((BYTE *)fls_slots + sizeof(LIST_ENTRY)) + index; ++} + + /*********************************************************************** + * Threads +@@ -916,6 +920,19 @@ static void init_fiber_context( struct fiber_data *fiber ) + #endif + } + ++typedef void WINAPI (*FLS_LOCK_FUNCTION)(void *); ++ ++static void lock_fls_section(void) ++{ ++ if (NtCurrentTeb()->Peb->FlsCallback) ++ ((FLS_LOCK_FUNCTION)NtCurrentTeb()->Peb->FlsCallback[0])(NULL); ++} ++ ++static void unlock_fls_section(void) ++{ ++ if (NtCurrentTeb()->Peb->FlsCallback) ++ ((FLS_LOCK_FUNCTION)NtCurrentTeb()->Peb->FlsCallback[1])(NULL); ++} + + /*********************************************************************** + * CreateFiber (kernelbase.@) +@@ -1023,7 +1040,16 @@ void WINAPI DECLSPEC_HOTPATCH DeleteFiber( LPVOID fiber_ptr ) + RtlExitUserThread( 1 ); + } + RtlFreeUserStack( fiber->stack_allocation ); +- HeapFree( GetProcessHeap(), 0, fiber->fls_slots ); ++ ++ if (fiber->fls_slots) ++ { ++ lock_fls_section(); ++ RemoveEntryList( (LIST_ENTRY *)fiber->fls_slots ); ++ unlock_fls_section(); ++ ++ HeapFree( GetProcessHeap(), 0, fiber->fls_slots ); ++ } ++ + HeapFree( GetProcessHeap(), 0, fiber ); + } + +@@ -1045,6 +1071,19 @@ void WINAPI DECLSPEC_HOTPATCH SwitchToFiber( LPVOID fiber ) + struct fiber_data *new_fiber = fiber; + struct fiber_data *current_fiber = NtCurrentTeb()->Tib.u.FiberData; + ++ if (!new_fiber->fls_slots) ++ { ++ TEB *teb = NtCurrentTeb(); ++ PEB *peb = teb->Peb; ++ ++ new_fiber->fls_slots = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, ++ sizeof(LIST_ENTRY) + 8 * sizeof(peb->FlsBitmapBits) * sizeof(void*) ); ++ ++ lock_fls_section(); ++ InsertTailList(&peb->FlsListHead, (LIST_ENTRY *)new_fiber->fls_slots); ++ unlock_fls_section(); ++ } ++ + current_fiber->except = NtCurrentTeb()->Tib.ExceptionList; + current_fiber->stack_limit = NtCurrentTeb()->Tib.StackLimit; + current_fiber->fls_slots = NtCurrentTeb()->FlsSlots; +@@ -1070,9 +1109,7 @@ DWORD WINAPI DECLSPEC_HOTPATCH FlsAlloc( PFLS_CALLBACK_FUNCTION callback ) + PEB * const peb = NtCurrentTeb()->Peb; + + RtlAcquirePebLock(); +- if (!peb->FlsCallback && +- !(peb->FlsCallback = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, +- 8 * sizeof(peb->FlsBitmapBits) * sizeof(void*) ))) ++ if (!peb->FlsCallback) + { + SetLastError( ERROR_NOT_ENOUGH_MEMORY ); + index = FLS_OUT_OF_INDEXES; +@@ -1082,9 +1119,7 @@ DWORD WINAPI DECLSPEC_HOTPATCH FlsAlloc( PFLS_CALLBACK_FUNCTION callback ) + index = RtlFindClearBitsAndSet( peb->FlsBitmap, 1, 1 ); + if (index != ~0U) + { +- if (!NtCurrentTeb()->FlsSlots && +- !(NtCurrentTeb()->FlsSlots = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, +- 8 * sizeof(peb->FlsBitmapBits) * sizeof(void*) ))) ++ if (!NtCurrentTeb()->FlsSlots) + { + RtlClearBits( peb->FlsBitmap, index, 1 ); + index = FLS_OUT_OF_INDEXES; +@@ -1092,8 +1127,8 @@ DWORD WINAPI DECLSPEC_HOTPATCH FlsAlloc( PFLS_CALLBACK_FUNCTION callback ) + } + else + { +- NtCurrentTeb()->FlsSlots[index] = 0; /* clear the value */ +- peb->FlsCallback[index] = callback; ++ *fls_addr_from_index(NtCurrentTeb()->FlsSlots, index) = NULL; /* clear the value */ ++ peb->FlsCallback[index + 2] = callback; + } + } + else SetLastError( ERROR_NO_MORE_ITEMS ); +@@ -1117,7 +1152,7 @@ BOOL WINAPI DECLSPEC_HOTPATCH FlsFree( DWORD index ) + { + /* FIXME: call Fls callback */ + /* FIXME: add equivalent of ThreadZeroTlsCell here */ +- if (NtCurrentTeb()->FlsSlots) NtCurrentTeb()->FlsSlots[index] = 0; ++ if (NtCurrentTeb()->FlsSlots) *fls_addr_from_index(NtCurrentTeb()->FlsSlots, index) = NULL; + } + else SetLastError( ERROR_INVALID_PARAMETER ); + RtlReleasePebLock(); +@@ -1136,7 +1171,7 @@ PVOID WINAPI DECLSPEC_HOTPATCH FlsGetValue( DWORD index ) + return NULL; + } + SetLastError( ERROR_SUCCESS ); +- return NtCurrentTeb()->FlsSlots[index]; ++ return *fls_addr_from_index(NtCurrentTeb()->FlsSlots, index); + } + + +@@ -1150,14 +1185,12 @@ BOOL WINAPI DECLSPEC_HOTPATCH FlsSetValue( DWORD index, PVOID data ) + SetLastError( ERROR_INVALID_PARAMETER ); + return FALSE; + } +- if (!NtCurrentTeb()->FlsSlots && +- !(NtCurrentTeb()->FlsSlots = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, +- 8 * sizeof(NtCurrentTeb()->Peb->FlsBitmapBits) * sizeof(void*) ))) ++ if (!NtCurrentTeb()->FlsSlots) + { + SetLastError( ERROR_NOT_ENOUGH_MEMORY ); + return FALSE; + } +- NtCurrentTeb()->FlsSlots[index] = data; ++ *fls_addr_from_index(NtCurrentTeb()->FlsSlots, index) = data; + return TRUE; + } + +diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c +index 5e8de8821dd..71ef1cfea0a 100644 +--- a/dlls/ntdll/loader.c ++++ b/dlls/ntdll/loader.c +@@ -179,6 +179,15 @@ static CRITICAL_SECTION_DEBUG dlldir_critsect_debug = + }; + static CRITICAL_SECTION dlldir_section = { &dlldir_critsect_debug, -1, 0, 0, 0, 0 }; + ++static CRITICAL_SECTION fls_section; ++static CRITICAL_SECTION_DEBUG fls_critsect_debug = ++{ ++ 0, 0, &fls_section, ++ { &fls_critsect_debug.ProcessLocksList, &fls_critsect_debug.ProcessLocksList }, ++ 0, 0, { (DWORD_PTR)(__FILE__ ": fls_section") } ++}; ++static CRITICAL_SECTION fls_section = { &fls_critsect_debug, -1, 0, 0, 0, 0 };; ++ + static WINE_MODREF *cached_modref; + static WINE_MODREF *current_modref; + static WINE_MODREF *last_failed_modref; +@@ -219,6 +228,16 @@ static RTL_UNLOAD_EVENT_TRACE unload_traces[RTL_UNLOAD_EVENT_TRACE_NUMBER]; + static RTL_UNLOAD_EVENT_TRACE *unload_trace_ptr; + static unsigned int unload_trace_seq; + ++static void WINAPI lock_fls_section( PVOID dummy ) ++{ ++ RtlEnterCriticalSection( &fls_section ); ++} ++ ++static void WINAPI unlock_fls_section( PVOID dummy ) ++{ ++ RtlLeaveCriticalSection( &fls_section ); ++} ++ + static void module_push_unload_trace( const LDR_DATA_TABLE_ENTRY *ldr ) + { + RTL_UNLOAD_EVENT_TRACE *ptr = &unload_traces[unload_trace_seq]; +@@ -3913,6 +3932,13 @@ void WINAPI LdrShutdownThread(void) + /* don't do any detach calls if process is exiting */ + if (process_detaching) return; + ++ if (NtCurrentTeb()->FlsSlots) ++ { ++ lock_fls_section( NULL ); ++ RemoveEntryList( (LIST_ENTRY *)NtCurrentTeb()->FlsSlots ); ++ unlock_fls_section( NULL ); ++ } ++ + RtlEnterCriticalSection( &loader_section ); + + mark = &NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList; +@@ -4153,6 +4179,7 @@ static void user_shared_data_init(void) + */ + void WINAPI LdrInitializeThunk( CONTEXT *context, void **entry, ULONG_PTR unknown3, ULONG_PTR unknown4 ) + { ++ static const unsigned int fls_slot_count = 8 * sizeof(NtCurrentTeb()->Peb->FlsBitmapBits); + static const LARGE_INTEGER zero; + static int attach_done; + int i; +@@ -4191,6 +4218,25 @@ void WINAPI LdrInitializeThunk( CONTEXT *context, void **entry, ULONG_PTR unknow + InsertHeadList( &tls_links, &NtCurrentTeb()->TlsLinks ); + RtlReleasePebLock(); + ++ if (!NtCurrentTeb()->Peb->FlsCallback) ++ { ++ NtCurrentTeb()->Peb->FlsCallback = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, ++ (fls_slot_count + 2) * sizeof(void*) ); ++ if (!NtCurrentTeb()->Peb->FlsCallback) ++ ERR( "No memory for FLS callbacks.\n" ); ++ ++ if (NtCurrentTeb()->Peb->FlsCallback) ++ { ++ NtCurrentTeb()->Peb->FlsCallback[0] = lock_fls_section; ++ NtCurrentTeb()->Peb->FlsCallback[1] = unlock_fls_section; ++ } ++ } ++ NtCurrentTeb()->FlsSlots = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, ++ sizeof(LIST_ENTRY) + fls_slot_count * sizeof(void*) ); ++ lock_fls_section( NULL ); ++ InsertTailList(&NtCurrentTeb()->Peb->FlsListHead, (LIST_ENTRY *)NtCurrentTeb()->FlsSlots); ++ unlock_fls_section( NULL ); ++ + if (!attach_done) /* first time around */ + { + attach_done = 1; +-- +2.25.3 + diff --git a/patches/ntdll-FLS_Callbacks/0002-kernelbase-Don-t-use-PEB-lock-for-FLS-data.patch b/patches/ntdll-FLS_Callbacks/0002-kernelbase-Don-t-use-PEB-lock-for-FLS-data.patch new file mode 100644 index 00000000..462b0a55 --- /dev/null +++ b/patches/ntdll-FLS_Callbacks/0002-kernelbase-Don-t-use-PEB-lock-for-FLS-data.patch @@ -0,0 +1,52 @@ +From 55dbeff93ce46bfba9beaea7b9a67ba7fcd6df88 Mon Sep 17 00:00:00 2001 +From: Paul Gofman +Date: Thu, 23 Apr 2020 19:44:32 +0300 +Subject: [PATCH] kernelbase: Don't use PEB lock for FLS data. + +--- + dlls/kernelbase/thread.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/dlls/kernelbase/thread.c b/dlls/kernelbase/thread.c +index 4409f120491..0ba67e1b6c9 100644 +--- a/dlls/kernelbase/thread.c ++++ b/dlls/kernelbase/thread.c +@@ -1108,7 +1108,7 @@ DWORD WINAPI DECLSPEC_HOTPATCH FlsAlloc( PFLS_CALLBACK_FUNCTION callback ) + DWORD index; + PEB * const peb = NtCurrentTeb()->Peb; + +- RtlAcquirePebLock(); ++ lock_fls_section(); + if (!peb->FlsCallback) + { + SetLastError( ERROR_NOT_ENOUGH_MEMORY ); +@@ -1133,7 +1133,7 @@ DWORD WINAPI DECLSPEC_HOTPATCH FlsAlloc( PFLS_CALLBACK_FUNCTION callback ) + } + else SetLastError( ERROR_NO_MORE_ITEMS ); + } +- RtlReleasePebLock(); ++ unlock_fls_section(); + return index; + } + +@@ -1145,7 +1145,7 @@ BOOL WINAPI DECLSPEC_HOTPATCH FlsFree( DWORD index ) + { + BOOL ret; + +- RtlAcquirePebLock(); ++ lock_fls_section(); + ret = RtlAreBitsSet( NtCurrentTeb()->Peb->FlsBitmap, index, 1 ); + if (ret) RtlClearBits( NtCurrentTeb()->Peb->FlsBitmap, index, 1 ); + if (ret) +@@ -1155,7 +1155,7 @@ BOOL WINAPI DECLSPEC_HOTPATCH FlsFree( DWORD index ) + if (NtCurrentTeb()->FlsSlots) *fls_addr_from_index(NtCurrentTeb()->FlsSlots, index) = NULL; + } + else SetLastError( ERROR_INVALID_PARAMETER ); +- RtlReleasePebLock(); ++ unlock_fls_section(); + return ret; + } + +-- +2.25.3 + diff --git a/patches/ntdll-FLS_Callbacks/0003-kernelbase-Zero-all-FLS-slots-instances-in-FlsFree.patch b/patches/ntdll-FLS_Callbacks/0003-kernelbase-Zero-all-FLS-slots-instances-in-FlsFree.patch new file mode 100644 index 00000000..886ed1b4 --- /dev/null +++ b/patches/ntdll-FLS_Callbacks/0003-kernelbase-Zero-all-FLS-slots-instances-in-FlsFree.patch @@ -0,0 +1,46 @@ +From ee30a9aeb8db442a9cea52449959178f9d449d39 Mon Sep 17 00:00:00 2001 +From: Paul Gofman +Date: Thu, 23 Apr 2020 15:00:48 +0300 +Subject: [PATCH] kernelbase: Zero all FLS slots instances in FlsFree(). + +--- + dlls/kernelbase/thread.c | 15 ++++++++++----- + 1 file changed, 10 insertions(+), 5 deletions(-) + +diff --git a/dlls/kernelbase/thread.c b/dlls/kernelbase/thread.c +index 0ba67e1b6c9..9a65630cca7 100644 +--- a/dlls/kernelbase/thread.c ++++ b/dlls/kernelbase/thread.c +@@ -1137,7 +1137,6 @@ DWORD WINAPI DECLSPEC_HOTPATCH FlsAlloc( PFLS_CALLBACK_FUNCTION callback ) + return index; + } + +- + /*********************************************************************** + * FlsFree (kernelbase.@) + */ +@@ -1148,11 +1147,17 @@ BOOL WINAPI DECLSPEC_HOTPATCH FlsFree( DWORD index ) + lock_fls_section(); + ret = RtlAreBitsSet( NtCurrentTeb()->Peb->FlsBitmap, index, 1 ); + if (ret) RtlClearBits( NtCurrentTeb()->Peb->FlsBitmap, index, 1 ); +- if (ret) ++ if (ret && NtCurrentTeb()->FlsSlots) + { +- /* FIXME: call Fls callback */ +- /* FIXME: add equivalent of ThreadZeroTlsCell here */ +- if (NtCurrentTeb()->FlsSlots) *fls_addr_from_index(NtCurrentTeb()->FlsSlots, index) = NULL; ++ LIST_ENTRY *entry; ++ ++ for (entry = NtCurrentTeb()->Peb->FlsListHead.Flink; ++ entry != &NtCurrentTeb()->Peb->FlsListHead; ++ entry = entry->Flink) ++ { ++ /* FIXME: call Fls callback */ ++ *fls_addr_from_index(entry, index) = NULL; ++ } + } + else SetLastError( ERROR_INVALID_PARAMETER ); + unlock_fls_section(); +-- +2.25.3 + diff --git a/patches/ntdll-FLS_Callbacks/0004-ntdll-Call-FLS-callbacks-on-thread-shutdown.patch b/patches/ntdll-FLS_Callbacks/0004-ntdll-Call-FLS-callbacks-on-thread-shutdown.patch new file mode 100644 index 00000000..9549fa23 --- /dev/null +++ b/patches/ntdll-FLS_Callbacks/0004-ntdll-Call-FLS-callbacks-on-thread-shutdown.patch @@ -0,0 +1,120 @@ +From 7a474e95ad8cb82140e541a65b2bf338b42c3090 Mon Sep 17 00:00:00 2001 +From: Paul Gofman +Date: Thu, 23 Apr 2020 16:09:11 +0300 +Subject: [PATCH] ntdll: Call FLS callbacks on thread shutdown. + +--- + dlls/kernel32/tests/loader.c | 26 ++++++++------------------ + dlls/ntdll/loader.c | 30 ++++++++++++++++++++++++++++++ + 2 files changed, 38 insertions(+), 18 deletions(-) + +diff --git a/dlls/kernel32/tests/loader.c b/dlls/kernel32/tests/loader.c +index 3ed3351c02e..9cddfb82d51 100644 +--- a/dlls/kernel32/tests/loader.c ++++ b/dlls/kernel32/tests/loader.c +@@ -2520,18 +2520,12 @@ todo_wine + void* value; + SetLastError(0xdeadbeef); + value = pFlsGetValue(fls_index); +- todo_wine +- { +- ok(broken(value == (void*) 0x31415) || /* Win2k3 */ +- value == NULL, "FlsGetValue returned %p, expected NULL\n", value); +- } ++ ok(broken(value == (void*) 0x31415) || /* Win2k3 */ ++ value == NULL, "FlsGetValue returned %p, expected NULL\n", value); + ok(GetLastError() == ERROR_SUCCESS, "FlsGetValue failed with error %u\n", GetLastError()); +- todo_wine +- { +- ok(broken(fls_callback_count == thread_detach_count) || /* Win2k3 */ +- fls_callback_count == thread_detach_count + 1, +- "wrong FLS callback count %d, expected %d\n", fls_callback_count, thread_detach_count + 1); +- } ++ ok(broken(fls_callback_count == thread_detach_count) || /* Win2k3 */ ++ fls_callback_count == thread_detach_count + 1, ++ "wrong FLS callback count %d, expected %d\n", fls_callback_count, thread_detach_count + 1); + } + if (pFlsFree) + { +@@ -2726,8 +2720,7 @@ todo_wine + SetLastError(0xdeadbeef); + value = pFlsGetValue(fls_index); + ok(!value, "FlsGetValue returned %p, expected NULL\n", value); +- todo_wine +- ok(GetLastError() == ERROR_SUCCESS, "FlsGetValue failed with error %u\n", GetLastError()); ++ ok(GetLastError() == ERROR_SUCCESS, "FlsGetValue failed with error %u\n", GetLastError()); + ret = pFlsSetValue(fls_index, (void*) 0x31415); + ok(ret, "FlsSetValue failed\n"); + fls_count++; +@@ -2757,11 +2750,8 @@ todo_wine + void* value; + SetLastError(0xdeadbeef); + value = pFlsGetValue(fls_index); +- todo_wine +- { +- ok(broken(value == (void*) 0x31415) || /* Win2k3 */ +- !value, "FlsGetValue returned %p, expected NULL\n", value); +- } ++ ok(broken(value == (void*) 0x31415) || /* Win2k3 */ ++ !value, "FlsGetValue returned %p, expected NULL\n", value); + ok(GetLastError() == ERROR_SUCCESS, "FlsGetValue failed with error %u\n", GetLastError()); + } + +diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c +index 71ef1cfea0a..681b7f4b114 100644 +--- a/dlls/ntdll/loader.c ++++ b/dlls/ntdll/loader.c +@@ -1621,6 +1621,30 @@ static void attach_implicitly_loaded_dlls( LPVOID reserved ) + } + } + ++static void call_fls_callbacks(void) ++{ ++ PFLS_CALLBACK_FUNCTION *fls_callbacks; ++ PRTL_BITMAP fls_bitmap; ++ void **fls_slot_data; ++ DWORD fls_index; ++ ++ if ((fls_callbacks = (PFLS_CALLBACK_FUNCTION *)NtCurrentTeb()->Peb->FlsCallback) && NtCurrentTeb()->FlsSlots) ++ { ++ fls_slot_data = (void **)((BYTE *)NtCurrentTeb()->FlsSlots + sizeof(LIST_ENTRY)); ++ fls_bitmap = NtCurrentTeb()->Peb->FlsBitmap; ++ fls_index = 0; ++ for (fls_index = 0; fls_index < fls_bitmap->SizeOfBitMap; ++fls_index) ++ { ++ if (!RtlAreBitsSet( fls_bitmap, fls_index, 1 )) ++ continue; ++ ++ if (fls_callbacks[fls_index + 2] && fls_slot_data[fls_index]) ++ fls_callbacks[fls_index + 2](fls_slot_data[fls_index]); ++ ++ fls_slot_data[fls_index] = NULL; ++ } ++ } ++} + + /************************************************************************* + * process_detach +@@ -3898,6 +3922,11 @@ fail: + void WINAPI LdrShutdownProcess(void) + { + TRACE("()\n"); ++ ++ lock_fls_section(NULL); ++ call_fls_callbacks(); ++ unlock_fls_section(NULL); ++ + process_detaching = TRUE; + process_detach(); + } +@@ -3936,6 +3965,7 @@ void WINAPI LdrShutdownThread(void) + { + lock_fls_section( NULL ); + RemoveEntryList( (LIST_ENTRY *)NtCurrentTeb()->FlsSlots ); ++ call_fls_callbacks(); + unlock_fls_section( NULL ); + } + +-- +2.25.3 + diff --git a/patches/ntdll-FLS_Callbacks/0005-kernelbase-Call-FLS-callbacks-from-FlsFree.patch b/patches/ntdll-FLS_Callbacks/0005-kernelbase-Call-FLS-callbacks-from-FlsFree.patch new file mode 100644 index 00000000..220f72ca --- /dev/null +++ b/patches/ntdll-FLS_Callbacks/0005-kernelbase-Call-FLS-callbacks-from-FlsFree.patch @@ -0,0 +1,85 @@ +From f675a05f09d1173308ab138ffdfcaee125c3c0ba Mon Sep 17 00:00:00 2001 +From: Paul Gofman +Date: Thu, 23 Apr 2020 16:58:42 +0300 +Subject: [PATCH] kernelbase: Call FLS callbacks from FlsFree(). + +--- + dlls/kernel32/tests/fiber.c | 4 ++-- + dlls/kernel32/tests/loader.c | 7 ++----- + dlls/kernelbase/thread.c | 13 +++++++++++-- + 3 files changed, 15 insertions(+), 9 deletions(-) + +diff --git a/dlls/kernel32/tests/fiber.c b/dlls/kernel32/tests/fiber.c +index 2bcc3ee60c4..3aae0400d03 100644 +--- a/dlls/kernel32/tests/fiber.c ++++ b/dlls/kernel32/tests/fiber.c +@@ -344,7 +344,7 @@ static void test_FiberLocalStorageCallback(PFLS_CALLBACK_FUNCTION cbfunc) + + ret = pFlsFree( fls ); + ok(ret, "FlsFree failed with error %u\n", GetLastError() ); +- todo_wine ok( cbCount == 1, "Wrong callback count: %d\n", cbCount ); ++ ok( cbCount == 1, "Wrong callback count: %d\n", cbCount ); + + /* Test that callback is not executed if value is NULL */ + cbCount = 0; +@@ -416,7 +416,7 @@ static void test_FiberLocalStorageWithFibers(PFLS_CALLBACK_FUNCTION cbfunc) + fls_value_to_set = val2; + pFlsFree(fls_index_to_set); + ok(fiberCount == 0, "Wrong fiber count: %d\n", fiberCount); +- todo_wine ok(cbCount == 2, "Wrong callback count: %d\n", cbCount); ++ ok(cbCount == 2, "Wrong callback count: %d\n", cbCount); + + fiberCount = 0; + cbCount = 0; +diff --git a/dlls/kernel32/tests/loader.c b/dlls/kernel32/tests/loader.c +index 9cddfb82d51..21af7b4ce7a 100644 +--- a/dlls/kernel32/tests/loader.c ++++ b/dlls/kernel32/tests/loader.c +@@ -2534,11 +2534,8 @@ todo_wine + ret = pFlsFree(fls_index); + ok(ret, "FlsFree failed with error %u\n", GetLastError()); + fls_index = FLS_OUT_OF_INDEXES; +- todo_wine +- { +- ok(fls_callback_count == fls_count, +- "wrong FLS callback count %d, expected %d\n", fls_callback_count, fls_count); +- } ++ ok(fls_callback_count == fls_count, ++ "wrong FLS callback count %d, expected %d\n", fls_callback_count, fls_count); + } + + ok(attached_thread_count >= 2, "attached thread count should be >= 2\n"); +diff --git a/dlls/kernelbase/thread.c b/dlls/kernelbase/thread.c +index 9a65630cca7..40ba9ea4f07 100644 +--- a/dlls/kernelbase/thread.c ++++ b/dlls/kernelbase/thread.c +@@ -1149,15 +1149,24 @@ BOOL WINAPI DECLSPEC_HOTPATCH FlsFree( DWORD index ) + if (ret) RtlClearBits( NtCurrentTeb()->Peb->FlsBitmap, index, 1 ); + if (ret && NtCurrentTeb()->FlsSlots) + { ++ PFLS_CALLBACK_FUNCTION *fls_callbacks; + LIST_ENTRY *entry; + ++ fls_callbacks = (PFLS_CALLBACK_FUNCTION *)NtCurrentTeb()->Peb->FlsCallback; ++ + for (entry = NtCurrentTeb()->Peb->FlsListHead.Flink; + entry != &NtCurrentTeb()->Peb->FlsListHead; + entry = entry->Flink) + { +- /* FIXME: call Fls callback */ +- *fls_addr_from_index(entry, index) = NULL; ++ void **value_ptr = fls_addr_from_index(entry, index); ++ ++ if (fls_callbacks && fls_callbacks[index + 2] && *value_ptr) ++ fls_callbacks[index + 2](*value_ptr); ++ ++ *value_ptr = NULL; + } ++ if (fls_callbacks) ++ fls_callbacks[index + 2] = NULL; + } + else SetLastError( ERROR_INVALID_PARAMETER ); + unlock_fls_section(); +-- +2.25.3 + diff --git a/patches/ntdll-FLS_Callbacks/0006-kernelbase-Call-FLS-callbacks-from-DeleteFiber.patch b/patches/ntdll-FLS_Callbacks/0006-kernelbase-Call-FLS-callbacks-from-DeleteFiber.patch new file mode 100644 index 00000000..03e4d5f4 --- /dev/null +++ b/patches/ntdll-FLS_Callbacks/0006-kernelbase-Call-FLS-callbacks-from-DeleteFiber.patch @@ -0,0 +1,71 @@ +From 9bd8f42cf95582935440a622c76a4579ba3659f6 Mon Sep 17 00:00:00 2001 +From: Paul Gofman +Date: Thu, 23 Apr 2020 18:22:59 +0300 +Subject: [PATCH] kernelbase: Call FLS callbacks from DeleteFiber(). + +--- + dlls/kernel32/tests/fiber.c | 2 +- + dlls/kernelbase/thread.c | 26 +++++++++++++++++++++++++- + 2 files changed, 26 insertions(+), 2 deletions(-) + +diff --git a/dlls/kernel32/tests/fiber.c b/dlls/kernel32/tests/fiber.c +index 3aae0400d03..b6ae9cdc2f6 100644 +--- a/dlls/kernel32/tests/fiber.c ++++ b/dlls/kernel32/tests/fiber.c +@@ -409,7 +409,7 @@ static void test_FiberLocalStorageWithFibers(PFLS_CALLBACK_FUNCTION cbfunc) + fls_value_to_set = val1; + pDeleteFiber(fibers[1]); + ok(fiberCount == 0, "Wrong fiber count: %d\n", fiberCount); +- todo_wine ok(cbCount == 1, "Wrong callback count: %d\n", cbCount); ++ ok(cbCount == 1, "Wrong callback count: %d\n", cbCount); + + fiberCount = 0; + cbCount = 0; +diff --git a/dlls/kernelbase/thread.c b/dlls/kernelbase/thread.c +index 40ba9ea4f07..09dfe162e17 100644 +--- a/dlls/kernelbase/thread.c ++++ b/dlls/kernelbase/thread.c +@@ -1025,6 +1025,30 @@ LPVOID WINAPI DECLSPEC_HOTPATCH ConvertThreadToFiberEx( LPVOID param, DWORD flag + return fiber; + } + ++static void call_fls_callbacks(void **fls_slots) ++{ ++ PFLS_CALLBACK_FUNCTION *fls_callbacks; ++ PRTL_BITMAP fls_bitmap; ++ void **fls_slot_data; ++ DWORD fls_index; ++ ++ if ((fls_callbacks = (PFLS_CALLBACK_FUNCTION *)NtCurrentTeb()->Peb->FlsCallback)) ++ { ++ fls_slot_data = (void **)((BYTE *)fls_slots + sizeof(LIST_ENTRY)); ++ fls_bitmap = NtCurrentTeb()->Peb->FlsBitmap; ++ fls_index = 0; ++ for (fls_index = 0; fls_index < fls_bitmap->SizeOfBitMap; ++fls_index) ++ { ++ if (!RtlAreBitsSet( fls_bitmap, fls_index, 1 )) ++ continue; ++ ++ if (fls_callbacks[fls_index + 2] && fls_slot_data[fls_index]) ++ fls_callbacks[fls_index + 2](fls_slot_data[fls_index]); ++ ++ fls_slot_data[fls_index] = NULL; ++ } ++ } ++} + + /*********************************************************************** + * DeleteFiber (kernelbase.@) +@@ -1045,8 +1069,8 @@ void WINAPI DECLSPEC_HOTPATCH DeleteFiber( LPVOID fiber_ptr ) + { + lock_fls_section(); + RemoveEntryList( (LIST_ENTRY *)fiber->fls_slots ); ++ call_fls_callbacks(fiber->fls_slots); + unlock_fls_section(); +- + HeapFree( GetProcessHeap(), 0, fiber->fls_slots ); + } + +-- +2.25.3 + diff --git a/patches/ntdll-FLS_Callbacks/definition b/patches/ntdll-FLS_Callbacks/definition new file mode 100644 index 00000000..58bcbd9d --- /dev/null +++ b/patches/ntdll-FLS_Callbacks/definition @@ -0,0 +1,2 @@ +Fixes: [49012] Application build with .NET CoreRT crashes due to FLS callbacks not being called + diff --git a/patches/patchinstall.sh b/patches/patchinstall.sh index e2f6b7f2..716290d5 100755 --- a/patches/patchinstall.sh +++ b/patches/patchinstall.sh @@ -176,6 +176,7 @@ patch_enable_all () enable_ntdll_Dealloc_Thread_Stack="$1" enable_ntdll_DeviceType_Systemroot="$1" enable_ntdll_Exception="$1" + enable_ntdll_FLS_Callbacks="$1" enable_ntdll_FileDispositionInformation="$1" enable_ntdll_FileFsFullSizeInformation="$1" enable_ntdll_Fix_Alignment="$1" @@ -635,6 +636,9 @@ patch_enable () ntdll-Exception) enable_ntdll_Exception="$2" ;; + ntdll-FLS_Callbacks) + enable_ntdll_FLS_Callbacks="$2" + ;; ntdll-FileDispositionInformation) enable_ntdll_FileDispositionInformation="$2" ;; @@ -4521,6 +4525,32 @@ if test "$enable_ntdll_Exception" -eq 1; then ) >> "$patchlist" fi +# Patchset ntdll-FLS_Callbacks +# | +# | This patchset fixes the following Wine bugs: +# | * [#49012] Application build with .NET CoreRT crashes due to FLS callbacks not being called +# | +# | Modified files: +# | * dlls/kernel32/tests/fiber.c, dlls/kernel32/tests/loader.c, dlls/kernel32/tests/thread.c, dlls/kernelbase/thread.c, +# | dlls/ntdll/loader.c +# | +if test "$enable_ntdll_FLS_Callbacks" -eq 1; then + patch_apply ntdll-FLS_Callbacks/0001-kernelbase-Maintain-FLS-storage-list-in-PEB.patch + patch_apply ntdll-FLS_Callbacks/0002-kernelbase-Don-t-use-PEB-lock-for-FLS-data.patch + patch_apply ntdll-FLS_Callbacks/0003-kernelbase-Zero-all-FLS-slots-instances-in-FlsFree.patch + patch_apply ntdll-FLS_Callbacks/0004-ntdll-Call-FLS-callbacks-on-thread-shutdown.patch + patch_apply ntdll-FLS_Callbacks/0005-kernelbase-Call-FLS-callbacks-from-FlsFree.patch + patch_apply ntdll-FLS_Callbacks/0006-kernelbase-Call-FLS-callbacks-from-DeleteFiber.patch + ( + printf '%s\n' '+ { "Paul Gofman", "kernelbase: Maintain FLS storage list in PEB.", 1 },'; + printf '%s\n' '+ { "Paul Gofman", "kernelbase: Don'\''t use PEB lock for FLS data.", 1 },'; + printf '%s\n' '+ { "Paul Gofman", "kernelbase: Zero all FLS slots instances in FlsFree().", 1 },'; + printf '%s\n' '+ { "Paul Gofman", "ntdll: Call FLS callbacks on thread shutdown.", 1 },'; + printf '%s\n' '+ { "Paul Gofman", "kernelbase: Call FLS callbacks from FlsFree().", 1 },'; + printf '%s\n' '+ { "Paul Gofman", "kernelbase: Call FLS callbacks from DeleteFiber().", 1 },'; + ) >> "$patchlist" +fi + # Patchset ntdll-FileFsFullSizeInformation # | # | Modified files: