[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:
committed by
GitHub
parent
1cdc7f8724
commit
44ec3e8f9c
@@ -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
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
@@ -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([=] {
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user