diff --git a/src/qml/qml/qqmlpropertybinding.cpp b/src/qml/qml/qqmlpropertybinding.cpp index e492b77d15..e55b5fa9d0 100644 --- a/src/qml/qml/qqmlpropertybinding.cpp +++ b/src/qml/qml/qqmlpropertybinding.cpp @@ -133,6 +133,9 @@ QUntypedPropertyBinding QQmlPropertyBinding::createFromBoundFunction(const QQmlP void QQmlPropertyBindingJS::expressionChanged() { + if (!hasValidContext()) + return; + auto binding = asBinding(); if (!binding->propertyDataPtr) return; diff --git a/tests/auto/qml/qqmlbinding/data/bindingInDeadContext.qml b/tests/auto/qml/qqmlbinding/data/bindingInDeadContext.qml new file mode 100644 index 0000000000..3e86a1a1fd --- /dev/null +++ b/tests/auto/qml/qqmlbinding/data/bindingInDeadContext.qml @@ -0,0 +1,18 @@ +import QtQml + +QtObject { + id: outer + objectName: "outer" + + property Component c: QtObject { + id: inner1 + objectName: inner2.objectName + "a" + } + + property QtObject inner1: c.createObject() + + property QtObject inner2: QtObject { + id: inner2 + objectName: "a" + } +} diff --git a/tests/auto/qml/qqmlbinding/tst_qqmlbinding.cpp b/tests/auto/qml/qqmlbinding/tst_qqmlbinding.cpp index 48f437387d..e4c1013cb9 100644 --- a/tests/auto/qml/qqmlbinding/tst_qqmlbinding.cpp +++ b/tests/auto/qml/qqmlbinding/tst_qqmlbinding.cpp @@ -41,6 +41,7 @@ private slots: void disabledOnReadonlyProperty(); void delayed(); void bindingOverwriting(); + void bindingInDeadContext(); void bindToQmlComponent(); void bindingDoesNoWeirdConversion(); void bindNaNToInt(); @@ -500,6 +501,40 @@ void tst_qqmlbinding::bindingOverwriting() QLoggingCategory::setFilterRules(QString()); } +void tst_qqmlbinding::bindingInDeadContext() +{ + // We manually control the deletion order of the objects here. + // This is what some of our views also do. One way to prevent + // the engine from deleting objects is to parent them to the + // application. + + QScopedPointer o; + QScopedPointer inner1; + { + QScopedPointer inner2; + + QQmlEngine engine; + QQmlComponent c(&engine, testFileUrl("bindingInDeadContext.qml")); + + QVERIFY2(c.isReady(), qPrintable(c.errorString())); + o.reset(c.create()); + QVERIFY(!o.isNull()); + o->setParent(QCoreApplication::instance()); + + inner1.reset(o->property("inner1").value()); + QVERIFY(inner1); + inner1->setParent(QCoreApplication::instance()); + + inner2.reset(o->property("inner2").value()); + QVERIFY(inner2); + inner2->setParent(QCoreApplication::instance()); + } + + // The objectName binding did not get re-evaluated when inner2 died + // because the engine was gone already. + QCOMPARE(inner1->objectName(), "aa"); +} + void tst_qqmlbinding::bindToQmlComponent() { QQmlEngine engine;