Don't crash when a signal/slot connection outlives the engine
authorSimon Hausmann <simon.hausmann@digia.com>
Wed, 12 Mar 2014 08:31:38 +0000 (09:31 +0100)
committerThe Qt Project <gerrit-noreply@qt-project.org>
Wed, 12 Mar 2014 14:10:04 +0000 (15:10 +0100)
In the test case in the bug, the signal was emitted from the QApplication
destructor (somewhere from the qpa plugin when the platform windows were
destroyed)

Task-number: QTBUG-37351
Change-Id: Ieec59e12be10bab1428743b80eecdf22ef9d8bf6
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
src/qml/jsruntime/qv4qobjectwrapper.cpp
tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp

index 004c3eb..1cfd2d8 100644 (file)
@@ -751,13 +751,18 @@ struct QObjectSlotDispatcher : public QtPrivate::QSlotObjectBase
         break;
         case Call: {
             QObjectSlotDispatcher *This = static_cast<QObjectSlotDispatcher*>(this_);
+            QV4::ExecutionEngine *v4 = This->function.engine();
+            // Might be that we're still connected to a signal that's emitted long
+            // after the engine died. We don't track connections in a global list, so
+            // we need this safeguard.
+            if (!v4)
+                break;
+
             QVarLengthArray<int, 9> dummy;
             int *argsTypes = QQmlPropertyCache::methodParameterTypes(r, This->signalIndex, dummy, 0);
 
             int argCount = argsTypes ? argsTypes[0]:0;
 
-            QV4::ExecutionEngine *v4 = This->function.engine();
-            Q_ASSERT(v4);
             QV4::Scope scope(v4);
             QV4::ScopedFunctionObject f(scope, This->function.value());
             QV4::ExecutionContext *ctx = v4->currentContext();
index 6e0ef16..b6c564a 100644 (file)
@@ -257,6 +257,7 @@ private slots:
     void include();
     void includeRemoteSuccess();
     void signalHandlers();
+    void qtbug_37351();
     void doubleEvaluate();
     void forInLoop();
     void nonNotifyable();
@@ -6087,6 +6088,27 @@ void tst_qqmlecmascript::signalHandlers()
     delete o;
 }
 
+void tst_qqmlecmascript::qtbug_37351()
+{
+    MyTypeObject signalEmitter;
+    {
+        QQmlEngine engine;
+        QQmlComponent component(&engine);
+        component.setData("import Qt.test 1.0; import QtQml 2.0;\nQtObject {\n"
+            "    Component.onCompleted: {\n"
+            "        testObject.action.connect(function() { print('dont crash'); });"
+            "    }\n"
+            "}", QUrl());
+
+        engine.rootContext()->setContextProperty("testObject", &signalEmitter);
+
+        QScopedPointer<QObject> object(component.create());
+        QVERIFY(!object.isNull());
+    }
+    signalEmitter.doAction();
+    // Don't crash
+}
+
 void tst_qqmlecmascript::qtbug_10696()
 {
     QQmlComponent component(&engine, testFileUrl("qtbug_10696.qml"));