Module: wine Branch: master Commit: a8ff0c12f4ce60315156b9cbfd13291ad6cd4452 URL: https://source.winehq.org/git/wine.git/?a=commit;h=a8ff0c12f4ce60315156b9cbf...
Author: Alexandre Julliard julliard@winehq.org Date: Mon May 17 09:58:46 2021 +0200
ntdll: Allocate a separate 64-bit stack for Wow64 threads.
Signed-off-by: Alexandre Julliard julliard@winehq.org
---
dlls/ntdll/tests/exception.c | 25 +++++++++++++++++++++++-- dlls/ntdll/unix/loader.c | 6 +----- dlls/ntdll/unix/thread.c | 41 +++++++++++++++++++++++++++++++++++------ dlls/ntdll/unix/unix_private.h | 2 ++ dlls/ntdll/unix/virtual.c | 15 +++++++++++++++ 5 files changed, 76 insertions(+), 13 deletions(-)
diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c index d6565c12fce..d784074394a 100644 --- a/dlls/ntdll/tests/exception.c +++ b/dlls/ntdll/tests/exception.c @@ -3745,18 +3745,20 @@ static void test_thread_context(void)
static void test_wow64_context(void) { - char cmdline[] = "C:\windows\syswow64\notepad.exe"; + THREAD_BASIC_INFORMATION info; PROCESS_INFORMATION pi; STARTUPINFOA si = {0}; WOW64_CONTEXT ctx; NTSTATUS ret; + SIZE_T res; + TEB teb;
memset(&ctx, 0x55, sizeof(ctx)); ctx.ContextFlags = WOW64_CONTEXT_ALL; ret = pRtlWow64GetThreadContext( GetCurrentThread(), &ctx ); ok(ret == STATUS_INVALID_PARAMETER || broken(ret == STATUS_PARTIAL_COPY), "got %#x\n", ret);
- CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi); + CreateProcessA("C:\windows\syswow64\notepad.exe", NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi);
ret = pRtlWow64GetThreadContext( pi.hThread, &ctx ); ok(ret == STATUS_SUCCESS, "got %#x\n", ret); @@ -3775,6 +3777,25 @@ static void test_wow64_context(void) ret = pRtlWow64SetThreadContext( pi.hThread, &ctx ); ok(ret == STATUS_SUCCESS, "got %#x\n", ret);
+ pNtQueryInformationThread( pi.hThread, ThreadBasicInformation, &info, sizeof(info), NULL ); + if (!ReadProcessMemory( pi.hProcess, info.TebBaseAddress, &teb, sizeof(teb), &res )) res = 0; + ok( res == sizeof(teb), "wrong len %lx\n", res ); + + if (teb.WowTebOffset > 1) + { + TEB32 teb32; + if (!ReadProcessMemory( pi.hProcess, (char *)info.TebBaseAddress + teb.WowTebOffset, + &teb32, sizeof(teb32), &res )) res = 0; + ok( res == sizeof(teb32), "wrong len %lx\n", res ); + + ok( ((ctx.Esp + 0xfff) & ~0xfff) == teb32.Tib.StackBase, + "esp is not at top of stack: %08x / %08x\n", ctx.Esp, teb32.Tib.StackBase ); + ok( ULongToPtr( teb32.Tib.StackBase ) <= teb.DeallocationStack || + ULongToPtr( teb32.DeallocationStack ) >= teb.Tib.StackBase, + "stacks overlap %08x-%08x / %p-%p\n", teb32.DeallocationStack, teb32.Tib.StackBase, + teb.DeallocationStack, teb.Tib.StackBase ); + } + pNtTerminateProcess(pi.hProcess, 0); }
diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index 1f1e6bc2796..1b79b71b252 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -1853,7 +1853,6 @@ static struct unix_funcs unix_funcs = static void start_main_thread(void) { NTSTATUS status; - INITIAL_TEB stack; TEB *teb = virtual_alloc_first_teb();
signal_init_threading(); @@ -1871,10 +1870,7 @@ static void start_main_thread(void) if (p___wine_main_argv) *p___wine_main_argv = main_argv; if (p___wine_main_wargv) *p___wine_main_wargv = main_wargv; set_load_order_app_name( main_wargv[0] ); - virtual_alloc_thread_stack( &stack, is_win64 ? 0x7fffffff : 0, 0, 0, NULL ); - teb->Tib.StackBase = stack.StackBase; - teb->Tib.StackLimit = stack.StackLimit; - teb->DeallocationStack = stack.DeallocationStack; + init_thread_stack( teb, is_win64 ? 0x7fffffff : 0, 0, 0, NULL ); NtCreateKeyedEvent( &keyed_event, GENERIC_READ | GENERIC_WRITE, NULL, 0 ); load_ntdll(); status = p__wine_set_unix_funcs( NTDLL_UNIXLIB_VERSION, &unix_funcs ); diff --git a/dlls/ntdll/unix/thread.c b/dlls/ntdll/unix/thread.c index 079ac16952d..d2c14ae33c1 100644 --- a/dlls/ntdll/unix/thread.c +++ b/dlls/ntdll/unix/thread.c @@ -141,6 +141,40 @@ void set_thread_id( TEB *teb, DWORD pid, DWORD tid ) }
+/*********************************************************************** + * init_thread_stack + */ +NTSTATUS init_thread_stack( TEB *teb, ULONG_PTR zero_bits, SIZE_T reserve_size, + SIZE_T commit_size, SIZE_T *pthread_size ) +{ + INITIAL_TEB stack, stack64; + NTSTATUS status; + + if ((status = virtual_alloc_thread_stack( &stack, zero_bits, reserve_size, commit_size, pthread_size ))) + return status; + + if (teb->WowTebOffset && !(status = virtual_alloc_thread_stack( &stack64, 0, 0x40000, 0x40000, NULL ))) + { +#ifdef _WIN64 + TEB32 *teb32 = (TEB32 *)((char *)teb + teb->WowTebOffset); + teb32->Tib.StackBase = PtrToUlong( stack.StackBase ); + teb32->Tib.StackLimit = PtrToUlong( stack.StackLimit ); + teb32->DeallocationStack = PtrToUlong( stack.DeallocationStack ); + stack = stack64; +#else + TEB64 *teb64 = (TEB64 *)((char *)teb + teb->WowTebOffset); + teb64->Tib.StackBase = PtrToUlong( stack64.StackBase ); + teb64->Tib.StackLimit = PtrToUlong( stack64.StackLimit ); + teb64->DeallocationStack = PtrToUlong( stack64.DeallocationStack ); +#endif + } + teb->Tib.StackBase = stack.StackBase; + teb->Tib.StackLimit = stack.StackLimit; + teb->DeallocationStack = stack.DeallocationStack; + return status; +} + + /*********************************************************************** * update_attr_list * @@ -196,7 +230,6 @@ NTSTATUS WINAPI NtCreateThreadEx( HANDLE *handle, ACCESS_MASK access, OBJECT_ATT int request_pipe[2]; SIZE_T extra_stack = PTHREAD_STACK_MIN; TEB *teb; - INITIAL_TEB stack; NTSTATUS status;
if (zero_bits > 21 && zero_bits < 32) return STATUS_INVALID_PARAMETER_3; @@ -269,7 +302,7 @@ NTSTATUS WINAPI NtCreateThreadEx( HANDLE *handle, ACCESS_MASK access, OBJECT_ATT
if ((status = virtual_alloc_teb( &teb ))) goto done;
- if ((status = virtual_alloc_thread_stack( &stack, zero_bits, stack_reserve, stack_commit, &extra_stack ))) + if ((status = init_thread_stack( teb, zero_bits, stack_reserve, stack_commit, &extra_stack ))) { virtual_free_teb( teb ); goto done; @@ -277,10 +310,6 @@ NTSTATUS WINAPI NtCreateThreadEx( HANDLE *handle, ACCESS_MASK access, OBJECT_ATT
set_thread_id( teb, GetCurrentProcessId(), tid );
- teb->Tib.StackBase = stack.StackBase; - teb->Tib.StackLimit = stack.StackLimit; - teb->DeallocationStack = stack.DeallocationStack; - thread_data = (struct ntdll_thread_data *)&teb->GdiTebBatch; thread_data->request_fd = request_pipe[1]; thread_data->start_stack = (char *)teb->Tib.StackBase; diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index 5c340107964..cdb36584326 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -173,6 +173,8 @@ extern void server_init_thread( void *entry_point, BOOL *suspend ) DECLSPEC_HIDD extern int server_pipe( int fd[2] ) DECLSPEC_HIDDEN;
extern void set_thread_id( TEB *teb, DWORD pid, DWORD tid ) DECLSPEC_HIDDEN; +extern NTSTATUS init_thread_stack( TEB *teb, ULONG_PTR zero_bits, SIZE_T reserve_size, + SIZE_T commit_size, SIZE_T *pthread_size ) DECLSPEC_HIDDEN; extern NTSTATUS context_to_server( context_t *to, const CONTEXT *from ) DECLSPEC_HIDDEN; extern NTSTATUS context_from_server( CONTEXT *to, const context_t *from ) DECLSPEC_HIDDEN; extern void DECLSPEC_NORETURN abort_thread( int status ) DECLSPEC_HIDDEN; diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index bcecc21989a..572ce960b77 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -2997,6 +2997,21 @@ void virtual_free_teb( TEB *teb ) size = 0; NtFreeVirtualMemory( GetCurrentProcess(), &thread_data->start_stack, &size, MEM_RELEASE ); } + if (teb->WowTebOffset) + { +#ifdef _WIN64 + TEB32 *teb32 = (TEB32 *)((char *)teb + teb->WowTebOffset); + void *addr = ULongToPtr( teb32->DeallocationStack ); +#else + TEB64 *teb64 = (TEB64 *)((char *)teb + teb->WowTebOffset); + void *addr = ULongToPtr( teb64->DeallocationStack ); +#endif + if (addr) + { + size = 0; + NtFreeVirtualMemory( GetCurrentProcess(), &addr, &size, MEM_RELEASE ); + } + }
server_enter_uninterrupted_section( &virtual_mutex, &sigset ); list_remove( &thread_data->entry );