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