Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-63036

qmlDeferredExecute() crashes with grouped properties

    XMLWordPrintable

    Details

    • Commits:
      a32cf1a22d096b33340cddbe91328c6c088e221d

      Description

      In Qt Quick Controls 2, we want to make Button backgrounds etc. deferred properties to avoid unnecessarily executing the default background when the background is overridden with a custom background.

      qtquickcontrols2/Button.qml:

      T.Button {
          implicitWidth: background.implicitWidth // depency
          background: Rectangle { ... } // deferred
      }
      

      // usercode1.qml

      Button {
          background: Rectangle { ... } // overrides
      }
      

      So far, so good. This is already working as desired. Problems arise if the deferred background property is not overridden, but accessed as a grouped property instead:

      usercode2.qml

      Button {
          background.visible: false // boom
      }
      

      Due to the dependent binding, this leads to an infinite loop qmlExecuteDeferred() => QQmlObjectCreator::setupBindings() => qmlExecuteDeferred().

      A minimal testcase:

      #include <QtQml>
      
      class DeferredType : public QObject
      {
          Q_OBJECT
          Q_PROPERTY(QObject *deferredObject READ deferredObject WRITE setDeferredObject NOTIFY deferredObjectChanged)
          Q_CLASSINFO("DeferredPropertyNames", "deferredObject")
      
      public:
          DeferredType(QObject *parent = nullptr) : QObject(parent) { }
      
          QObject *deferredObject() const
          {
              if (!m_deferredObject)
                  qmlExecuteDeferred(const_cast<DeferredType *>(this));
              return m_deferredObject;
          }
      
          void setDeferredObject(QObject *object)
          {
              if (m_deferredObject == object)
                  return;
              delete m_deferredObject;
              m_deferredObject = object;
              emit deferredObjectChanged();
          }
      
      signals:
          void deferredObjectChanged();
      
      private:
          QObject *m_deferredObject = nullptr;
      };
      
      int main(int argc, char *argv[])
      {
          QCoreApplication app(argc, argv);
      
          qmlRegisterType<DeferredType>("main", 1, 0, "DeferredType");
      
          QQmlEngine engine;
          QQmlComponent component(&engine);
          component.setData("import main 1.0; DeferredType { deferredObject.objectName: 'foo'; objectName: deferredObject.objectName }", QUrl());
          component.create(); // BOOM
      }
      
      #include "main.moc"
      

      Relevant part of the stacktrace:

      Thread 1 "untitled811" received signal SIGSEGV, Segmentation fault.
      0x0000000000401da4 in DeferredType::qt_static_metacall (_o=<error reading variable: Cannot access memory at address 0x7fffff7fefe8>, _c=<error reading variable: Cannot access memory at address 0x7fffff7fefe4>, 
          _id=<error reading variable: Cannot access memory at address 0x7fffff7fefe0>, _a=<error reading variable: Cannot access memory at address 0x7fffff7fefd8>) at ./main.moc:78
      78	{
      (gdb) bt
      #0  0x0000000000401da4 in DeferredType::qt_static_metacall (_o=<error reading variable: Cannot access memory at address 0x7fffff7fefe8>, 
          _c=<error reading variable: Cannot access memory at address 0x7fffff7fefe4>, _id=<error reading variable: Cannot access memory at address 0x7fffff7fefe0>, 
          _a=<error reading variable: Cannot access memory at address 0x7fffff7fefd8>) at ./main.moc:78
      #1  0x000000000040200b in DeferredType::qt_metacall (this=0x668e10, _c=QMetaObject::ReadProperty, _id=0, _a=0x7fffff7ff0e0) at ./main.moc:156
      #2  0x00007f3bdd4a2388 in QMetaObject::metacall (object=<optimized out>, cl=cl@entry=QMetaObject::ReadProperty, idx=<optimized out>, argv=argv@entry=0x7fffff7ff0e0) at kernel/qmetaobject.cpp:301
      #3  0x00007f3bddaa1d3f in QQmlObjectCreator::setPropertyBinding (this=this@entry=0x95ea60, property=property@entry=0x7f3bcc0054c8, binding=binding@entry=0x7f3bcc00b218) at qml/qqmlobjectcreator.cpp:781
      #4  0x00007f3bddaa3662 in QQmlObjectCreator::setupBindings (this=this@entry=0x95ea60, applyDeferredBindings=applyDeferredBindings@entry=true) at qml/qqmlobjectcreator.cpp:703
      #5  0x00007f3bddaa3a61 in QQmlObjectCreator::populateDeferredProperties (this=0x95ea60, instance=0x0, instance@entry=0x668e10) at qml/qqmlobjectcreator.cpp:273
      #6  0x00007f3bdda10a08 in QQmlComponentPrivate::beginDeferred (enginePriv=enginePriv@entry=0x623700, object=object@entry=0x668e10, state=state@entry=0x7fffff7ff480) at qml/qqmlcomponent.cpp:892
      #7  0x00007f3bdd9f752a in QtQml::qmlExecuteDeferred (object=0x668e10) at qml/qqmlengine.cpp:1467
      #8  0x0000000000402539 in DeferredType::deferredObject (this=0x668e10) at ../untitled811/main.cpp:15
      #9  0x0000000000401e77 in DeferredType::qt_static_metacall (_o=0x668e10, _c=QMetaObject::ReadProperty, _id=0, _a=0x7fffff7ff5f0) at ./main.moc:103
      #10 0x000000000040200b in DeferredType::qt_metacall (this=0x668e10, _c=QMetaObject::ReadProperty, _id=0, _a=0x7fffff7ff5f0) at ./main.moc:156
      #11 0x00007f3bdd4a2388 in QMetaObject::metacall (object=<optimized out>, cl=cl@entry=QMetaObject::ReadProperty, idx=<optimized out>, argv=argv@entry=0x7fffff7ff5f0) at kernel/qmetaobject.cpp:301
      #12 0x00007f3bddaa1d3f in QQmlObjectCreator::setPropertyBinding (this=this@entry=0x95e880, property=property@entry=0x7f3bcc0054c8, binding=binding@entry=0x7f3bcc00b218) at qml/qqmlobjectcreator.cpp:781
      #13 0x00007f3bddaa3662 in QQmlObjectCreator::setupBindings (this=this@entry=0x95e880, applyDeferredBindings=applyDeferredBindings@entry=true) at qml/qqmlobjectcreator.cpp:703
      #14 0x00007f3bddaa3a61 in QQmlObjectCreator::populateDeferredProperties (this=0x95e880, instance=0x0, instance@entry=0x668e10) at qml/qqmlobjectcreator.cpp:273
      #15 0x00007f3bdda10a08 in QQmlComponentPrivate::beginDeferred (enginePriv=enginePriv@entry=0x623700, object=object@entry=0x668e10, state=state@entry=0x7fffff7ff990) at qml/qqmlcomponent.cpp:892
      #16 0x00007f3bdd9f752a in QtQml::qmlExecuteDeferred (object=0x668e10) at qml/qqmlengine.cpp:1467
      

        Attachments

          Issue Links

          For Gerrit Dashboard: QTBUG-63036
          # Subject Branch Project Status CR V

            Activity

              People

              • Assignee:
                Unassigned
                Reporter:
                jpnurmi J-P Nurmi
              • Votes:
                0 Vote for this issue
                Watchers:
                1 Start watching this issue

                Dates

                • Created:
                  Updated:
                  Resolved:

                  Gerrit Reviews

                  There are no open Gerrit changes