]> granicus.if.org Git - clang/commitdiff
[analyzer] Always include destructors in the analysis CFG.
authorJordan Rose <jordan_rose@apple.com>
Wed, 5 Sep 2012 22:55:23 +0000 (22:55 +0000)
committerJordan Rose <jordan_rose@apple.com>
Wed, 5 Sep 2012 22:55:23 +0000 (22:55 +0000)
While destructors will continue to not be inlined (unless the analyzer
config option 'c++-inlining' is set to 'destructors'), leaving them out
of the CFG is an incomplete model of the behavior of an object, and
can cause false positive warnings (like PR13751, now working).

Destructors for temporaries are still not on by default, since
(a) we haven't actually checked this code to be sure it's fully correct
    (in particular, we probably need to be very careful with regard to
    lifetime-extension when a temporary is bound to a reference,
    C++11 [class.temporary]p5), and
(b) ExprEngine doesn't actually do anything when it sees a temporary
    destructor in the CFG -- not even invalidate the object region.

To enable temporary destructors, set the 'cfg-temporary-dtors' analyzer
config option to '1'. The old -cfg-add-implicit-dtors cc1 option, which
controlled all implicit destructors, has been removed.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@163264 91177308-0d34-0410-b5e6-96231b3b80d8

14 files changed:
include/clang/Analysis/AnalysisContext.h
include/clang/Analysis/CFG.h
include/clang/Driver/CC1Options.td
include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
lib/Analysis/AnalysisDeclContext.cpp
lib/Analysis/CFG.cpp
lib/Frontend/CompilerInvocation.cpp
lib/StaticAnalyzer/Core/AnalysisManager.cpp
lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
test/Analysis/auto-obj-dtors-cfg-output.cpp
test/Analysis/dtor.cpp
test/Analysis/dtors-in-dtor-cfg-output.cpp
test/Analysis/malloc.cpp
test/Analysis/temp-obj-dtors-cfg-output.cpp

index 46b4e93bb7d4e596b448648f3669b4895818ef80..41b57b3104bbb059784965736f7c5d09b1e1071f 100644 (file)
@@ -382,8 +382,9 @@ class AnalysisDeclContextManager {
 
 public:
   AnalysisDeclContextManager(bool useUnoptimizedCFG = false,
-                         bool addImplicitDtors = false,
-                         bool addInitializers = false);
+                             bool addImplicitDtors = false,
+                             bool addInitializers = false,
+                             bool addTemporaryDtors = false);
 
   ~AnalysisDeclContextManager();
 
index 4d087e74983032f7b90fbac32219a6546121f278..30a1db2f62227678ea753c35bcf9323d69ce15dd 100644 (file)
@@ -568,6 +568,7 @@ public:
     bool AddEHEdges;
     bool AddInitializers;
     bool AddImplicitDtors;
+    bool AddTemporaryDtors;
 
     bool alwaysAdd(const Stmt *stmt) const {
       return alwaysAddMask[stmt->getStmtClass()];
@@ -587,7 +588,8 @@ public:
     : forcedBlkExprs(0), PruneTriviallyFalseEdges(true)
       ,AddEHEdges(false)
       ,AddInitializers(false)
-      ,AddImplicitDtors(false) {}
+      ,AddImplicitDtors(false)
+      ,AddTemporaryDtors(false) {}
   };
 
   /// \brief Provides a custom implementation of the iterator class to have the
index 8089a0a7327fd936f199bb613a777356cd9ab39a..d65bf209915148352f44e40be88ec4a5169841be 100644 (file)
@@ -37,8 +37,6 @@ def triple_EQ : Joined<"-triple=">, Alias<triple>;
 
 def analysis_UnoptimizedCFG : Flag<"-unoptimized-cfg">,
   HelpText<"Generate unoptimized CFGs for all analyses">;
-def analysis_CFGAddImplicitDtors : Flag<"-cfg-add-implicit-dtors">,
-  HelpText<"Add C++ implicit destructors to CFGs for all analyses">;
 
 def analyzer_store : Separate<"-analyzer-store">,
   HelpText<"Source Code Analysis - Abstract Memory Store Models">;
index 1ed5658876ef9d9d2040d0cd07b0e79ffaee2d2d..5dba158f1238003356d939663975e25bf270d53e 100644 (file)
@@ -147,7 +147,6 @@ public:
   unsigned visualizeExplodedGraphWithGraphViz : 1;
   unsigned visualizeExplodedGraphWithUbiGraph : 1;
   unsigned UnoptimizedCFG : 1;
-  unsigned CFGAddImplicitDtors : 1;
   unsigned eagerlyTrimExplodedGraph : 1;
   unsigned PrintStats : 1;
   
@@ -172,9 +171,18 @@ public:
   /// Returns the option controlling which C++ member functions will be
   /// considered for inlining.
   ///
+  /// This is controlled by the 'c++-inlining' config option.
+  ///
   /// \sa CXXMemberInliningMode
   bool mayInlineCXXMemberFunction(CXXInlineableMemberKind K) const;
 
+  /// Returns whether or not the destructors for C++ temporary objects should
+  /// be included in the CFG.
+  ///
+  /// This is controlled by the 'cfg-temporary-dtors' config option. Any
+  /// non-empty value is considered to be 'true'.
+  bool includeTemporaryDtorsInCFG() const;
+
 public:
   AnalyzerOptions() : CXXMemberInliningMode() {
     AnalysisStoreOpt = RegionStoreModel;
@@ -191,7 +199,6 @@ public:
     visualizeExplodedGraphWithGraphViz = 0;
     visualizeExplodedGraphWithUbiGraph = 0;
     UnoptimizedCFG = 0;
-    CFGAddImplicitDtors = 0;
     eagerlyTrimExplodedGraph = 0;
     PrintStats = 0;
     NoRetryExhausted = 0;
index 7de7f395e8a7f9900fd448925e4067f72b96e70c..f2ef0defd772b8263b53329153bf4399cc1ecd5e 100644 (file)
@@ -62,11 +62,13 @@ AnalysisDeclContext::AnalysisDeclContext(AnalysisDeclContextManager *Mgr,
 }
 
 AnalysisDeclContextManager::AnalysisDeclContextManager(bool useUnoptimizedCFG,
-                                               bool addImplicitDtors,
-                                               bool addInitializers) {
+                                                       bool addImplicitDtors,
+                                                       bool addInitializers,
+                                                       bool addTemporaryDtors) {
   cfgBuildOptions.PruneTriviallyFalseEdges = !useUnoptimizedCFG;
   cfgBuildOptions.AddImplicitDtors = addImplicitDtors;
   cfgBuildOptions.AddInitializers = addInitializers;
+  cfgBuildOptions.AddTemporaryDtors = addTemporaryDtors;
 }
 
 void AnalysisDeclContextManager::clear() {
index f811fa3f0f86fd75aece5d72f93d9ad527101034..a179b6dffe2de1ad4df0702dfdae894d2fda54fe 100644 (file)
@@ -706,7 +706,7 @@ CFGBlock *CFGBuilder::addInitializer(CXXCtorInitializer *I) {
       IsReference = FD->getType()->isReferenceType();
     HasTemporaries = isa<ExprWithCleanups>(Init);
 
-    if (BuildOpts.AddImplicitDtors && HasTemporaries) {
+    if (BuildOpts.AddTemporaryDtors && HasTemporaries) {
       // Generate destructors for temporaries in initialization expression.
       VisitForTemporaryDtors(cast<ExprWithCleanups>(Init)->getSubExpr(),
           IsReference);
@@ -1617,7 +1617,7 @@ CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt *DS) {
     IsReference = VD->getType()->isReferenceType();
     HasTemporaries = isa<ExprWithCleanups>(Init);
 
-    if (BuildOpts.AddImplicitDtors && HasTemporaries) {
+    if (BuildOpts.AddTemporaryDtors && HasTemporaries) {
       // Generate destructors for temporaries in initialization expression.
       VisitForTemporaryDtors(cast<ExprWithCleanups>(Init)->getSubExpr(),
           IsReference);
@@ -2972,7 +2972,7 @@ CFGBlock *CFGBuilder::VisitCXXForRangeStmt(CXXForRangeStmt *S) {
 
 CFGBlock *CFGBuilder::VisitExprWithCleanups(ExprWithCleanups *E,
     AddStmtChoice asc) {
-  if (BuildOpts.AddImplicitDtors) {
+  if (BuildOpts.AddTemporaryDtors) {
     // If adding implicit destructors visit the full expression for adding
     // destructors of temporaries.
     VisitForTemporaryDtors(E->getSubExpr());
@@ -3052,6 +3052,8 @@ CFGBlock *CFGBuilder::VisitIndirectGotoStmt(IndirectGotoStmt *I) {
 }
 
 CFGBlock *CFGBuilder::VisitForTemporaryDtors(Stmt *E, bool BindToTemporary) {
+  assert(BuildOpts.AddImplicitDtors && BuildOpts.AddTemporaryDtors);
+
 tryAgain:
   if (!E) {
     badCFG = true;
index bf1a80c94c7d7ff01973a20d95306259d82f762d..6d6dbfcc2865bf6cd2a59466e2bdd1096e48be64 100644 (file)
@@ -1130,7 +1130,6 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
   Opts.eagerlyAssumeBinOpBifurcation = Args.hasArg(OPT_analyzer_eagerly_assume);
   Opts.AnalyzeSpecificFunction = Args.getLastArgValue(OPT_analyze_function);
   Opts.UnoptimizedCFG = Args.hasArg(OPT_analysis_UnoptimizedCFG);
-  Opts.CFGAddImplicitDtors = Args.hasArg(OPT_analysis_CFGAddImplicitDtors);
   Opts.TrimGraph = Args.hasArg(OPT_trim_egraph);
   Opts.MaxNodes = Args.getLastArgIntValue(OPT_analyzer_max_nodes, 150000,Diags);
   Opts.maxBlockVisitOnPath = Args.getLastArgIntValue(OPT_analyzer_max_loop, 4, Diags);
index 6a01edf7ce11d2835d8e707d9acc98a51820ab8d..ebd2336080a5edba02634a57a985cba2e0bb49dc 100644 (file)
@@ -22,8 +22,9 @@ AnalysisManager::AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags,
                                  CheckerManager *checkerMgr,
                                  const AnalyzerOptions &Options)
   : AnaCtxMgr(Options.UnoptimizedCFG,
-              Options.CFGAddImplicitDtors,
-              /*addInitializers=*/true),
+              /*AddImplicitDtors=*/true,
+              /*AddInitializers=*/true,
+              Options.includeTemporaryDtorsInCFG()),
     Ctx(ctx),
     Diags(diags),
     LangOpts(lang),
index 5574a2f226907ba8d54d8db1dafc252001fadd9a..9e45a115283a9a65781bda6e64a6e3d99f5ca41d 100644 (file)
@@ -46,3 +46,7 @@ AnalyzerOptions::mayInlineCXXMemberFunction(CXXInlineableMemberKind K) const {
 
   return CXXMemberInliningMode >= K;
 }
+
+bool AnalyzerOptions::includeTemporaryDtorsInCFG() const {
+  return !Config.lookup("cfg-temporary-dtors").empty();
+}
index 566e6caed60d49592832095a83952d112031c4c2..e4b49dc10f1bfc50ed7260ba008ed9df6aa95958 100644 (file)
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -analyze -analyzer-checker=debug.DumpCFG -cfg-add-implicit-dtors %s > %t 2>&1
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -analyze -analyzer-checker=debug.DumpCFG %s > %t 2>&1
 // RUN: FileCheck --input-file=%t %s
 // XPASS: *
 
index a5d3d3f015f0844f945984e000934653fd19aad4..a762ebed122363dcc3eaaa6f8b3b9d5e218006f9 100644 (file)
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-ipa=inlining  -analyzer-config c++-inlining=destructors -cfg-add-implicit-dtors -Wno-null-dereference -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-ipa=inlining  -analyzer-config c++-inlining=destructors -Wno-null-dereference -verify %s
 
 void clang_analyzer_eval(bool);
 void clang_analyzer_checkInlined(bool);
index 68ba37ebf3990ef7a0a4572e4192bb9124a85459..f0546fc8bffac5280c5cc152412ccc4e4c7d3ae6 100644 (file)
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=debug.DumpCFG -cfg-add-implicit-dtors %s 2>&1 | FileCheck %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=debug.DumpCFG %s 2>&1 | FileCheck %s
 // XPASS: *
 
 class A {
index 864477b587bccfa2358edcf45d230beead1a0d7f..220d74625bc0b388f00188e59bc0861f8c989e0c 100644 (file)
@@ -6,6 +6,11 @@ void free(void *);
 void *realloc(void *ptr, size_t size);
 void *calloc(size_t nmemb, size_t size);
 
+
+void checkThatMallocCheckerIsRunning() {
+  malloc(4); // expected-warning{{leak}}
+}
+
 // Test for radar://11110132.
 struct Foo {
     mutable void* m_data;
@@ -35,3 +40,23 @@ void r11160612_3(CanFreeMemory* p) {
   const_ptr_and_callback_def_param(0, x, 12, p->myFree);
 }
 
+
+namespace PR13751 {
+  class OwningVector {
+    void **storage;
+    size_t length;
+  public:
+    OwningVector();
+    ~OwningVector();
+    void push_back(void *Item) {
+      storage[length++] = Item;
+    }
+  };
+
+  void testDestructors() {
+    OwningVector v;
+    v.push_back(malloc(4));
+    // no leak warning; freed in destructor
+  }
+}
+
index 6dbbc821bbbb2ed3714d5806b42b7144c26c9a2b..d13083ddf011b9232a0d9b9339549c911c735eb5 100644 (file)
@@ -1,5 +1,5 @@
 // RUN: rm -f %t
-// RUN: %clang_cc1 -analyze -analyzer-checker=debug.DumpCFG -cfg-add-implicit-dtors %s > %t 2>&1
+// RUN: %clang_cc1 -analyze -analyzer-checker=debug.DumpCFG -analyzer-config cfg-temporary-dtors=1 %s > %t 2>&1
 // RUN: FileCheck --input-file=%t %s
 // XPASS: *