ntdll: Support growing both 32- and 64-bit stacks.
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
e91d19a58a
commit
de89ce1bfe
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue