ntdll: Unwind the stack before calling exit/abort_thread.
This prevents pthread_exit() from trying to do it and failing.
This commit is contained in:
parent
8101a2fa1e
commit
ecdcf060a5
|
@ -2552,29 +2552,100 @@ void WINAPI __regs_RtlRaiseException( EXCEPTION_RECORD *rec, CONTEXT *context )
|
||||||
DEFINE_REGS_ENTRYPOINT( RtlRaiseException, 1 )
|
DEFINE_REGS_ENTRYPOINT( RtlRaiseException, 1 )
|
||||||
|
|
||||||
|
|
||||||
|
struct topmost_frame
|
||||||
|
{
|
||||||
|
EXCEPTION_REGISTRATION_RECORD frame;
|
||||||
|
sigjmp_buf jmp;
|
||||||
|
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;
|
||||||
|
EXCEPTION_POINTERS ptrs;
|
||||||
|
|
||||||
|
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:
|
||||||
|
return ExceptionContinueSearch;
|
||||||
|
case EXCEPTION_CONTINUE_EXECUTION:
|
||||||
|
return ExceptionContinueExecution;
|
||||||
|
case EXCEPTION_EXECUTE_HANDLER:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* send the exit code to the server */
|
||||||
|
/* 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() );
|
||||||
|
req->exit_code = record->ExceptionCode;
|
||||||
|
wine_server_call( req );
|
||||||
|
}
|
||||||
|
SERVER_END_REQ;
|
||||||
|
topmost_frame->exit_code = record->ExceptionCode;
|
||||||
|
for (;;) RtlUnwind( frame, topmost_abort_unwind_target, record, 0 );
|
||||||
|
}
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* call_thread_entry_point
|
* call_thread_entry_point
|
||||||
*/
|
*/
|
||||||
void call_thread_entry_point( LPTHREAD_START_ROUTINE entry, void *arg )
|
void call_thread_entry_point( LPTHREAD_START_ROUTINE entry, void *arg )
|
||||||
{
|
{
|
||||||
__TRY
|
struct topmost_frame frame;
|
||||||
{
|
|
||||||
exit_thread( entry( arg ));
|
|
||||||
}
|
|
||||||
__EXCEPT(unhandled_exception_filter)
|
|
||||||
{
|
|
||||||
NtTerminateThread( GetCurrentThread(), GetExceptionCode() );
|
|
||||||
}
|
|
||||||
__ENDTRY
|
|
||||||
abort(); /* should not be reached */
|
|
||||||
}
|
|
||||||
|
|
||||||
|
frame.frame.Handler = topmost_handler;
|
||||||
|
switch (sigsetjmp( frame.jmp, 0 ))
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
__wine_push_frame( &frame.frame );
|
||||||
|
frame.exit_code = entry( arg );
|
||||||
|
__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;
|
||||||
|
|
||||||
|
/* 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 );
|
exit_thread( status );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2583,6 +2654,16 @@ void WINAPI RtlExitUserThread( ULONG status )
|
||||||
*/
|
*/
|
||||||
void abort_thread( int status )
|
void abort_thread( int status )
|
||||||
{
|
{
|
||||||
|
EXCEPTION_REGISTRATION_RECORD *teb_frame = NtCurrentTeb()->Tib.ExceptionList;
|
||||||
|
|
||||||
|
/* 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 );
|
terminate_thread( status );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue