Ensure context is valid before VME method creation
authorMatthew Vogt <matthew.vogt@nokia.com>
Fri, 27 Apr 2012 06:09:22 +0000 (16:09 +1000)
committerQt by Nokia <qt-info@nokia.com>
Tue, 1 May 2012 04:04:47 +0000 (06:04 +0200)
Ensure that a valid context exists prior to evaluation of a VME method
function.  Invalid contexts can occur if a method's first invocation is
triggered after the destruction of the component's context.

Task-number: QTBUG-25516
Change-Id: I349a73c5713e178f920c44f5ddcaa1dc6eec199f
Reviewed-by: Chris Adams <christopher.adams@nokia.com>
src/qml/qml/qqmlvmemetaobject.cpp
tests/auto/qml/qqmlcontext/data/ContainerComponent.qml [new file with mode: 0644]
tests/auto/qml/qqmlcontext/data/ContentComponent.qml [new file with mode: 0644]
tests/auto/qml/qqmlcontext/data/evalAfterInvalidate.qml [new file with mode: 0644]
tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp

index 9778161..dd2fe4b 100644 (file)
@@ -809,6 +809,11 @@ int QQmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a)
 
 v8::Handle<v8::Function> QQmlVMEMetaObject::method(int index)
 {
+    if (!ctxt || !ctxt->isValid()) {
+        qWarning("QQmlVMEMetaObject: Internal error - attempted to evaluate a function in an invalid context");
+        return v8::Handle<v8::Function>();
+    }
+
     if (!v8methods) 
         v8methods = new v8::Persistent<v8::Function>[metaData->methodCount];
 
diff --git a/tests/auto/qml/qqmlcontext/data/ContainerComponent.qml b/tests/auto/qml/qqmlcontext/data/ContainerComponent.qml
new file mode 100644 (file)
index 0000000..ae90c20
--- /dev/null
@@ -0,0 +1,5 @@
+import QtQuick 2.0
+
+Item {
+    function doSomething() { if (333 == 666) console.log('doSomething') }
+}
diff --git a/tests/auto/qml/qqmlcontext/data/ContentComponent.qml b/tests/auto/qml/qqmlcontext/data/ContentComponent.qml
new file mode 100644 (file)
index 0000000..f937b19
--- /dev/null
@@ -0,0 +1,10 @@
+import QtQuick 2.0
+
+Item {
+    property int count: 0
+    property bool hasValidParent: parent && parent.children.length != 0
+
+    onHasValidParentChanged: {
+        if (++count > 1) parent.doSomething()
+    }
+}
diff --git a/tests/auto/qml/qqmlcontext/data/evalAfterInvalidate.qml b/tests/auto/qml/qqmlcontext/data/evalAfterInvalidate.qml
new file mode 100644 (file)
index 0000000..27879c4
--- /dev/null
@@ -0,0 +1,14 @@
+import QtQuick 2.0
+
+Rectangle {
+    id: root
+
+    Component.onCompleted: {
+        var i = containerComponent.createObject(root);
+        contentComponent.createObject(i);
+        i.destroy()
+    }
+
+    property Component containerComponent: ContainerComponent {}
+    property Component contentComponent: ContentComponent {}
+}
index 16365ee..55f93c6 100644 (file)
@@ -71,6 +71,8 @@ private slots:
     void refreshExpressionsRootContext();
 
     void qtbug_22535();
+    void evalAfterInvalidate();
+
 private:
     QQmlEngine engine;
 };
@@ -647,6 +649,16 @@ void tst_qqmlcontext::qtbug_22535()
     delete o;
 }
 
+void tst_qqmlcontext::evalAfterInvalidate()
+{
+    QQmlEngine engine;
+    QQmlComponent component(&engine, testFileUrl("evalAfterInvalidate.qml"));
+    QScopedPointer<QObject> o(component.create());
+
+    QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+    QCoreApplication::processEvents();
+}
+
 QTEST_MAIN(tst_qqmlcontext)
 
 #include "tst_qqmlcontext.moc"