From e22280692261f5911f38c2674c6bf1fb6859ca72 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bernhard=20=C3=83=C2=83=C3=82=C2=9Cbelacker?=
 <bernhardu@mailbox.org>
Date: Fri, 10 Feb 2017 21:27:49 +0100
Subject: QTBUG-57714: Avoid access to declarativeData when isDeletingChildren
 is set.

---
 src/qml/jsruntime/qv4qobjectwrapper_p.h | 2 +-
 src/qml/qml/qqmldata_p.h                | 4 ++--
 src/qml/qml/qqmlengine.cpp              | 7 +++++--
 src/qml/qml/qqmlproperty.cpp            | 4 +++-
 src/qml/types/qqmldelegatemodel.cpp     | 2 ++
 5 files changed, 13 insertions(+), 6 deletions(-)

diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h
index 9c5862b..1115429 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper_p.h
+++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h
@@ -154,7 +154,7 @@ inline ReturnedValue QObjectWrapper::wrap(ExecutionEngine *engine, QObject *obje
 {
     if (Q_LIKELY(!QQmlData::wasDeleted(object))) {
         QObjectPrivate *priv = QObjectPrivate::get(const_cast<QObject *>(object));
-        if (Q_LIKELY(priv->declarativeData)) {
+        if (Q_LIKELY(!priv->isDeletingChildren && priv->declarativeData)) {
             auto ddata = static_cast<QQmlData *>(priv->declarativeData);
             if (Q_LIKELY(ddata->jsEngineId == engine->m_engineId && !ddata->jsWrapper.isUndefined())) {
                 // We own the JS object
diff --git a/src/qml/qml/qqmldata_p.h b/src/qml/qml/qqmldata_p.h
index 7ccab57..d1f7895 100644
--- a/src/qml/qml/qqmldata_p.h
+++ b/src/qml/qml/qqmldata_p.h
@@ -193,7 +193,7 @@ public:
 
     static QQmlData *get(const QObject *object, bool create = false) {
         QObjectPrivate *priv = QObjectPrivate::get(const_cast<QObject *>(object));
-        if (priv->wasDeleted) {
+        if (priv->isDeletingChildren || priv->wasDeleted) {
             Q_ASSERT(!create);
             return 0;
         } else if (priv->declarativeData) {
@@ -238,7 +238,7 @@ bool QQmlData::wasDeleted(QObject *object)
         return true;
 
     QObjectPrivate *priv = QObjectPrivate::get(object);
-    if (!priv || priv->wasDeleted)
+    if (!priv || priv->isDeletingChildren || priv->wasDeleted)
         return true;
 
     return priv->declarativeData &&
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index 71795a2..25c433d 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -653,7 +653,7 @@ void QQmlEnginePrivate::enableProfiler()
 void QQmlPrivate::qdeclarativeelement_destructor(QObject *o)
 {
     QObjectPrivate *p = QObjectPrivate::get(o);
-    if (p->declarativeData) {
+    if (!p->isDeletingChildren && p->declarativeData) {
         QQmlData *d = static_cast<QQmlData*>(p->declarativeData);
         if (d->ownContext && d->context) {
             d->context->destroy();
@@ -824,7 +824,7 @@ void QQmlData::setQueuedForDeletion(QObject *object)
 {
     if (object) {
         if (QObjectPrivate *priv = QObjectPrivate::get(object)) {
-            if (!priv->wasDeleted && priv->declarativeData) {
+            if (!priv->isDeletingChildren && !priv->wasDeleted && priv->declarativeData) {
                 QQmlData *ddata = QQmlData::get(object, false);
                 if (ddata->ownContext && ddata->context)
                     ddata->context->emitDestruction();
@@ -1266,6 +1266,9 @@ QQmlContext *QQmlEngine::contextForObject(const QObject *object)
 
     QObjectPrivate *priv = QObjectPrivate::get(const_cast<QObject *>(object));
 
+    if (priv->isDeletingChildren)
+        return 0;
+
     QQmlData *data =
         static_cast<QQmlData *>(priv->declarativeData);
 
diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp
index 0ef0a5b..120d2c6 100644
--- a/src/qml/qml/qqmlproperty.cpp
+++ b/src/qml/qml/qqmlproperty.cpp
@@ -1669,7 +1669,9 @@ QMetaMethod QQmlPropertyPrivate::findSignalByName(const QMetaObject *mo, const Q
 */
 static inline void flush_vme_signal(const QObject *object, int index, bool indexInSignalRange)
 {
-    QQmlData *data = static_cast<QQmlData *>(QObjectPrivate::get(const_cast<QObject *>(object))->declarativeData);
+    QObjectPrivate* p = QObjectPrivate::get(const_cast<QObject *>(object));
+    Q_ASSERT(!p->isDeletingChildren);
+    QQmlData *data = static_cast<QQmlData *>(p->declarativeData);
     if (data && data->propertyCache) {
         QQmlPropertyData *property = indexInSignalRange ? data->propertyCache->signal(index)
                                                         : data->propertyCache->method(index);
diff --git a/src/qml/types/qqmldelegatemodel.cpp b/src/qml/types/qqmldelegatemodel.cpp
index 4052427..f33e24e 100644
--- a/src/qml/types/qqmldelegatemodel.cpp
+++ b/src/qml/types/qqmldelegatemodel.cpp
@@ -1949,6 +1949,7 @@ void QQmlDelegateModelItem::destroyObject()
     Q_ASSERT(contextData);
 
     QObjectPrivate *p = QObjectPrivate::get(object);
+    Q_ASSERT(!p->isDeletingChildren);
     Q_ASSERT(p->declarativeData);
     QQmlData *data = static_cast<QQmlData*>(p->declarativeData);
     if (data->ownContext && data->context)
@@ -1968,6 +1969,7 @@ void QQmlDelegateModelItem::destroyObject()
 QQmlDelegateModelItem *QQmlDelegateModelItem::dataForObject(QObject *object)
 {
     QObjectPrivate *p = QObjectPrivate::get(object);
+    Q_ASSERT(!p->isDeletingChildren);
     QQmlContextData *context = p->declarativeData
             ? static_cast<QQmlData *>(p->declarativeData)->context
             : 0;
-- 
2.11.0

