Handle exceptions inside QV8QObjectConnectionList::qt_metacall
authorChris Adams <christopher.adams@nokia.com>
Thu, 29 Dec 2011 00:32:52 +0000 (10:32 +1000)
committerQt by Nokia <qt-info@nokia.com>
Thu, 29 Dec 2011 04:52:22 +0000 (05:52 +0100)
Previously, exceptions were not handled in the connectionlist.
This could cause v8 to assert under certain circumstances.

Task-number: QTBUG-23375
Change-Id: Ie5f043b50bb6b02a77be464ca18ea8e3bbb0f501
Reviewed-by: Alan Alpert <alan.alpert@nokia.com>

src/declarative/qml/v8/qv8qobjectwrapper.cpp
tests/auto/declarative/qdeclarativeecmascript/data/qobjectConnectionListExceptionHandling.qml [new file with mode: 0644]
tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp

index 40ad93a..098894a 100644 (file)
@@ -51,6 +51,7 @@
 #include <private/qjsvalue_p.h>
 #include <private/qscript_impl_p.h>
 #include <private/qdeclarativeaccessors_p.h>
+#include <private/qdeclarativeexpression_p.h>
 
 #include <QtDeclarative/qjsvalue.h>
 #include <QtCore/qvarlengtharray.h>
@@ -1229,11 +1230,22 @@ int QV8QObjectConnectionList::qt_metacall(QMetaObject::Call method, int index, v
             Connection &connection = connections[ii];
             if (connection.needsDestroy)
                 continue;
+
+            v8::TryCatch try_catch;
             if (connection.thisObject.IsEmpty()) {
                 connection.function->Call(engine->global(), argCount, args.data());
             } else {
                 connection.function->Call(connection.thisObject, argCount, args.data());
             }
+
+            if (try_catch.HasCaught()) {
+                QDeclarativeError error;
+                error.setDescription(QString(QLatin1String("Unknown exception occurred during evaluation of connected function: %1")).arg(engine->toString(connection.function->GetName())));
+                v8::Local<v8::Message> message = try_catch.Message();
+                if (!message.IsEmpty())
+                    QDeclarativeExpressionPrivate::exceptionToError(message, error);
+                QDeclarativeEnginePrivate::get(engine->engine())->warning(error);
+            }
         }
 
         connectionList.connectionsInUse--;
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/qobjectConnectionListExceptionHandling.qml b/tests/auto/declarative/qdeclarativeecmascript/data/qobjectConnectionListExceptionHandling.qml
new file mode 100644 (file)
index 0000000..acd512a
--- /dev/null
@@ -0,0 +1,24 @@
+import QtQuick 2.0
+
+Item {
+    id: root
+    property int first: 5
+    property bool test: false
+
+    Item {
+        id: exceptional
+        function exceptionalFunction() {
+            var obj = undefined;
+            var prop = undefined;
+            return obj[prop];
+        }
+    }
+
+    Component.onCompleted: {
+        root["firstChanged"].connect(exceptional.exceptionalFunction);
+        root["firstChanged"].connect(exceptional.exceptionalFunction);
+        root["firstChanged"].connect(exceptional.exceptionalFunction);
+        first = 6;
+        test = true;
+    }
+}
index 0e3cfd8..05e14cf 100644 (file)
@@ -199,6 +199,7 @@ private slots:
     void qtbug_11606();
     void qtbug_11600();
     void qtbug_21864();
+    void qobjectConnectionListExceptionHandling();
     void nonscriptable();
     void deleteLater();
     void in();
@@ -5181,6 +5182,20 @@ void tst_qdeclarativeecmascript::qtbug_21864()
     delete o;
 }
 
+void tst_qdeclarativeecmascript::qobjectConnectionListExceptionHandling()
+{
+    // QTBUG-23375
+    QDeclarativeComponent component(&engine, testFileUrl("qobjectConnectionListExceptionHandling.qml"));
+    QString warning = component.url().toString() + QLatin1String(":13: TypeError: Cannot read property 'undefined' of undefined");
+    QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
+    QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
+    QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
+    QObject *o = component.create();
+    QVERIFY(o != 0);
+    QCOMPARE(o->property("test").toBool(), true);
+    delete o;
+}
+
 // Reading and writing non-scriptable properties should fail
 void tst_qdeclarativeecmascript::nonscriptable()
 {