e274cb3f76
1 OBS-URL: https://build.opensuse.org/request/show/247019 OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/libqt5-qtdeclarative?expand=0&rev=17
143 lines
5.3 KiB
Diff
143 lines
5.3 KiB
Diff
From b0835b31fd456c30ea3fcaae6edc58212556477d Mon Sep 17 00:00:00 2001
|
|
From: Simon Hausmann <simon.hausmann@digia.com>
|
|
Date: Thu, 21 Aug 2014 13:10:33 +0200
|
|
Subject: [PATCH] Fix crash with early QObject property access
|
|
|
|
In the reported bug, it can happen that we try to access the compile-time resolved
|
|
QObject property of an object that is referenced by id. The binding that uses this is
|
|
triggered when the property changes but _also_ when the id referenced object gets either
|
|
created or deleted. The first time the binding is evaluated is very early on, when the
|
|
id referenced object is not created yet, so the binding evaluation fails. However the
|
|
dependency is set up, and so later then the id referenced object is created and the id
|
|
property is set on the context, the notification triggers and the binding is re-evaluated.
|
|
During that binding evaluation a QObject property access happens by index on an object that
|
|
doesn't have its VME meta-object set up yet. Therefore the property access fails and a
|
|
crash occurs or the Q_ASSERT(property) assertion fails.
|
|
|
|
The fix is to set register the id named object in the context _after_ the VME meta-object is
|
|
setup.
|
|
|
|
Task-number: QTBUG-40018
|
|
Change-Id: Ic2d7b4a0c49635efe68e93f2f6c316eb65f0c309
|
|
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
|
|
---
|
|
src/qml/qml/qqmlobjectcreator.cpp | 18 ++++++++++++-----
|
|
src/qml/qml/qqmlobjectcreator_p.h | 2 ++
|
|
.../qml/qqmllanguage/data/earlyIdObjectAccess.qml | 23 ++++++++++++++++++++++
|
|
tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp | 10 ++++++++++
|
|
4 files changed, 48 insertions(+), 5 deletions(-)
|
|
create mode 100644 tests/auto/qml/qqmllanguage/data/earlyIdObjectAccess.qml
|
|
|
|
--- qtdeclarative-opensource-src-5.3.1.orig/src/qml/qml/qqmlobjectcreator.cpp
|
|
+++ qtdeclarative-opensource-src-5.3.1/src/qml/qml/qqmlobjectcreator.cpp
|
|
@@ -1013,6 +1013,13 @@ void QQmlObjectCreator::recordError(cons
|
|
errors << error;
|
|
}
|
|
|
|
+void QQmlObjectCreator::registerObjectWithContextById(int objectIndex, QObject *instance) const
|
|
+{
|
|
+ QHash<int, int>::ConstIterator idEntry = objectIndexToId.find(objectIndex);
|
|
+ if (idEntry != objectIndexToId.constEnd())
|
|
+ context->setIdProperty(idEntry.value(), instance);
|
|
+}
|
|
+
|
|
QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isContextObject)
|
|
{
|
|
QQmlObjectCreationProfiler profiler(sharedState->profiler.profiler);
|
|
@@ -1112,10 +1119,6 @@ QObject *QQmlObjectCreator::createInstan
|
|
parserStatus->d = &sharedState->allParserStatusCallbacks.top();
|
|
}
|
|
|
|
- QHash<int, int>::ConstIterator idEntry = objectIndexToId.find(index);
|
|
- if (idEntry != objectIndexToId.constEnd())
|
|
- context->setIdProperty(idEntry.value(), instance);
|
|
-
|
|
// Register the context object in the context early on in order for pending binding
|
|
// initialization to find it available.
|
|
if (isContextObject)
|
|
@@ -1130,8 +1133,10 @@ QObject *QQmlObjectCreator::createInstan
|
|
}
|
|
}
|
|
|
|
- if (isComponent)
|
|
+ if (isComponent) {
|
|
+ registerObjectWithContextById(index, instance);
|
|
return instance;
|
|
+ }
|
|
|
|
QQmlRefPointer<QQmlPropertyCache> cache = propertyCaches.at(index);
|
|
Q_ASSERT(!cache.isNull());
|
|
@@ -1288,6 +1293,9 @@ bool QQmlObjectCreator::populateInstance
|
|
} else {
|
|
vmeMetaObject = QQmlVMEMetaObject::get(_qobject);
|
|
}
|
|
+
|
|
+ registerObjectWithContextById(index, _qobject);
|
|
+
|
|
qSwap(_propertyCache, cache);
|
|
qSwap(_vmeMetaObject, vmeMetaObject);
|
|
|
|
--- qtdeclarative-opensource-src-5.3.1.orig/src/qml/qml/qqmlobjectcreator_p.h
|
|
+++ qtdeclarative-opensource-src-5.3.1/src/qml/qml/qqmlobjectcreator_p.h
|
|
@@ -110,6 +110,8 @@ private:
|
|
QString stringAt(int idx) const { return qmlUnit->header.stringAt(idx); }
|
|
void recordError(const QV4::CompiledData::Location &location, const QString &description);
|
|
|
|
+ void registerObjectWithContextById(int objectIndex, QObject *instance) const;
|
|
+
|
|
enum Phase {
|
|
Startup,
|
|
CreatingObjects,
|
|
--- /dev/null
|
|
+++ qtdeclarative-opensource-src-5.3.1/tests/auto/qml/qqmllanguage/data/earlyIdObjectAccess.qml
|
|
@@ -0,0 +1,23 @@
|
|
+import QtQuick 2.0
|
|
+
|
|
+Item {
|
|
+ visible: false
|
|
+ property bool success: false
|
|
+ property bool loading: true
|
|
+
|
|
+ Item {
|
|
+ visible: someOtherItem.someProperty
|
|
+ onVisibleChanged: {
|
|
+ if (!visible) {
|
|
+ success = loading
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ Item {
|
|
+ id: someOtherItem
|
|
+ property bool someProperty: true
|
|
+ }
|
|
+
|
|
+ Component.onCompleted: loading = false
|
|
+}
|
|
--- qtdeclarative-opensource-src-5.3.1.orig/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
|
|
+++ qtdeclarative-opensource-src-5.3.1/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
|
|
@@ -240,6 +240,8 @@ private slots:
|
|
|
|
void noChildEvents();
|
|
|
|
+ void earlyIdObjectAccess();
|
|
+
|
|
private:
|
|
QQmlEngine engine;
|
|
QStringList defaultImportPathList;
|
|
@@ -3791,6 +3793,14 @@ void tst_qqmllanguage::noChildEvents()
|
|
QCOMPARE(object->childAddedEventCount(), 0);
|
|
}
|
|
|
|
+void tst_qqmllanguage::earlyIdObjectAccess()
|
|
+{
|
|
+ QQmlComponent component(&engine, testFileUrl("earlyIdObjectAccess.qml"));
|
|
+ QScopedPointer<QObject> o(component.create());
|
|
+ QVERIFY(!o.isNull());
|
|
+ QVERIFY(o->property("success").toBool());
|
|
+}
|
|
+
|
|
QTEST_MAIN(tst_qqmllanguage)
|
|
|
|
#include "tst_qqmllanguage.moc"
|