[cfe-commits] r50661 - /cfe/trunk/lib/Analysis/CFRefCount.cpp

Ted Kremenek kremenek at apple.com
Mon May 5 11:50:19 PDT 2008


Author: kremenek
Date: Mon May  5 13:50:19 2008
New Revision: 50661

URL: http://llvm.org/viewvc/llvm-project?rev=50661&view=rev
Log:
Improve leak diagnostics to not report a leak on the same line where 
the object was last used.  This can be confusing to users.

For example:

 // 'y' is leaked
x = foo(y);

instead:

x = foo(y);
  // 'y' is leaked

Modified:
    cfe/trunk/lib/Analysis/CFRefCount.cpp

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

==============================================================================
--- cfe/trunk/lib/Analysis/CFRefCount.cpp (original)
+++ cfe/trunk/lib/Analysis/CFRefCount.cpp Mon May  5 13:50:19 2008
@@ -1707,10 +1707,10 @@
 }
 
 PathDiagnosticPiece* CFRefReport::getEndPath(BugReporter& BR,
-                                             ExplodedNode<ValueState>* N) {
+                                             ExplodedNode<ValueState>* EndN) {
   
   if (!getBugType().isLeak())
-    return RangedBugReport::getEndPath(BR, N);
+    return RangedBugReport::getEndPath(BR, EndN);
 
   typedef CFRefCount::RefBindings RefBindings;
 
@@ -1718,7 +1718,7 @@
   unsigned long RetCount = 0;
   
   {
-    ValueState* St = N->getState();
+    ValueState* St = EndN->getState();
     RefBindings B = RefBindings((RefBindings::TreeTy*) St->CheckerState);
     RefBindings::TreeTy* T = B.SlimFind(Sym);
     assert (T);
@@ -1728,13 +1728,14 @@
   // We are a leak.  Walk up the graph to get to the first node where the
   // symbol appeared.
   
+  ExplodedNode<ValueState>* N = EndN;
   ExplodedNode<ValueState>* Last = N;
-    
+  
   // Find the first node that referred to the tracked symbol.  We also
   // try and find the first VarDecl the value was stored to.
   
   VarDecl* FirstDecl = 0;
-  
+
   while (N) {
     ValueState* St = N->getState();
     RefBindings B = RefBindings((RefBindings::TreeTy*) St->CheckerState);
@@ -1765,17 +1766,85 @@
     N = N->pred_empty() ? NULL : *(N->pred_begin());    
   }
   
-  // Get the location.
+  // Get the allocate site.
   
   assert (Last);
   Stmt* FirstStmt = cast<PostStmt>(Last->getLocation()).getStmt();
 
-  unsigned Line =
-   BR.getSourceManager().getLogicalLineNumber(FirstStmt->getLocStart());
+  SourceManager& SMgr = BR.getContext().getSourceManager();
+  unsigned AllocLine = SMgr.getLogicalLineNumber(FirstStmt->getLocStart());
+
+  // Get the leak site.  We may have multiple ExplodedNodes (one with the
+  // leak) that occur on the same line number; if the node with the leak
+  // has any immediate predecessor nodes with the same line number, find
+  // any transitive-successors that have a different statement and use that
+  // line number instead.  This avoids emiting a diagnostic like:
+  //
+  //    // 'y' is leaked.
+  //  int x = foo(y);
+  //
+  //  instead we want:
+  //
+  //  int x = foo(y);
+  //   // 'y' is leaked.
+  
+  Stmt* S = getStmt(BR);  // This is the statement where the leak occured.
+  assert (S);
+  unsigned EndLine = SMgr.getLogicalLineNumber(S->getLocStart());
+
+  // Look in the *trimmed* graph at the immediate predecessor of EndN.  Does
+  // it occur on the same line?
+  
+  assert (!EndN->pred_empty()); // Not possible to have 0 predecessors.
+  N = *(EndN->pred_begin());
+  
+  do {
+    ProgramPoint P = N->getLocation();
 
+    if (!isa<PostStmt>(P))
+      break;
+    
+    // Predecessor at same line?
+    
+    Stmt* SPred = cast<PostStmt>(P).getStmt();
+    
+    if (SMgr.getLogicalLineNumber(SPred->getLocStart()) != EndLine)
+      break;
+    
+    // The predecessor (where the object was not yet leaked) is a statement
+    // on the same line.  Get the first successor statement that appears
+    // on a different line.  For this operation, we can traverse the
+    // non-trimmed graph.
+    
+    N = getEndNode(); // This is the node where the leak occured in the
+                      // original graph.
+        
+    while (!N->succ_empty()) {
+      
+      N = *(N->succ_begin());
+      ProgramPoint P = N->getLocation();
+      
+      if (!isa<PostStmt>(P))
+        continue;
+      
+      Stmt* SSucc = cast<PostStmt>(P).getStmt();
+      
+      if (SMgr.getLogicalLineNumber(SSucc->getLocStart()) != EndLine) {
+        S = SSucc;
+        break;
+      }
+    }    
+  }
+  while (false);
+  
+  // Construct the location.
+    
+  FullSourceLoc L(S->getLocStart(), SMgr);
+  
+  // Generate the diagnostic.
   std::ostringstream os;
   
-  os << "Object allocated on line " << Line;
+  os << "Object allocated on line " << AllocLine;
   
   if (FirstDecl)
     os << " and stored into '" << FirstDecl->getName() << '\'';
@@ -1783,12 +1852,7 @@
   os << " is no longer referenced after this point and has a retain count of +"
      << RetCount << " (object leaked).";
   
-  Stmt* S = getStmt(BR);
-  assert (S);  
-  FullSourceLoc L(S->getLocStart(), BR.getContext().getSourceManager());    
-  PathDiagnosticPiece* P = new PathDiagnosticPiece(L, os.str());
-    
-  return P;  
+  return new PathDiagnosticPiece(L, os.str());
 }
 
 void UseAfterRelease::EmitWarnings(BugReporter& BR) {





More information about the cfe-commits mailing list