Skip to content

Commit 96d53fe

Browse files
committed
CFGBuilder: Fix crash when visiting delete expression on dependent type
Summary: CXXDeleteExpr::getDestroyedType() can return a null QualType if the destroyed type is a dependent type. This patch protects against this. Reviewers: klimek Subscribers: cfe-commits Differential Revision: https://reviews.llvm.org/D27350 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@288665 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 581ee41 commit 96d53fe

File tree

2 files changed

+52
-28
lines changed

2 files changed

+52
-28
lines changed

lib/Analysis/CFG.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3581,11 +3581,13 @@ CFGBlock *CFGBuilder::VisitCXXDeleteExpr(CXXDeleteExpr *DE,
35813581
autoCreateBlock();
35823582
appendStmt(Block, DE);
35833583
QualType DTy = DE->getDestroyedType();
3584-
DTy = DTy.getNonReferenceType();
3585-
CXXRecordDecl *RD = Context->getBaseElementType(DTy)->getAsCXXRecordDecl();
3586-
if (RD) {
3587-
if (RD->isCompleteDefinition() && !RD->hasTrivialDestructor())
3588-
appendDeleteDtor(Block, RD, DE);
3584+
if (!DTy.isNull()) {
3585+
DTy = DTy.getNonReferenceType();
3586+
CXXRecordDecl *RD = Context->getBaseElementType(DTy)->getAsCXXRecordDecl();
3587+
if (RD) {
3588+
if (RD->isCompleteDefinition() && !RD->hasTrivialDestructor())
3589+
appendDeleteDtor(Block, RD, DE);
3590+
}
35893591
}
35903592

35913593
return VisitChildren(DE);

unittests/Analysis/CFGTest.cpp

Lines changed: 45 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,41 @@ namespace clang {
1818
namespace analysis {
1919
namespace {
2020

21+
enum BuildResult {
22+
ToolFailed,
23+
ToolRan,
24+
SawFunctionBody,
25+
BuiltCFG,
26+
};
27+
28+
class CFGCallback : public ast_matchers::MatchFinder::MatchCallback {
29+
public:
30+
BuildResult TheBuildResult = ToolRan;
31+
32+
void run(const ast_matchers::MatchFinder::MatchResult &Result) override {
33+
const auto *Func = Result.Nodes.getNodeAs<FunctionDecl>("func");
34+
Stmt *Body = Func->getBody();
35+
if (!Body)
36+
return;
37+
TheBuildResult = SawFunctionBody;
38+
if (CFG::buildCFG(nullptr, Body, Result.Context, CFG::BuildOptions()))
39+
TheBuildResult = BuiltCFG;
40+
}
41+
};
42+
43+
BuildResult BuildCFG(const char *Code) {
44+
CFGCallback Callback;
45+
46+
ast_matchers::MatchFinder Finder;
47+
Finder.addMatcher(ast_matchers::functionDecl().bind("func"), &Callback);
48+
std::unique_ptr<tooling::FrontendActionFactory> Factory(
49+
tooling::newFrontendActionFactory(&Finder));
50+
std::vector<std::string> Args = {"-std=c++11", "-fno-delayed-template-parsing"};
51+
if (!tooling::runToolOnCodeWithArgs(Factory->create(), Code, Args))
52+
return ToolFailed;
53+
return Callback.TheBuildResult;
54+
}
55+
2156
// Constructing a CFG for a range-based for over a dependent type fails (but
2257
// should not crash).
2358
TEST(CFG, RangeBasedForOverDependentType) {
@@ -27,30 +62,17 @@ TEST(CFG, RangeBasedForOverDependentType) {
2762
" for (const Foo *TheFoo : Range) {\n"
2863
" }\n"
2964
"}\n";
65+
EXPECT_EQ(SawFunctionBody, BuildCFG(Code));
66+
}
3067

31-
class CFGCallback : public ast_matchers::MatchFinder::MatchCallback {
32-
public:
33-
bool SawFunctionBody = false;
34-
35-
void run(const ast_matchers::MatchFinder::MatchResult &Result) override {
36-
const auto *Func = Result.Nodes.getNodeAs<FunctionDecl>("func");
37-
Stmt *Body = Func->getBody();
38-
if (!Body)
39-
return;
40-
SawFunctionBody = true;
41-
std::unique_ptr<CFG> cfg =
42-
CFG::buildCFG(nullptr, Body, Result.Context, CFG::BuildOptions());
43-
EXPECT_EQ(nullptr, cfg);
44-
}
45-
} Callback;
46-
47-
ast_matchers::MatchFinder Finder;
48-
Finder.addMatcher(ast_matchers::functionDecl().bind("func"), &Callback);
49-
std::unique_ptr<tooling::FrontendActionFactory> Factory(
50-
tooling::newFrontendActionFactory(&Finder));
51-
std::vector<std::string> Args = {"-std=c++11", "-fno-delayed-template-parsing"};
52-
ASSERT_TRUE(tooling::runToolOnCodeWithArgs(Factory->create(), Code, Args));
53-
EXPECT_TRUE(Callback.SawFunctionBody);
68+
// Constructing a CFG containing a delete expression on a dependent type should
69+
// not crash.
70+
TEST(CFG, DeleteExpressionOnDependentType) {
71+
const char *Code = "template<class T>\n"
72+
"void f(T t) {\n"
73+
" delete t;\n"
74+
"}\n";
75+
EXPECT_EQ(BuiltCFG, BuildCFG(Code));
5476
}
5577

5678
} // namespace

0 commit comments

Comments
 (0)