Alexandre Julliard : ntdll: Support growing both 32- and 64-bit stacks.
Alexandre Julliard
julliard at winehq.org
Thu Jun 17 15:38:06 CDT 2021
Module: wine
Branch: master
Commit: de89ce1bfedeb386baddd047884dc73dfe6f70bf
URL: https://source.winehq.org/git/wine.git/?a=commit;h=de89ce1bfedeb386baddd047884dc73dfe6f70bf
Author: Alexandre Julliard <julliard at winehq.org>
Date: Thu Jun 17 09:25:19 2021 +0200
ntdll: Support growing both 32- and 64-bit stacks.
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
---
dlls/ntdll/unix/virtual.c | 90 +++++++++++++++++++++++++++++++++--------------
1 file changed, 63 insertions(+), 27 deletions(-)
diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c
index 0a4004d2db9..52af195aa56 100644
--- a/dlls/ntdll/unix/virtual.c
+++ b/dlls/ntdll/unix/virtual.c
@@ -3131,29 +3131,67 @@ void virtual_map_user_shared_data(void)
}
+struct thread_stack_info
+{
+ char *start;
+ char *limit;
+ char *end;
+ SIZE_T guaranteed;
+ BOOL is_wow;
+};
+
+/***********************************************************************
+ * is_inside_thread_stack
+ */
+static BOOL is_inside_thread_stack( void *ptr, struct thread_stack_info *stack )
+{
+ TEB *teb = NtCurrentTeb();
+ WOW_TEB *wow_teb = get_wow_teb( teb );
+
+ stack->start = teb->DeallocationStack;
+ stack->limit = teb->Tib.StackLimit;
+ stack->end = teb->Tib.StackBase;
+ stack->guaranteed = max( teb->GuaranteedStackBytes, page_size * (is_win64 ? 2 : 1) );
+ stack->is_wow = FALSE;
+ if ((char *)ptr > stack->start && (char *)ptr <= stack->end) return TRUE;
+
+ if (!wow_teb) return FALSE;
+ stack->start = ULongToPtr( wow_teb->DeallocationStack );
+ stack->limit = ULongToPtr( wow_teb->Tib.StackLimit );
+ stack->end = ULongToPtr( wow_teb->Tib.StackBase );
+ stack->guaranteed = max( wow_teb->GuaranteedStackBytes, page_size * (is_win64 ? 1 : 2) );
+ stack->is_wow = TRUE;
+ return ((char *)ptr > stack->start && (char *)ptr <= stack->end);
+}
+
+
/***********************************************************************
* grow_thread_stack
*/
-static NTSTATUS grow_thread_stack( char *page )
+static NTSTATUS grow_thread_stack( char *page, struct thread_stack_info *stack_info )
{
NTSTATUS ret = 0;
- size_t guaranteed = max( NtCurrentTeb()->GuaranteedStackBytes, page_size * (is_win64 ? 2 : 1) );
set_page_vprot_bits( page, page_size, 0, VPROT_GUARD );
mprotect_range( page, page_size, 0, 0 );
- if (page >= (char *)NtCurrentTeb()->DeallocationStack + page_size + guaranteed)
+ if (page >= stack_info->start + page_size + stack_info->guaranteed)
{
set_page_vprot_bits( page - page_size, page_size, VPROT_COMMITTED | VPROT_GUARD, 0 );
mprotect_range( page - page_size, page_size, 0, 0 );
}
else /* inside guaranteed space -> overflow exception */
{
- page = (char *)NtCurrentTeb()->DeallocationStack + page_size;
- set_page_vprot_bits( page, guaranteed, VPROT_COMMITTED, VPROT_GUARD );
- mprotect_range( page, guaranteed, 0, 0 );
+ page = stack_info->start + page_size;
+ set_page_vprot_bits( page, stack_info->guaranteed, VPROT_COMMITTED, VPROT_GUARD );
+ mprotect_range( page, stack_info->guaranteed, 0, 0 );
ret = STATUS_STACK_OVERFLOW;
}
- NtCurrentTeb()->Tib.StackLimit = page;
+ if (stack_info->is_wow)
+ {
+ WOW_TEB *wow_teb = get_wow_teb( NtCurrentTeb() );
+ wow_teb->Tib.StackLimit = PtrToUlong( page );
+ }
+ else NtCurrentTeb()->Tib.StackLimit = page;
return ret;
}
@@ -3171,14 +3209,14 @@ NTSTATUS virtual_handle_fault( void *addr, DWORD err, void *stack )
vprot = get_page_vprot( page );
if (!is_inside_signal_stack( stack ) && (vprot & VPROT_GUARD))
{
- if (page < (char *)NtCurrentTeb()->DeallocationStack ||
- page >= (char *)NtCurrentTeb()->Tib.StackBase)
+ struct thread_stack_info stack_info;
+ if (!is_inside_thread_stack( page, &stack_info ))
{
set_page_vprot_bits( page, page_size, 0, VPROT_GUARD );
mprotect_range( page, page_size, 0, 0 );
ret = STATUS_GUARD_PAGE_VIOLATION;
}
- else ret = grow_thread_stack( page );
+ else ret = grow_thread_stack( page, &stack_info );
}
else if (err & EXCEPTION_WRITE_FAULT)
{
@@ -3205,19 +3243,16 @@ NTSTATUS virtual_handle_fault( void *addr, DWORD err, void *stack )
void *virtual_setup_exception( void *stack_ptr, size_t size, EXCEPTION_RECORD *rec )
{
char *stack = stack_ptr;
+ struct thread_stack_info stack_info;
- if (is_inside_signal_stack( stack ))
- {
- ERR( "nested exception on signal stack in thread %04x addr %p stack %p (%p-%p-%p)\n",
- GetCurrentThreadId(), rec->ExceptionAddress, stack, NtCurrentTeb()->DeallocationStack,
- NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase );
- abort_thread(1);
- }
-
- if (stack - size > stack || /* check for overflow in subtraction */
- stack <= (char *)NtCurrentTeb()->DeallocationStack ||
- stack > (char *)NtCurrentTeb()->Tib.StackBase)
+ if (!is_inside_thread_stack( stack, &stack_info ))
{
+ if (is_inside_signal_stack( stack ))
+ {
+ ERR( "nested exception on signal stack in thread %04x addr %p stack %p\n",
+ GetCurrentThreadId(), rec->ExceptionAddress, stack );
+ abort_thread(1);
+ }
WARN( "exception outside of stack limits in thread %04x addr %p stack %p (%p-%p-%p)\n",
GetCurrentThreadId(), rec->ExceptionAddress, stack, NtCurrentTeb()->DeallocationStack,
NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase );
@@ -3226,19 +3261,20 @@ void *virtual_setup_exception( void *stack_ptr, size_t size, EXCEPTION_RECORD *r
stack -= size;
- if (stack < (char *)NtCurrentTeb()->DeallocationStack + 4096)
+ if (stack < stack_info.start + 4096)
{
/* stack overflow on last page, unrecoverable */
- UINT diff = (char *)NtCurrentTeb()->DeallocationStack + 4096 - stack;
+ UINT diff = stack_info.start + 4096 - stack;
ERR( "stack overflow %u bytes in thread %04x addr %p stack %p (%p-%p-%p)\n",
- diff, GetCurrentThreadId(), rec->ExceptionAddress, stack, NtCurrentTeb()->DeallocationStack,
- NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase );
+ diff, GetCurrentThreadId(), rec->ExceptionAddress, stack, stack_info.start,
+ stack_info.limit, stack_info.end );
abort_thread(1);
}
- else if (stack < (char *)NtCurrentTeb()->Tib.StackLimit)
+ else if (stack < stack_info.limit)
{
mutex_lock( &virtual_mutex ); /* no need for signal masking inside signal handler */
- if ((get_page_vprot( stack ) & VPROT_GUARD) && grow_thread_stack( ROUND_ADDR( stack, page_mask )))
+ if ((get_page_vprot( stack ) & VPROT_GUARD) &&
+ grow_thread_stack( ROUND_ADDR( stack, page_mask ), &stack_info ))
{
rec->ExceptionCode = STATUS_STACK_OVERFLOW;
rec->NumberParameters = 0;
More information about the wine-cvs
mailing list