From 5084c274aac111db3f5f0c38258aa06aa9448bda Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Wed, 3 Aug 2011 11:01:52 +1000 Subject: [PATCH] Prevent Binding from crashing when its target object is deleted. Task-number: QTBUG-20692 Change-Id: Ia9a3d532c45baf01b8c20c7aac9ef373942a75d8 Reviewed-on: http://codereview.qt.nokia.com/2531 Reviewed-by: Qt Sanity Bot Reviewed-by: Martin Jones --- src/declarative/util/qdeclarativebind.cpp | 21 ++++++++++++------- src/qtquick1/util/qdeclarativebind.cpp | 3 ++- .../qdeclarativebinding/data/deletedObject.qml | 24 ++++++++++++++++++++++ .../tst_qdeclarativebinding.cpp | 17 +++++++++++++++ .../qdeclarativebinding/data/deletedObject.qml | 24 ++++++++++++++++++++++ .../tst_qdeclarativebinding.cpp | 17 +++++++++++++++ 6 files changed, 98 insertions(+), 8 deletions(-) create mode 100644 tests/auto/declarative/qdeclarativebinding/data/deletedObject.qml create mode 100644 tests/auto/qtquick1/qdeclarativebinding/data/deletedObject.qml diff --git a/src/declarative/util/qdeclarativebind.cpp b/src/declarative/util/qdeclarativebind.cpp index fa463eb..320bca8 100644 --- a/src/declarative/util/qdeclarativebind.cpp +++ b/src/declarative/util/qdeclarativebind.cpp @@ -44,6 +44,7 @@ #include "private/qdeclarativenullablevalue_p_p.h" #include "private/qdeclarativeproperty_p.h" #include "private/qdeclarativebinding_p.h" +#include "private/qdeclarativeguard_p.h" #include #include @@ -67,7 +68,7 @@ public: QDeclarativeNullableValue when; bool componentComplete; - QObject *obj; + QDeclarativeGuard obj; QString propName; QDeclarativeNullableValue value; QDeclarativeProperty prop; @@ -196,9 +197,12 @@ QObject *QDeclarativeBind::object() void QDeclarativeBind::setObject(QObject *obj) { Q_D(QDeclarativeBind); - if (d->obj && d->obj != obj) { - qmlInfo(this) << tr("Cannot change the object assigned to a Binding."); - return; + if (d->obj && d->when.isValid() && d->when) { + /* if we switch the object at runtime, we need to restore the + previous binding on the old object before continuing */ + d->when = false; + eval(); + d->when = true; } d->obj = obj; if (d->componentComplete) @@ -220,9 +224,12 @@ QString QDeclarativeBind::property() const void QDeclarativeBind::setProperty(const QString &p) { Q_D(QDeclarativeBind); - if (!d->propName.isEmpty() && d->propName != p) { - qmlInfo(this) << tr("Cannot change the property assigned to a Binding."); - return; + if (!d->propName.isEmpty() && d->when.isValid() && d->when) { + /* if we switch the property name at runtime, we need to restore the + previous binding on the old object before continuing */ + d->when = false; + eval(); + d->when = true; } d->propName = p; if (d->componentComplete) diff --git a/src/qtquick1/util/qdeclarativebind.cpp b/src/qtquick1/util/qdeclarativebind.cpp index 5051423..7afe848 100644 --- a/src/qtquick1/util/qdeclarativebind.cpp +++ b/src/qtquick1/util/qdeclarativebind.cpp @@ -42,6 +42,7 @@ #include "QtQuick1/private/qdeclarativebind_p.h" #include "QtDeclarative/private/qdeclarativenullablevalue_p_p.h" +#include "QtDeclarative/private/qdeclarativeguard_p.h" #include #include @@ -65,7 +66,7 @@ public: bool when : 1; bool componentComplete : 1; - QObject *obj; + QDeclarativeGuard obj; QString prop; QDeclarativeNullableValue value; }; diff --git a/tests/auto/declarative/qdeclarativebinding/data/deletedObject.qml b/tests/auto/declarative/qdeclarativebinding/data/deletedObject.qml new file mode 100644 index 0000000..f9cf869 --- /dev/null +++ b/tests/auto/declarative/qdeclarativebinding/data/deletedObject.qml @@ -0,0 +1,24 @@ +import QtQuick 2.0 + +Rectangle { + id: wrapper + width: 400 + height: 400 + + property bool activateBinding: false + + Binding { + id: binding + target: Qt.createQmlObject('import QtQuick 2.0; Item { property real value: 10 }', wrapper) + property: "value" + when: activateBinding + value: x + y + } + + Component.onCompleted: binding.target.destroy(); + +// MouseArea { +// anchors.fill: parent +// onClicked: activateBinding = true; +// } +} diff --git a/tests/auto/declarative/qdeclarativebinding/tst_qdeclarativebinding.cpp b/tests/auto/declarative/qdeclarativebinding/tst_qdeclarativebinding.cpp index 2e64fed..3effd68 100644 --- a/tests/auto/declarative/qdeclarativebinding/tst_qdeclarativebinding.cpp +++ b/tests/auto/declarative/qdeclarativebinding/tst_qdeclarativebinding.cpp @@ -62,6 +62,7 @@ private slots: void whenAfterValue(); void restoreBinding(); void restoreBindingWithLoop(); + void deletedObject(); private: QDeclarativeEngine engine; @@ -179,6 +180,22 @@ void tst_qdeclarativebinding::restoreBindingWithLoop() delete rect; } +//QTBUG-20692 +void tst_qdeclarativebinding::deletedObject() +{ + QDeclarativeEngine engine; + QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/deletedObject.qml")); + QSGRectangle *rect = qobject_cast(c.create()); + QVERIFY(rect != 0); + + QApplication::sendPostedEvents(0, QEvent::DeferredDelete); + + //don't crash + rect->setProperty("activateBinding", true); + + delete rect; +} + QTEST_MAIN(tst_qdeclarativebinding) #include "tst_qdeclarativebinding.moc" diff --git a/tests/auto/qtquick1/qdeclarativebinding/data/deletedObject.qml b/tests/auto/qtquick1/qdeclarativebinding/data/deletedObject.qml new file mode 100644 index 0000000..ba4c9f6 --- /dev/null +++ b/tests/auto/qtquick1/qdeclarativebinding/data/deletedObject.qml @@ -0,0 +1,24 @@ +import QtQuick 1.0 + +Rectangle { + id: wrapper + width: 400 + height: 400 + + property bool activateBinding: false + + Binding { + id: binding + target: Qt.createQmlObject('import QtQuick 1.0; Item { property real value: 10 }', wrapper) + property: "value" + when: activateBinding + value: x + y + } + + Component.onCompleted: binding.target.destroy(); + +// MouseArea { +// anchors.fill: parent +// onClicked: activateBinding = true; +// } +} diff --git a/tests/auto/qtquick1/qdeclarativebinding/tst_qdeclarativebinding.cpp b/tests/auto/qtquick1/qdeclarativebinding/tst_qdeclarativebinding.cpp index 776fa52..54ff801 100644 --- a/tests/auto/qtquick1/qdeclarativebinding/tst_qdeclarativebinding.cpp +++ b/tests/auto/qtquick1/qdeclarativebinding/tst_qdeclarativebinding.cpp @@ -60,6 +60,7 @@ public: private slots: void binding(); void whenAfterValue(); + void deletedObject(); private: QDeclarativeEngine engine; @@ -113,6 +114,22 @@ void tst_qdeclarativebinding::whenAfterValue() delete rect; } +//QTBUG-20692 +void tst_qdeclarativebinding::deletedObject() +{ + QDeclarativeEngine engine; + QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/deletedObject.qml")); + QDeclarative1Rectangle *rect = qobject_cast(c.create()); + QVERIFY(rect != 0); + + QApplication::sendPostedEvents(0, QEvent::DeferredDelete); + + //don't crash + rect->setProperty("activateBinding", true); + + delete rect; +} + QTEST_MAIN(tst_qdeclarativebinding) #include "tst_qdeclarativebinding.moc" -- 2.7.4