Don't crash when importing script with syntax error
authorKent Hansen <kent.hansen@nokia.com>
Mon, 21 Nov 2011 12:35:40 +0000 (13:35 +0100)
committerQt by Nokia <qt-info@nokia.com>
Wed, 23 Nov 2011 09:11:19 +0000 (10:11 +0100)
Task-number: QTBUG-22843
Change-Id: I2b1ed6cbbc7a566f54b441359941ea121a9033ba
Reviewed-by: Aaron Kennedy <aaron.kennedy@nokia.com>
src/declarative/qml/qdeclarativevme.cpp
tests/auto/declarative/qdeclarativeecmascript/data/qtbug_22843.js [new file with mode: 0644]
tests/auto/declarative/qdeclarativeecmascript/data/qtbug_22843.library.js [new file with mode: 0644]
tests/auto/declarative/qdeclarativeecmascript/data/qtbug_22843.library.qml [new file with mode: 0644]
tests/auto/declarative/qdeclarativeecmascript/data/qtbug_22843.qml [new file with mode: 0644]
tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp
tests/auto/declarative/qmlmin/tst_qmlmin.cpp

index 19df527..313d7f1 100644 (file)
@@ -1239,8 +1239,11 @@ void QDeclarativeScriptData::initialize(QDeclarativeEngine *engine)
     QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
     QV8Engine *v8engine = ep->v8engine();
 
-    // XXX Handle errors during the script compile!
+    // If compilation throws an error, a surrounding v8::TryCatch will record it.
     v8::Local<v8::Script> program = v8engine->qmlModeCompile(m_programSource, url.toString(), 1);
+    if (program.IsEmpty())
+        return;
+
     m_program = qPersistentNew<v8::Script>(program);
 
     addToEngine(engine);
@@ -1301,13 +1304,18 @@ v8::Persistent<v8::Object> QDeclarativeVME::run(QDeclarativeContextData *parentC
     v8::HandleScope handle_scope;
     v8::Context::Scope scope(v8engine->context());
 
-    if (!script->isInitialized()) 
+    v8::TryCatch try_catch;
+    if (!script->isInitialized())
         script->initialize(parentCtxt->engine);
 
     v8::Local<v8::Object> qmlglobal = v8engine->qmlScope(ctxt, 0);
 
-    v8::TryCatch try_catch;
-    script->m_program->Run(qmlglobal);
+    if (!script->m_program.IsEmpty()) {
+        script->m_program->Run(qmlglobal);
+    } else {
+        // Compilation failed.
+        Q_ASSERT(try_catch.HasCaught());
+    }
 
     v8::Persistent<v8::Object> rv;
     
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/qtbug_22843.js b/tests/auto/declarative/qdeclarativeecmascript/data/qtbug_22843.js
new file mode 100644 (file)
index 0000000..6d19fe0
--- /dev/null
@@ -0,0 +1,5 @@
+
+function func()
+{
+    isFinite() )
+}
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/qtbug_22843.library.js b/tests/auto/declarative/qdeclarativeecmascript/data/qtbug_22843.library.js
new file mode 100644 (file)
index 0000000..1a7c8a2
--- /dev/null
@@ -0,0 +1,5 @@
+.pragma library
+function func()
+{
+    isFinite() )
+}
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/qtbug_22843.library.qml b/tests/auto/declarative/qdeclarativeecmascript/data/qtbug_22843.library.qml
new file mode 100644 (file)
index 0000000..281765b
--- /dev/null
@@ -0,0 +1,6 @@
+import "qtbug_22843.library.js" as MyScript
+import QtQuick 2.0
+
+QtObject {
+  Component.onCompleted: MyScript.func()
+}
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/qtbug_22843.qml b/tests/auto/declarative/qdeclarativeecmascript/data/qtbug_22843.qml
new file mode 100644 (file)
index 0000000..90a47c0
--- /dev/null
@@ -0,0 +1,6 @@
+import "qtbug_22843.js" as MyScript
+import QtQuick 2.0
+
+QtObject {
+  Component.onCompleted: MyScript.func()
+}
index 4c43a02..1e0f1a8 100644 (file)
@@ -225,6 +225,8 @@ private slots:
     void invokableObjectRet();
     void qtbug_20344();
     void qtbug_22679();
+    void qtbug_22843_data();
+    void qtbug_22843();
     void revisionErrors();
     void revision();
 
@@ -5178,6 +5180,46 @@ void tst_qdeclarativeecmascript::qtbug_22679()
     delete o;
 }
 
+void tst_qdeclarativeecmascript::qtbug_22843_data()
+{
+    QTest::addColumn<bool>("library");
+
+    QTest::newRow("without .pragma library") << false;
+    QTest::newRow("with .pragma library") << true;
+}
+
+void tst_qdeclarativeecmascript::qtbug_22843()
+{
+    QFETCH(bool, library);
+
+    QString fileName("qtbug_22843");
+    if (library)
+        fileName += QLatin1String(".library");
+    fileName += QLatin1String(".qml");
+
+    QDeclarativeComponent component(&engine, TEST_FILE(fileName));
+    QString url = component.url().toString();
+    QString warning1 = url.left(url.length()-3) + QLatin1String("js:4: SyntaxError: Unexpected token )");
+    QString warning2 = url + QLatin1String(":5: TypeError: Object [object Object] has no method 'func'");
+
+    qRegisterMetaType<QList<QDeclarativeError> >("QList<QDeclarativeError>");
+    QSignalSpy warningsSpy(&engine, SIGNAL(warnings(QList<QDeclarativeError>)));
+    for (int x = 0; x < 3; ++x) {
+        warningsSpy.clear();
+        // For libraries, only the first import attempt should produce a
+        // SyntaxError warning; subsequent component creation should not
+        // attempt to reload the script.
+        bool expectSyntaxError = !library || (x == 0);
+        if (expectSyntaxError)
+            QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
+        QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
+        QObject *object = component.create();
+        QVERIFY(object != 0);
+        QCOMPARE(warningsSpy.count(), 1 + (expectSyntaxError?1:0));
+        delete object;
+    }
+}
+
 QTEST_MAIN(tst_qdeclarativeecmascript)
 
 #include "tst_qdeclarativeecmascript.moc"
index 38de65f..53b0e37 100644 (file)
@@ -105,6 +105,8 @@ void tst_qmlmin::initTestCase()
     invalidFiles << "tests/auto/declarative/qdeclarativelanguage/data/nonexistantProperty.5.qml";
     invalidFiles << "tests/auto/declarative/qdeclarativefolderlistmodel/data/dummy.qml";
     invalidFiles << "tests/auto/declarative/qdeclarativeecmascript/data/blank.js";
+    invalidFiles << "tests/auto/declarative/qdeclarativeecmascript/data/qtbug_22843.js";
+    invalidFiles << "tests/auto/declarative/qdeclarativeecmascript/data/qtbug_22843.library.js";
     invalidFiles << "tests/auto/declarative/qdeclarativeworkerscript/data/script_error_onLoad.js";
     invalidFiles << "tests/auto/declarative/qdeclarativelanguage/data/test.js";
     invalidFiles << "tests/auto/declarative/qdeclarativelanguage/data/test2.js";