diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2019-02-27 16:01:54 +0100 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2019-03-15 11:53:22 +0000 |
commit | 73231fe953145ac0df4e62f173e1a90076466012 (patch) | |
tree | 031a29f9c67be0f4fd903b18847d12081483e1b7 /src/qml/parser | |
parent | 93601b1fd4aae326562c6e7cfe16d5ecf2532a6a (diff) |
Unify the JavaScript parsing recursion checks
We only need to check in one central location and we can allow for more
recursion. 4k recursions seem tolerable. A common default for stack
sizes is 8MB. Each recursion step takes up to 1k stack space in debug
mode. So, exhausting this would burn about half of the available stack
size. We don't report the exact source location in this case as finding
the source location may itself trigger a deep recursion.
Fixes: QTBUG-74087
Change-Id: I43e6e20b322f6035c7136a6f381230ec285c30ae
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'src/qml/parser')
-rw-r--r-- | src/qml/parser/qqmljs.g | 10 | ||||
-rw-r--r-- | src/qml/parser/qqmljsast_p.h | 11 | ||||
-rw-r--r-- | src/qml/parser/qqmljsastvisitor.cpp | 2 | ||||
-rw-r--r-- | src/qml/parser/qqmljsastvisitor_p.h | 36 |
4 files changed, 45 insertions, 14 deletions
diff --git a/src/qml/parser/qqmljs.g b/src/qml/parser/qqmljs.g index b86dba6daa..8ae51a795f 100644 --- a/src/qml/parser/qqmljs.g +++ b/src/qml/parser/qqmljs.g @@ -614,16 +614,8 @@ bool Parser::parse(int startToken) program = 0; do { - if (++tos == stack_size) { + if (++tos == stack_size) reallocateStack(); - if (stack_size > 10000) { - // We're now in some serious right-recursive stuff, which will probably result in - // an AST that's so deep that recursively visiting it will run out of stack space. - const QString msg = QCoreApplication::translate("QQmlParser", "Maximum statement or expression depth exceeded"); - diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg)); - return false; - } - } state_stack[tos] = action; diff --git a/src/qml/parser/qqmljsast_p.h b/src/qml/parser/qqmljsast_p.h index 0978ab523a..e84c62af2f 100644 --- a/src/qml/parser/qqmljsast_p.h +++ b/src/qml/parser/qqmljsast_p.h @@ -273,9 +273,14 @@ public: inline void accept(Visitor *visitor) { - if (visitor->preVisit(this)) - accept0(visitor); - visitor->postVisit(this); + Visitor::RecursionDepthCheck recursionCheck(visitor); + if (recursionCheck()) { + if (visitor->preVisit(this)) + accept0(visitor); + visitor->postVisit(this); + } else { + visitor->throwRecursionDepthError(); + } } inline static void accept(Node *node, Visitor *visitor) diff --git a/src/qml/parser/qqmljsastvisitor.cpp b/src/qml/parser/qqmljsastvisitor.cpp index eec151298e..666623eecc 100644 --- a/src/qml/parser/qqmljsastvisitor.cpp +++ b/src/qml/parser/qqmljsastvisitor.cpp @@ -43,7 +43,7 @@ QT_QML_BEGIN_NAMESPACE namespace QQmlJS { namespace AST { -Visitor::Visitor() +Visitor::Visitor(quint16 parentRecursionDepth) : m_recursionDepth(parentRecursionDepth) { } diff --git a/src/qml/parser/qqmljsastvisitor_p.h b/src/qml/parser/qqmljsastvisitor_p.h index c925096de6..9c69f88e0c 100644 --- a/src/qml/parser/qqmljsastvisitor_p.h +++ b/src/qml/parser/qqmljsastvisitor_p.h @@ -61,7 +61,33 @@ namespace QQmlJS { namespace AST { class QML_PARSER_EXPORT Visitor { public: - Visitor(); + class RecursionDepthCheck + { + Q_DISABLE_COPY(RecursionDepthCheck) + public: + RecursionDepthCheck(RecursionDepthCheck &&) = delete; + RecursionDepthCheck &operator=(RecursionDepthCheck &&) = delete; + + RecursionDepthCheck(Visitor *visitor) : m_visitor(visitor) + { + ++(m_visitor->m_recursionDepth); + } + + ~RecursionDepthCheck() + { + --(m_visitor->m_recursionDepth); + } + + bool operator()() const { + return m_visitor->m_recursionDepth < s_recursionLimit; + } + + private: + static const quint16 s_recursionLimit = 4096; + Visitor *m_visitor; + }; + + Visitor(quint16 parentRecursionDepth = 0); virtual ~Visitor(); virtual bool preVisit(Node *) { return true; } @@ -374,6 +400,14 @@ public: virtual bool visit(DebuggerStatement *) { return true; } virtual void endVisit(DebuggerStatement *) {} + + virtual void throwRecursionDepthError() = 0; + + quint16 recursionDepth() const { return m_recursionDepth; } + +protected: + quint16 m_recursionDepth = 0; + friend class RecursionDepthCheck; }; } } // namespace AST |