aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2019-09-02 14:44:29 +0200
committerUlf Hermann <ulf.hermann@qt.io>2019-09-17 10:05:04 +0200
commit873f13164d63cbb7db7d2289fd3e504d7553fb5b (patch)
tree2328ca556fa7f3190fbb32f75899951cf3dd8d90
parentd1071eed3f4c72b553903b47a7afca955b62f029 (diff)
V4: Provide an environment variable to disable runtime stack size checks
With QV4_CRASH_ON_STACKOVERFLOW set you can use up all the stack provided by the operating system to parse and execute JavaScript. Once the stack space is exhausted the program crashes like it would in case of a C++ stack overflow. We cannot reliably determine either the maximum stack size or the amount of stack space currently in use at runtime. Therefore, the guards we usually put in place are necessarily conservative. [ChangeLog][QtQml] There is now an option to disable the (necessarily) conservative stack size checks when parsing and executing JavaScript. If the environment variable QV4_CRASH_ON_STACKOVERFLOW is set, JavaScript stack overflows crash the program the same way C++ stack overflows do. On the flip side, more stack space is made available that way. Task-number: QTBUG-74087 Change-Id: I5e9d9ec6c0c9c6258c31d9e2d04a5c1819fbf400 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io> Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
-rw-r--r--src/qml/jsruntime/qv4engine.cpp16
-rw-r--r--src/qml/parser/qqmljsast.cpp6
-rw-r--r--src/qml/parser/qqmljsast_p.h8
3 files changed, 23 insertions, 7 deletions
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index be0de09d79..fca97d2e0c 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -216,15 +216,19 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
memoryManager = new QV4::MemoryManager(this);
if (maxCallDepth == -1) {
- ok = false;
- maxCallDepth = qEnvironmentVariableIntValue("QV4_MAX_CALL_DEPTH", &ok);
- if (!ok || maxCallDepth <= 0) {
+ if (qEnvironmentVariableIsSet("QV4_CRASH_ON_STACKOVERFLOW")) {
+ maxCallDepth = std::numeric_limits<qint32>::max();
+ } else {
+ ok = false;
+ maxCallDepth = qEnvironmentVariableIntValue("QV4_MAX_CALL_DEPTH", &ok);
+ if (!ok || maxCallDepth <= 0) {
#if defined(QT_NO_DEBUG) && !defined(__SANITIZE_ADDRESS__) && !QT_HAS_FEATURE(address_sanitizer)
- maxCallDepth = 1234;
+ maxCallDepth = 1234;
#else
- // no (tail call) optimization is done, so there'll be a lot mare stack frames active
- maxCallDepth = 200;
+ // no (tail call) optimization is done, so there'll be a lot mare stack frames active
+ maxCallDepth = 200;
#endif
+ }
}
}
Q_ASSERT(maxCallDepth > 0);
diff --git a/src/qml/parser/qqmljsast.cpp b/src/qml/parser/qqmljsast.cpp
index b63b2191b9..03355b3e38 100644
--- a/src/qml/parser/qqmljsast.cpp
+++ b/src/qml/parser/qqmljsast.cpp
@@ -105,6 +105,12 @@ ClassExpression *Node::asClassDefinition()
return nullptr;
}
+bool Node::ignoreRecursionDepth() const
+{
+ static const bool doIgnore = qEnvironmentVariableIsSet("QV4_CRASH_ON_STACKOVERFLOW");
+ return doIgnore;
+}
+
ExpressionNode *ExpressionNode::expressionCast()
{
return this;
diff --git a/src/qml/parser/qqmljsast_p.h b/src/qml/parser/qqmljsast_p.h
index 4247785905..bdda46da90 100644
--- a/src/qml/parser/qqmljsast_p.h
+++ b/src/qml/parser/qqmljsast_p.h
@@ -275,10 +275,16 @@ public:
virtual FunctionExpression *asFunctionDefinition();
virtual ClassExpression *asClassDefinition();
+ bool ignoreRecursionDepth() const;
+
inline void accept(Visitor *visitor)
{
Visitor::RecursionDepthCheck recursionCheck(visitor);
- if (recursionCheck()) {
+
+ // Stack overflow is uncommon, ignoreRecursionDepth() only returns true if
+ // QV4_CRASH_ON_STACKOVERFLOW is set, and ignoreRecursionDepth() needs to be out of line.
+ // Therefore, check for ignoreRecursionDepth() _after_ calling the inline recursionCheck().
+ if (recursionCheck() || ignoreRecursionDepth()) {
if (visitor->preVisit(this))
accept0(visitor);
visitor->postVisit(this);