Commit a8ff0c12 authored by Alexandre Julliard's avatar Alexandre Julliard

ntdll: Allocate a separate 64-bit stack for Wow64 threads.

parent 711bde7c
......@@ -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);
}
......
......@@ -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 );
......
......@@ -142,6 +142,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
*
* Update the output attributes.
......@@ -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;
......
......@@ -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;
......
......@@ -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 );
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment