Alexandre Julliard : ntdll: Add a guard page at the bottom of the stack and raise a stack overflow exception when hit .

Alexandre Julliard julliard at winehq.org
Tue Apr 1 16:44:11 CDT 2008


Module: wine
Branch: master
Commit: cc33f6c8a5df21589efa7ce26f8b13715e698008
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=cc33f6c8a5df21589efa7ce26f8b13715e698008

Author: Alexandre Julliard <julliard at winehq.org>
Date:   Tue Apr  1 17:40:37 2008 +0200

ntdll: Add a guard page at the bottom of the stack and raise a stack overflow exception when hit.

---

 dlls/ntdll/signal_i386.c |   46 ++++++++++++++++++++++++++++++++++++----------
 dlls/ntdll/virtual.c     |    4 +++-
 2 files changed, 39 insertions(+), 11 deletions(-)

diff --git a/dlls/ntdll/signal_i386.c b/dlls/ntdll/signal_i386.c
index 7920d0a..d9c6aba 100644
--- a/dlls/ntdll/signal_i386.c
+++ b/dlls/ntdll/signal_i386.c
@@ -1026,6 +1026,7 @@ static EXCEPTION_RECORD *setup_exception_record( SIGCONTEXT *sigcontext, void *s
         DWORD             ebp;
         DWORD             eip;
     } *stack = stack_ptr;
+    DWORD exception_code = 0;
 
     /* stack sanity checks */
 
@@ -1040,22 +1041,37 @@ static EXCEPTION_RECORD *setup_exception_record( SIGCONTEXT *sigcontext, void *s
     }
 
     if (stack - 1 > stack || /* check for overflow in subtraction */
-        (char *)(stack - 1) < (char *)NtCurrentTeb()->Tib.StackLimit ||
+        (char *)stack <= (char *)NtCurrentTeb()->DeallocationStack ||
         (char *)stack > (char *)NtCurrentTeb()->Tib.StackBase)
     {
-        UINT diff = (char *)NtCurrentTeb()->Tib.StackLimit - (char *)stack;
-        if (diff < 4096)
+        WARN( "exception outside of stack limits in thread %04x eip %08x esp %08x stack %p-%p\n",
+              GetCurrentThreadId(), (unsigned int) EIP_sig(sigcontext),
+              (unsigned int) ESP_sig(sigcontext), NtCurrentTeb()->Tib.StackLimit,
+              NtCurrentTeb()->Tib.StackBase );
+    }
+    else if ((char *)(stack - 1) < (char *)NtCurrentTeb()->DeallocationStack + 4096)
+    {
+        /* stack overflow on last page, unrecoverable */
+        UINT diff = (char *)NtCurrentTeb()->DeallocationStack + 4096 - (char *)(stack - 1);
+        WINE_ERR( "stack overflow %u bytes in thread %04x eip %08x esp %08x stack %p-%p-%p\n",
+                  diff, GetCurrentThreadId(), (unsigned int) EIP_sig(sigcontext),
+                  (unsigned int) ESP_sig(sigcontext), NtCurrentTeb()->DeallocationStack,
+                  NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase );
+        server_abort_thread(1);
+    }
+    else if ((char *)(stack - 1) < (char *)NtCurrentTeb()->Tib.StackLimit)
+    {
+        /* stack access below stack limit, may be recoverable */
+        if (virtual_handle_stack_fault( stack - 1 )) exception_code = EXCEPTION_STACK_OVERFLOW;
+        else
         {
-            WINE_ERR( "stack overflow %u bytes in thread %04x eip %08x esp %08x stack %p-%p\n",
+            UINT diff = (char *)NtCurrentTeb()->Tib.StackLimit - (char *)(stack - 1);
+            WINE_ERR( "stack overflow %u bytes in thread %04x eip %08x esp %08x stack %p-%p-%p\n",
                       diff, GetCurrentThreadId(), (unsigned int) EIP_sig(sigcontext),
-                      (unsigned int) ESP_sig(sigcontext), NtCurrentTeb()->Tib.StackLimit,
-                      NtCurrentTeb()->Tib.StackBase );
+                      (unsigned int) ESP_sig(sigcontext), NtCurrentTeb()->DeallocationStack,
+                      NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase );
             server_abort_thread(1);
         }
-        else WARN( "exception outside of stack limits in thread %04x eip %08x esp %08x stack %p-%p\n",
-                   GetCurrentThreadId(), (unsigned int) EIP_sig(sigcontext),
-                   (unsigned int) ESP_sig(sigcontext), NtCurrentTeb()->Tib.StackLimit,
-                   NtCurrentTeb()->Tib.StackBase );
     }
 
     stack--;  /* push the stack_layout structure */
@@ -1069,6 +1085,7 @@ static EXCEPTION_RECORD *setup_exception_record( SIGCONTEXT *sigcontext, void *s
     stack->context_ptr  = &stack->context;
 
     stack->rec.ExceptionRecord  = NULL;
+    stack->rec.ExceptionCode    = exception_code;
     stack->rec.ExceptionFlags   = EXCEPTION_CONTINUABLE;
     stack->rec.ExceptionAddress = (LPVOID)EIP_sig(sigcontext);
     stack->rec.NumberParameters = 0;
@@ -1280,9 +1297,18 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext )
         (char *)siginfo->si_addr >= (char *)NtCurrentTeb()->DeallocationStack &&
         (char *)siginfo->si_addr < (char *)NtCurrentTeb()->Tib.StackBase &&
         virtual_handle_stack_fault( siginfo->si_addr ))
+    {
+        /* check if this was the last guard page */
+        if ((char *)siginfo->si_addr < (char *)NtCurrentTeb()->DeallocationStack + 2*4096)
+        {
+            rec = setup_exception_record( context, stack, fs, gs, raise_segv_exception );
+            rec->ExceptionCode = EXCEPTION_STACK_OVERFLOW;
+        }
         return;
+    }
 
     rec = setup_exception_record( context, stack, fs, gs, raise_segv_exception );
+    if (rec->ExceptionCode == EXCEPTION_STACK_OVERFLOW) return;
 
     switch(get_trap_code(context))
     {
diff --git a/dlls/ntdll/virtual.c b/dlls/ntdll/virtual.c
index 5e4327b..a5b299d 100644
--- a/dlls/ntdll/virtual.c
+++ b/dlls/ntdll/virtual.c
@@ -1303,11 +1303,13 @@ NTSTATUS virtual_alloc_thread_stack( void *base, SIZE_T size )
 
     /* setup no access guard page */
     VIRTUAL_SetProt( view, view->base, page_size, VPROT_COMMITTED );
+    VIRTUAL_SetProt( view, (char *)view->base + page_size, page_size,
+                     VPROT_READ | VPROT_WRITE | VPROT_COMMITTED | VPROT_GUARD );
 
     /* note: limit is lower than base since the stack grows down */
     NtCurrentTeb()->DeallocationStack = view->base;
     NtCurrentTeb()->Tib.StackBase     = (char *)view->base + view->size;
-    NtCurrentTeb()->Tib.StackLimit    = (char *)view->base + page_size;
+    NtCurrentTeb()->Tib.StackLimit    = (char *)view->base + 2 * page_size;
 
 done:
     server_leave_uninterrupted_section( &csVirtual, &sigset );




More information about the wine-cvs mailing list