diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/sksl/SkSLParser.cpp | 33 | ||||
-rw-r--r-- | src/sksl/SkSLParser.h | 6 |
2 files changed, 38 insertions, 1 deletions
diff --git a/src/sksl/SkSLParser.cpp b/src/sksl/SkSLParser.cpp index 2699d9c113..7eac0ce567 100644 --- a/src/sksl/SkSLParser.cpp +++ b/src/sksl/SkSLParser.cpp @@ -73,6 +73,31 @@ namespace SkSL { +#define MAX_PARSE_DEPTH 50 + +class AutoDepth { +public: + AutoDepth(Parser* p) + : fParser(p) { + fParser->fDepth++; + } + + ~AutoDepth() { + fParser->fDepth--; + } + + bool checkValid() { + if (fParser->fDepth > MAX_PARSE_DEPTH) { + fParser->error(fParser->peek().fPosition, "exceeded max parse depth"); + return false; + } + return true; + } + +private: + Parser* fParser; +}; + Parser::Parser(std::string text, SymbolTable& types, ErrorReporter& errors) : fPushback(Position(-1, -1), Token::INVALID_TOKEN, "") , fTypes(types) @@ -920,6 +945,10 @@ std::unique_ptr<ASTDiscardStatement> Parser::discardStatement() { /* LBRACE statement* RBRACE */ std::unique_ptr<ASTBlock> Parser::block() { + AutoDepth depth(this); + if (!depth.checkValid()) { + return nullptr; + } Token start; if (!this->expect(Token::LBRACE, "'{'", &start)) { return nullptr; @@ -959,6 +988,10 @@ std::unique_ptr<ASTExpressionStatement> Parser::expressionStatement() { /* assignmentExpression */ std::unique_ptr<ASTExpression> Parser::expression() { + AutoDepth depth(this); + if (!depth.checkValid()) { + return nullptr; + } return this->assignmentExpression(); } diff --git a/src/sksl/SkSLParser.h b/src/sksl/SkSLParser.h index d1ae0d0e9f..f9dcde244f 100644 --- a/src/sksl/SkSLParser.h +++ b/src/sksl/SkSLParser.h @@ -197,12 +197,16 @@ private: bool identifier(std::string* dest); - void* fScanner; YY_BUFFER_STATE fBuffer; + // current parse depth, used to enforce a recursion limit to try to keep us from overflowing the + // stack on pathological inputs + int fDepth = 0; Token fPushback; SymbolTable& fTypes; ErrorReporter& fErrors; + + friend class AutoDepth; }; } // namespace |