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? -
Hi,
You need to provide Qt version, OS version, compiler and compiler version.
-
In addition to what @SGaist said, go back in the debugger and see what's the event at:
#14 QCoreApplicationPrivate::sendPostedEventsAs 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
-
@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 fromclear()
.Have you tried disabling BSP indexing?
Edit:
This looks very suspicious:sender_ 0x0 QObject * slotObj_ 0x0 QtPrivate::QSlotObjectBase *
If this ain't a lambda, thenslotObj_
shouldn't be null.
I believe it shouldn't be null either way. Is it possible someQObject
were deleted while a queued event for it is pending? Are you sure you don't usedelete
anywhere? -
@kshegunov said in Intermittent crash in QGraphicsScene:
Are you sure you don't use delete anywhere?
Yes - literally the only
delete
s 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.
-
@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>
-
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()
. -
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)
returningfalse
. 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 callsclear()
. In the subclass that owns_selectionRegion
I overload this virtual function, call the parent (thereby callingclear()
) and then explicitly nullify_selectionRegion
. Hopefully this sequence prevents any queued events from calling the_selectionRegion
update code in between calls toclear()
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 settingselectionRegion
to a Nullpointer after the clear cmdselectionRegion->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 :/ -
@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.