From: Rose Hellsing <rose@pinkro.se> Applications may inline the IsThreadAFiber functions which check wether the FiberData field is the constant 0x1E00. Since Wine didn't set it to this value, applications would think the thread is a fiber and attempt to dereference the value, causing a segfault. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=59296 --- dlls/kernel32/tests/fiber.c | 28 ++++++++++++++++++++++++++++ dlls/kernelbase/thread.c | 9 +++++---- dlls/ntdll/unix/virtual.c | 6 ++++++ 3 files changed, 39 insertions(+), 4 deletions(-) diff --git a/dlls/kernel32/tests/fiber.c b/dlls/kernel32/tests/fiber.c index 9d730b3e65e..852b45974e9 100644 --- a/dlls/kernel32/tests/fiber.c +++ b/dlls/kernel32/tests/fiber.c @@ -180,6 +180,33 @@ static void test_ConvertFiberToThread(void) } } +/* Windows initialises NT_TIB.FiberData to 0x1E00 for non-fiber threads. + * Some applications inline IsThreadAFiber and dereference FiberData + * when it differs from this sentinel, so the value must match Windows exactly. + */ +static DWORD WINAPI fiberdata_sentinel_thread(void *arg) +{ + return (DWORD)(ULONG_PTR)NtCurrentTeb()->Tib.FiberData; +} + +static void test_FiberDataSentinel(void) +{ + HANDLE thread; + DWORD exit_code; + + ok(NtCurrentTeb()->Tib.FiberData == (void *)0x1E00, + "Tib.FiberData on main thread is %p, expected 0x1E00\n", + NtCurrentTeb()->Tib.FiberData); + + thread = CreateThread(NULL, 0, fiberdata_sentinel_thread, NULL, 0, NULL); + ok(thread != NULL, "CreateThread failed with error %lu\n", GetLastError()); + WaitForSingleObject(thread, INFINITE); + GetExitCodeThread(thread, &exit_code); + ok(exit_code == 0x1E00, + "Tib.FiberData on fresh thread is %#lx, expected 0x1E00\n", exit_code); + CloseHandle(thread); +} + static void test_FiberHandling(void) { fiberCount = 0; @@ -1086,6 +1113,7 @@ START_TEST(fiber) return; } + test_FiberDataSentinel(); test_FiberHandling(); test_FiberLocalStorage(); test_FiberLocalStorageCallback(FiberLocalStorageProc); diff --git a/dlls/kernelbase/thread.c b/dlls/kernelbase/thread.c index 13040915817..96042886c50 100644 --- a/dlls/kernelbase/thread.c +++ b/dlls/kernelbase/thread.c @@ -1151,10 +1151,10 @@ BOOL WINAPI DECLSPEC_HOTPATCH ConvertFiberToThread(void) { struct fiber_data *fiber = NtCurrentTeb()->Tib.FiberData; - if (fiber) + if (fiber && fiber != (void *)0x1E00) { relocate_thread_actctx_stack( &NtCurrentTeb()->ActivationContextStack ); - NtCurrentTeb()->Tib.FiberData = NULL; + NtCurrentTeb()->Tib.FiberData = (void *)0x1E00; HeapFree( GetProcessHeap(), 0, fiber ); } return TRUE; @@ -1177,7 +1177,7 @@ LPVOID WINAPI DECLSPEC_HOTPATCH ConvertThreadToFiberEx( LPVOID param, DWORD flag { struct fiber_data *fiber; - if (NtCurrentTeb()->Tib.FiberData) + if (NtCurrentTeb()->Tib.FiberData && NtCurrentTeb()->Tib.FiberData != (void *)0x1E00) { SetLastError( ERROR_ALREADY_FIBER ); return NULL; @@ -1228,7 +1228,8 @@ void WINAPI DECLSPEC_HOTPATCH DeleteFiber( LPVOID fiber_ptr ) */ BOOL WINAPI DECLSPEC_HOTPATCH IsThreadAFiber(void) { - return NtCurrentTeb()->Tib.FiberData != NULL; + void *fiber = NtCurrentTeb()->Tib.FiberData; + return fiber != NULL && fiber != (void *)0x1E00; } diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index a2ea5244b9f..a00023954e0 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -4001,6 +4001,9 @@ static TEB *init_teb( void *ptr, BOOL is_wow ) teb32->Peb = PtrToUlong( (char *)peb + page_size ); teb32->Tib.Self = PtrToUlong( teb32 ); teb32->Tib.ExceptionList = ~0u; + + /* non-fiber thread, needs to be set for some applications */ + teb32->Tib.FiberData = 0x1E00; teb32->ActivationContextStackPointer = PtrToUlong( &teb32->ActivationContextStack ); teb32->ActivationContextStack.FrameListCache.Flink = teb32->ActivationContextStack.FrameListCache.Blink = @@ -4013,9 +4016,11 @@ static TEB *init_teb( void *ptr, BOOL is_wow ) #else teb = (TEB *)teb32; teb32->Tib.ExceptionList = ~0u; + teb32->Tib.FiberData = 0x1E00; teb64->Peb = PtrToUlong( (char *)peb - page_size ); teb64->Tib.Self = PtrToUlong( teb64 ); teb64->Tib.ExceptionList = PtrToUlong( teb32 ); + teb64->Tib.FiberData = 0x1E00; teb64->ActivationContextStackPointer = PtrToUlong( &teb64->ActivationContextStack ); teb64->ActivationContextStack.FrameListCache.Flink = teb64->ActivationContextStack.FrameListCache.Blink = @@ -4032,6 +4037,7 @@ static TEB *init_teb( void *ptr, BOOL is_wow ) teb->Peb = peb; teb->Tib.Self = &teb->Tib; teb->Tib.StackBase = (void *)~0ul; + teb->Tib.FiberData = (void *)0x1E00; teb->ActivationContextStackPointer = &teb->ActivationContextStack; InitializeListHead( &teb->ActivationContextStack.FrameListCache ); teb->StaticUnicodeString.Buffer = teb->StaticUnicodeBuffer; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11027