From 2699e8dae2b160f8d001459a7993b61fe4b1fac3 Mon Sep 17 00:00:00 2001 From: Kent Hansen Date: Tue, 1 Mar 2011 09:43:48 +0100 Subject: Don't assert in abortEvaluation() autotest When QtScript is built without NDEBUG defined, the tst_QScriptEngine::abortEvaluation() test would assert. This was due to commit 716e0284c8f569d71e42354fd6fc3b965233e019, which fixed the tst_QScriptEngine::throwErrorFromProcessEvents() autotest for a script containing an infinite while-loop with an empty body. The CHECK_FOR_EXCEPTION_AT_END() that we added should only be done if the timeout checker did not report a timeout; otherwise the JSC state becomes corrupted due to returnToThrowTrampoline() being called twice. This caused an assert later when calculating the line number of the exception. Also add test cases for scripts with try-catch statements. For abortEvaluation(), scripts should not be able to observe (i.e. catch) the interrupted exception, but if an error is thrown using QScriptContext::throwError(), the script should be able to catch it. Task-number: QTBUG-17854 Reviewed-by: Olivier Goffart --- .../javascriptcore/JavaScriptCore/jit/JITStubs.cpp | 13 +++++- tests/auto/qscriptengine/tst_qscriptengine.cpp | 51 ++++++++++++++++++++-- 2 files changed, 59 insertions(+), 5 deletions(-) diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/jit/JITStubs.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/jit/JITStubs.cpp index b3c229e..d8027ff 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/jit/JITStubs.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/jit/JITStubs.cpp @@ -1168,8 +1168,17 @@ DEFINE_STUB_FUNCTION(int, timeout_check) globalData->exception = createInterruptedExecutionException(globalData); VM_THROW_EXCEPTION_AT_END(); } - - CHECK_FOR_EXCEPTION_AT_END(); +#ifdef QT_BUILD_SCRIPT_LIB + else { + // It's possible that the call to QtScript's implementation of + // TimeoutChecker::didTimeOut() caused an error to be thrown. + // In that case, didTimeOut() should still return false, since + // we don't want the interrupted-exception to override the + // user-thrown error. But we need to check for exception here, + // otherwise JSC would continue normal execution. + CHECK_FOR_EXCEPTION_AT_END(); + } +#endif return timeoutChecker->ticksUntilNextCheck(); } diff --git a/tests/auto/qscriptengine/tst_qscriptengine.cpp b/tests/auto/qscriptengine/tst_qscriptengine.cpp index 2d7feee..aac9601 100644 --- a/tests/auto/qscriptengine/tst_qscriptengine.cpp +++ b/tests/auto/qscriptengine/tst_qscriptengine.cpp @@ -157,6 +157,7 @@ private slots: void reportAdditionalMemoryCost(); void gcWithNestedDataStructure(); void processEventsWhileRunning(); + void throwErrorFromProcessEvents_data(); void throwErrorFromProcessEvents(); void disableProcessEventsInterval(); void stacktrace(); @@ -164,6 +165,7 @@ private slots: void numberParsing(); void automaticSemicolonInsertion(); void abortEvaluation_notEvaluating(); + void abortEvaluation_data(); void abortEvaluation(); void abortEvaluation_tryCatch(); void abortEvaluation_fromNative(); @@ -2961,17 +2963,42 @@ public: QScriptEngine *engine; }; +void tst_QScriptEngine::throwErrorFromProcessEvents_data() +{ + QTest::addColumn("script"); + QTest::addColumn("error"); + + QTest::newRow("while (1)") + << QString::fromLatin1("while (1) { }") + << QString::fromLatin1("Error: Killed"); + QTest::newRow("while (1) i++") + << QString::fromLatin1("i = 0; while (1) { i++; }") + << QString::fromLatin1("Error: Killed"); + // Unlike abortEvaluation(), scripts should be able to catch the + // exception. + QTest::newRow("try catch") + << QString::fromLatin1("try {" + " while (1) { }" + "} catch(e) {" + " throw new Error('Caught');" + "}") + << QString::fromLatin1("Error: Caught"); +} + void tst_QScriptEngine::throwErrorFromProcessEvents() { + QFETCH(QString, script); + QFETCH(QString, error); + QScriptEngine eng; EventReceiver2 receiver(&eng); QCoreApplication::postEvent(&receiver, new QEvent(QEvent::Type(QEvent::User+1))); eng.setProcessEventsInterval(100); - QScriptValue ret = eng.evaluate(QString::fromLatin1("while (1) { }")); + QScriptValue ret = eng.evaluate(script); QVERIFY(ret.isError()); - QCOMPARE(ret.toString(), QString::fromLatin1("Error: Killed")); + QCOMPARE(ret.toString(), error); } void tst_QScriptEngine::disableProcessEventsInterval() @@ -3386,8 +3413,26 @@ void tst_QScriptEngine::abortEvaluation_notEvaluating() } } +void tst_QScriptEngine::abortEvaluation_data() +{ + QTest::addColumn("script"); + + QTest::newRow("while (1)") + << QString::fromLatin1("while (1) { }"); + QTest::newRow("while (1) i++") + << QString::fromLatin1("i = 0; while (1) { i++; }"); + QTest::newRow("try catch") + << QString::fromLatin1("try {" + " while (1) { }" + "} catch(e) {" + " throw new Error('Caught');" + "}"); +} + void tst_QScriptEngine::abortEvaluation() { + QFETCH(QString, script); + QScriptEngine eng; EventReceiver3 receiver(&eng); @@ -3395,7 +3440,7 @@ void tst_QScriptEngine::abortEvaluation() for (int x = 0; x < 4; ++x) { QCoreApplication::postEvent(&receiver, new QEvent(QEvent::Type(QEvent::User+1))); receiver.resultType = EventReceiver3::AbortionResult(x); - QScriptValue ret = eng.evaluate(QString::fromLatin1("while (1) { }")); + QScriptValue ret = eng.evaluate(script); switch (receiver.resultType) { case EventReceiver3::None: QVERIFY(!eng.hasUncaughtException()); -- cgit v0.12