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

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

XMLWordPrintable

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

      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);
      }
      

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

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

              Created:
              Updated:
              Resolved:

                There are no open Gerrit changes