From 9da818bd948256572640e17766a14a72e58ce100 Mon Sep 17 00:00:00 2001 From: Sebastian Lackner Date: Wed, 25 Feb 2015 22:45:42 +0100 Subject: [PATCH] ntdll: Fix race-condition when threads are killed during shutdown. When exit_thread is executed, nb_threads is decremented before the thread is fully shutdown. When another thread runs ExitProcess() this will cause a SIGQUIT signal to all threads, effectively decrementing nb_threads twice. The process will terminate with a wrong exitcode then because the refcount reaches zero too early. Currently Wine has no locking protection of LdrShutdownProcess(), so it can only be executed safely when all other threads have terminated before. Most likely there are more Wine bugs in this area, but the attached patch should fix the most critical one (messed up refcounting of threads) for now. --- dlls/ntdll/thread.c | 2 +- dlls/ntdll/unix/thread.c | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/dlls/ntdll/thread.c b/dlls/ntdll/thread.c index d5e34cae3b1..83237b3569a 100644 --- a/dlls/ntdll/thread.c +++ b/dlls/ntdll/thread.c @@ -295,7 +295,7 @@ void WINAPI RtlExitUserThread( ULONG status ) SERVER_END_REQ; } - if (InterlockedDecrement( &nb_threads ) <= 0) + if (InterlockedCompareExchange( &nb_threads, 0, 0 ) <= 0) { LdrShutdownProcess(); unix_funcs->exit_process( status ); diff --git a/dlls/ntdll/unix/thread.c b/dlls/ntdll/unix/thread.c index 205a1312e92..563712bd59e 100644 --- a/dlls/ntdll/unix/thread.c +++ b/dlls/ntdll/unix/thread.c @@ -219,6 +219,7 @@ void CDECL abort_thread( int status ) void CDECL exit_thread( int status ) { static void *prev_teb; + sigset_t sigset; TEB *teb; pthread_sigmask( SIG_BLOCK, &server_block_set, NULL ); @@ -233,6 +234,12 @@ void CDECL exit_thread( int status ) virtual_free_teb( teb ); } } + + sigemptyset( &sigset ); + sigaddset( &sigset, SIGQUIT ); + pthread_sigmask( SIG_BLOCK, &sigset, NULL ); + if (!InterlockedDecrement( nb_threads )) _exit( status ); + signal_exit_thread( status, pthread_exit_wrapper ); } -- 2.26.2