[clang] Fix AST IgnoreUnlessSpelledInSource traversal nullptr dereference (PR #146103)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Jun 27 09:15:43 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Jonathan Marriott (JonathanMarriott)
<details>
<summary>Changes</summary>
Fixes #<!-- -->146101, 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
---
Full diff: https://github.com/llvm/llvm-project/pull/146103.diff
2 Files Affected:
- (modified) clang/include/clang/AST/ASTNodeTraverser.h (+1-1)
- (modified) clang/unittests/AST/ASTTraverserTest.cpp (+75)
``````````diff
diff --git a/clang/include/clang/AST/ASTNodeTraverser.h b/clang/include/clang/AST/ASTNodeTraverser.h
index 8d02a50e2e8a5..8ebabb2bde10d 100644
--- a/clang/include/clang/AST/ASTNodeTraverser.h
+++ b/clang/include/clang/AST/ASTNodeTraverser.h
@@ -99,7 +99,7 @@ class ASTNodeTraverser
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([=] {
diff --git a/clang/unittests/AST/ASTTraverserTest.cpp b/clang/unittests/AST/ASTTraverserTest.cpp
index 8b6e3e90c0ea6..988e81d8e51de 100644
--- a/clang/unittests/AST/ASTTraverserTest.cpp
+++ b/clang/unittests/AST/ASTTraverserTest.cpp
@@ -28,6 +28,10 @@ class NodeTreePrinter : public TextTreeStructure {
: 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
``````````
</details>
https://github.com/llvm/llvm-project/pull/146103
More information about the cfe-commits
mailing list