]> granicus.if.org Git - clang/commitdiff
Do a better job at computing dead symbols.
authorTed Kremenek <kremenek@apple.com>
Fri, 25 Apr 2008 01:25:15 +0000 (01:25 +0000)
committerTed Kremenek <kremenek@apple.com>
Fri, 25 Apr 2008 01:25:15 +0000 (01:25 +0000)
Implemented support for better localized leaks in the CF reference count checker.
Now leaks should be flagged close to where they occur.

This should implement the desired functionality in <rdar://problem/5879592>, although the diagnostics still need to be improved.

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

include/clang/Analysis/PathSensitive/GRTransferFuncs.h
lib/Analysis/BugReporter.cpp
lib/Analysis/CFRefCount.cpp
lib/Analysis/GRExprEngine.cpp
lib/Analysis/ValueState.cpp
test/Analysis-Apple/CFDate.m

index 769353039c02e908ea51460c076dd14724102638..3dd296941376986a1fe6de6c1b45640db73b9bbb 100644 (file)
@@ -93,7 +93,8 @@ public:
   virtual void EvalDeadSymbols(ExplodedNodeSet<ValueState>& Dst,
                                GRExprEngine& Engine,
                                GRStmtNodeBuilder<ValueState>& Builder,
-                               ProgramPoint P, ExplodedNode<ValueState>* Pred,
+                               ExplodedNode<ValueState>* Pred,
+                               Stmt* S,
                                ValueState* St,
                                const ValueStateManager::DeadSymbolsTy& Dead) {}
   
index d213d993f3fb37f5db5572110635bb9a307457a4..5a0e9cb90ab7ed22d64c119da83490241d6c38d2 100644 (file)
@@ -144,14 +144,16 @@ MakeReportGraph(ExplodedGraph<ValueState>* G, ExplodedNode<ValueState>* N) {
   
   llvm::OwningPtr<ExplodedGraph<ValueState> > GTrim(G->Trim(&N, &N+1));    
     
-  // Find the sink node in the trimmed graph.  
+  // Find the error node in the trimmed graph.  
   
-  N = NULL;
+  ExplodedNode<ValueState>* NOld = N;
+  N = 0;
   
   for (ExplodedGraph<ValueState>::node_iterator
        I = GTrim->nodes_begin(), E = GTrim->nodes_end(); I != E; ++I) {
     
-    if (I->isSink()) {
+    if (I->getState() == NOld->getState() &&
+        I->getLocation() == NOld->getLocation()) {
       N = &*I;
       break;
     }    
index a1380af497980ce29456e72bff2a465053f678d4..ad72d27a82f8e2dc44f2333f9adeefe1b170a39e 100644 (file)
@@ -687,10 +687,10 @@ public:
   virtual void EvalDeadSymbols(ExplodedNodeSet<ValueState>& Dst,
                                GRExprEngine& Engine,
                                GRStmtNodeBuilder<ValueState>& Builder,
-                               ProgramPoint P, ExplodedNode<ValueState>* Pred,
+                               ExplodedNode<ValueState>* Pred,
+                               Stmt* S,
                                ValueState* St,
                                const ValueStateManager::DeadSymbolsTy& Dead);
-  
   // Return statements.
   
   virtual void EvalReturn(ExplodedNodeSet<ValueState>& Dst,
@@ -1096,21 +1096,11 @@ void CFRefCount::EvalEndPath(GRExprEngine& Eng,
 void CFRefCount::EvalDeadSymbols(ExplodedNodeSet<ValueState>& Dst,
                                  GRExprEngine& Eng,
                                  GRStmtNodeBuilder<ValueState>& Builder,
-                                 ProgramPoint P, ExplodedNode<ValueState>* Pred,
+                                 ExplodedNode<ValueState>* Pred,
+                                 Stmt* S,
                                  ValueState* St,
                                  const ValueStateManager::DeadSymbolsTy& Dead) {
-  
-  // FIXME: Have GRStmtNodeBuilder handle the case where 'P' is not PostStmt;
-  //  This won't result in missed leaks; we'll just flag these ones at the
-  //  end-of-path.
-  
-  Stmt* S = NULL;
-  
-  if (!isa<PostStmt>(P))
-    return;
-  
-  S = cast<PostStmt>(P).getStmt();
-  
+    
   // FIXME: a lot of copy-and-paste from EvalEndPath.  Refactor.
   
   RefBindings B = GetRefBindings(*St);
index 0438059f6c21108cae846808024c8217914fabd5..287c6e982aa1654efa82b6d8bd155cd1e1ba6e7d 100644 (file)
@@ -199,8 +199,8 @@ void GRExprEngine::ProcessStmt(Stmt* S, StmtNodeBuilder& builder) {
     SaveAndRestore<bool> OldSink(Builder->BuildSinks);
     SaveOr OldHasGen(Builder->HasGeneratedNode);
 
-    TF->EvalDeadSymbols(Tmp, *this, *Builder, EntryNode->getLocation(),
-                        EntryNode, CleanedState, DeadSymbols);
+    TF->EvalDeadSymbols(Tmp, *this, *Builder, EntryNode, S, 
+                        CleanedState, DeadSymbols);
 
     if (!Builder->BuildSinks && !Builder->HasGeneratedNode)
       Tmp.Add(EntryNode);
index ed6a86075b136913d7499032a286ce01f465b84a..94c62281aa3a807f68c3a4ca3f2610ad35e72fb1 100644 (file)
@@ -129,14 +129,22 @@ ValueStateManager::RemoveDeadBindings(ValueState* St, Stmt* Loc,
   }
   
   // Remove dead variable bindings.
+  
+  DeadSymbols.clear();
+  
   for (ValueState::vb_iterator I = St->vb_begin(), E = St->vb_end(); I!=E ; ++I)
-    if (!Marked.count(I.getKey()))
+    if (!Marked.count(I.getKey())) {
       NewSt.VarBindings = Remove(NewSt, I.getKey());
+      
+      RVal X = I.getData();
+      
+      for (RVal::symbol_iterator SI = X.symbol_begin(), SE = X.symbol_end(); 
+           SI != SE; ++SI)
+        if (!MarkedSymbols.count(*SI)) DeadSymbols.insert(*SI);
+    }      
   
   // Remove dead symbols.
-  
-  DeadSymbols.clear();
-  
+
   for (ValueState::ce_iterator I = St->ce_begin(), E=St->ce_end(); I!=E; ++I) {
 
     SymbolID sym = I.getKey();    
index 58267403970cca9daaf4fb15198e3cc5da108c0e..09db82a161bdd8e4fd12207de5d5a194be01bb5b 100644 (file)
@@ -84,3 +84,11 @@ CFDateRef f6(int x) {
   return date; // expected-warning{{leak}}
 }
 
+// Test a leak involving an overwrite.
+
+CFDateRef f7() {
+  CFDateRef date = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent());
+  CFRetain(date);
+  date = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent()); //expected-warning{{leak}}
+  return date;
+}