[cfe-commits] r81803 - in /cfe/trunk: include/clang/Analysis/PathSensitive/BugReporter.h lib/Analysis/BugReporter.cpp lib/Analysis/CFRefCount.cpp

Ted Kremenek kremenek at apple.com
Mon Sep 14 15:01:32 PDT 2009


Author: kremenek
Date: Mon Sep 14 17:01:32 2009
New Revision: 81803

URL: http://llvm.org/viewvc/llvm-project?rev=81803&view=rev
Log:
Fix: <rdar://problem/5905851> do not report a leak when post-dominated by a call
                              to a noreturn or panic function

Modified:
    cfe/trunk/include/clang/Analysis/PathSensitive/BugReporter.h
    cfe/trunk/lib/Analysis/BugReporter.cpp
    cfe/trunk/lib/Analysis/CFRefCount.cpp

Modified: cfe/trunk/include/clang/Analysis/PathSensitive/BugReporter.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/PathSensitive/BugReporter.h?rev=81803&r1=81802&r2=81803&view=diff

==============================================================================
--- cfe/trunk/include/clang/Analysis/PathSensitive/BugReporter.h (original)
+++ cfe/trunk/include/clang/Analysis/PathSensitive/BugReporter.h Mon Sep 14 17:01:32 2009
@@ -189,13 +189,21 @@
   const std::string Category;
   llvm::FoldingSet<BugReportEquivClass> EQClasses;
   friend class BugReporter;
+  bool SuppressonSink;
 public:
-  BugType(const char *name, const char* cat) : Name(name), Category(cat) {}
+  BugType(const char *name, const char* cat)
+    : Name(name), Category(cat), SuppressonSink(false) {}
   virtual ~BugType();
 
   // FIXME: Should these be made strings as well?
   const std::string& getName() const { return Name; }
   const std::string& getCategory() const { return Category; }
+  
+  /// isSuppressOnSink - Returns true if bug reports associated with this bug
+  ///  type should be suppressed if the end node of the report is post-dominated
+  ///  by a sink node.
+  bool isSuppressOnSink() const { return SuppressonSink; }
+  void setSuppressOnSink(bool x) { SuppressonSink = x; }
 
   virtual void FlushReports(BugReporter& BR);
 

Modified: cfe/trunk/lib/Analysis/BugReporter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/BugReporter.cpp?rev=81803&r1=81802&r2=81803&view=diff

==============================================================================
--- cfe/trunk/lib/Analysis/BugReporter.cpp (original)
+++ cfe/trunk/lib/Analysis/BugReporter.cpp Mon Sep 14 17:01:32 2009
@@ -1639,34 +1639,131 @@
     EQ->AddReport(R);
 }
 
+
+//===----------------------------------------------------------------------===//
+// Emitting reports in equivalence classes.
+//===----------------------------------------------------------------------===//
+
+namespace {
+struct VISIBILITY_HIDDEN FRIEC_WLItem {
+  const ExplodedNode *N;
+  ExplodedNode::const_succ_iterator I, E;
+  
+  FRIEC_WLItem(const ExplodedNode *n)
+  : N(n), I(N->succ_begin()), E(N->succ_end()) {}
+};  
+}
+
+static BugReport *FindReportInEquivalenceClass(BugReportEquivClass& EQ) {
+  BugReportEquivClass::iterator I = EQ.begin(), E = EQ.end();
+  assert(I != E);
+  BugReport *R = *I;
+  BugType& BT = R->getBugType();
+  
+  if (!BT.isSuppressOnSink())
+    return R;
+  
+  // For bug reports that should be suppressed when all paths are post-dominated
+  // by a sink node, iterate through the reports in the equivalence class
+  // until we find one that isn't post-dominated (if one exists).  We use a
+  // DFS traversal of the ExplodedGraph to find a non-sink node.  We could write
+  // this as a recursive function, but we don't want to risk blowing out the
+  // stack for very long paths.
+  for (; I != E; ++I) {
+    R = *I;
+    const ExplodedNode *N = R->getEndNode();
+
+    if (!N)
+      continue;
+
+    if (N->isSink()) {
+      assert(false &&
+           "BugType::isSuppressSink() should not be 'true' for sink end nodes");
+      return R;
+    }
+    
+    if (N->succ_empty())
+      return R;
+    
+    // At this point we know that 'N' is not a sink and it has at least one
+    // successor.  Use a DFS worklist to find a non-sink end-of-path node.    
+    typedef FRIEC_WLItem WLItem;
+    typedef llvm::SmallVector<WLItem, 10> DFSWorkList;
+    llvm::DenseMap<const ExplodedNode *, unsigned> Visited;
+    
+    DFSWorkList WL;
+    WL.push_back(N);
+    Visited[N] = 1;
+    
+    while (!WL.empty()) {
+      WLItem &WI = WL.back();
+      assert(!WI.N->succ_empty());
+            
+      for (; WI.I != WI.E; ++WI.I) {
+        const ExplodedNode *Succ = *WI.I;        
+        // End-of-path node?
+        if (Succ->succ_empty()) {
+          // If we found an end-of-path node that is not a sink, then return
+          // this report.
+          if (!Succ->isSink())
+            return R;
+         
+          // Found a sink?  Continue on to the next successor.
+          continue;
+        }
+        
+        // Mark the successor as visited.  If it hasn't been explored,
+        // enqueue it to the DFS worklist.
+        unsigned &mark = Visited[Succ];
+        if (!mark) {
+          mark = 1;
+          WL.push_back(Succ);
+          break;
+        }
+      }
+      
+      if (&WL.back() == &WI)
+        WL.pop_back();
+    }
+  }
+  
+  // If we reach here, the end nodes for all reports in the equiavalence
+  // class are post-dominated by a sink node.
+  return NULL;
+}
+
 void BugReporter::FlushReport(BugReportEquivClass& EQ) {
-  assert(!EQ.Reports.empty());
-  BugReport &R = **EQ.begin();
+  BugReport *R = FindReportInEquivalenceClass(EQ);
+
+  if (!R)
+    return;
+  
   PathDiagnosticClient* PD = getPathDiagnosticClient();
 
   // FIXME: Make sure we use the 'R' for the path that was actually used.
   // Probably doesn't make a difference in practice.
-  BugType& BT = R.getBugType();
+  BugType& BT = R->getBugType();
 
   llvm::OwningPtr<PathDiagnostic>
-    D(new PathDiagnostic(R.getBugType().getName(),
+    D(new PathDiagnostic(R->getBugType().getName(),
                          !PD || PD->useVerboseDescription()
-                         ? R.getDescription() : R.getShortDescription(),
+                         ? R->getDescription() : R->getShortDescription(),
                          BT.getCategory()));
 
   GeneratePathDiagnostic(*D.get(), EQ);
 
   // Get the meta data.
-  std::pair<const char**, const char**> Meta = R.getExtraDescriptiveText();
-  for (const char** s = Meta.first; s != Meta.second; ++s) D->addMeta(*s);
+  std::pair<const char**, const char**> Meta = R->getExtraDescriptiveText();
+  for (const char** s = Meta.first; s != Meta.second; ++s)
+    D->addMeta(*s);
 
   // Emit a summary diagnostic to the regular Diagnostics engine.
   const SourceRange *Beg = 0, *End = 0;
-  R.getRanges(Beg, End);
+  R->getRanges(Beg, End);
   Diagnostic& Diag = getDiagnostic();
-  FullSourceLoc L(R.getLocation(), getSourceManager());
+  FullSourceLoc L(R->getLocation(), getSourceManager());
   unsigned ErrorDiag = Diag.getCustomDiagID(Diagnostic::Warning,
-                                            R.getShortDescription().c_str());
+                                            R->getShortDescription().c_str());
 
   switch (End-Beg) {
     default: assert(0 && "Don't handle this many ranges yet!");
@@ -1682,7 +1779,7 @@
 
   if (D->empty()) {
     PathDiagnosticPiece* piece =
-      new PathDiagnosticEventPiece(L, R.getDescription());
+      new PathDiagnosticEventPiece(L, R->getDescription());
 
     for ( ; Beg != End; ++Beg) piece->addRange(*Beg);
     D->push_back(piece);

Modified: cfe/trunk/lib/Analysis/CFRefCount.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFRefCount.cpp?rev=81803&r1=81802&r2=81803&view=diff

==============================================================================
--- cfe/trunk/lib/Analysis/CFRefCount.cpp (original)
+++ cfe/trunk/lib/Analysis/CFRefCount.cpp Mon Sep 14 17:01:32 2009
@@ -2216,7 +2216,9 @@
     name = "Leak of returned object";
   }
 
+  // Leaks should not be reported if they are post-dominated by a sink.
   leakAtReturn = new LeakAtReturn(this, name);
+  leakAtReturn->setSuppressOnSink(true);
   BR.Register(leakAtReturn);
 
   // Second, register leaks within a function/method.
@@ -2230,7 +2232,9 @@
     name = "Leak";
   }
 
+  // Leaks should not be reported if they are post-dominated by sinks.
   leakWithinFunction = new LeakWithinFunction(this, name);
+  leakWithinFunction->setSuppressOnSink(true);
   BR.Register(leakWithinFunction);
 
   // Save the reference to the BugReporter.





More information about the cfe-commits mailing list