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

QScene lookup table not correctly cleared

    XMLWordPrintable

Details

    • Bug
    • Resolution: Done
    • P2: Important
    • 5.9.0 Beta 2
    • 5.7.0, 5.8
    • Qt3D
    • None

    Description

      When destroying an entity tree, all node are not remove from the scene observables list leaving dangling pointer in the lookup table.

      Having a aspect that send a lot of update to the model, I got crashes when deleting an object has the aspect back end produce new update event just before handling deletion event. When those update event get handle in the main loop, the scene lookup return dangling pointers and the application crash.

      I did found the source of this bug:

      // in 5.7 and 5.8
      void QNodePrivate::notifyDestructionChangesAndRemoveFromScene()
      {
          Q_Q(QNode);
          // ......
          QNodeVisitor visitor;
          visitor.traverse(q, this, &QNodePrivate::unsetSceneHelper);
      }
      
      void QNodePrivate::unsetSceneHelper(QNode *root)
      {
          // ....
          if (m_scene != nullptr)
              m_scene->removeObservable(root);
          root->d_func()->setScene(nullptr);
      }
      

      During the visitation unsetSceneHelper() is first called with the node being destroyed as the 'root' argument and then called on every children node. this->m_scene is set to nullptr on the first call so the 'if' statement is always false on children call and children are not remove from the observable list.

      The QNodePrivate::unsetSceneHelper should probably have being a static function from the start. Here a possible implementation that fix this bug:

      void QNodePrivate::unsetSceneHelper(QNode *root)
      {
          // We also need to handle QEntity <-> QComponent relationships removal
          if (QComponent *c = qobject_cast<QComponent *>(root)) {
              const QVector<QEntity *> entities = c->entities();
              for (QEntity *entity : entities) {
                  if (root->d_func()->scene())
                      root->d_func()->scene()->removeEntityForComponent(c->id(), entity->id());
              }
          }
      
          if (root->d_func()->scene() != nullptr)
              root->d_func()->scene()->removeObservable(root);
          root->d_func()->setScene(nullptr);
      }
      

      Has an attached file a minimalist project that does reproduce this bug.

      Attachments

        No reviews matched the request. Check your Options in the drop-down menu of this sections header.

        Activity

          People

            whagen Wieland Hagen
            gvallat guilhem vallat
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved:

              Gerrit Reviews

                There are no open Gerrit changes