From e267a9566af0f12eeb429637db14ea482f06d195 Mon Sep 17 00:00:00 2001 From: nussaiba shaikh Date: Sun, 18 Oct 2026 23:27:32 +0530 Subject: [PATCH 1/2] clang import: reject AST nodes without the ext tokens the handlers read --- lib/clangimport.cpp | 12 ++++++++++-- test/testclangimport.cpp | 14 +++++++++++++- 2 files changed, 23 insertions(+), 3 deletions(-) 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) From 24d64ec1875cbe682eb78d6a8dfdc8e88bae9e86 Mon Sep 17 00:00:00 2001 From: nussaiba shaikh Date: Mon, 19 Oct 2026 13:20:12 +0530 Subject: [PATCH 2/2] clang import: reject address-only function and enumerator declarations --- lib/clangimport.cpp | 11 +++++++++-- test/testclangimport.cpp | 5 +++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/lib/clangimport.cpp b/lib/clangimport.cpp index 60376ba7119..53b2d25a4f5 100644 --- a/lib/clangimport.cpp +++ b/lib/clangimport.cpp @@ -1055,7 +1055,10 @@ Token *clangimport::AstNode::createTokens(TokenList &tokenList) return nullptr; } if (nodeType == EnumConstantDecl) { - Token *nameToken = addtoken(tokenList, getSpelling()); + const std::string name = getSpelling(); + if (name.empty()) + throw InternalError(nullptr, "invalid AST node: " + nodeType, InternalError::AST); + Token *nameToken = addtoken(tokenList, name); auto *scope = const_cast(nameToken->scope()); scope->enumeratorList.emplace_back(nameToken->scope()); Enumerator *e = &scope->enumeratorList.back(); @@ -1386,6 +1389,10 @@ Token * clangimport::AstNode::createTokensCall(TokenList &tokenList) void clangimport::AstNode::createTokensFunctionDecl(TokenList &tokenList) { + // an address-only node has no name: addtoken("") adds nothing and would return a null back() + const std::string name = getSpelling(); + if (name.empty()) + throw InternalError(nullptr, "invalid AST node: " + nodeType, InternalError::AST); const bool prev = contains(mExtTokens, "prev"); const bool hasBody = !children.empty() && children.back()->nodeType == CompoundStmt; const bool isStatic = contains(mExtTokens, "static"); @@ -1407,7 +1414,7 @@ void clangimport::AstNode::createTokensFunctionDecl(TokenList &tokenList) if (mExtTokens.size() > 4 && mExtTokens[1] == "parent") addFullScopeNameTokens(tokenList, mData->getScope(mExtTokens[2])); - Token *nameToken = addtoken(tokenList, getSpelling() + getTemplateParameters()); + Token *nameToken = addtoken(tokenList, name + getTemplateParameters()); auto *nestedIn = const_cast(nameToken->scope()); if (prev) { diff --git a/test/testclangimport.cpp b/test/testclangimport.cpp index 865faa9a618..bc7431e0d58 100644 --- a/test/testclangimport.cpp +++ b/test/testclangimport.cpp @@ -1440,6 +1440,11 @@ class TestClangImport : public TestFixture { 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"); + // address-only declarations: getSpelling() is empty, addtoken() adds nothing and back() is null + ASSERT_THROW_INTERNAL_EQUALS(parse("`-FunctionDecl 0x1"), AST, "invalid AST node: FunctionDecl"); + ASSERT_THROW_INTERNAL_EQUALS(parse("`-CXXConstructorDecl 0x1"), AST, "invalid AST node: CXXConstructorDecl"); + ASSERT_THROW_INTERNAL_EQUALS(parse("`-CXXMethodDecl 0x1"), AST, "invalid AST node: CXXMethodDecl"); + ASSERT_THROW_INTERNAL_EQUALS(parse("`-EnumConstantDecl 0x1"), AST, "invalid AST node: EnumConstantDecl"); } };