Solved Crash when reading a loader status
-
Hi,
I am having crashs at a part of code, where I'd not expect them to be possible - when reading from an existing property of an existing QML object.This is not a startup issue, it occurs when using the app, so the Loader must be constructed (not necessarily the loaderItem, of course).
I have been working with m_choiceOfFour quite a bit before the crash, so that seems to be perfectly valid. The problem seems to be load-related. It occurs more frequently on mobile than on desktop. It occurs more frequently when switching some costly animations on.How can this crash occur? I wouldn't think it could.
I seem to either lack understanding of a basic conceptual thing here or stare upon an obvious error that I just don't see.This is the c++ code where the crash happens:
auto loader0 = qvariant_cast<QQuickItem*>(m_choiceOfFour->property("eq0Loader")); auto loader1 = qvariant_cast<QQuickItem*>(m_choiceOfFour->property("eq1Loader")); //... qDebug()<<"loaders: "; qDebug()<<"loader0: "<<loader0; if (loader0) { qDebug()<<loader0->property("status"); // <- crash happens here } qDebug()<<"loader1: "<<loader1; if (loader1) { qDebug()<<loader1->property("status"); // <- or here } //...
The Loaders belong to several Buttons in a qml file ChoiceOfFour.qml:
Column { id: choiceColumn objectName: "choiceOfFour" property var eq0Loader: button0.loader property var eq1Loader: button1.loader //... ChoiceButton { id: button0 //... } ChoiceButton { id: button1 /…
Each ChoiceButton.qml contains a loader:
Button { id: button property alias loader: eqLoader visible: eqLoader.sourceComponent !== null //... Loader { asynchronous: false id: eqLoader onVisibleChanged: { if (!visible) { sourceComponent = null } } } }
A typical stacktrace would be:
1 QQmlComponent::status qqmlcomponent.cpp 417 0xf16e6ea 2 QQuickLoader::status qquickloader.cpp 798 0x1a9e8fa2 3 QQuickLoader::qt_static_metacall moc_qquickloader_p.cpp 247 0x1a9eaf15 4 QQuickLoader::qt_metacall moc_qquickloader_p.cpp 310 0x1a9eb05a 5 QMetaObject::metacall qmetaobject.cpp 301 0x6bafe04d 6 QMetaProperty::read qmetaobject.cpp 3105 0x6bb045a2 7 QObject::property qobject.cpp 3952 0x6bb1b2bc 8 QmlGenerator::createFourChoices qmlgenerator.cpp 412 0x40f510 <---- my file 9 Controller::displayOneMoreStep controller.cpp 88 0x411a1b <---- my file 10 Controller::qt_static_metacall moc_controller.cpp 178 0x41d2dc <---- (my file) 11 QMetaObject::activate qobject.cpp 3771 0x6bb1bfc9 12 QMetaObject::activate qobject.cpp 3633 0x6bb1c25d 13 QSingleShotTimer::timeout qtimer.moc 125 0x6bb2484b 14 QSingleShotTimer::timerEvent qtimer.cpp 321 0x6bb2496a 15 QObject::event qobject.cpp 1232 0x6bb1c600 16 QCoreApplicationPrivate::notify_helper qcoreapplication.cpp 1197 0x6baf4cfb 17 doNotify qcoreapplication.cpp 1138 0x6baf4d71 18 QCoreApplication::notify qcoreapplication.cpp 1124 0x6baf4eaf 19 QGuiApplication::notify qguiapplication.cpp 1770 0x17d67ec 20 QCoreApplication::notifyInternal2 qcoreapplication.cpp 1048 0x6baf4e01 ... <More>
The actual crash being in QQmlComponent::status:
417 [1] in qml\qqmlcomponent.cpp 0xf16e6ea <+0x000c> 8b 4a 08 mov 0x8(%edx),%ecx 0xf16e6ed <+0x000f> 39 4a 0c cmp %ecx,0xc(%edx) 0xf16e6f0 <+0x0012> 75 2f jne 0xf16e721 <QQmlComponent::status() const+67>
Any ideas?
-
@SeDi
QML and it's inner workings are not really my forte.But I know that your standart QML pages do not guarantee the existance of the objects for the whole duration of the app existance.
So my guess is, your page/file gets unloaded or the gc frees the memory and your cpp side does not get notfied of this change. This than makes the pointer you (potentially !?) store invalid and your program crashes.
-
@J.Hilk Thank you for your answer! I would understand that, if I'd have ChoiceOfFour.qml or ChoiceButton.qml in a loader or if I'd close a Dialog where they live in. But ChoiceOfFour.qml lives in the ApplicationWindow and is never tampered with. The four ChoiceButtons (containing the loaders) live inside it and are also not tampered with, other than being set invisible at times. I just don't see any garbage collection wanting to clean them up. On the other hand, I am filling those loaders with complex components (constructed in c++), where I carefully set ownership to JavaScript on each component:
QQmlComponent* component = new QQmlComponent(m_engine, QUrl(QStringLiteral("qrc:/ElementVariable.qml"))); m_engine->setObjectOwnership(component, QQmlEngine::JavaScriptOwnership); loader->setProperty("sourceComponent", QVariant::fromValue<QQmlComponent*>(component)); QQuickItem* loaderItem = qvariant_cast<QQuickItem*>(loader->property("item")); loaderItem->setProperty("text", v->name()); m_engine->setObjectOwnership(loaderItem, QQmlEngine::JavaScriptOwnership);
I don't see, where this could be causing a crash on reading(!) a property of the loader itself, though.
-
@J.Hilk You have been right after all. What first seemed to be a problem with animation has definitely been a problem of JavaScript deleting objects it shouldn't, at times where I'd not expected it to. I've since taken ownership of almost all objects to cpp and carefully check which one I have to ->deleteLater(). The bug is gone. Thank you!