Alexandre Julliard : ntdll: Unwind the stack before calling exit/ abort_thread.
Alexandre Julliard
julliard at winehq.org
Fri Aug 28 10:18:45 CDT 2009
Module: wine
Branch: master
Commit: ecdcf060a57648f9ceb94fe2f6ac2b9c55176d68
URL: http://source.winehq.org/git/wine.git/?a=commit;h=ecdcf060a57648f9ceb94fe2f6ac2b9c55176d68
Author: Alexandre Julliard <julliard at 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 );
}
More information about the wine-cvs
mailing list