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

Ted Kremenek kremenek at apple.com
Fri May 8 16:09:42 PDT 2009


Author: kremenek
Date: Fri May  8 18:09:42 2009
New Revision: 71283

URL: http://llvm.org/viewvc/llvm-project?rev=71283&view=rev
Log:
retain/release checker: Refactor error-reporting code in EvalDeadSymbols and
EvalEndPath. This sets the stage for handling autorelease counts.

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=71283&r1=71282&r2=71283&view=diff

==============================================================================
--- cfe/trunk/lib/Analysis/CFRefCount.cpp (original)
+++ cfe/trunk/lib/Analysis/CFRefCount.cpp Fri May  8 18:09:42 2009
@@ -159,6 +159,31 @@
          : ID->lookupClassMethod(Context, MD->getSelector());
 }
 
+namespace {
+class VISIBILITY_HIDDEN GenericNodeBuilder {
+  GRStmtNodeBuilder<GRState> *SNB;
+  Stmt *S;
+  const void *tag;
+  GREndPathNodeBuilder<GRState> *ENB;
+public:
+  GenericNodeBuilder(GRStmtNodeBuilder<GRState> &snb, Stmt *s,
+                     const void *t)
+  : SNB(&snb), S(s), tag(t), ENB(0) {}
+  GenericNodeBuilder(GREndPathNodeBuilder<GRState> &enb)
+  : SNB(0), S(0), tag(0), ENB(&enb) {}
+  
+  ExplodedNode<GRState> *MakeNode(const GRState *state,
+                                  ExplodedNode<GRState> *Pred) {
+    if (SNB)
+      return SNB->generateNode(PostStmt(S, tag), state,
+                               Pred);
+    
+    assert(ENB);
+    return ENB->MakeNode(state, Pred);
+  }
+};
+} // end anonymous namespace
+
 //===----------------------------------------------------------------------===//
 // Selector creation functions.
 //===----------------------------------------------------------------------===//
@@ -1539,7 +1564,6 @@
   
 typedef llvm::ImmutableMap<SymbolRef, RefVal> RefBindings;
 static int RefBIndex = 0;
-static std::pair<const void*, const void*> LeakProgramPointTag(&RefBIndex, 0);
 
 namespace clang {
   template<>
@@ -1634,9 +1658,14 @@
                            const GRState* St,
                            RefVal::Kind hasErr, SymbolRef Sym);
   
-  std::pair<GRStateRef, bool>
-  HandleSymbolDeath(GRStateManager& VMgr, const GRState* St,
-                    const Decl* CD, SymbolRef sid, RefVal V, bool& hasLeak);
+  GRStateRef HandleSymbolDeath(GRStateRef state, SymbolRef sid, RefVal V,
+                               llvm::SmallVectorImpl<SymbolRef> &Leaked);
+    
+  ExplodedNode<GRState>* ProcessLeaks(GRStateRef state,
+                                      llvm::SmallVectorImpl<SymbolRef> &Leaked,
+                                      GenericNodeBuilder &Builder,
+                                      GRExprEngine &Eng,
+                                      ExplodedNode<GRState> *Pred = 0);
   
 public:  
   CFRefCount(ASTContext& Ctx, bool gcenabled, const LangOptions& lopts)
@@ -2854,30 +2883,6 @@
   B.MakeNode(state.scanReachableSymbols<StopTrackingCallback>(val).getState());
 }
 
-std::pair<GRStateRef,bool>
-CFRefCount::HandleSymbolDeath(GRStateManager& VMgr,
-                              const GRState* St, const Decl* CD,
-                              SymbolRef sid,
-                              RefVal V, bool& hasLeak) {
-
-  // Any remaining leaks?
-  hasLeak = V.isOwned() || 
-            ((V.isNotOwned() || V.isReturnedOwned()) && V.getCount() > 0);
-
-  GRStateRef state(St, VMgr);
-  
-  if (!hasLeak)
-    return std::make_pair(state.remove<RefBindings>(sid), false);
-  
-  return std::make_pair(state.set<RefBindings>(sid, V ^ RefVal::ErrorLeak),
-                        false);
-}
-
-
-
-// Dead symbols.
-
-
 
  // Return statements.
 
@@ -2932,7 +2937,7 @@
   // Did we cache out?
   if (!Pred)
     return;
-  
+    
   // Any leaks or other errors?
   if (X.isReturnedOwned() && X.getCount() == 0) {
     const Decl *CD = &Eng.getStateManager().getCodeDecl();
@@ -2953,6 +2958,8 @@
       }
     }
   }
+  
+
 }
 
 // Assumptions.
@@ -3125,43 +3132,60 @@
 // Handle dead symbols and end-of-path.
 //===----------------------------------------------------------------------===//
 
-void CFRefCount::EvalEndPath(GRExprEngine& Eng,
-                             GREndPathNodeBuilder<GRState>& Builder) {
+
+GRStateRef
+CFRefCount::HandleSymbolDeath(GRStateRef state, SymbolRef sid, RefVal V,
+                              llvm::SmallVectorImpl<SymbolRef> &Leaked) {
   
-  const GRState* St = Builder.getState();
-  RefBindings B = St->get<RefBindings>();
+  bool hasLeak = V.isOwned() || 
+  ((V.isNotOwned() || V.isReturnedOwned()) && V.getCount() > 0);
   
-  llvm::SmallVector<std::pair<SymbolRef, bool>, 10> Leaked;
-  const Decl* CodeDecl = &Eng.getGraph().getCodeDecl();
+  if (!hasLeak)
+    return state.remove<RefBindings>(sid);
   
-  for (RefBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) {
-    bool hasLeak = false;
-    
-    std::pair<GRStateRef, bool> X =
-      HandleSymbolDeath(Eng.getStateManager(), St, CodeDecl,
-                        (*I).first, (*I).second, hasLeak);
-    
-    St = X.first;
-    if (hasLeak) Leaked.push_back(std::make_pair((*I).first, X.second));
-  }
+  Leaked.push_back(sid);
+  return state.set<RefBindings>(sid, V ^ RefVal::ErrorLeak);
+}
+
+ExplodedNode<GRState>*
+CFRefCount::ProcessLeaks(GRStateRef state,
+                         llvm::SmallVectorImpl<SymbolRef> &Leaked,
+                         GenericNodeBuilder &Builder,
+                         GRExprEngine& Eng,
+                         ExplodedNode<GRState> *Pred) {
   
   if (Leaked.empty())
-    return;
+    return Pred;
   
-  ExplodedNode<GRState>* N = Builder.MakeNode(St);  
+  ExplodedNode<GRState> *N = Builder.MakeNode(state, Pred);  
   
-  if (!N)
-    return;
-  
-  for (llvm::SmallVector<std::pair<SymbolRef,bool>, 10>::iterator
-       I = Leaked.begin(), E = Leaked.end(); I != E; ++I) {
-    
-    CFRefBug *BT = static_cast<CFRefBug*>(I->second ? leakAtReturn 
-                                                    : leakWithinFunction);
-    assert(BT && "BugType not initialized.");
-    CFRefLeakReport* report = new CFRefLeakReport(*BT, *this, N, I->first, Eng);
-    BR->EmitReport(report);
+  if (N) {
+    for (llvm::SmallVectorImpl<SymbolRef>::iterator
+         I = Leaked.begin(), E = Leaked.end(); I != E; ++I) {
+      
+      CFRefBug *BT = static_cast<CFRefBug*>(Pred ? leakWithinFunction 
+                                                 : leakAtReturn);
+      assert(BT && "BugType not initialized.");
+      CFRefLeakReport* report = new CFRefLeakReport(*BT, *this, N, *I, Eng);
+      BR->EmitReport(report);
+    }
   }
+  
+  return N;
+}
+
+void CFRefCount::EvalEndPath(GRExprEngine& Eng,
+                             GREndPathNodeBuilder<GRState>& Builder) {
+  
+  GRStateRef state(Builder.getState(), Eng.getStateManager());
+  RefBindings B = state.get<RefBindings>();  
+  llvm::SmallVector<SymbolRef, 10> Leaked;  
+  
+  for (RefBindings::iterator I = B.begin(), E = B.end(); I != E; ++I)
+    state = HandleSymbolDeath(state, (*I).first, (*I).second, Leaked);
+
+  GenericNodeBuilder Bd(Builder);
+  ProcessLeaks(state, Leaked, Bd, Eng, NULL);
 }
 
 void CFRefCount::EvalDeadSymbols(ExplodedNodeSet<GRState>& Dst,
@@ -3171,65 +3195,31 @@
                                  Stmt* S,
                                  const GRState* St,
                                  SymbolReaper& SymReaper) {
-  
-  // FIXME: a lot of copy-and-paste from EvalEndPath.  Refactor.  
+
+  GRStateRef state(St, Eng.getStateManager());
   RefBindings B = St->get<RefBindings>();
-  llvm::SmallVector<std::pair<SymbolRef,bool>, 10> Leaked;
+  llvm::SmallVector<SymbolRef, 10> Leaked;
   
   for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(),
-       E = SymReaper.dead_end(); I != E; ++I) {
-    
-    const RefVal* T = B.lookup(*I);
-    if (!T) continue;
-    
-    bool hasLeak = false;
-    
-    std::pair<GRStateRef, bool> X
-      = HandleSymbolDeath(Eng.getStateManager(), St, 0, *I, *T, hasLeak);
-    
-    St = X.first;
-    
-    if (hasLeak)
-      Leaked.push_back(std::make_pair(*I,X.second));    
-  }
-  
-  if (!Leaked.empty()) {
-    // Create a new intermediate node representing the leak point.  We
-    // use a special program point that represents this checker-specific
-    // transition.  We use the address of RefBIndex as a unique tag for this
-    // checker.  We will create another node (if we don't cache out) that
-    // removes the retain-count bindings from the state.
-    // NOTE: We use 'generateNode' so that it does interplay with the
-    // auto-transition logic.
-    ExplodedNode<GRState>* N =
-      Builder.generateNode(PostStmtCustom(S, &LeakProgramPointTag), St, Pred);
+       E = SymReaper.dead_end(); I != E; ++I) {    
+      if (const RefVal* T = B.lookup(*I))
+        state = HandleSymbolDeath(state, *I, *T, Leaked);
+  }    
+  
+  static unsigned LeakPPTag = 0;
+  GenericNodeBuilder Bd(Builder, S, &LeakPPTag);
+  Pred = ProcessLeaks(state, Leaked, Bd, Eng, Pred);
   
-    if (!N)
-      return;
-
-    // Generate the bug reports.
-    for (llvm::SmallVectorImpl<std::pair<SymbolRef,bool> >::iterator
-         I = Leaked.begin(), E = Leaked.end(); I != E; ++I) {
-      
-      CFRefBug *BT = static_cast<CFRefBug*>(I->second ? leakAtReturn 
-                                            : leakWithinFunction);
-      assert(BT && "BugType not initialized.");
-      CFRefLeakReport* report = new CFRefLeakReport(*BT, *this, N,
-                                                    I->first, Eng);
-      BR->EmitReport(report);
-    }
-    
-    Pred = N;
-  }
+  // Did we cache out?
+  if (!Pred)
+    return;
   
   // Now generate a new node that nukes the old bindings.
-  GRStateRef state(St, Eng.getStateManager());
   RefBindings::Factory& F = state.get_context<RefBindings>();
-
+  
   for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(),
-        E = SymReaper.dead_end(); I!=E; ++I)
-       B = F.Remove(B, *I);
-
+       E = SymReaper.dead_end(); I!=E; ++I) B = F.Remove(B, *I);
+  
   state = state.set<RefBindings>(B);
   Builder.MakeNode(Dst, S, Pred, state);
 }





More information about the cfe-commits mailing list