Commit 690cf4a6 authored by Alexandre Julliard's avatar Alexandre Julliard

ntdll: Use a more drastic (and simpler) method for unwinding the stack on thread exit.

parent c9d85dd5
...@@ -201,7 +201,11 @@ struct ntdll_thread_data ...@@ -201,7 +201,11 @@ struct ntdll_thread_data
int reply_fd; /* 1e4/314 fd for receiving server replies */ int reply_fd; /* 1e4/314 fd for receiving server replies */
int wait_fd[2]; /* 1e8/318 fd for sleeping server requests */ int wait_fd[2]; /* 1e8/318 fd for sleeping server requests */
BOOL wow64_redir; /* 1f0/320 Wow64 filesystem redirection flag */ BOOL wow64_redir; /* 1f0/320 Wow64 filesystem redirection flag */
#ifdef __i386__
void *vm86_ptr; /* 1f4/328 data for vm86 mode */ void *vm86_ptr; /* 1f4/328 data for vm86 mode */
#else
void *exit_frame; /* 1f4/328 exit frame pointer */
#endif
pthread_t pthread_id; /* 1f8/330 pthread thread id */ pthread_t pthread_id; /* 1f8/330 pthread thread id */
}; };
......
...@@ -2880,101 +2880,45 @@ void WINAPI __regs_RtlRaiseException( EXCEPTION_RECORD *rec, CONTEXT *context ) ...@@ -2880,101 +2880,45 @@ void WINAPI __regs_RtlRaiseException( EXCEPTION_RECORD *rec, CONTEXT *context )
DEFINE_REGS_ENTRYPOINT( RtlRaiseException, 1 ) DEFINE_REGS_ENTRYPOINT( RtlRaiseException, 1 )
struct topmost_frame /***********************************************************************
{ * call_thread_func
EXCEPTION_REGISTRATION_RECORD frame; */
sigjmp_buf jmp; void call_thread_func( LPTHREAD_START_ROUTINE entry, void *arg, void *frame )
int exit_code;
};
static void DECLSPEC_NORETURN topmost_exit_unwind_target(void)
{
struct topmost_frame *topmost_frame = (struct topmost_frame *)__wine_get_frame();
__wine_pop_frame( &topmost_frame->frame );
siglongjmp( topmost_frame->jmp, 1 );
}
static void DECLSPEC_NORETURN topmost_abort_unwind_target(void)
{
struct topmost_frame *topmost_frame = (struct topmost_frame *)__wine_get_frame();
__wine_pop_frame( &topmost_frame->frame );
siglongjmp( topmost_frame->jmp, 2 );
}
static DWORD topmost_handler( EXCEPTION_RECORD *record,
EXCEPTION_REGISTRATION_RECORD *frame,
CONTEXT *context,
EXCEPTION_REGISTRATION_RECORD **pdispatcher )
{ {
struct topmost_frame *topmost_frame = (struct topmost_frame *)frame; ntdll_get_thread_data()->exit_frame = frame;
EXCEPTION_POINTERS ptrs; __TRY
if (record->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND | EH_NESTED_CALL))
return ExceptionContinueSearch;
ptrs.ExceptionRecord = record;
ptrs.ContextRecord = context;
switch (unhandled_exception_filter( &ptrs ))
{ {
case EXCEPTION_CONTINUE_SEARCH: RtlExitUserThread( entry( arg ));
return ExceptionContinueSearch;
case EXCEPTION_CONTINUE_EXECUTION:
return ExceptionContinueExecution;
case EXCEPTION_EXECUTE_HANDLER:
break;
} }
/* send the exit code to the server */ __EXCEPT(unhandled_exception_filter)
/* we can't simply call NtTerminateThread since it's a WINAPI function */
/* and libgcc unwinding doesn't handle those correctly */
SERVER_START_REQ( terminate_thread )
{ {
req->handle = wine_server_obj_handle( GetCurrentThread() ); NtTerminateThread( GetCurrentThread(), GetExceptionCode() );
req->exit_code = record->ExceptionCode;
wine_server_call( req );
} }
SERVER_END_REQ; __ENDTRY
topmost_frame->exit_code = record->ExceptionCode; abort(); /* should not be reached */
for (;;) RtlUnwind( frame, topmost_abort_unwind_target, record, 0 );
} }
/*********************************************************************** extern void DECLSPEC_NORETURN call_thread_entry_point( LPTHREAD_START_ROUTINE entry, void *arg );
* call_thread_entry_point __ASM_GLOBAL_FUNC( call_thread_entry_point,
*/ "subq $8,%rsp\n\t"
void call_thread_entry_point( LPTHREAD_START_ROUTINE entry, void *arg ) ".cfi_adjust_cfa_offset 8\n\t"
{ "movq %rsp,%rdx\n\t"
struct topmost_frame frame; "call " __ASM_NAME("call_thread_func") );
frame.frame.Handler = topmost_handler; extern void DECLSPEC_NORETURN call_thread_exit_func( int status, void (*func)(int), void *frame );
switch (sigsetjmp( frame.jmp, 0 )) __ASM_GLOBAL_FUNC( call_thread_exit_func,
{ "subq $8,%rsp\n\t"
case 0: ".cfi_adjust_cfa_offset 8\n\t"
__wine_push_frame( &frame.frame ); "movq %rdx,%rsp\n\t"
frame.exit_code = entry( arg ); "call *%rsi" );
__wine_pop_frame( &frame.frame );
/* fall through */
case 1:
exit_thread( frame.exit_code );
default:
terminate_thread( frame.exit_code );
}
}
/*********************************************************************** /***********************************************************************
* RtlExitUserThread (NTDLL.@) * RtlExitUserThread (NTDLL.@)
*/ */
void WINAPI RtlExitUserThread( ULONG status ) void WINAPI RtlExitUserThread( ULONG status )
{ {
EXCEPTION_REGISTRATION_RECORD *teb_frame = NtCurrentTeb()->Tib.ExceptionList; if (!ntdll_get_thread_data()->exit_frame) exit_thread( status );
call_thread_exit_func( status, exit_thread, ntdll_get_thread_data()->exit_frame );
/* hack: find the top TEB frame and use it as unwind target */
if (teb_frame != (EXCEPTION_REGISTRATION_RECORD *)~0UL)
{
while (teb_frame->Prev != (EXCEPTION_REGISTRATION_RECORD *)~0UL) teb_frame = teb_frame->Prev;
TRACE( "unwinding to frame %p for thread exit\n", teb_frame );
((struct topmost_frame *)teb_frame)->exit_code = status;
RtlUnwind( teb_frame, topmost_exit_unwind_target, NULL, 0 );
}
exit_thread( status );
} }
/*********************************************************************** /***********************************************************************
...@@ -2982,17 +2926,8 @@ void WINAPI RtlExitUserThread( ULONG status ) ...@@ -2982,17 +2926,8 @@ void WINAPI RtlExitUserThread( ULONG status )
*/ */
void abort_thread( int status ) void abort_thread( int status )
{ {
EXCEPTION_REGISTRATION_RECORD *teb_frame = NtCurrentTeb()->Tib.ExceptionList; if (!ntdll_get_thread_data()->exit_frame) terminate_thread( status );
call_thread_exit_func( status, terminate_thread, ntdll_get_thread_data()->exit_frame );
/* hack: find the top TEB frame and use it as unwind target */
if (teb_frame != (EXCEPTION_REGISTRATION_RECORD *)~0UL)
{
while (teb_frame->Prev != (EXCEPTION_REGISTRATION_RECORD *)~0UL) teb_frame = teb_frame->Prev;
TRACE( "unwinding to frame %p for thread exit\n", teb_frame );
((struct topmost_frame *)teb_frame)->exit_code = status;
RtlUnwind( teb_frame, topmost_abort_unwind_target, NULL, 0 );
}
terminate_thread( status );
} }
/********************************************************************** /**********************************************************************
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment