aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jsapi
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2019-04-18 15:37:17 +0200
committerUlf Hermann <ulf.hermann@qt.io>2019-04-30 16:24:45 +0000
commit9b6c20cb719542cfcf3e031afd5b2b0b1cd3833e (patch)
tree2130fe9f9179eccb604c3e3eacc18cbd62202b0b /src/qml/jsapi
parentd7db2ef07bf6f0f7c39f342aed94d51cca42df11 (diff)
Make JavaScript execution interruptible
Add an atomic isInterrupted flag to BaseEngine and check that in addition to the hasException flag on checkException(). Add some more exception checks to cover all possible infinite loops. Also, remove the writeBarrierActive member from QV4::EngineBase. It isn't used. Fixes: QTBUG-49080 Change-Id: I86b3114e3e61aff3e5eb9b020749a908ed801c2b Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'src/qml/jsapi')
-rw-r--r--src/qml/jsapi/qjsengine.cpp36
-rw-r--r--src/qml/jsapi/qjsengine.h3
-rw-r--r--src/qml/jsapi/qjsvalue.cpp6
3 files changed, 44 insertions, 1 deletions
diff --git a/src/qml/jsapi/qjsengine.cpp b/src/qml/jsapi/qjsengine.cpp
index aab72f8b2d..45ea79d31a 100644
--- a/src/qml/jsapi/qjsengine.cpp
+++ b/src/qml/jsapi/qjsengine.cpp
@@ -470,6 +470,33 @@ void QJSEngine::installExtensions(QJSEngine::Extensions extensions, const QJSVal
QV4::GlobalExtensions::init(obj, extensions);
}
+/*!
+ \since 5.14
+ Interrupts or re-enables JavaScript execution.
+
+ If \a interrupted is \c true, any JavaScript executed by this engine
+ immediately aborts and returns an error object until this function is
+ called again with a value of \c false for \a interrupted.
+
+ This function is thread safe. You may call it from a different thread
+ in order to interrupt, for example, an infinite loop in JavaScript.
+*/
+void QJSEngine::setInterrupted(bool interrupted)
+{
+ m_v4Engine->isInterrupted = interrupted;
+}
+
+/*!
+ \since 5.14
+ Returns whether JavaScript execution is currently interrupted.
+
+ \sa setInterrupted()
+*/
+bool QJSEngine::isInterrupted() const
+{
+ return m_v4Engine->isInterrupted;
+}
+
static QUrl urlForFileName(const QString &fileName)
{
if (!fileName.startsWith(QLatin1Char(':')))
@@ -527,6 +554,8 @@ QJSValue QJSEngine::evaluate(const QString& program, const QString& fileName, in
result = script.run();
if (scope.engine->hasException)
result = v4->catchException();
+ if (v4->isInterrupted)
+ result = v4->newErrorObject(QStringLiteral("Interrupted"));
QJSValue retval(v4, result->asReturnedValue());
@@ -565,7 +594,12 @@ QJSValue QJSEngine::importModule(const QString &fileName)
if (m_v4Engine->hasException)
return QJSValue(m_v4Engine, m_v4Engine->catchException());
moduleUnit->evaluate();
- return QJSValue(m_v4Engine, moduleNamespace->asReturnedValue());
+ if (!m_v4Engine->isInterrupted)
+ return QJSValue(m_v4Engine, moduleNamespace->asReturnedValue());
+
+ return QJSValue(
+ m_v4Engine,
+ m_v4Engine->newErrorObject(QStringLiteral("Interrupted"))->asReturnedValue());
}
/*!
diff --git a/src/qml/jsapi/qjsengine.h b/src/qml/jsapi/qjsengine.h
index 6300842341..31a4d68baa 100644
--- a/src/qml/jsapi/qjsengine.h
+++ b/src/qml/jsapi/qjsengine.h
@@ -113,6 +113,9 @@ public:
void installExtensions(Extensions extensions, const QJSValue &object = QJSValue());
+ void setInterrupted(bool interrupted);
+ bool isInterrupted() const;
+
QV4::ExecutionEngine *handle() const { return m_v4Engine; }
void throwError(const QString &message);
diff --git a/src/qml/jsapi/qjsvalue.cpp b/src/qml/jsapi/qjsvalue.cpp
index e0bd986920..92eaf1d8ee 100644
--- a/src/qml/jsapi/qjsvalue.cpp
+++ b/src/qml/jsapi/qjsvalue.cpp
@@ -769,6 +769,8 @@ QJSValue QJSValue::call(const QJSValueList &args)
ScopedValue result(scope, f->call(jsCallData));
if (engine->hasException)
result = engine->catchException();
+ if (engine->isInterrupted)
+ result = engine->newErrorObject(QStringLiteral("Interrupted"));
return QJSValue(engine, result->asReturnedValue());
}
@@ -825,6 +827,8 @@ QJSValue QJSValue::callWithInstance(const QJSValue &instance, const QJSValueList
ScopedValue result(scope, f->call(jsCallData));
if (engine->hasException)
result = engine->catchException();
+ if (engine->isInterrupted)
+ result = engine->newErrorObject(QStringLiteral("Interrupted"));
return QJSValue(engine, result->asReturnedValue());
}
@@ -873,6 +877,8 @@ QJSValue QJSValue::callAsConstructor(const QJSValueList &args)
ScopedValue result(scope, f->callAsConstructor(jsCallData));
if (engine->hasException)
result = engine->catchException();
+ if (engine->isInterrupted)
+ result = engine->newErrorObject(QStringLiteral("Interrupted"));
return QJSValue(engine, result->asReturnedValue());
}