Details
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
- relates to
-
QTBUG-72236 Qt3D crashes when adding layer component to entity dynamically
- Closed