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