Ticket #14626 (closed defect: fixed)

Opened 10 months ago

Last modified 9 months ago

wxThread::Kill causes whole program to abort in Linux

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

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

2.8.12thread.diff download (0.7 KB) - added by ZaneUJi 10 months ago.
Patch for 2.8.12

Change History

  Changed 10 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.

  Changed 10 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 10 months ago by ZaneUJi

Patch for 2.8.12

  Changed 10 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.

  Changed 10 months ago by vadz

  • keywords NPTL added
  • priority changed from normal to high
  • status changed from new to confirmed
  • component changed from wxGTK to base
  • 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" 
     
    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.

follow-up: ↓ 6   Changed 10 months ago by ZaneUJi

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

in reply to: ↑ 5   Changed 10 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?

  Changed 10 months ago by ZaneUJi

Yes, it does.

  Changed 9 months ago by VZ

  • status changed from confirmed to closed
  • resolution set to fixed

(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.

  Changed 9 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.