diff --git a/lib/tokenlist.cpp b/lib/tokenlist.cpp index 5cf7cb0df..f55a26ba6 100644 --- a/lib/tokenlist.cpp +++ b/lib/tokenlist.cpp @@ -1057,6 +1057,34 @@ void TokenList::createAst() for (Token *tok = _front; tok; tok = tok ? tok->next() : NULL) { tok = createAstAtToken(tok, isCPP()); } + + validateAst(); +} + +void TokenList::validateAst() +{ + // Verify that ast looks ok + for (const Token *tok = _front; tok; tok = tok->next()) { + // Syntax error if binary operator only has 1 operand + if ((tok->isAssignmentOp() || tok->isComparisonOp() || Token::Match(tok,"[|^/%]")) && tok->astOperand1() && !tok->astOperand2()) + throw InternalError(tok, "Syntax Error: AST broken, binary operator has only one operand.", InternalError::SYNTAX); + + // Syntax error if we encounter "?" with operand2 that is not ":" + if (tok->astOperand2() && tok->str() == "?" && tok->astOperand2()->str() != ":") + throw InternalError(tok, "Syntax Error: AST broken, ternary operator lacks ':'.", InternalError::SYNTAX); + + // check for endless recursion + const Token* parent=tok; + while (parent = parent->astParent()) { + if (parent==tok) + throw InternalError(tok, "AST broken: endless recursion from '" + tok->str() + "'", InternalError::SYNTAX); + } + } +} + +void TokenList::cppcheckError(const Token *tok) const +{ + throw InternalError(tok, "Analysis failed - inconsisten AST. If the code is valid then please report this failure.", InternalError::INTERNAL); } const std::string& TokenList::file(const Token *tok) const diff --git a/lib/tokenlist.h b/lib/tokenlist.h index e1ae34916..c6830e2fc 100644 --- a/lib/tokenlist.h +++ b/lib/tokenlist.h @@ -126,9 +126,24 @@ public: */ unsigned long long calculateChecksum() const; + /** + * Create abstract syntax tree. + */ void createAst(); + /** + * Create abstract syntax tree. + */ + void validateAst(); + private: + + /** + * Send error message to error logger about internal bug. + * @param tok the token that this bug concerns. + */ + void cppcheckError(const Token *tok) const; + /** Disable copy constructor, no implementation */ TokenList(const TokenList &); diff --git a/test/testgarbage.cpp b/test/testgarbage.cpp index d73a962d1..0664764fd 100644 --- a/test/testgarbage.cpp +++ b/test/testgarbage.cpp @@ -210,6 +210,7 @@ private: TEST_CASE(garbageCode159); // #7119 TEST_CASE(garbageCode160); // #7190 TEST_CASE(garbageCode161); // #7200 + TEST_CASE(garbageCode162); // #7208 TEST_CASE(garbageValueFlow); TEST_CASE(garbageSymbolDatabase); TEST_CASE(garbageAST); @@ -1386,6 +1387,12 @@ private: //7200 ASSERT_THROW(checkCode("{ }{ if () try { } catch (...)} B : : ~B { }"), InternalError); } + + void garbageCode162() { + //7208 + ASSERT_THROW(checkCode("return << >> x return << >> x ", "test.c"), InternalError); + } + }; REGISTER_TEST(TestGarbage)