ntdll: Add a helper function to push the exception data to the thread stack.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alexandre Julliard 2020-07-15 10:30:45 +02:00
parent 9a9fb47e24
commit ca45eda758
6 changed files with 78 additions and 186 deletions

View File

@ -531,17 +531,12 @@ static EXCEPTION_RECORD *setup_exception( ucontext_t *sigcontext, raise_func fun
CONTEXT context;
EXCEPTION_RECORD rec;
} *stack;
DWORD exception_code = 0;
stack = (struct stack_layout *)(SP_sig(sigcontext) & ~3);
stack--; /* push the stack_layout structure */
stack->rec.ExceptionRecord = NULL;
stack->rec.ExceptionCode = exception_code;
stack->rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
stack->rec.ExceptionAddress = (LPVOID)PC_sig(sigcontext);
stack->rec.NumberParameters = 0;
EXCEPTION_RECORD rec = { 0 };
void *stack_ptr = (void *)(SP_sig(sigcontext) & ~3);
rec.ExceptionAddress = (void *)PC_sig(sigcontext);
stack = virtual_setup_exception( stack_ptr, sizeof(*stack), &rec );
stack->rec = rec;
save_context( &stack->context, sigcontext );
/* now modify the sigcontext to return to the raise function */

View File

@ -121,8 +121,9 @@ struct stack_layout
{
CONTEXT context;
EXCEPTION_RECORD rec;
void *redzone[2];
void *redzone[3];
};
C_ASSERT( !(sizeof(struct stack_layout) % 16) );
struct arm64_thread_data
{
@ -540,18 +541,13 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context )
*/
static struct stack_layout *setup_exception( ucontext_t *sigcontext )
{
EXCEPTION_RECORD rec = { 0 };
void *stack_ptr = (void *)(SP_sig(sigcontext) & ~15);
struct stack_layout *stack;
DWORD exception_code = 0;
/* push the stack_layout structure */
stack = (struct stack_layout *)((SP_sig(sigcontext) - sizeof(*stack)) & ~15);
stack->rec.ExceptionRecord = NULL;
stack->rec.ExceptionCode = exception_code;
stack->rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
stack->rec.ExceptionAddress = (LPVOID)PC_sig(sigcontext);
stack->rec.NumberParameters = 0;
rec.ExceptionAddress = (void *)PC_sig(sigcontext);
stack = virtual_setup_exception( stack_ptr, sizeof(*stack), &rec );
stack->rec = rec;
save_context( &stack->context, sigcontext );
save_fpu( &stack->context, sigcontext );
return stack;

View File

@ -1460,72 +1460,12 @@ static BOOL check_atl_thunk( ucontext_t *sigcontext, struct stack_layout *stack
*/
static struct stack_layout *setup_exception_record( ucontext_t *sigcontext, void *stack_ptr )
{
struct stack_layout *stack = stack_ptr;
DWORD exception_code = 0;
/* stack sanity checks */
if ((char *)stack >= (char *)get_signal_stack() &&
(char *)stack < (char *)get_signal_stack() + signal_stack_size)
{
WINE_ERR( "nested exception on signal stack 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 );
abort_thread(1);
}
if (stack - 1 > stack || /* check for overflow in subtraction */
(char *)stack <= (char *)NtCurrentTeb()->DeallocationStack ||
(char *)stack > (char *)NtCurrentTeb()->Tib.StackBase)
{
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 );
abort_thread(1);
}
else if ((char *)(stack - 1) < (char *)NtCurrentTeb()->Tib.StackLimit)
{
/* stack access below stack limit, may be recoverable */
switch (virtual_handle_stack_fault( stack - 1 ))
{
case 0: /* not handled */
{
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()->DeallocationStack,
NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase );
abort_thread(1);
}
case -1: /* overflow */
exception_code = EXCEPTION_STACK_OVERFLOW;
break;
}
}
stack--; /* push the stack_layout structure */
#if defined(VALGRIND_MAKE_MEM_UNDEFINED)
VALGRIND_MAKE_MEM_UNDEFINED(stack, sizeof(*stack));
#elif defined(VALGRIND_MAKE_WRITABLE)
VALGRIND_MAKE_WRITABLE(stack, sizeof(*stack));
#endif
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;
EXCEPTION_RECORD rec = { 0 };
struct stack_layout *stack;
rec.ExceptionAddress = (void *)EIP_sig(sigcontext);
stack = virtual_setup_exception( stack_ptr, sizeof(*stack), &rec );
stack->rec = rec;
save_context( &stack->context, sigcontext );
return stack;
}

View File

@ -1377,18 +1377,6 @@ static inline void set_sigcontext( const CONTEXT *context, ucontext_t *sigcontex
}
/***********************************************************************
* is_inside_signal_stack
*
* Check if pointer is inside the signal stack.
*/
static inline BOOL is_inside_signal_stack( void *ptr )
{
return ((char *)ptr >= (char *)get_signal_stack() &&
(char *)ptr < (char *)get_signal_stack() + signal_stack_size);
}
/***********************************************************************
* save_context
*
@ -1847,72 +1835,14 @@ __ASM_GLOBAL_FUNC( raise_func_trampoline,
*/
static struct stack_layout *setup_exception( ucontext_t *sigcontext )
{
EXCEPTION_RECORD rec = { 0 };
void *stack_ptr = (void *)(RSP_sig(sigcontext) & ~15);
struct stack_layout *stack;
DWORD exception_code = 0;
stack = (struct stack_layout *)(RSP_sig(sigcontext) & ~15);
/* stack sanity checks */
if (is_inside_signal_stack( stack ))
{
ERR( "nested exception on signal stack in thread %04x eip %016lx esp %016lx stack %p-%p\n",
GetCurrentThreadId(), (ULONG_PTR)RIP_sig(sigcontext), (ULONG_PTR)RSP_sig(sigcontext),
NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase );
abort_thread(1);
}
if (stack - 1 > stack || /* check for overflow in subtraction */
(char *)stack <= (char *)NtCurrentTeb()->DeallocationStack ||
(char *)stack > (char *)NtCurrentTeb()->Tib.StackBase)
{
WARN( "exception outside of stack limits in thread %04x eip %016lx esp %016lx stack %p-%p\n",
GetCurrentThreadId(), (ULONG_PTR)RIP_sig(sigcontext), (ULONG_PTR)RSP_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);
ERR( "stack overflow %u bytes in thread %04x eip %016lx esp %016lx stack %p-%p-%p\n",
diff, GetCurrentThreadId(), (ULONG_PTR)RIP_sig(sigcontext),
(ULONG_PTR)RSP_sig(sigcontext), NtCurrentTeb()->DeallocationStack,
NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase );
abort_thread(1);
}
else if ((char *)(stack - 1) < (char *)NtCurrentTeb()->Tib.StackLimit)
{
/* stack access below stack limit, may be recoverable */
switch (virtual_handle_stack_fault( stack - 1 ))
{
case 0: /* not handled */
{
UINT diff = (char *)NtCurrentTeb()->Tib.StackLimit - (char *)(stack - 1);
ERR( "stack overflow %u bytes in thread %04x eip %016lx esp %016lx stack %p-%p-%p\n",
diff, GetCurrentThreadId(), (ULONG_PTR)RIP_sig(sigcontext),
(ULONG_PTR)RSP_sig(sigcontext), NtCurrentTeb()->DeallocationStack,
NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase );
abort_thread(1);
}
case -1: /* overflow */
exception_code = EXCEPTION_STACK_OVERFLOW;
break;
}
}
stack--; /* push the stack_layout structure */
#if defined(VALGRIND_MAKE_MEM_UNDEFINED)
VALGRIND_MAKE_MEM_UNDEFINED(stack, sizeof(*stack));
#elif defined(VALGRIND_MAKE_WRITABLE)
VALGRIND_MAKE_WRITABLE(stack, sizeof(*stack));
#endif
stack->rec.ExceptionRecord = NULL;
stack->rec.ExceptionCode = exception_code;
stack->rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
stack->rec.ExceptionAddress = (void *)RIP_sig(sigcontext);
stack->rec.NumberParameters = 0;
rec.ExceptionAddress = (void *)RIP_sig(sigcontext);
stack = virtual_setup_exception( stack_ptr, sizeof(*stack), &rec );
stack->rec = rec;
save_context( &stack->context, sigcontext );
return stack;
}

View File

@ -201,7 +201,7 @@ extern unsigned int virtual_locked_server_call( void *req_ptr ) DECLSPEC_HIDDEN;
extern ssize_t virtual_locked_read( int fd, void *addr, size_t size ) DECLSPEC_HIDDEN;
extern ssize_t virtual_locked_pread( int fd, void *addr, size_t size, off_t offset ) DECLSPEC_HIDDEN;
extern BOOL virtual_is_valid_code_address( const void *addr, SIZE_T size ) DECLSPEC_HIDDEN;
extern int virtual_handle_stack_fault( void *addr ) DECLSPEC_HIDDEN;
extern void *virtual_setup_exception( void *stack_ptr, size_t size, EXCEPTION_RECORD *rec ) DECLSPEC_HIDDEN;
extern BOOL virtual_check_buffer_for_read( const void *ptr, SIZE_T size ) DECLSPEC_HIDDEN;
extern BOOL virtual_check_buffer_for_write( void *ptr, SIZE_T size ) DECLSPEC_HIDDEN;
extern SIZE_T virtual_uninterrupted_read_memory( const void *addr, void *buffer, SIZE_T size ) DECLSPEC_HIDDEN;

View File

@ -2912,6 +2912,61 @@ NTSTATUS virtual_handle_fault( void *addr, DWORD err, void *stack )
}
/***********************************************************************
* virtual_setup_exception
*/
void *virtual_setup_exception( void *stack_ptr, size_t size, EXCEPTION_RECORD *rec )
{
char *stack = stack_ptr;
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)
{
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 );
return stack - size;
}
stack -= size;
if (stack < (char *)NtCurrentTeb()->DeallocationStack + 4096)
{
/* stack overflow on last page, unrecoverable */
UINT diff = (char *)NtCurrentTeb()->DeallocationStack + 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 );
abort_thread(1);
}
else if (stack < (char *)NtCurrentTeb()->Tib.StackLimit)
{
pthread_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 )))
{
rec->ExceptionCode = STATUS_STACK_OVERFLOW;
rec->NumberParameters = 0;
}
pthread_mutex_unlock( &virtual_mutex );
}
#if defined(VALGRIND_MAKE_MEM_UNDEFINED)
VALGRIND_MAKE_MEM_UNDEFINED( stack, size );
#elif defined(VALGRIND_MAKE_WRITABLE)
VALGRIND_MAKE_WRITABLE( stack, size );
#endif
return stack;
}
/***********************************************************************
* check_write_access
*
@ -3060,30 +3115,6 @@ BOOL virtual_is_valid_code_address( const void *addr, SIZE_T size )
}
/***********************************************************************
* virtual_handle_stack_fault
*
* Handle an access fault inside the current thread stack.
* Return 1 if safely handled, -1 if handled into the overflow space.
* Called from inside a signal handler.
*/
int virtual_handle_stack_fault( void *addr )
{
int ret = 0;
if ((char *)addr < (char *)NtCurrentTeb()->DeallocationStack) return 0;
if ((char *)addr >= (char *)NtCurrentTeb()->Tib.StackBase) return 0;
pthread_mutex_lock( &virtual_mutex ); /* no need for signal masking inside signal handler */
if (get_page_vprot( addr ) & VPROT_GUARD)
{
ret = grow_thread_stack( ROUND_ADDR( addr, page_mask )) ? -1 : 1;
}
pthread_mutex_unlock( &virtual_mutex );
return ret;
}
/***********************************************************************
* virtual_check_buffer_for_read
*