Skip to content

Commit 44ec3e8

Browse files
[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
1 parent 1cdc7f8 commit 44ec3e8

File tree

3 files changed

+77
-1
lines changed

3 files changed

+77
-1
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -903,6 +903,7 @@ Bug Fixes to AST Handling
903903
- Fixed dependency calculation for TypedefTypes (#GH89774)
904904
- The ODR checker now correctly hashes the names of conversion operators. (#GH143152)
905905
- Fixed the right parenthesis source location of ``CXXTemporaryObjectExpr``. (#GH143711)
906+
- Fixed a crash when performing an ``IgnoreUnlessSpelledInSource`` traversal of ASTs containing ``catch(...)`` statements. (#GH146103)
906907

907908
Miscellaneous Bug Fixes
908909
^^^^^^^^^^^^^^^^^^^^^^^

clang/include/clang/AST/ASTNodeTraverser.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ class ASTNodeTraverser
9999
TraversalKind GetTraversalKind() const { return Traversal; }
100100

101101
void Visit(const Decl *D, bool VisitLocs = false) {
102-
if (Traversal == TK_IgnoreUnlessSpelledInSource && D->isImplicit())
102+
if (Traversal == TK_IgnoreUnlessSpelledInSource && D && D->isImplicit())
103103
return;
104104

105105
getNodeDelegate().AddChild([=] {

clang/unittests/AST/ASTTraverserTest.cpp

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ class NodeTreePrinter : public TextTreeStructure {
2828
: TextTreeStructure(OS, /* showColors */ false), OS(OS) {}
2929

3030
void Visit(const Decl *D) {
31+
if (!D) {
32+
OS << "<<<NULL>>>";
33+
return;
34+
}
3135
OS << D->getDeclKindName() << "Decl";
3236
if (auto *ND = dyn_cast<NamedDecl>(D)) {
3337
OS << " '" << ND->getDeclName() << "'";
@@ -1932,4 +1936,75 @@ CXXRewrittenBinaryOperator
19321936
}
19331937
}
19341938

1939+
TEST(Traverse, CatchStatements) {
1940+
1941+
auto AST = buildASTFromCode(R"cpp(
1942+
void test()
1943+
{
1944+
try
1945+
{
1946+
int a;
1947+
}
1948+
catch (...)
1949+
{
1950+
int b;
1951+
}
1952+
1953+
try
1954+
{
1955+
int a;
1956+
}
1957+
catch (const int&)
1958+
{
1959+
int b;
1960+
}
1961+
}
1962+
)cpp");
1963+
1964+
auto BN =
1965+
ast_matchers::match(cxxCatchStmt().bind("catch"), AST->getASTContext());
1966+
EXPECT_EQ(BN.size(), 2u);
1967+
const auto *catchWithoutDecl = BN[0].getNodeAs<Stmt>("catch");
1968+
1969+
llvm::StringRef Expected = R"cpp(
1970+
CXXCatchStmt
1971+
|-<<<NULL>>>
1972+
`-CompoundStmt
1973+
`-DeclStmt
1974+
`-VarDecl 'b'
1975+
)cpp";
1976+
EXPECT_EQ(dumpASTString(TK_AsIs, catchWithoutDecl), Expected);
1977+
1978+
Expected = R"cpp(
1979+
CXXCatchStmt
1980+
|-<<<NULL>>>
1981+
`-CompoundStmt
1982+
`-DeclStmt
1983+
`-VarDecl 'b'
1984+
)cpp";
1985+
EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, catchWithoutDecl),
1986+
Expected);
1987+
1988+
const auto *catchWithDecl = BN[1].getNodeAs<Stmt>("catch");
1989+
1990+
Expected = R"cpp(
1991+
CXXCatchStmt
1992+
|-VarDecl ''
1993+
`-CompoundStmt
1994+
`-DeclStmt
1995+
`-VarDecl 'b'
1996+
)cpp";
1997+
EXPECT_EQ(dumpASTString(TK_AsIs, catchWithDecl), Expected);
1998+
1999+
Expected = R"cpp(
2000+
CXXCatchStmt
2001+
|-VarDecl ''
2002+
`-CompoundStmt
2003+
`-DeclStmt
2004+
`-VarDecl 'b'
2005+
)cpp";
2006+
EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, catchWithDecl),
2007+
Expected);
2008+
}
2009+
19352010
} // namespace clang

0 commit comments

Comments
 (0)