Details
-
Bug
-
Resolution: Cannot Reproduce
-
P1: Critical
-
6.6.1
-
None
-
-
a6700d247 (dev), 297d96a4f (6.8), af61e2f31 (6.7), 3771cedce (tqtc/lts-6.5)
Description
I have a type (lets call it MyType.qml) which looks something like:
import QtQuick Rectangle { id: bgRect clip: true color: "lightsteelblue" width: 70 height: 400 property bool animationEnabled: true property real nextYPos: 0.0 onNextYPosChanged: if (visible) maybeAnimate() function maybeAnimate() { if (animationEnabled) { if (!yAnim.running && fgRect.y != nextYPos) { yAnim.from = fgRect.y yAnim.to = nextYPos yAnim.start() } } } Timer { running: true repeat: true interval: 450 onTriggered: bgRect.nextYPos = Math.random() * bgRect.height } Rectangle { id: fgRect color: "blue" width: bgRect.width height: bgRect.height z: 2 } YAnimator { id: yAnim target: animTarget easing.type: Easing.InOutQuad duration: 200 onRunningChanged: if (!running) Qt.callLater(maybeAnimate) } }
If you construct a whole lot of these and destroy them after random times (e.g. between 0.5 and 10 seconds) you should eventually hit the crash.
The backtrace is:
1 QQmlPrivate::loadObjectProperty<0> qqml.cpp 907 0x7fff17ec9c23 2 QQmlPrivate::AOTCompiledContext::loadScopeObjectPropertyLookup qqml.cpp 1660 0x7fff17ecf483 3 `QmlCacheGeneratedCode::_qt_qml_MyType_qml::<lambda_10>::operator()'::`2'::<lambda_1>::operator() MyType_qml.cpp 1554 0x7ff7991f916c 4 QV4::Moth::VME::exec qv4vme_moth.cpp 536 0x7fff17e9a79d 5 <lambda_ca494cc21659423f5644870c1a1f4b97>::operator() qv4functionobject.cpp 544 0x7fff17e0be39 6 QV4::convertAndCall<<lambda_ca494cc21659423f5644870c1a1f4b97>> qv4jscall_p.h 137 0x7fff17e0bc7f 7 QV4::ArrowFunction::virtualCall qv4functionobject.cpp 557 0x7fff17e0a2a8 8 QQmlDelayedCallQueue::DelayedFunctionCall::execute qqmldelayedcallqueue.cpp 43 0x7fff17f022a4 9 QQmlDelayedCallQueue::qt_static_metacall moc_qqmldelayedcallqueue_p.cpp 111 0x7fff17f0036f 10 QMetaCallEvent::placeMetaCall qobject.cpp 656 0x7fff177d8114 11 QObject::event qobject.cpp 1437 0x7fff177d6303 12 QCoreApplication::notify qcoreapplication.cpp 1201 0x7fff1778b5c6 13 QCoreApplication::notifyInternal2 qcoreapplication.cpp 1121 0x7fff1778b6ff 14 QCoreApplicationPrivate::sendPostedEvents qcoreapplication.cpp 1901 0x7fff1778e826 15 QWindowsGuiEventDispatcher::sendPostedEvents qwindowsguieventdispatcher.cpp 44 0x7fff185619af 16 QEventDispatcherWin32::processEvents qeventdispatcher_win.cpp 471 0x7fff17912d70 17 QWindowsGuiEventDispatcher::processEvents qwindowsguieventdispatcher.cpp 37 0x7fff18561989 18 QEventLoop::exec qeventloop.cpp 182 0x7fff17792f8f 19 QCoreApplication::exec qcoreapplication.cpp 1442 0x7fff17788c8d 20 main main.cpp 300 0x7ff7991165a5 21 __scrt_common_main_seh exe_common.inl 288 0x7ff7995b9824 22 BaseThreadInitThunk KERNEL32 0x7ffff6b7257d 23 RtlUserThreadStart ntdll 0x7ffff77caa48
The relevant bit of code from the AOT generated cpp is:
// generate_LoadQmlContextPropertyLookup while (!aotContext->loadScopeObjectPropertyLookup(58, &r2_0)) {
I am not sure, but I believe what is happening is that the YAnimator finishes running just before the MyType instance is destroyed, so it posts the `Qt.callLater(maybeAnimate)` event to the event queue; the instance is then destroyed, and then the callLater is serviced, so maybeAnimate is invoked with an invalid/deleted scope object.
There is a bit of a hack workaround: if I instead have:
... function maybeAnimate(scopeObject) { if (scopeObject == null) return; if (animationEnabled) { ... } } onNextYPosChanged: if (visible) maybeAnimate(bgRect) yAnim.onRunningChanged: if (!running) Qt.callLater(maybeAnimate, bgRect) ...
Then it looks like either (1) the reference keeps the scope object alive long enough to avoid the crash, OR (2) the check catches that the reference has become null and so the crash is avoided. If it's (1) then I do wonder when the reference will be cleaned up, or if this is just a perma leak. I didn't dig that far.
Tested on windows, Qt 6.6.1, msvc2022, without NO_CACHEGEN specified.