Opened 6 years ago

Closed 6 years ago

Last modified 6 years ago

#14626 closed defect (fixed)

wxThread::Kill causes whole program to abort in Linux

Reported by: ZaneUJi Owned by:
Priority: high Milestone:
Component: base Version: stable-latest
Keywords: wxThread Kill abort NPTL Cc:
Blocked By: Blocking:
Patch: no


After change the code:

--- samples/thread/thread0.cpp	2012-09-01 18:23:18.335144821 +0800
+++ samples/thread/thread.cpp	2012-09-01 22:46:30.617642120 +0800
@@ -360,9 +360,38 @@
     m_waitingUntilAllDone = false;
+class BlockingThread : public wxThread
+    BlockingThread() : wxThread(wxTHREAD_JOINABLE)
+    {
+        Create();
+    }
+    virtual void *Entry()
+    {
+        try {
+            char ch;
+            std::cin >> ch;
+        } catch (...) {
+            //if (TestDestroy()) {
+                throw;
+            //}
+        }
+    }
 // `Main program' equivalent, creating windows and returning main app frame
 bool MyApp::OnInit()
+    wxThread *thread = new BlockingThread();
+    if (thread->Run() != wxTHREAD_NO_ERROR) {
+        wxLogError(wxT("Can't start thread!"));
+    }
+    wxThread::Sleep(1000);
+    thread->Kill();
+    thread->Wait();
+    delete thread;
     // uncomment this to get some debugging messages from the trace code
     // on the console (or just set WXTRACE env variable to include "thread")

compile it:

g++ -c -o thread.o `wx-config --cxxflags` thread.cpp
g++ thread.o `wx-config --libs` -o thread

The program aborts with the following message:

terminate called without an active exception
Aborted (core dumped)

When I comment out the call to pthread_exit

--- src/unix/threadpsx0.cpp	Sat Sep 01 22:33:15 2012
+++ src/unix/threadpsx.cpp	Sat Sep 01 21:28:33 2012
@@ -806,11 +806,12 @@
         // terminate the thread
+        void *ret = pthread->m_exitcode;
-        wxFAIL_MSG(wxT("wxThread::Exit() can't return."));
+        //wxFAIL_MSG(wxT("wxThread::Exit() can't return."));
-        return NULL;
+        return ret;//NULL;
@@ -1502,9 +1503,9 @@
     // terminate the thread (pthread_exit() never returns)
-    pthread_exit(status);
+    //pthread_exit(status);
-    wxFAIL_MSG(_T("pthread_exit() failed"));
+    //wxFAIL_MSG(_T("pthread_exit() failed"));
 // also test whether we were paused

everything works just fine.

Attachments (1)

2.8.12thread.diff download (708 bytes) - added by ZaneUJi 6 years ago.
Patch for 2.8.12

Download all attachments as: .zip

Change History (10)

comment:1 Changed 6 years ago by vadz

I didn't have time to test this but I'd be curious if you could put a breakpoint on terminate under gdb to see where it is called from. The only idea I have is that pthread_exit() is wrongly called from the main thread (this, again, can be easily checked by just putting a breakpoint on the line calling it) but I don't see how can it happen.

Also, can you test this code with 2.9.4?

P.S. Please attach your patches as files to make them easy to apply.

comment:2 Changed 6 years ago by ZaneUJi

Call stack:

(gdb) r
Starting program: /home/zane/examples/samples/thread/thread 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/i386-linux-gnu/".
[New Thread 0xb677eb40 (LWP 3689)]
[New Thread 0xb5dffb40 (LWP 3690)]
[New Thread 0xb53ffb40 (LWP 3691)]
terminate called without an active exception

Program received signal SIGABRT, Aborted.
[Switching to Thread 0xb53ffb40 (LWP 3691)]
0xb7fdd424 in __kernel_vsyscall ()
(gdb) bt
#0  0xb7fdd424 in __kernel_vsyscall ()
#1  0xb78d51ef in raise () from /lib/i386-linux-gnu/
#2  0xb78d8835 in abort () from /lib/i386-linux-gnu/
#3  0xb7b1713d in __gnu_cxx::__verbose_terminate_handler() ()
   from /usr/lib/i386-linux-gnu/
#4  0xb7b14ed3 in ?? () from /usr/lib/i386-linux-gnu/
#5  0xb7b14f0f in std::terminate() () from /usr/lib/i386-linux-gnu/
#6  0xb7b149d7 in __gxx_personality_v0 () from /usr/lib/i386-linux-gnu/
#7  0xb7a62056 in ?? () from /lib/i386-linux-gnu/
#8  0xb7a62448 in _Unwind_ForcedUnwind () from /lib/i386-linux-gnu/             
#9  0xb70b18c2 in _Unwind_ForcedUnwind () from /lib/i386-linux-gnu/           
#10 0xb70af381 in __pthread_unwind () from /lib/i386-linux-gnu/               
#11 0xb70a9cc1 in pthread_exit () from /lib/i386-linux-gnu/                   
#12 0xb799f472 in pthread_exit () from /lib/i386-linux-gnu/                         
#13 0xb7c20c29 in wxThread::Exit(void*) () from /usr/lib/i386-linux-gnu/ 
#14 0xb7c20d0c in wxThreadInternal::Cleanup(wxThread*) ()                                    
   from /usr/lib/i386-linux-gnu/                                         
#15 0xb7c20d5b in wxPthreadCleanup () from /usr/lib/i386-linux-gnu/      
#16 0xb7c214c5 in wxThreadInternal::PthreadStart(wxThread*) ()                               
   from /usr/lib/i386-linux-gnu/                                         
#17 0xb7c214eb in wxPthreadStart () from /usr/lib/i386-linux-gnu/        
#18 0xb70a8d4c in start_thread () from /lib/i386-linux-gnu/
#19 0xb7991ace in clone () from /lib/i386-linux-gnu/
(gdb) info threads
  Id   Target Id         Frame 
* 4    Thread 0xb53ffb40 (LWP 3691) "thread" 0xb7fdd424 in __kernel_vsyscall ()
  3    Thread 0xb5dffb40 (LWP 3690) "gdbus" 0xb7fdd424 in __kernel_vsyscall ()
  2    Thread 0xb677eb40 (LWP 3689) "dconf worker" 0xb7fdd424 in __kernel_vsyscall ()
  1    Thread 0xb6a0e880 (LWP 3686) "thread" 0xb7fdd424 in __kernel_vsyscall ()
(gdb) thread 1
[Switching to thread 1 (Thread 0xb6a0e880 (LWP 3686))]
#0  0xb7fdd424 in __kernel_vsyscall ()
(gdb) bt
#0  0xb7fdd424 in __kernel_vsyscall ()
#1  0xb70a9e1c in pthread_join () from /lib/i386-linux-gnu/
#2  0xb7c20563 in wxThreadInternal::Wait() ()
   from /usr/lib/i386-linux-gnu/
#3  0xb7c20629 in wxThread::Wait() () from /usr/lib/i386-linux-gnu/
#4  0x080501a2 in MyApp::OnInit() ()
#5  0x0805297e in wxAppConsole::CallOnInit() ()
#6  0xb7bc8f28 in wxEntry(int&, wchar_t**) ()
   from /usr/lib/i386-linux-gnu/
#7  0xb7bc8fd6 in wxEntry(int&, char**) () from /usr/lib/i386-linux-gnu/
#8  0x0804fc5b in main ()

And there is no luck with the latest trunk:

(gdb) r
Starting program: /home/zane/e/wxWidgets/mydbuild/samples/thread/thread 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/i386-linux-gnu/".
[New Thread 0xb6562b40 (LWP 1034)]
[New Thread 0xb5bffb40 (LWP 1035)]
[New Thread 0xb51ffb40 (LWP 1036)]
FATAL: exception not rethrown

Program received signal SIGABRT, Aborted.
[Switching to Thread 0xb51ffb40 (LWP 1036)]
0xb7fdd424 in __kernel_vsyscall ()
(gdb) bt
#0  0xb7fdd424 in __kernel_vsyscall ()
#1  0xb75e31ef in raise () from /lib/i386-linux-gnu/
#2  0xb75e6835 in abort () from /lib/i386-linux-gnu/
#3  0xb7767205 in unwind_cleanup () from /lib/i386-linux-gnu/
#4  0xb778b67b in _Unwind_DeleteException ()
   from /lib/i386-linux-gnu/
#5  0xb783cdfd in __cxa_end_catch ()
   from /usr/lib/i386-linux-gnu/
#6  0xb78ec4c6 in wxAppConsoleBase::OnUnhandledException (this=0x8094f00)
    at ../src/common/appbase.cpp:625
#7  0xb79c8a2c in wxThreadInternal::PthreadStart (thread=0x80d7588)
    at ../src/unix/threadpsx.cpp:860
#8  0xb79c8246 in wxPthreadStart (ptr=0x80d7588)
    at ../src/unix/threadpsx.cpp:804
#9  0xb7760d4c in start_thread () from /lib/i386-linux-gnu/
#10 0xb769face in clone () from /lib/i386-linux-gnu/

Changed 6 years ago by ZaneUJi

Patch for 2.8.12

comment:3 Changed 6 years ago by ZaneUJi

I don't know the purpose of the TRY CATCH block that surrounds thread->Entry(). So I am not able to patch 2.9.4. I don't mind somebody taking from here and improving my patch.

comment:4 Changed 6 years ago by vadz

  • Component changed from wxGTK to base
  • Keywords NPTL added
  • Priority changed from normal to high
  • Status changed from new to confirmed
  • Version changed from 2.8.12 to 2.9-svn

OK, pthread_cancel() in Linux uses exceptions to trigger stack unwinding which results in this problem because we don't rethrow the unwinding exception in wxAppConsoleBase::OnUnhandledException().

The solution, according to Ulrich Drepper himself is to always rethrow abi::__forced_unwind& exceptions. And this patch does seem to solve the problem:

  • src/unix/threadpsx.cpp

    diff --git a/src/unix/threadpsx.cpp b/src/unix/threadpsx.cpp
    index ed33ff3..79e800f 100644
    a b  
    5454    #include <thread.h>
     57#include <cxxabi.h>
    5759// we use wxFFile under Linux in GetCPUCount()
    5860#ifdef __LINUX__
    5961    #include "wx/ffile.h"
    void *wxThreadInternal::PthreadStart(wxThread *thread) 
    857859                       wxT("Thread %p Entry() returned %lu."),
    858860                       THR_ID(pthread), wxPtrToUInt(pthread->m_exitcode));
    859861        }
     862        catch ( abi::__forced_unwind& )
     863        {
     864            wxCriticalSectionLocker lock(thread->m_critsect);
     865            pthread->SetState(STATE_EXITED);
     866            throw;
     867        }
    860868        wxCATCH_ALL( wxTheApp->OnUnhandledException(); )
    862870        {

Please let me know if you have any problems with this in your real application. If not, we should conditionalize this properly and commit.

P.S. Note to self: the patch above is in the local git branch 14626.

comment:5 follow-up: Changed 6 years ago by ZaneUJi

I found the problem when I work on an open source project.

comment:6 in reply to: ↑ 5 Changed 6 years ago by vadz

Replying to ZaneUJi:

I found the problem when I work on an open source project.

So does the patch above work with this open source project?

comment:7 Changed 6 years ago by ZaneUJi

Yes, it does.

comment:8 Changed 6 years ago by VZ

  • Resolution set to fixed
  • Status changed from confirmed to closed

(In [72531]) Rethrow abi::forced_unwind in wxThread code under Unix.

We must always rethrow the special abi::forced_unwind exception when
handling exception in threads under Linux as the NPTL simply terminates the
process at first opportunity if this exception is not rethrown.

See for more details.

Closes #14626.

comment:9 Changed 6 years ago by VZ

(In [72532]) Fix wrong configure test for abi::forced_unwind in previous commit.

The previous commit was accidental and contained an initial version of the
patch which didn't test for NPTL abi::forced_unwind correctly and just
tested whether cxxabi.h header was available.

Tighten the check to work on the other systems and check for forced_unwind
existence itself.

Also check for cxxabi.h before testing for cxa_demangle as there is no need
to try to compile another test program if we already know that this entire
header is unavailable anyhow.

See #14626.

Note: See TracTickets for help on using tickets.