Alexandre Julliard : ntdll: Add support for handling page faults caused by guard pages on the thread stack .
Alexandre Julliard
julliard at winehq.org
Tue Apr 1 16:44:10 CDT 2008
Module: wine
Branch: master
Commit: 061bfac076b1c191b123f64f51579cc9ea8b68cc
URL: http://source.winehq.org/git/wine.git/?a=commit;h=061bfac076b1c191b123f64f51579cc9ea8b68cc
Author: Alexandre Julliard <julliard at 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
*
More information about the wine-cvs
mailing list