From 7a474e95ad8cb82140e541a65b2bf338b42c3090 Mon Sep 17 00:00:00 2001
From: Paul Gofman <pgofman@codeweavers.com>
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

