diff --git a/lib/clangimport.cpp b/lib/clangimport.cpp index f4c66b738bc..60376ba7119 100644 --- a/lib/clangimport.cpp +++ b/lib/clangimport.cpp @@ -336,7 +336,10 @@ namespace clangimport { public: AstNode(std::string nodeType, const std::string &ext, Data *data) : nodeType(std::move(nodeType)), mExtTokens(splitString(ext)), mData(data) - {} + { + if (mExtTokens.empty()) + throw InternalError(nullptr, "invalid AST node: " + this->nodeType, InternalError::AST); + } std::string nodeType; std::vector children; @@ -1408,7 +1411,10 @@ void clangimport::AstNode::createTokensFunctionDecl(TokenList &tokenList) auto *nestedIn = const_cast(nameToken->scope()); if (prev) { - const std::string addr = *(std::find(mExtTokens.cbegin(), mExtTokens.cend(), "prev") + 1); + const auto it = std::find(mExtTokens.cbegin(), mExtTokens.cend(), "prev"); + if (it + 1 == mExtTokens.cend()) + throw InternalError(nullptr, "invalid AST node: " + nodeType, InternalError::AST); + const std::string addr = *(it + 1); mData->ref(addr, nameToken); } if (!nameToken->function()) { @@ -1549,6 +1555,8 @@ void clangimport::AstNode::createTokensForCXXRecord(TokenList &tokenList) Token * clangimport::AstNode::createTokensVarDecl(TokenList &tokenList) { + if (mExtTokens.size() < 2) + throw InternalError(nullptr, "invalid AST node: " + nodeType, InternalError::AST); const std::string addr = mExtTokens.front(); if (contains(mExtTokens, "static")) addtoken(tokenList, "static"); diff --git a/test/testclangimport.cpp b/test/testclangimport.cpp index 13a27c7e7a0..865faa9a618 100644 --- a/test/testclangimport.cpp +++ b/test/testclangimport.cpp @@ -143,6 +143,7 @@ class TestClangImport : public TestFixture { TEST_CASE(crash); TEST_CASE(crash2); TEST_CASE(nullNodeInvalidLevel); + TEST_CASE(invalidExtTokens); } std::string parse(const char clang[]) { @@ -1420,7 +1421,7 @@ class TestClangImport : public TestFixture { // getSpelling() indexed mExtTokens[typeIndex - 1] without a lower-bound // check, so a node whose line carries no ext tokens (typeIndex <= 0) read // out of bounds. - (void)parse("`-RecordDecl "); // don't crash + ASSERT_THROW_INTERNAL_EQUALS(parse("`-RecordDecl "), AST, "invalid AST node: RecordDecl"); } void nullNodeInvalidLevel() { @@ -1429,6 +1430,17 @@ class TestClangImport : public TestFixture { "`-<<>>\n"; ASSERT_EQUALS("void foo ( ) ;", parse(clang)); } + + void invalidExtTokens() { + // nodes without the ext tokens the handlers read must not index out of bounds + ASSERT_THROW_INTERNAL_EQUALS(parse("`-FunctionDecl 0x1 col:5 f 'int ()'\n" + " `-CompoundStmt 0x2 \n" + " `-ReturnStmt 0x3 \n" + " `-IntegerLiteral \n"), AST, "invalid AST node: IntegerLiteral"); + ASSERT_THROW_INTERNAL_EQUALS(parse("`-EnumDecl "), AST, "invalid AST node: EnumDecl"); + ASSERT_THROW_INTERNAL_EQUALS(parse("`-VarDecl 0x1"), AST, "invalid AST node: VarDecl"); + ASSERT_THROW_INTERNAL_EQUALS(parse("`-FunctionDecl 0x1 col:5 f 'int ()' prev"), AST, "invalid AST node: FunctionDecl"); + } }; REGISTER_TEST(TestClangImport)