From 9c515a6de24bc8d5709136cc099ceeae8e3e642c Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Tue, 25 Jul 2017 13:14:21 +0200 Subject: Do not (dis)connectNotify on dynamically created model item objects These item objects are direct subclasses of QObject, and cannot override connectNotify/disconnectNotify. This prevents the creation of the backing QMetaObject during disconnect, which happens during destruction, which in turn will call back into the model that is being destroyed. Task-number: QTBUG-59704 Change-Id: I7f997e5d2fda242b38e67b9147224d72aa4508ba Reviewed-by: Simon Hausmann --- src/qml/qml/qqmljavascriptexpression.cpp | 4 ++-- src/qml/qml/qqmljavascriptexpression_p.h | 2 +- src/qml/qml/qqmlnotifier.cpp | 9 ++++++--- src/qml/qml/qqmlnotifier_p.h | 10 ++++++---- src/qml/types/qqmllistmodel.cpp | 10 +++------- 5 files changed, 18 insertions(+), 17 deletions(-) diff --git a/src/qml/qml/qqmljavascriptexpression.cpp b/src/qml/qml/qqmljavascriptexpression.cpp index 9d4e46e254..eec5d1ae57 100644 --- a/src/qml/qml/qqmljavascriptexpression.cpp +++ b/src/qml/qml/qqmljavascriptexpression.cpp @@ -283,7 +283,7 @@ void QQmlPropertyCapture::captureProperty(QQmlNotifier *n, Duration duration) \a n is in the signal index range (see QObjectPrivate::signalIndex()). */ -void QQmlPropertyCapture::captureProperty(QObject *o, int c, int n, Duration duration) +void QQmlPropertyCapture::captureProperty(QObject *o, int c, int n, Duration duration, bool doNotify) { if (watcher->wasDeleted()) return; @@ -319,7 +319,7 @@ void QQmlPropertyCapture::captureProperty(QObject *o, int c, int n, Duration dur Q_ASSERT(g->isConnected(o, n)); } else { g = QQmlJavaScriptExpressionGuard::New(expression, engine); - g->connect(o, n, engine); + g->connect(o, n, engine, doNotify); } if (duration == Permanently) diff --git a/src/qml/qml/qqmljavascriptexpression_p.h b/src/qml/qml/qqmljavascriptexpression_p.h index 646cc5ab3d..eeed272793 100644 --- a/src/qml/qml/qqmljavascriptexpression_p.h +++ b/src/qml/qml/qqmljavascriptexpression_p.h @@ -204,7 +204,7 @@ public: static void registerQmlDependencies(const QV4::CompiledData::Function *compiledFunction, const QV4::Scope &scope); void captureProperty(QQmlNotifier *, Duration duration = OnlyOnce); - void captureProperty(QObject *, int, int, Duration duration = OnlyOnce); + void captureProperty(QObject *, int, int, Duration duration = OnlyOnce, bool doNotify = true); QQmlEngine *engine; QQmlJavaScriptExpression *expression; diff --git a/src/qml/qml/qqmlnotifier.cpp b/src/qml/qml/qqmlnotifier.cpp index 538ca822ee..938e2b77e2 100644 --- a/src/qml/qml/qqmlnotifier.cpp +++ b/src/qml/qml/qqmlnotifier.cpp @@ -117,7 +117,7 @@ void QQmlNotifier::emitNotify(QQmlNotifierEndpoint *endpoint, void **a) \a sourceSignal MUST be in the signal index range (see QObjectPrivate::signalIndex()). This is different from QMetaMethod::methodIndex(). */ -void QQmlNotifierEndpoint::connect(QObject *source, int sourceSignal, QQmlEngine *engine) +void QQmlNotifierEndpoint::connect(QObject *source, int sourceSignal, QQmlEngine *engine, bool doNotify) { disconnect(); @@ -142,8 +142,11 @@ void QQmlNotifierEndpoint::connect(QObject *source, int sourceSignal, QQmlEngine QQmlPropertyPrivate::flushSignal(source, sourceSignal); QQmlData *ddata = QQmlData::get(source, true); ddata->addNotify(sourceSignal, this); - QObjectPrivate * const priv = QObjectPrivate::get(source); - priv->connectNotify(QMetaObjectPrivate::signal(source->metaObject(), sourceSignal)); + if (doNotify) { + needsConnectNotify = doNotify; + QObjectPrivate * const priv = QObjectPrivate::get(source); + priv->connectNotify(QMetaObjectPrivate::signal(source->metaObject(), sourceSignal)); + } } QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlnotifier_p.h b/src/qml/qml/qqmlnotifier_p.h index dad79e0e55..6e91369793 100644 --- a/src/qml/qml/qqmlnotifier_p.h +++ b/src/qml/qml/qqmlnotifier_p.h @@ -100,7 +100,7 @@ public: inline bool isConnected(QObject *source, int sourceSignal) const; inline bool isConnected(QQmlNotifier *) const; - void connect(QObject *source, int sourceSignal, QQmlEngine *engine); + void connect(QObject *source, int sourceSignal, QQmlEngine *engine, bool doNotify = true); inline void connect(QQmlNotifier *); inline void disconnect(); @@ -121,9 +121,10 @@ private: inline QQmlNotifier *senderAsNotifier() const; Callback callback:4; + int needsConnectNotify:1; // The index is in the range returned by QObjectPrivate::signalIndex(). // This is different from QMetaMethod::methodIndex(). - signed int sourceSignal:28; + signed int sourceSignal:27; }; QQmlNotifier::QQmlNotifier() @@ -155,7 +156,7 @@ void QQmlNotifier::notify() } QQmlNotifierEndpoint::QQmlNotifierEndpoint(Callback callback) -: next(0), prev(0), senderPtr(0), callback(callback), sourceSignal(-1) +: next(0), prev(0), senderPtr(0), callback(callback), needsConnectNotify(false), sourceSignal(-1) { } @@ -205,7 +206,8 @@ void QQmlNotifierEndpoint::disconnect() if (sourceSignal != -1) { QObject * const obj = senderAsObject(); QObjectPrivate * const priv = QObjectPrivate::get(obj); - priv->disconnectNotify(QMetaObjectPrivate::signal(obj->metaObject(), sourceSignal)); + if (needsConnectNotify) + priv->disconnectNotify(QMetaObjectPrivate::signal(obj->metaObject(), sourceSignal)); } if (isNotifying()) *((qintptr *)(senderPtr & ~0x1)) = 0; diff --git a/src/qml/types/qqmllistmodel.cpp b/src/qml/types/qqmllistmodel.cpp index 4d8f213284..9d0f1afb32 100644 --- a/src/qml/types/qqmllistmodel.cpp +++ b/src/qml/types/qqmllistmodel.cpp @@ -1361,13 +1361,9 @@ ReturnedValue ModelObject::get(const Managed *m, String *name, bool *hasProperty if (QQmlEngine *qmlEngine = that->engine()->qmlEngine()) { QQmlEnginePrivate *ep = QQmlEnginePrivate::get(qmlEngine); - if (ep && ep->propertyCapture) { - QObjectPrivate *op = QObjectPrivate::get(that->object()); - // Temporarily hide the dynamic meta-object, to prevent it from being created when the capture - // triggers a QObject::connectNotify() by calling obj->metaObject(). - QScopedValueRollback metaObjectBlocker(op->metaObject, 0); - ep->propertyCapture->captureProperty(that->object(), -1, role->index); - } + if (ep && ep->propertyCapture) + ep->propertyCapture->captureProperty(that->object(), -1, role->index, + QQmlPropertyCapture::OnlyOnce, false); } const int elementIndex = that->d()->m_elementIndex; -- cgit v1.2.3