Module: wine Branch: master Commit: 061bfac076b1c191b123f64f51579cc9ea8b68cc URL: http://source.winehq.org/git/wine.git/?a=commit;h=061bfac076b1c191b123f64f51...
Author: Alexandre Julliard julliard@winehq.org Date: Tue Apr 1 17:37:17 2008 +0200
ntdll: Add support for handling page faults caused by guard pages on the thread stack.
---
dlls/ntdll/ntdll_misc.h | 1 + dlls/ntdll/signal_i386.c | 44 +++++++++++++++++++++++++++++++++----------- dlls/ntdll/virtual.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 11 deletions(-)
diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h index 3a12b8f..cba9643 100644 --- a/dlls/ntdll/ntdll_misc.h +++ b/dlls/ntdll/ntdll_misc.h @@ -134,6 +134,7 @@ extern unsigned int DIR_get_drives_info( struct drive_info info[MAX_DOS_DRIVES]
/* virtual memory */ extern NTSTATUS virtual_alloc_thread_stack( void *base, SIZE_T stack_size ); +extern BOOL virtual_handle_stack_fault( void *addr ); extern NTSTATUS VIRTUAL_HandleFault(LPCVOID addr); extern void VIRTUAL_SetForceExec( BOOL enable ); extern void VIRTUAL_UseLargeAddressSpace(void); diff --git a/dlls/ntdll/signal_i386.c b/dlls/ntdll/signal_i386.c index bb8332a..7920d0a 100644 --- a/dlls/ntdll/signal_i386.c +++ b/dlls/ntdll/signal_i386.c @@ -1009,13 +1009,12 @@ static BOOL check_atl_thunk( EXCEPTION_RECORD *rec, CONTEXT *context )
/*********************************************************************** - * setup_exception + * setup_exception_record * - * Setup a proper stack frame for the raise function, and modify the - * sigcontext so that the return from the signal handler will call - * the raise function. + * Setup the exception record and context on the thread stack. */ -static EXCEPTION_RECORD *setup_exception( SIGCONTEXT *sigcontext, raise_func func ) +static EXCEPTION_RECORD *setup_exception_record( SIGCONTEXT *sigcontext, void *stack_ptr, + WORD fs, WORD gs, raise_func func ) { struct stack_layout { @@ -1026,11 +1025,7 @@ static EXCEPTION_RECORD *setup_exception( SIGCONTEXT *sigcontext, raise_func fun EXCEPTION_RECORD rec; DWORD ebp; DWORD eip; - } *stack; - - WORD fs, gs; - - stack = init_handler( sigcontext, &fs, &gs ); + } *stack = stack_ptr;
/* stack sanity checks */
@@ -1097,6 +1092,22 @@ static EXCEPTION_RECORD *setup_exception( SIGCONTEXT *sigcontext, raise_func fun
/*********************************************************************** + * setup_exception + * + * Setup a proper stack frame for the raise function, and modify the + * sigcontext so that the return from the signal handler will call + * the raise function. + */ +static EXCEPTION_RECORD *setup_exception( SIGCONTEXT *sigcontext, raise_func func ) +{ + WORD fs, gs; + void *stack = init_handler( sigcontext, &fs, &gs ); + + return setup_exception_record( sigcontext, stack, fs, gs, func ); +} + + +/*********************************************************************** * get_exception_context * * Get a pointer to the context built by setup_exception. @@ -1259,8 +1270,19 @@ static void usr2_handler( int signal, siginfo_t *siginfo, void *sigcontext ) */ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext ) { + WORD fs, gs; + EXCEPTION_RECORD *rec; SIGCONTEXT *context = sigcontext; - EXCEPTION_RECORD *rec = setup_exception( context, raise_segv_exception ); + void *stack = init_handler( sigcontext, &fs, &gs ); + + /* check for page fault inside the thread stack */ + if (get_trap_code(context) == TRAP_x86_PAGEFLT && + (char *)siginfo->si_addr >= (char *)NtCurrentTeb()->DeallocationStack && + (char *)siginfo->si_addr < (char *)NtCurrentTeb()->Tib.StackBase && + virtual_handle_stack_fault( siginfo->si_addr )) + return; + + rec = setup_exception_record( context, stack, fs, gs, raise_segv_exception );
switch(get_trap_code(context)) { diff --git a/dlls/ntdll/virtual.c b/dlls/ntdll/virtual.c index 548e819..5e4327b 100644 --- a/dlls/ntdll/virtual.c +++ b/dlls/ntdll/virtual.c @@ -571,6 +571,19 @@ static BOOL VIRTUAL_SetProt( FILE_VIEW *view, /* [in] Pointer to view */ TRACE("%p-%p %s\n", base, (char *)base + size - 1, VIRTUAL_GetProtStr( vprot ) );
+ /* if setting stack guard pages, store the permissions first, as the guard may be + * triggered at any point after mprotect and change the permissions again */ + if ((vprot & VPROT_GUARD) && + ((char *)base >= (char *)NtCurrentTeb()->DeallocationStack) && + ((char *)base < (char *)NtCurrentTeb()->Tib.StackBase)) + { + memset( view->prot + (((char *)base - (char *)view->base) >> page_shift), + vprot, size >> page_shift ); + mprotect( base, size, unix_prot ); + VIRTUAL_DEBUG_DUMP_VIEW( view ); + return TRUE; + } + if (force_exec_prot && (unix_prot & PROT_READ) && !(unix_prot & PROT_EXEC)) { TRACE( "forcing exec permission on %p-%p\n", base, (char *)base + size - 1 ); @@ -1327,6 +1340,36 @@ NTSTATUS VIRTUAL_HandleFault( LPCVOID addr ) }
+ +/*********************************************************************** + * virtual_handle_stack_fault + * + * Handle an access fault inside the current thread stack. + * Called from inside a signal handler. + */ +BOOL virtual_handle_stack_fault( void *addr ) +{ + FILE_VIEW *view; + BOOL ret = FALSE; + + RtlEnterCriticalSection( &csVirtual ); /* no need for signal masking inside signal handler */ + if ((view = VIRTUAL_FindView( addr ))) + { + void *page = ROUND_ADDR( addr, page_mask ); + BYTE vprot = view->prot[((const char *)page - (const char *)view->base) >> page_shift]; + if (vprot & VPROT_GUARD) + { + VIRTUAL_SetProt( view, page, page_size, vprot & ~VPROT_GUARD ); + if ((char *)page + page_size == NtCurrentTeb()->Tib.StackLimit) + NtCurrentTeb()->Tib.StackLimit = page; + ret = TRUE; + } + } + RtlLeaveCriticalSection( &csVirtual ); + return ret; +} + + /*********************************************************************** * VIRTUAL_SetForceExec *