Opened 20 months ago

Closed 19 months ago

Last modified 19 months 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

Description

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
+{
+public:
+    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")
     //wxLog::AddTraceMask("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 @@
     else
     {
         // terminate the thread
+        void *ret = pthread->m_exitcode;
         thread->Exit(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 20 months ago.
Patch for 2.8.12

Download all attachments as: .zip

Change History (10)

comment:1 Changed 20 months 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 20 months 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/libthread_db.so.1".
[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/libc.so.6
#2  0xb78d8835 in abort () from /lib/i386-linux-gnu/libc.so.6
#3  0xb7b1713d in __gnu_cxx::__verbose_terminate_handler() ()
   from /usr/lib/i386-linux-gnu/libstdc++.so.6
#4  0xb7b14ed3 in ?? () from /usr/lib/i386-linux-gnu/libstdc++.so.6
#5  0xb7b14f0f in std::terminate() () from /usr/lib/i386-linux-gnu/libstdc++.so.6
#6  0xb7b149d7 in __gxx_personality_v0 () from /usr/lib/i386-linux-gnu/libstdc++.so.6
#7  0xb7a62056 in ?? () from /lib/i386-linux-gnu/libgcc_s.so.1
#8  0xb7a62448 in _Unwind_ForcedUnwind () from /lib/i386-linux-gnu/libgcc_s.so.1             
#9  0xb70b18c2 in _Unwind_ForcedUnwind () from /lib/i386-linux-gnu/libpthread.so.0           
#10 0xb70af381 in __pthread_unwind () from /lib/i386-linux-gnu/libpthread.so.0               
#11 0xb70a9cc1 in pthread_exit () from /lib/i386-linux-gnu/libpthread.so.0                   
#12 0xb799f472 in pthread_exit () from /lib/i386-linux-gnu/libc.so.6                         
#13 0xb7c20c29 in wxThread::Exit(void*) () from /usr/lib/i386-linux-gnu/libwx_baseu-2.8.so.0 
#14 0xb7c20d0c in wxThreadInternal::Cleanup(wxThread*) ()                                    
   from /usr/lib/i386-linux-gnu/libwx_baseu-2.8.so.0                                         
#15 0xb7c20d5b in wxPthreadCleanup () from /usr/lib/i386-linux-gnu/libwx_baseu-2.8.so.0      
#16 0xb7c214c5 in wxThreadInternal::PthreadStart(wxThread*) ()                               
   from /usr/lib/i386-linux-gnu/libwx_baseu-2.8.so.0                                         
#17 0xb7c214eb in wxPthreadStart () from /usr/lib/i386-linux-gnu/libwx_baseu-2.8.so.0        
#18 0xb70a8d4c in start_thread () from /lib/i386-linux-gnu/libpthread.so.0
#19 0xb7991ace in clone () from /lib/i386-linux-gnu/libc.so.6
(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/libpthread.so.0
#2  0xb7c20563 in wxThreadInternal::Wait() ()
   from /usr/lib/i386-linux-gnu/libwx_baseu-2.8.so.0
#3  0xb7c20629 in wxThread::Wait() () from /usr/lib/i386-linux-gnu/libwx_baseu-2.8.so.0
#4  0x080501a2 in MyApp::OnInit() ()
#5  0x0805297e in wxAppConsole::CallOnInit() ()
#6  0xb7bc8f28 in wxEntry(int&, wchar_t**) ()
   from /usr/lib/i386-linux-gnu/libwx_baseu-2.8.so.0
#7  0xb7bc8fd6 in wxEntry(int&, char**) () from /usr/lib/i386-linux-gnu/libwx_baseu-2.8.so.0
#8  0x0804fc5b in main ()
(gdb) 

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/libthread_db.so.1".
[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/libc.so.6
#2  0xb75e6835 in abort () from /lib/i386-linux-gnu/libc.so.6
#3  0xb7767205 in unwind_cleanup () from /lib/i386-linux-gnu/libpthread.so.0
#4  0xb778b67b in _Unwind_DeleteException ()
   from /lib/i386-linux-gnu/libgcc_s.so.1
#5  0xb783cdfd in __cxa_end_catch ()
   from /usr/lib/i386-linux-gnu/libstdc++.so.6
#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/libpthread.so.0
#10 0xb769face in clone () from /lib/i386-linux-gnu/libc.so.6
(gdb) 

Changed 20 months ago by ZaneUJi

Patch for 2.8.12

comment:3 Changed 20 months 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 20 months 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> 
    5555#endif 
    5656 
     57#include <cxxabi.h> 
     58 
    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(); ) 
    861869 
    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 20 months ago by ZaneUJi

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

comment:6 in reply to: ↑ 5 Changed 20 months 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 20 months ago by ZaneUJi

Yes, it does.

comment:8 Changed 19 months 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 http://udrepper.livejournal.com/21541.html for more details.

Closes #14626.

comment:9 Changed 19 months 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.