]> granicus.if.org Git - clang/commitdiff
CFGBuilder: Fix crash when visiting delete expression on dependent type
authorMartin Bohme <mboehme@google.com>
Mon, 5 Dec 2016 11:33:19 +0000 (11:33 +0000)
committerMartin Bohme <mboehme@google.com>
Mon, 5 Dec 2016 11:33:19 +0000 (11:33 +0000)
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

lib/Analysis/CFG.cpp
unittests/Analysis/CFGTest.cpp

index ddf0e988fd30d84641d752fdcdacea758b656b54..a4470c13c057e04473d1a152a2be6cd6c8f363ce 100644 (file)
@@ -3581,11 +3581,13 @@ CFGBlock *CFGBuilder::VisitCXXDeleteExpr(CXXDeleteExpr *DE,
   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);
index a8d397e9a534be38692682a07c12e4fe058b0cc2..e691110050a22dbefdbb1ff2ef299459e1f44cb1 100644 (file)
@@ -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