Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

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?


  • Moderators

    @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!


Log in to reply