Details
-
Bug
-
Resolution: Done
-
P2: Important
-
5.7.0, 5.8
-
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.