Module: wine Branch: master Commit: ecdcf060a57648f9ceb94fe2f6ac2b9c55176d68 URL: http://source.winehq.org/git/wine.git/?a=commit;h=ecdcf060a57648f9ceb94fe2f6...
Author: Alexandre Julliard julliard@winehq.org Date: Fri Aug 28 12:13:21 2009 +0200
ntdll: Unwind the stack before calling exit/abort_thread.
This prevents pthread_exit() from trying to do it and failing.
---
dlls/ntdll/signal_x86_64.c | 99 ++++++++++++++++++++++++++++++++++++++++---- 1 files changed, 90 insertions(+), 9 deletions(-)
diff --git a/dlls/ntdll/signal_x86_64.c b/dlls/ntdll/signal_x86_64.c index 9b138f0..825fb47 100644 --- a/dlls/ntdll/signal_x86_64.c +++ b/dlls/ntdll/signal_x86_64.c @@ -2552,29 +2552,100 @@ void WINAPI __regs_RtlRaiseException( EXCEPTION_RECORD *rec, CONTEXT *context ) 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 */ void call_thread_entry_point( LPTHREAD_START_ROUTINE entry, void *arg ) { - __TRY - { - exit_thread( entry( arg )); - } - __EXCEPT(unhandled_exception_filter) + struct topmost_frame frame; + + frame.frame.Handler = topmost_handler; + switch (sigsetjmp( frame.jmp, 0 )) { - NtTerminateThread( GetCurrentThread(), GetExceptionCode() ); + 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 ); } - __ENDTRY - abort(); /* should not be reached */ }
- /*********************************************************************** * RtlExitUserThread (NTDLL.@) */ 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 ); }
@@ -2583,6 +2654,16 @@ void WINAPI RtlExitUserThread( ULONG 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 ); }