From 9f32a5c8655add0b197daaf92a1b857c2839c303 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Tue, 9 Aug 2005 10:43:47 +0000 Subject: [PATCH] Added a VIRTUAL_alloc_teb function to allocate TEBs while making sure they don't end up above the address space limit. --- dlls/ntdll/ntdll_misc.h | 2 +- dlls/ntdll/thread.c | 72 +++++++++++++++++------------------------ dlls/ntdll/virtual.c | 49 ++++++++++++++++++++++++++-- 3 files changed, 78 insertions(+), 45 deletions(-) diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h index dbbcefa6353..748bf6ebfff 100644 --- a/dlls/ntdll/ntdll_misc.h +++ b/dlls/ntdll/ntdll_misc.h @@ -51,7 +51,6 @@ extern NTSTATUS NTDLL_wait_for_multiple_objects( UINT count, const HANDLE *handl extern BOOL SIGNAL_Init(void); extern void debug_init(void); extern void thread_init(void); -extern void virtual_init(void); /* server support */ extern time_t server_start_time; @@ -90,6 +89,7 @@ extern NTSTATUS FILE_GetNtStatus(void); extern BOOL DIR_is_hidden_file( const UNICODE_STRING *name ); /* virtual memory */ +extern NTSTATUS VIRTUAL_alloc_teb( void **ret, size_t size, BOOL first ); extern NTSTATUS VIRTUAL_HandleFault(LPCVOID addr); extern BOOL VIRTUAL_HasMapping( LPCVOID addr ); extern void VIRTUAL_UseLargeAddressSpace(void); diff --git a/dlls/ntdll/thread.c b/dlls/ntdll/thread.c index 481d2082a65..42bddadfc4a 100644 --- a/dlls/ntdll/thread.c +++ b/dlls/ntdll/thread.c @@ -55,29 +55,26 @@ static LIST_ENTRY tls_links; /*********************************************************************** - * alloc_teb + * init_teb */ -static TEB *alloc_teb( ULONG *size ) +static inline NTSTATUS init_teb( TEB *teb ) { - TEB *teb; - struct ntdll_thread_data *thread_data; + struct ntdll_thread_data *thread_data = (struct ntdll_thread_data *)teb->SystemReserved2; - *size = SIGNAL_STACK_SIZE + sizeof(TEB); - teb = wine_anon_mmap( NULL, *size, PROT_READ | PROT_WRITE, 0 ); - if (teb == (TEB *)-1) return NULL; - thread_data = (struct ntdll_thread_data *)teb->SystemReserved2; - if (!(thread_data->teb_sel = wine_ldt_alloc_fs())) - { - munmap( teb, *size ); - return NULL; - } teb->Tib.ExceptionList = (void *)~0UL; teb->Tib.StackBase = (void *)~0UL; teb->Tib.Self = &teb->Tib; teb->Peb = &peb; teb->StaticUnicodeString.Buffer = teb->StaticUnicodeBuffer; teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer); - return teb; + + if (!(thread_data->teb_sel = wine_ldt_alloc_fs())) return STATUS_TOO_MANY_THREADS; + thread_data->request_fd = -1; + thread_data->reply_fd = -1; + thread_data->wait_fd[0] = -1; + thread_data->wait_fd[1] = -1; + + return STATUS_SUCCESS; } @@ -107,7 +104,7 @@ void thread_init(void) { TEB *teb; void *addr; - ULONG size, info_size; + ULONG info_size; struct ntdll_thread_data *thread_data; struct wine_pthread_thread_info thread_info; static struct debug_info debug_info; /* debug info for initial thread */ @@ -127,19 +124,17 @@ void thread_init(void) InitializeListHead( &ldr.InInitializationOrderModuleList ); InitializeListHead( &tls_links ); - teb = alloc_teb( &size ); + thread_info.teb_size = SIGNAL_STACK_SIZE + sizeof(TEB); + VIRTUAL_alloc_teb( &addr, thread_info.teb_size, TRUE ); + teb = addr; + init_teb( teb ); thread_data = (struct ntdll_thread_data *)teb->SystemReserved2; - thread_data->request_fd = -1; - thread_data->reply_fd = -1; - thread_data->wait_fd[0] = -1; - thread_data->wait_fd[1] = -1; thread_data->debug_info = &debug_info; InsertHeadList( &tls_links, &teb->TlsLinks ); thread_info.stack_base = NULL; thread_info.stack_size = 0; thread_info.teb_base = teb; - thread_info.teb_size = size; thread_info.teb_sel = thread_data->teb_sel; wine_pthread_init_current_teb( &thread_info ); wine_pthread_init_thread( &thread_info ); @@ -147,17 +142,11 @@ void thread_init(void) debug_info.str_pos = debug_info.strings; debug_info.out_pos = debug_info.output; debug_init(); - virtual_init(); /* setup the server connection */ server_init_process(); info_size = server_init_thread( thread_info.pid, thread_info.tid, NULL ); - /* create a memory view for the TEB */ - addr = teb; - NtAllocateVirtualMemory( NtCurrentProcess(), &addr, 0, &size, - MEM_SYSTEM, PAGE_READWRITE ); - /* create the process heap */ if (!(peb.ProcessHeap = RtlCreateHeap( HEAP_GROWABLE, NULL, 0, 0, NULL, NULL ))) { @@ -245,12 +234,12 @@ NTSTATUS WINAPI RtlCreateUserThread( HANDLE process, const SECURITY_DESCRIPTOR * PRTL_THREAD_START_ROUTINE start, void *param, HANDLE *handle_ptr, CLIENT_ID *id ) { - struct ntdll_thread_data *thread_data; + struct ntdll_thread_data *thread_data = NULL; struct startup_info *info = NULL; + void *addr; HANDLE handle = 0; - TEB *teb = NULL; + TEB *teb; DWORD tid = 0; - ULONG size; int request_pipe[2]; NTSTATUS status; @@ -286,24 +275,18 @@ NTSTATUS WINAPI RtlCreateUserThread( HANDLE process, const SECURITY_DESCRIPTOR * goto error; } - if (!(teb = alloc_teb( &size ))) - { - status = STATUS_NO_MEMORY; - goto error; - } + info->pthread_info.teb_size = SIGNAL_STACK_SIZE + sizeof(TEB); + if ((status = VIRTUAL_alloc_teb( &addr, info->pthread_info.teb_size, FALSE ))) goto error; + teb = addr; + if ((status = init_teb( teb ))) goto error; + teb->ClientId.UniqueProcess = (HANDLE)GetCurrentProcessId(); teb->ClientId.UniqueThread = (HANDLE)tid; thread_data = (struct ntdll_thread_data *)teb->SystemReserved2; thread_data->request_fd = request_pipe[1]; - thread_data->reply_fd = -1; - thread_data->wait_fd[0] = -1; - thread_data->wait_fd[1] = -1; info->pthread_info.teb_base = teb; - NtAllocateVirtualMemory( NtCurrentProcess(), &info->pthread_info.teb_base, 0, &size, - MEM_SYSTEM, PAGE_READWRITE ); - info->pthread_info.teb_size = size; info->pthread_info.teb_sel = thread_data->teb_sel; if (!stack_reserve || !stack_commit) @@ -335,7 +318,12 @@ NTSTATUS WINAPI RtlCreateUserThread( HANDLE process, const SECURITY_DESCRIPTOR * return STATUS_SUCCESS; error: - if (teb) free_teb( teb ); + if (thread_data) wine_ldt_free_fs( thread_data->teb_sel ); + if (addr) + { + ULONG size = 0; + NtFreeVirtualMemory( NtCurrentProcess(), &addr, &size, MEM_RELEASE ); + } if (info) RtlFreeHeap( GetProcessHeap(), 0, info ); if (handle) NtClose( handle ); close( request_pipe[1] ); diff --git a/dlls/ntdll/virtual.c b/dlls/ntdll/virtual.c index 4200c7a4649..43c53b212ea 100644 --- a/dlls/ntdll/virtual.c +++ b/dlls/ntdll/virtual.c @@ -1081,7 +1081,7 @@ BOOL is_current_process( HANDLE handle ) /*********************************************************************** * virtual_init */ -void virtual_init(void) +static inline void virtual_init(void) { #ifndef page_mask page_size = getpagesize(); @@ -1094,6 +1094,51 @@ void virtual_init(void) } +/*********************************************************************** + * VIRTUAL_alloc_teb + * + * Allocate a memory view for a new TEB. We don't care about granularity for TEBs. + */ +NTSTATUS VIRTUAL_alloc_teb( void **ret, size_t size, BOOL first ) +{ + void *ptr; + NTSTATUS status; + struct file_view *view; + BYTE vprot = VPROT_READ | VPROT_WRITE | VPROT_COMMITTED; + + if (first) virtual_init(); + + *ret = NULL; + size = ROUND_SIZE( 0, size ); + + for (;;) + { + if ((ptr = wine_anon_mmap( NULL, size, VIRTUAL_GetUnixProt(vprot), 0 )) == (void *)-1) + { + if (errno == ENOMEM) return STATUS_NO_MEMORY; + return STATUS_INVALID_PARAMETER; + } + /* if we got something beyond the user limit, unmap it and retry */ + if (is_beyond_limit( ptr, size, user_space_limit )) add_reserved_area( ptr, size ); + else break; + } + + if (!first) RtlEnterCriticalSection( &csVirtual ); + + status = create_view( &view, ptr, size, vprot ); + if (status == STATUS_SUCCESS) + { + view->flags |= VFLAG_VALLOC; + *ret = ptr; + } + else unmap_area( ptr, size ); + + if (!first) RtlLeaveCriticalSection( &csVirtual ); + + return status; +} + + /*********************************************************************** * VIRTUAL_HandleFault */ @@ -1456,7 +1501,7 @@ NTSTATUS WINAPI NtQueryVirtualMemory( HANDLE process, LPCVOID addr, { /* make the address space end at the user limit, except if * the last view was mapped beyond that */ - if (alloc_base < (char *)user_space_limit) + if (alloc_base <= (char *)user_space_limit) { if (user_space_limit && base >= (char *)user_space_limit) {