[mythtv-commits] Ticket #13571: Crash of backend on delete of program being recorded

MythTV noreply at mythtv.org
Sat Apr 4 21:33:14 UTC 2020


#13571: Crash of backend on delete of program being recorded
--------------------------------+-------------------------------
 Reporter:  Klaas de Waal       |          Owner:  Klaas de Waal
     Type:  Bug Report - Crash  |         Status:  assigned
 Priority:  minor               |      Milestone:  32.0
Component:  MythTV - General    |        Version:  Master Head
 Severity:  medium              |     Resolution:
 Keywords:                      |  Ticket locked:  0
--------------------------------+-------------------------------

Comment (by Klaas de Waal):

 The crash can now be reproduced easily by accessing the m_encoderList
 repeatedly right after StopRecording in line mainserver.cpp:2920 as shown
 in the following code fragment:

 {{{
             elink->StopRecording();

             // Repeated access of m_encoderList after StopRecording causes
 crash
             for (int i=0; i<100000; i++)
             {
                 int j = 0;
                 for (auto iter2 = m_encoderList->begin(); iter2 !=
 m_encoderList->end(); ++iter2)
                 {
                     j++;
                     EncoderLink *elink2 = *iter2;
                     if (elink2->IsLocal())
                     {
                         (void) iter2.key();
                     }
                 }
             }

 }}}
 The backtrace is usually similar to that in the initial post but
 incidentally the crash is in the QMap code, as shown here:

 {{{
 Thread 50 "PT3" received signal SIGSEGV, Segmentation fault.
 [Switching to Thread 0x7ffe9f7fe700 (LWP 2029089)]
 0x00007ffff20caa43 in QMapNodeBase::nextNode (this=0x8c3df0) at
 tools/qmap.cpp:58
 58              while (n->left)
 (gdb) bt
 #0  0x00007ffff20caa43 in QMapNodeBase::nextNode() const (this=0x8c3df0)
 at tools/qmap.cpp:58
 #1  0x0000000000446a66 in QMapNodeBase::nextNode() (this=0x8c3df0) at
 /usr/include/qt5/QtCore/qmap.h:92
 #2  0x000000000044b102 in QMapNode<int, EncoderLink*>::nextNode()
 (this=0x8c3df0) at /usr/include/qt5/QtCore/qmap.h:120
 #3  0x00000000004c6859 in QMap<int, EncoderLink*>::iterator::operator++()
 (this=0x7ffe9f7fd0b8) at /usr/include/qt5/QtCore/qmap.h:430
 #4  0x00000000004875fa in
 MainServer::DoHandleStopRecording(RecordingInfo&, PlaybackSock*)
 (this=0x714690, recinfo=..., pbs=0x0) at mainserver.cpp:2926
 #5  0x00000000004880c6 in
 MainServer::DoHandleDeleteRecording(RecordingInfo&, PlaybackSock*, bool,
 bool, bool)
     (this=0x714690, recinfo=..., pbs=0x7ffe98005440,
 forceMetadataDelete=false, lexpirer=false, forgetHistory=false) at
 mainserver.cpp:3038
 #6  0x00000000004879f3 in MainServer::HandleDeleteRecording(QString&,
 QString&, PlaybackSock*, bool, bool)
     (this=0x714690, chanid=..., starttime=..., pbs=0x7ffe98005440,
 forceMetadataDelete=false, forgetHistory=false) at mainserver.cpp:2987
 #7  0x000000000046fda7 in MainServer::ProcessRequestWork(MythSocket*)
 (this=0x714690, sock=0xa7a200) at mainserver.cpp:641
 #8  0x000000000046ea30 in MainServer::ProcessRequest(MythSocket*)
 (this=0x714690, sock=0xa7a200) at mainserver.cpp:456
 #9  0x00000000004c38d6 in ProcessRequestRunnable::run()
 (this=0x7ffea400b830) at mainserver.cpp:160
 #10 0x00007ffff5412909 in MPoolThread::run() (this=0x7ffe940036a0) at
 mthreadpool.cpp:140
 #11 0x00007ffff540f284 in MThreadInternal::run() (this=0x70de00) at
 mthread.cpp:79
 #12 0x00007ffff2067d96 in QThreadPrivate::start(void*) (arg=0x70de00) at
 thread/qthread_unix.cpp:360
 #13 0x00007ffff35d04e2 in start_thread () at /lib64/libpthread.so.0
 #14 0x00007ffff1b836d3 in clone () at /lib64/libc.so.6
 (gdb) l
 53      const QMapNodeBase *QMapNodeBase::nextNode() const
 54      {
 55          const QMapNodeBase *n = this;
 56          if (n->right) {
 57              n = n->right;
 58              while (n->left)
 59                  n = n->left;
 60          } else {
 61              const QMapNodeBase *y = n->parent();
 62              while (y && n == y->right) {
 (gdb)


 }}}

 It can take a few thousand loops across the m_encoderLink before the crash
 happens:
 {{{
 (gdb) fr 4
 #4  0x00000000004875fa in MainServer::DoHandleStopRecording
 (this=0x714690, recinfo=..., pbs=0x0) at mainserver.cpp:2926
 2926                    for (auto iter2 = m_encoderList->begin(); iter2 !=
 m_encoderList->end(); ++iter2)
 (gdb) l
 2921
 2922                // Repeated access of m_encoderList after
 stopRecording causes crash
 2923                for (int i=0; i<100000; i++)
 2924                {
 2925                    int j = 0;
 2926                    for (auto iter2 = m_encoderList->begin(); iter2 !=
 m_encoderList->end(); ++iter2)
 2927                    {
 2928                        j++;
 2929                        EncoderLink *elink2 = *iter2;
 2930                        if (elink2->IsLocal())
 (gdb) p i
 $13 = 6000
 (gdb) p j
 $14 = 14

 }}}

 The crash can also happen when stopping a recording. Deleting is not
 essential.
 The crash can also happen when creating and deleting recordings via the
 Services API with the script vcr.py from Bill Meek but then still a large
 number of deletes are needed. With the GUI it takes now only one or two
 deletes to produce the crash in the backend.

 Having a large m_encoderList, so having a lot of tuners and a lot of
 multirec virtual tuners, and making more recordings at the same time
 definitely increases the chance of crashing to, on my system, close to
 certain.

 The critical point is accessing the m_encoderList after the StopRecording
 is done which is what the patch is doing repeatedly. Therefore the patch
 20200325_stop_one_recording.patch does actually work because then the
 m_encoderList is not accessed anymore after the StopRecording.

 A patch with the "repeated access" code is attached.

-- 
Ticket URL: <https://code.mythtv.org/trac/ticket/13571#comment:11>
MythTV <http://www.mythtv.org>
MythTV Media Center


More information about the mythtv-commits mailing list