Intermittent crash in QGraphicsScene



  • I'm having a problem with a QGraphicsScene that I am using to display an audio waveform. Occasionally when I load a new audio file, during the load of the new file, my code is crashing, and I am having a very difficult time pinpointing what is going wrong. The stack at the time of crash looks like this:

    1  QPen::widthF                                      qpen.cpp                       636  
    2  QGraphicsLineItem::boundingRect                   qgraphicsitem.cpp              9386 
    3  QGraphicsItemPrivate::effectiveBoundingRect       qgraphicsitem.cpp              2960 
    4  QGraphicsItemPrivate::sceneEffectiveBoundingRect  qgraphicsitem.cpp              3016 
    5  QGraphicsSceneBspTreeIndexPrivate::_q_updateIndex qgraphicsscenebsptreeindex.cpp 176  
    6  QGraphicsSceneBspTreeIndex::event                 qgraphicsscenebsptreeindex.cpp 
    7  QApplicationPrivate::notify_helper                qapplication.cpp               3718 
    8  QApplication::notify                              qapplication.cpp               3680 
    9  QCoreApplication::notifyInternal2                 qcoreapplication.cpp           1018 
    10 QEventDispatcherWin32::event                      qeventdispatcher_win.cpp       1040 
    11 QApplicationPrivate::notify_helper                qapplication.cpp               3718 
    12 QApplication::notify                              qapplication.cpp               3680 
    13 QCoreApplication::notifyInternal2                 qcoreapplication.cpp           1018 
    14 QCoreApplicationPrivate::sendPostedEvents         qcoreapplication.cpp           1678 
    15 QWindowsGuiEventDispatcher::sendPostedEvents      qwindowsguieventdispatcher.cpp 82   
    16 qt_internal_proc                                  qeventdispatcher_win.cpp       236  
    17 UserCallWinProcCheckWow                           USER32                              
    18 DispatchMessageWorker                             USER32                              
    19 QEventDispatcherWin32::processEvents              qeventdispatcher_win.cpp       627  
    20 QWindowsGuiEventDispatcher::processEvents         qwindowsguieventdispatcher.cpp 75   
    21 QEventLoop::exec                                  qeventloop.cpp                 211  
    22 QCoreApplication::exec                            qcoreapplication.cpp           1291 
    23 image00007ff7_8a830000                                                                
    24 image00007ff7_8a830000                                                                
    25 image00007ff7_8a830000                                                                
    26 BaseThreadInitThunk                               KERNEL32                            
    27 RtlUserThreadStart                                ntdll                               
    

    I cannot figure out what is going on. I never explicitly delete or remove anything from the scene, I just call clear() and then start telling it to add new items. But that line it is crashing on is just trying to access the Qt internal storage structure of the Pen, which must somehow be invalid. Any suggestions? What other info can I provide here to help diagnose?


  • Lifetime Qt Champion

    Hi,

    You need to provide Qt version, OS version, compiler and compiler version.


  • Qt Champions 2016

    In addition to what @SGaist said, go back in the debugger and see what's the event at:
    #14 QCoreApplicationPrivate::sendPostedEvents

    As a possible check, you could try disabling the BSP in the graphic scene and see if the crash still occurs.



  • This is a Windows 10 compile with MSVC2015_64bit and Qt 5.9.0. I had the same problem with a build against Qt 5.8.0.

    I don't know how to make it give the debugger the correct paths to the Qt source, however, so I can't look at the event. Right now the debugger's tooltip on all those filenames lists "C:\Users\qt\work\qt" as the source location, but that's not where I've installed Qt. How do I tell the debugger (or compiler) that the actual source locations for Qt are in "C:\Qt\5.9\src"? I'm using Qt Creator to do this build, and debugging with CDB.

    EDIT: Never mind, figured that out.



  • @kshegunov -- the event_type variable in QCoreApplicationPrivate::sendPostedEvents is 0 at the time of the crash, but I don't know if it's been modified by that function beforehand. The contents of the event actually being sent to QCoreApplication and onto the QGraphicsScene are opaque to me:

    	e	@0x27cc29e4e10	QMetaCallEvent
    		[QEvent]	@0x27cc29e4e10	QEvent
    		args_	0x0	void *
    		callFunction_	1436094857	<function>
    		method_offset_	5	unsigned short
    		method_relative_	15	unsigned short
    		nargs_	1	int
    		semaphore_	0x0	QSemaphore *
    		sender_	0x0	QObject *
    		signalId_	-1	int
    		slotObj_	0x0	QtPrivate::QSlotObjectBase *
    		types_	0	int
    

  • Qt Champions 2016

    @Chris-Hennes said in Intermittent crash in QGraphicsScene:

    @0x27cc29e4e10 QMetaCallEvent

    It's a queued slot call. This may very well be a bug ... You should investigate clear() it may queue some operation that is done later on an invalid BSP node, or possibly your adding items is somehow "concurrent" with queued call(s) coming from clear().

    Have you tried disabling BSP indexing?

    Edit:
    This looks very suspicious:

    sender_  0x0	QObject *
    slotObj_ 0x0	QtPrivate::QSlotObjectBase *
    

    If this ain't a lambda, then slotObj_ shouldn't be null.
    I believe it shouldn't be null either way. Is it possible some QObject were deleted while a queued event for it is pending? Are you sure you don't use delete anywhere?



  • @kshegunov said in Intermittent crash in QGraphicsScene:

    Are you sure you don't use delete anywhere?

    Yes - literally the only deletes in this code are in dialog class destructors, and those are only used at the end of the program execution (all of my dialogs are constructed up front and stored for later use).

    I'm trying it without the BSP tree now (it takes a while to generate the crash, so I can't tell yet whether it worked).



  • No luck on disabling the BSP tree index, the code still crashes in the same place. If I look at the QGraphicsLineItem object with the broken pen, although pen->d is null, line->d is not, and shows a set of coordinates that cannot actually be a line I have drawn in my code (it's diagonal, all of mine are perfectly vertical or horizontal). I can't tell if that's a clue or if it's an artifact of the same thing that is breaking the pen.


  • Qt Champions 2016

    @Chris-Hennes said in Intermittent crash in QGraphicsScene:

    No luck on disabling the BSP tree index, the code still crashes in the same place.

    I don't see how that's possible, as _q_updateIndex is specific to BSP indexing.

    I can't tell if that's a clue or if it's an artifact of the same thing that is breaking the pen.

    Probably unreliable. If the pen is null you can't be sure the object holding the pen's valid - the rationale is like with the 13th clock stroke.



  • @kshegunov said in Intermittent crash in QGraphicsScene:

    I don't see how that's possible, as _q_updateIndex is specific to BSP indexing.

    Sorry I wasn't clear: when I said "in the same place" I was referring to

    1  QPen::widthF                                      qpen.cpp                       636
    

    The path to get there is different, but it's still ultimately doing the same thing, and still crashing under the same circumstances. The new call stack is:

    1   QPen::widthF                                      qpen.cpp                       636  0x7fff9217711d 
    2   QGraphicsLineItem::boundingRect                   qgraphicsitem.cpp              9386 0x55f6dec7     
    3   QGraphicsItemPrivate::effectiveBoundingRect       qgraphicsitem.cpp              2960 0x55f77cc6     
    4   adjustedItemEffectiveBoundingRect                 qgraphicsscene_p.h             353  0x55fbfe43     
    5   QGraphicsScenePrivate::processDirtyItemsRecursive qgraphicsscene.cpp             5205 0x55fba406     
    6   QGraphicsScenePrivate::_q_processDirtyItems       qgraphicsscene.cpp             487  0x55fb105e     
    7   QGraphicsScene::qt_static_metacall                moc_qgraphicsscene.cpp         184  0x55fa7966     
    8   QMetaCallEvent::placeMetaCall                     qobject.cpp                    504  0x55255821     
    9   QObject::event                                    qobject.cpp                    1246 0x5524e17f     
    10  QGraphicsScene::event                             qgraphicsscene.cpp             3523 0x55fad6f8     
    11  QApplicationPrivate::notify_helper                qapplication.cpp               3717 0x559d6f3e     
    12  QApplication::notify                              qapplication.cpp               3089 0x559d1973     
    13  QCoreApplication::notifyInternal2                 qcoreapplication.cpp           1018 0x551f61f6     
    14  QCoreApplication::sendEvent                       qcoreapplication.h             233  0x552010b2     
    15  QCoreApplicationPrivate::sendPostedEvents         qcoreapplication.cpp           1678 0x551f7ab2     
    16  QEventDispatcherWin32::sendPostedEvents           qeventdispatcher_win.cpp       1063 0x552b1dea     
    17  QWindowsGuiEventDispatcher::sendPostedEvents      qwindowsguieventdispatcher.cpp 82   0x7fff9a2dfd74 
    18  qt_internal_proc                                  qeventdispatcher_win.cpp       236  0x552afacd     
    19  UserCallWinProcCheckWow                           USER32                              0x7fffdb8dbc50 
    20  DispatchMessageWorker                             USER32                              0x7fffdb8db5cf 
    ... <More>                                                                                               
    

  • Qt Champions 2016

    Mind sharing some code - how you clear and create the scene items. I can't tell anything to be plainly wrong by looking at the trace. Perhaps try "delaying" the item reinsertions by some time (e.g. few seconds) to see if it's not some kind event concurrency problem ...?



  • It looks like the following code is the culprit:

        if (_selectionRegion && _scene.items().contains(_selectionRegion)) {
            _selectionRegion->setRect (r);
        } else {
            QPen pen (Qt::black);
            QBrush brush (QColor(0,0,0,70));
            _selectionRegion = _scene.addRect (r, pen, brush);
        }
    

    In particular, something about that first "if" clause. If I just let the thing rebuild the rectangle every time it does not crash (e.g. I comment out the conditional and just execute the second path). This bit of code is called in a number of places, including at the beginning of execution, and at various times pre- and post- clear().



  • Hi @Chris-Hennes

    Then selectionRegion is probably deleted (or not yet created) at the moment that you use it. If deleted you can set a breakpoint in the object's destructor and see in the backtrace where this deletion comes from.

    -Michael.



  • Well, I know exactly where it's being deleted -- in the calls to clear(). But it seemed to me that those calls would result in _scene.items().contains(_selectionRegion) returning false. And while this seems to be true most of the time, every once in a while it's not. The rectangle is invalid, but is still in the items list.

    So, the current workaround (which is being stress-tested as I type) is that the superclass which calls clear() now instead calls a virtual function that calls clear(). In the subclass that owns _selectionRegion I overload this virtual function, call the parent (thereby calling clear()) and then explicitly nullify _selectionRegion. Hopefully this sequence prevents any queued events from calling the _selectionRegion update code in between calls to clear() and the nullification of the member. I've managed to type this whole thing without the code crashing yet, so this looks promising.



  • @Chris-Hennes
    hi, I think the easiest solution would be setting selectionRegion to a Nullpointer after the clear cmd

    selectionRegion->clear();
    selectionReadion = Q_NULLPTR;
    

    that way the first part of your if condition will return false and not crash.



  • Right, that's essentially the solution I've got, with the caveat that clear() is called by a superclass that knows nothing about the _selectionRegion so I had to do a bit of refactoring to achieve that effect. The crash seems to be gone with that change, so I'm going to mark this as solved here (and in GitHub). But we all know how this type of bug goes, I might be back tomorrow :/


  • Qt Champions 2016

    @Chris-Hennes said in Intermittent crash in QGraphicsScene:

    But we all know how this type of bug goes, I might be back tomorrow :/

    In either case, please report it to the bugtracker. It might not get fixed soon, or ever, but it's a good idea to be there so others won't struggle with this as much as you had.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.