Alexandre Julliard : ntdll: Allocate a separate 64-bit stack for Wow64 threads.
Alexandre Julliard
julliard at winehq.org
Mon May 17 15:45:29 CDT 2021
Module: wine
Branch: master
Commit: a8ff0c12f4ce60315156b9cbfd13291ad6cd4452
URL: https://source.winehq.org/git/wine.git/?a=commit;h=a8ff0c12f4ce60315156b9cbfd13291ad6cd4452
Author: Alexandre Julliard <julliard at 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 at 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 );
More information about the wine-cvs
mailing list