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

Nodes may be referenced on the backend before they have been created

    XMLWordPrintable

Details

    • Bug
    • Resolution: Done
    • P1: Critical
    • 5.9.5
    • 5.10.0
    • Qt3D
    • None
    • Need to handle list properties where the payload is QNode*'s too.
    • 8fa23602cff47de6d19d05a8428a8e753bf73d61

    Description

      If the following happens, a node may be referenced by the backend before it has been created:

      1) Any change occurs, calling QPostman::notifyBackend(), which queues a new batch by calling submitChangeBatch.invoke(this, Qt::QueuedConnection).
      2) Node A is created and added to a list in node B (for instance a QAttribute is added to a QGeometry). This adds the change to the current batch on QPostman, but also queues a call to _q_postConstruction which will happen after the batch. (QNodePrivate::init() calls QMetaObject::invokeMethod(q, "_q_postConstructorInit", Qt::QueuedConnection)).
      3) processEvents() is called and starts processing the submitChangeBatch
      4) While processing, QAbstractAspect::syncChanges() is called, processes the change that set node A on node B.
      5) processEvents() continues with _q_postConstructionInit for node A. This adds a new batch to QPostman, but it is too late, the backend may already have started using A.
      6) Backend crashes by trying to use A.
      7) If not for the crash, A would have been created on the backend.

      It turned out hard to create a small example that reproduces the issue. It should be mentioned that it was discovered for a case where more attributes were added through a connection listening on a 'geometryChanged' signal. Something along these lines:

      connect(mesh, &Qt3DRender::QGeometryRenderer::geometryChanged, [=] () {
          setupMoreAttributes();
      });
      

      A possible fix is to queue a new event for each property change, but performance will likely suffer:

      void QPostman::notifyBackend(const QSceneChangePtr &change)
      {
          QMetaObject::invokeMethod(this, "notifyBackendHack", Qt::QueuedConnection, Q_ARG(QSceneChangePtr, change));
      }
      
      void QPostman::notifyBackendHack(const QSceneChangePtr &change)
      {
          Q_D(QPostman);
          if (d->m_batch.empty()) {
              static const QMetaMethod submitChangeBatch = submitChangeBatchMethod();
              submitChangeBatch.invoke(this, Qt::QueuedConnection);
          }
          d->m_batch.push_back(change);
      }
      

      Attachments

        Issue Links

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

          Activity

            People

              seanharmer Sean Harmer
              dragly Svenn-Arne Dragly
              Votes:
              0 Vote for this issue
              Watchers:
              2 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved:

                Gerrit Reviews

                  There are no open Gerrit changes