[clang][AST] Fix AST IgnoreUnlessSpelledInSource traversal nullptr dereference (#146103)

In summary dumping a `catch(...)` statement using
IgnoreUnlessSpelledInSource AST traversal causes a seg fault, as the
variable declaration of the catch is `nullptr`.

Diagnosed the cause by attaching the debugger to `clang-query`, this PR
adds a fix to check for `nullptr` before accessing the `isImplicit()`
method of the `Decl` pointee in the AST node traverser visitor

Fixes #146101
This commit is contained in:
Jonathan Marriott
2025-06-30 15:48:26 +01:00
committed by GitHub
parent 1cdc7f8724
commit 44ec3e8f9c
3 changed files with 77 additions and 1 deletions

View File

@@ -903,6 +903,7 @@ Bug Fixes to AST Handling
- Fixed dependency calculation for TypedefTypes (#GH89774)
- The ODR checker now correctly hashes the names of conversion operators. (#GH143152)
- Fixed the right parenthesis source location of ``CXXTemporaryObjectExpr``. (#GH143711)
- Fixed a crash when performing an ``IgnoreUnlessSpelledInSource`` traversal of ASTs containing ``catch(...)`` statements. (#GH146103)
Miscellaneous Bug Fixes
^^^^^^^^^^^^^^^^^^^^^^^

View File

@@ -99,7 +99,7 @@ public:
TraversalKind GetTraversalKind() const { return Traversal; }
void Visit(const Decl *D, bool VisitLocs = false) {
if (Traversal == TK_IgnoreUnlessSpelledInSource && D->isImplicit())
if (Traversal == TK_IgnoreUnlessSpelledInSource && D && D->isImplicit())
return;
getNodeDelegate().AddChild([=] {

View File

@@ -28,6 +28,10 @@ public:
: TextTreeStructure(OS, /* showColors */ false), OS(OS) {}
void Visit(const Decl *D) {
if (!D) {
OS << "<<<NULL>>>";
return;
}
OS << D->getDeclKindName() << "Decl";
if (auto *ND = dyn_cast<NamedDecl>(D)) {
OS << " '" << ND->getDeclName() << "'";
@@ -1932,4 +1936,75 @@ CXXRewrittenBinaryOperator
}
}
TEST(Traverse, CatchStatements) {
auto AST = buildASTFromCode(R"cpp(
void test()
{
try
{
int a;
}
catch (...)
{
int b;
}
try
{
int a;
}
catch (const int&)
{
int b;
}
}
)cpp");
auto BN =
ast_matchers::match(cxxCatchStmt().bind("catch"), AST->getASTContext());
EXPECT_EQ(BN.size(), 2u);
const auto *catchWithoutDecl = BN[0].getNodeAs<Stmt>("catch");
llvm::StringRef Expected = R"cpp(
CXXCatchStmt
|-<<<NULL>>>
`-CompoundStmt
`-DeclStmt
`-VarDecl 'b'
)cpp";
EXPECT_EQ(dumpASTString(TK_AsIs, catchWithoutDecl), Expected);
Expected = R"cpp(
CXXCatchStmt
|-<<<NULL>>>
`-CompoundStmt
`-DeclStmt
`-VarDecl 'b'
)cpp";
EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, catchWithoutDecl),
Expected);
const auto *catchWithDecl = BN[1].getNodeAs<Stmt>("catch");
Expected = R"cpp(
CXXCatchStmt
|-VarDecl ''
`-CompoundStmt
`-DeclStmt
`-VarDecl 'b'
)cpp";
EXPECT_EQ(dumpASTString(TK_AsIs, catchWithDecl), Expected);
Expected = R"cpp(
CXXCatchStmt
|-VarDecl ''
`-CompoundStmt
`-DeclStmt
`-VarDecl 'b'
)cpp";
EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, catchWithDecl),
Expected);
}
} // namespace clang