Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/ntdll/loader.c | 7 ++++++- dlls/ntdll/ntdll.spec | 3 ++- dlls/ntdll/ntdll_misc.h | 2 +- dlls/ntdll/thread.c | 7 ++++++- dlls/ntdll/virtual.c | 46 +++++++++++++++++++++++++++++++++++++---- include/winternl.h | 12 ++++++----- 6 files changed, 64 insertions(+), 13 deletions(-)
diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c index 3f422a9c0bee..3d747edaba3b 100644 --- a/dlls/ntdll/loader.c +++ b/dlls/ntdll/loader.c @@ -3787,6 +3787,7 @@ void __wine_process_init(void) ANSI_STRING func_name; UNICODE_STRING nt_name; void * (CDECL *init_func)(void); + INITIAL_TEB stack;
thread_init();
@@ -3838,11 +3839,15 @@ void __wine_process_init(void) RemoveEntryList( &wm->ldr.InMemoryOrderModuleList ); InsertHeadList( &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList, &wm->ldr.InMemoryOrderModuleList );
- if ((status = virtual_alloc_thread_stack( NtCurrentTeb(), 0, 0, NULL )) != STATUS_SUCCESS) + if ((status = virtual_alloc_thread_stack( &stack, 0, 0, NULL )) != STATUS_SUCCESS) { ERR( "Main exe initialization for %s failed, status %x\n", debugstr_w(wm->ldr.FullDllName.Buffer), status ); NtTerminateProcess( GetCurrentProcess(), status ); } + NtCurrentTeb()->Tib.StackBase = stack.StackBase; + NtCurrentTeb()->Tib.StackLimit = stack.StackLimit; + NtCurrentTeb()->DeallocationStack = stack.DeallocationStack; + server_init_process_done(); } diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index aeb9735ba100..e0def228de07 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -526,6 +526,7 @@ @ stdcall RtlCreateUnicodeStringFromAsciiz(ptr str) @ stdcall RtlCreateUserProcess(ptr long ptr ptr ptr long long long long ptr) @ stub RtlCreateUserSecurityObject +@ stdcall RtlCreateUserStack(long long long long long ptr) @ stdcall RtlCreateUserThread(long ptr long ptr long long ptr ptr ptr ptr) @ stub RtlCustomCPToUnicodeN @ stub RtlCutoverTimeToSystemTime @@ -644,7 +645,7 @@ @ stdcall RtlFreeSid (ptr) @ stdcall RtlFreeThreadActivationContextStack() @ stdcall RtlFreeUnicodeString(ptr) -@ stub RtlFreeUserThreadStack +@ stdcall RtlFreeUserStack(ptr) @ stdcall RtlGUIDFromString(ptr ptr) @ stub RtlGenerate8dot3Name @ stdcall RtlGetAce(ptr long ptr) diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h index 3463ebd38adc..d1b895cd364a 100644 --- a/dlls/ntdll/ntdll_misc.h +++ b/dlls/ntdll/ntdll_misc.h @@ -173,7 +173,7 @@ extern NTSTATUS virtual_map_section( HANDLE handle, PVOID *addr_ptr, ULONG zero_ pe_image_info_t *image_info ) DECLSPEC_HIDDEN; extern void virtual_get_system_info( SYSTEM_BASIC_INFORMATION *info ) DECLSPEC_HIDDEN; extern NTSTATUS virtual_create_builtin_view( void *base ) DECLSPEC_HIDDEN; -extern NTSTATUS virtual_alloc_thread_stack( TEB *teb, SIZE_T reserve_size, +extern NTSTATUS virtual_alloc_thread_stack( INITIAL_TEB *stack, SIZE_T reserve_size, SIZE_T commit_size, SIZE_T *pthread_size ) DECLSPEC_HIDDEN; extern void virtual_clear_thread_stack( void *stack_end ) DECLSPEC_HIDDEN; extern BOOL virtual_handle_stack_fault( void *addr ) DECLSPEC_HIDDEN; diff --git a/dlls/ntdll/thread.c b/dlls/ntdll/thread.c index 46de839400d2..f612d135273f 100644 --- a/dlls/ntdll/thread.c +++ b/dlls/ntdll/thread.c @@ -416,6 +416,7 @@ NTSTATUS WINAPI RtlCreateUserThread( HANDLE process, SECURITY_DESCRIPTOR *descr, SIZE_T extra_stack = PTHREAD_STACK_MIN; data_size_t len = 0; struct object_attributes *objattr = NULL; + INITIAL_TEB stack;
if (process != NtCurrentProcess()) { @@ -507,9 +508,13 @@ NTSTATUS WINAPI RtlCreateUserThread( HANDLE process, SECURITY_DESCRIPTOR *descr, info->entry_point = start; info->entry_arg = param;
- if ((status = virtual_alloc_thread_stack( teb, stack_reserve, stack_commit, &extra_stack ))) + if ((status = virtual_alloc_thread_stack( &stack, stack_reserve, stack_commit, &extra_stack ))) goto error;
+ 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->reply_fd = -1; diff --git a/dlls/ntdll/virtual.c b/dlls/ntdll/virtual.c index 78973a8cda43..a3ea195c917b 100644 --- a/dlls/ntdll/virtual.c +++ b/dlls/ntdll/virtual.c @@ -1924,7 +1924,7 @@ NTSTATUS virtual_create_builtin_view( void *module ) /*********************************************************************** * virtual_alloc_thread_stack */ -NTSTATUS virtual_alloc_thread_stack( TEB *teb, SIZE_T reserve_size, SIZE_T commit_size, SIZE_T *pthread_size ) +NTSTATUS virtual_alloc_thread_stack( INITIAL_TEB *stack, SIZE_T reserve_size, SIZE_T commit_size, SIZE_T *pthread_size ) { struct file_view *view; NTSTATUS status; @@ -1978,9 +1978,11 @@ NTSTATUS virtual_alloc_thread_stack( TEB *teb, SIZE_T reserve_size, SIZE_T commi }
/* note: limit is lower than base since the stack grows down */ - teb->DeallocationStack = view->base; - teb->Tib.StackBase = (char *)view->base + view->size; - teb->Tib.StackLimit = (char *)view->base + 2 * page_size; + stack->OldStackBase = 0; + stack->OldStackLimit = 0; + stack->DeallocationStack = view->base; + stack->StackBase = (char *)view->base + view->size; + stack->StackLimit = (char *)view->base + 2 * page_size; done: server_leave_uninterrupted_section( &csVirtual, &sigset ); return status; @@ -2001,6 +2003,42 @@ void virtual_clear_thread_stack( void *stack_end ) if (force_exec_prot) mprotect( stack, size, PROT_READ | PROT_WRITE | PROT_EXEC ); }
+/********************************************************************** + * RtlCreateUserStack (NTDLL.@) + */ +NTSTATUS WINAPI RtlCreateUserStack( SIZE_T commit, SIZE_T reserve, ULONG zero_bits, + SIZE_T commit_align, SIZE_T reserve_align, INITIAL_TEB *stack ) +{ + TRACE("commit %#lx, reserve %#lx, zero_bits %u, commit_align %#lx, reserve_align %#lx, stack %p\n", + commit, reserve, zero_bits, commit_align, reserve_align, stack); + + if (!commit_align || !reserve_align) + return STATUS_INVALID_PARAMETER; + + if (!commit || !reserve) + { + IMAGE_NT_HEADERS *nt = RtlImageNtHeader( NtCurrentTeb()->Peb->ImageBaseAddress ); + if (!reserve) reserve = nt->OptionalHeader.SizeOfStackReserve; + if (!commit) commit = nt->OptionalHeader.SizeOfStackCommit; + } + + reserve = (reserve + reserve_align - 1) & ~(reserve_align - 1); + commit = (commit + commit_align - 1) & ~(commit_align - 1); + + return virtual_alloc_thread_stack( stack, reserve, commit, NULL ); +} + +/********************************************************************** + * RtlFreeUserStack (NTDLL.@) + */ +void WINAPI RtlFreeUserStack( void *stack ) +{ + SIZE_T size = 0; + + TRACE("stack %p\n", stack); + + NtFreeVirtualMemory( NtCurrentProcess(), &stack, &size, MEM_RELEASE ); +}
/*********************************************************************** * virtual_handle_fault diff --git a/include/winternl.h b/include/winternl.h index e7f89b005922..b87aa2298c6b 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -2104,11 +2104,11 @@ typedef struct _DIRECTORY_BASIC_INFORMATION { } DIRECTORY_BASIC_INFORMATION, *PDIRECTORY_BASIC_INFORMATION;
typedef struct _INITIAL_TEB { - PVOID StackBase; - PVOID StackLimit; - PVOID StackCommit; - PVOID StackCommitMax; - PVOID StackReserved; + void *OldStackBase; + void *OldStackLimit; + void *StackBase; + void *StackLimit; + void *DeallocationStack; } INITIAL_TEB, *PINITIAL_TEB;
typedef enum _PORT_INFORMATION_CLASS { @@ -2618,6 +2618,7 @@ NTSYSAPI BOOLEAN WINAPI RtlCreateUnicodeString(PUNICODE_STRING,LPCWSTR); NTSYSAPI BOOLEAN WINAPI RtlCreateUnicodeStringFromAsciiz(PUNICODE_STRING,LPCSTR); NTSYSAPI NTSTATUS WINAPI RtlCreateUserProcess(UNICODE_STRING*,ULONG,RTL_USER_PROCESS_PARAMETERS*,SECURITY_DESCRIPTOR*,SECURITY_DESCRIPTOR*,HANDLE,BOOLEAN,HANDLE,HANDLE,RTL_USER_PROCESS_INFORMATION*); NTSYSAPI NTSTATUS WINAPI RtlCreateUserThread(HANDLE,SECURITY_DESCRIPTOR*,BOOLEAN,PVOID,SIZE_T,SIZE_T,PRTL_THREAD_START_ROUTINE,void*,HANDLE*,CLIENT_ID*); +NTSYSAPI NTSTATUS WINAPI RtlCreateUserStack(SIZE_T,SIZE_T,ULONG,SIZE_T,SIZE_T,INITIAL_TEB*); NTSYSAPI void WINAPI RtlDeactivateActivationContext(DWORD,ULONG_PTR); NTSYSAPI PVOID WINAPI RtlDecodePointer(PVOID); NTSYSAPI NTSTATUS WINAPI RtlDecompressBuffer(USHORT,PUCHAR,ULONG,PUCHAR,ULONG,PULONG); @@ -2691,6 +2692,7 @@ NTSYSAPI void WINAPI RtlFreeOemString(POEM_STRING); NTSYSAPI DWORD WINAPI RtlFreeSid(PSID); NTSYSAPI void WINAPI RtlFreeThreadActivationContextStack(void); NTSYSAPI void WINAPI RtlFreeUnicodeString(PUNICODE_STRING); +NTSYSAPI void WINAPI RtlFreeUserStack(void*); NTSYSAPI NTSTATUS WINAPI RtlGetAce(PACL,DWORD,LPVOID *); NTSYSAPI NTSTATUS WINAPI RtlGetActiveActivationContext(HANDLE*); NTSYSAPI NTSTATUS WINAPI RtlGetCompressionWorkSpaceSize(USHORT,PULONG,PULONG);
Planet Coaster allocates 128kB of stack (both reserve and commit) but expects to be able to use at least one page more than that. Native Windows always reserves at least 1MB of stack.
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/kernel32/fiber.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-)
diff --git a/dlls/kernel32/fiber.c b/dlls/kernel32/fiber.c index 151a6765a8bf..27abd78760c8 100644 --- a/dlls/kernel32/fiber.c +++ b/dlls/kernel32/fiber.c @@ -89,6 +89,8 @@ LPVOID WINAPI CreateFiberEx( SIZE_T stack_commit, SIZE_T stack_reserve, DWORD fl LPFIBER_START_ROUTINE start, LPVOID param ) { struct fiber_data *fiber; + INITIAL_TEB stack; + NTSTATUS status;
if (!(fiber = HeapAlloc( GetProcessHeap(), 0, sizeof(*fiber) ))) { @@ -96,15 +98,15 @@ LPVOID WINAPI CreateFiberEx( SIZE_T stack_commit, SIZE_T stack_reserve, DWORD fl return NULL; }
- /* FIXME: should use the thread stack allocation routines here */ - if (!stack_reserve) stack_reserve = 1024*1024; - if(!(fiber->stack_allocation = VirtualAlloc( 0, stack_reserve, MEM_COMMIT, PAGE_READWRITE ))) + if ((status = RtlCreateUserStack( stack_commit, stack_reserve, 0, 1, 1, &stack ))) { - HeapFree( GetProcessHeap(), 0, fiber ); + SetLastError( RtlNtStatusToDosError(status) ); return NULL; } - fiber->stack_base = (char *)fiber->stack_allocation + stack_reserve; - fiber->stack_limit = fiber->stack_allocation; + + fiber->stack_allocation = stack.DeallocationStack; + fiber->stack_base = stack.StackBase; + fiber->stack_limit = stack.StackLimit; fiber->param = param; fiber->except = (void *)-1; fiber->start = start; @@ -127,7 +129,7 @@ void WINAPI DeleteFiber( LPVOID fiber_ptr ) HeapFree( GetProcessHeap(), 0, fiber ); ExitThread(1); } - VirtualFree( fiber->stack_allocation, 0, MEM_RELEASE ); + RtlFreeUserStack( fiber->stack_allocation ); HeapFree( GetProcessHeap(), 0, fiber->fls_slots ); HeapFree( GetProcessHeap(), 0, fiber ); }
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/ntdll/tests/Makefile.in | 1 + dlls/ntdll/tests/virtual.c | 74 ++++++++++++++++++++++++++++++++++-- 2 files changed, 72 insertions(+), 3 deletions(-)
diff --git a/dlls/ntdll/tests/Makefile.in b/dlls/ntdll/tests/Makefile.in index ed15c51339f3..b0aa94a6496e 100644 --- a/dlls/ntdll/tests/Makefile.in +++ b/dlls/ntdll/tests/Makefile.in @@ -1,5 +1,6 @@ TESTDLL = ntdll.dll IMPORTS = user32 advapi32 +EXTRADLLFLAGS = -Xlinker --stack=0x300000,0x3000
C_SRCS = \ atom.c \ diff --git a/dlls/ntdll/tests/virtual.c b/dlls/ntdll/tests/virtual.c index 195a54704fb4..841ecca42125 100644 --- a/dlls/ntdll/tests/virtual.c +++ b/dlls/ntdll/tests/virtual.c @@ -26,6 +26,10 @@ #include "winternl.h" #include "wine/test.h"
+static unsigned int page_size; + +static NTSTATUS (WINAPI *pRtlCreateUserStack)(SIZE_T, SIZE_T, ULONG, SIZE_T, SIZE_T, INITIAL_TEB *); +static NTSTATUS (WINAPI *pRtlFreeUserStack)(void *); static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL);
static void test_AllocateVirtualMemory(void) @@ -169,16 +173,80 @@ static void test_AllocateVirtualMemory(void) ok(status == STATUS_SUCCESS, "NtFreeVirtualMemory failed\n"); }
+static void test_RtlCreateUserStack(void) +{ + INITIAL_TEB stack = {0}; + unsigned int i; + NTSTATUS ret; + + static const struct + { + SIZE_T commit, reserve, commit_align, reserve_align, expect_commit, expect_reserve; + } + tests[] = + { + { 0, 0, 1, 1, 0x3000, 0x300000}, + { 0x2000, 0, 1, 1, 0x2000, 0x300000}, + { 0x4000, 0, 1, 1, 0x4000, 0x300000}, + { 0, 0x200000, 1, 1, 0x3000, 0x200000}, + { 0x4000, 0x200000, 1, 1, 0x4000, 0x200000}, + {0x100000, 0x100000, 1, 1, 0x100000, 0x100000}, + { 0x20000, 0x20000, 1, 1, 0x20000, 0x100000}, + + { 0, 0x110000, 1, 1, 0x3000, 0x110000}, + { 0, 0x110000, 1, 0x40000, 0x3000, 0x140000}, + { 0, 0x140000, 1, 0x40000, 0x3000, 0x140000}, + { 0x11000, 0x140000, 1, 0x40000, 0x11000, 0x140000}, + { 0x11000, 0x140000, 0x4000, 0x40000, 0x14000, 0x140000}, + { 0, 0, 0x2000, 0x200000, 0x4000, 0x400000}, + }; + + if (!pRtlCreateUserStack) + { + win_skip("RtlCreateUserStack() is missing\n"); + return; + } + + for (i = 0; i < ARRAY_SIZE(tests); ++i) + { + memset(&stack, 0xcc, sizeof(stack)); + ret = pRtlCreateUserStack(tests[i].commit, tests[i].reserve, 0, + tests[i].commit_align, tests[i].reserve_align, &stack); + ok(!ret, "%u: got status %#x\n", i, ret); + ok(!stack.OldStackBase, "%u: got OldStackBase %p\n", i, stack.OldStackBase); + ok(!stack.OldStackLimit, "%u: got OldStackLimit %p\n", i, stack.OldStackLimit); + ok(!((ULONG_PTR)stack.DeallocationStack & (page_size - 1)), + "%u: got unaligned memory %p\n", i, stack.DeallocationStack); + ok((ULONG_PTR)stack.StackBase - (ULONG_PTR)stack.DeallocationStack == tests[i].expect_reserve, + "%u: got reserve %#lx\n", i, (ULONG_PTR)stack.StackBase - (ULONG_PTR)stack.DeallocationStack); + todo_wine ok((ULONG_PTR)stack.StackBase - (ULONG_PTR)stack.StackLimit == tests[i].expect_commit, + "%u: got commit %#lx\n", i, (ULONG_PTR)stack.StackBase - (ULONG_PTR)stack.StackLimit); + pRtlFreeUserStack(stack.DeallocationStack); + } + + ret = pRtlCreateUserStack(0x11000, 0x110000, 0, 1, 0, &stack); + ok(ret == STATUS_INVALID_PARAMETER, "got %#x\n", ret); + + ret = pRtlCreateUserStack(0x11000, 0x110000, 0, 0, 1, &stack); + ok(ret == STATUS_INVALID_PARAMETER, "got %#x\n", ret); +} + START_TEST(virtual) { SYSTEM_BASIC_INFORMATION sbi; - HMODULE hkernel32; + HMODULE mod;
- hkernel32 = GetModuleHandleA("kernel32.dll"); - pIsWow64Process = (void *)GetProcAddress(hkernel32, "IsWow64Process"); + mod = GetModuleHandleA("kernel32.dll"); + pIsWow64Process = (void *)GetProcAddress(mod, "IsWow64Process"); + + mod = GetModuleHandleA("ntdll.dll"); + pRtlCreateUserStack = (void *)GetProcAddress(mod, "RtlCreateUserStack"); + pRtlFreeUserStack = (void *)GetProcAddress(mod, "RtlFreeUserStack");
NtQuerySystemInformation(SystemBasicInformation, &sbi, sizeof(sbi), NULL); trace("system page size %#x\n", sbi.PageSize); + page_size = sbi.PageSize;
test_AllocateVirtualMemory(); + test_RtlCreateUserStack(); }
Zebediah Figura zfigura@codeweavers.com writes:
@@ -1,5 +1,6 @@ TESTDLL = ntdll.dll IMPORTS = user32 advapi32 +EXTRADLLFLAGS = -Xlinker --stack=0x300000,0x3000
That's not going to work when not using Mingw.