r288665 - CFGBuilder: Fix crash when visiting delete expression on dependent type

Martin Bohme via cfe-commits cfe-commits at lists.llvm.org
Mon Dec 5 03:33:20 PST 2016


Author: mboehme
Date: Mon Dec  5 05:33:19 2016
New Revision: 288665

URL: http://llvm.org/viewvc/llvm-project?rev=288665&view=rev
Log:
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

Modified:
    cfe/trunk/lib/Analysis/CFG.cpp
    cfe/trunk/unittests/Analysis/CFGTest.cpp

Modified: cfe/trunk/lib/Analysis/CFG.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFG.cpp?rev=288665&r1=288664&r2=288665&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/CFG.cpp (original)
+++ cfe/trunk/lib/Analysis/CFG.cpp Mon Dec  5 05:33:19 2016
@@ -3581,11 +3581,13 @@ CFGBlock *CFGBuilder::VisitCXXDeleteExpr
   autoCreateBlock();
   appendStmt(Block, DE);
   QualType DTy = DE->getDestroyedType();
-  DTy = DTy.getNonReferenceType();
-  CXXRecordDecl *RD = Context->getBaseElementType(DTy)->getAsCXXRecordDecl();
-  if (RD) {
-    if (RD->isCompleteDefinition() && !RD->hasTrivialDestructor())
-      appendDeleteDtor(Block, RD, DE);
+  if (!DTy.isNull()) {
+    DTy = DTy.getNonReferenceType();
+    CXXRecordDecl *RD = Context->getBaseElementType(DTy)->getAsCXXRecordDecl();
+    if (RD) {
+      if (RD->isCompleteDefinition() && !RD->hasTrivialDestructor())
+        appendDeleteDtor(Block, RD, DE);
+    }
   }
 
   return VisitChildren(DE);

Modified: cfe/trunk/unittests/Analysis/CFGTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Analysis/CFGTest.cpp?rev=288665&r1=288664&r2=288665&view=diff
==============================================================================
--- cfe/trunk/unittests/Analysis/CFGTest.cpp (original)
+++ cfe/trunk/unittests/Analysis/CFGTest.cpp Mon Dec  5 05:33:19 2016
@@ -18,6 +18,41 @@ namespace clang {
 namespace analysis {
 namespace {
 
+enum BuildResult {
+  ToolFailed,
+  ToolRan,
+  SawFunctionBody,
+  BuiltCFG,
+};
+
+class CFGCallback : public ast_matchers::MatchFinder::MatchCallback {
+public:
+  BuildResult TheBuildResult = ToolRan;
+
+  void run(const ast_matchers::MatchFinder::MatchResult &Result) override {
+    const auto *Func = Result.Nodes.getNodeAs<FunctionDecl>("func");
+    Stmt *Body = Func->getBody();
+    if (!Body)
+      return;
+    TheBuildResult = SawFunctionBody;
+    if (CFG::buildCFG(nullptr, Body, Result.Context, CFG::BuildOptions()))
+        TheBuildResult = BuiltCFG;
+  }
+};
+
+BuildResult BuildCFG(const char *Code) {
+  CFGCallback Callback;
+
+  ast_matchers::MatchFinder Finder;
+  Finder.addMatcher(ast_matchers::functionDecl().bind("func"), &Callback);
+  std::unique_ptr<tooling::FrontendActionFactory> Factory(
+      tooling::newFrontendActionFactory(&Finder));
+  std::vector<std::string> Args = {"-std=c++11", "-fno-delayed-template-parsing"};
+  if (!tooling::runToolOnCodeWithArgs(Factory->create(), Code, Args))
+    return ToolFailed;
+  return Callback.TheBuildResult;
+}
+
 // Constructing a CFG for a range-based for over a dependent type fails (but
 // should not crash).
 TEST(CFG, RangeBasedForOverDependentType) {
@@ -27,30 +62,17 @@ TEST(CFG, RangeBasedForOverDependentType
                      "  for (const Foo *TheFoo : Range) {\n"
                      "  }\n"
                      "}\n";
+  EXPECT_EQ(SawFunctionBody, BuildCFG(Code));
+}
 
-  class CFGCallback : public ast_matchers::MatchFinder::MatchCallback {
-  public:
-    bool SawFunctionBody = false;
-
-    void run(const ast_matchers::MatchFinder::MatchResult &Result) override {
-      const auto *Func = Result.Nodes.getNodeAs<FunctionDecl>("func");
-      Stmt *Body = Func->getBody();
-      if (!Body)
-        return;
-      SawFunctionBody = true;
-      std::unique_ptr<CFG> cfg =
-          CFG::buildCFG(nullptr, Body, Result.Context, CFG::BuildOptions());
-      EXPECT_EQ(nullptr, cfg);
-    }
-  } Callback;
-
-  ast_matchers::MatchFinder Finder;
-  Finder.addMatcher(ast_matchers::functionDecl().bind("func"), &Callback);
-  std::unique_ptr<tooling::FrontendActionFactory> Factory(
-      tooling::newFrontendActionFactory(&Finder));
-  std::vector<std::string> Args = {"-std=c++11", "-fno-delayed-template-parsing"};
-  ASSERT_TRUE(tooling::runToolOnCodeWithArgs(Factory->create(), Code, Args));
-  EXPECT_TRUE(Callback.SawFunctionBody);
+// Constructing a CFG containing a delete expression on a dependent type should
+// not crash.
+TEST(CFG, DeleteExpressionOnDependentType) {
+  const char *Code = "template<class T>\n"
+                     "void f(T t) {\n"
+                     "  delete t;\n"
+                     "}\n";
+  EXPECT_EQ(BuiltCFG, BuildCFG(Code));
 }
 
 } // namespace




More information about the cfe-commits mailing list