[cfe-commits] r138353 - in /cfe/trunk/lib/StaticAnalyzer/Core: CFRefCount.cpp ExprEngine.cpp

Jordy Rose jediknil at belkadan.com
Tue Aug 23 12:01:07 PDT 2011


Author: jrose
Date: Tue Aug 23 14:01:07 2011
New Revision: 138353

URL: http://llvm.org/viewvc/llvm-project?rev=138353&view=rev
Log:
[analyzer] Move symbol death leak analysis from CFRefCount to RetainReleaseChecker.

Modified:
    cfe/trunk/lib/StaticAnalyzer/Core/CFRefCount.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp

Modified: cfe/trunk/lib/StaticAnalyzer/Core/CFRefCount.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/CFRefCount.cpp?rev=138353&r1=138352&r2=138353&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/CFRefCount.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/CFRefCount.cpp Tue Aug 23 14:01:07 2011
@@ -1649,8 +1649,6 @@
   BugType *overAutorelease;
   BugType *returnNotOwnedForOwned;
   BugReporter *BR;
-  
-  llvm::DenseMap<SymbolRef, const SimpleProgramPointTag*> DeadSymbolTags;
 
   const ProgramState *Update(const ProgramState * state,
                              SymbolRef sym,
@@ -1658,17 +1656,6 @@
                              ArgEffect E,
                              RefVal::Kind& hasErr);
 
-  const ProgramState *HandleSymbolDeath(const ProgramState * state,
-                                        SymbolRef sid,
-                                        RefVal V,
-                                        SmallVectorImpl<SymbolRef> &Leaked);
-
-  ExplodedNode *ProcessLeaks(const ProgramState * state,
-                             SmallVectorImpl<SymbolRef> &Leaked,
-                             GenericNodeBuilderRefCount &Builder,
-                             ExprEngine &Eng,
-                             ExplodedNode *Pred = 0);
-
 public:
   CFRefCount(ASTContext &Ctx, bool gcenabled, const LangOptions& lopts)
     : Summaries(Ctx, gcenabled, (bool)lopts.ObjCAutoRefCount),
@@ -1677,12 +1664,6 @@
       leakWithinFunction(0), leakAtReturn(0), overAutorelease(0),
       returnNotOwnedForOwned(0), BR(0) {}
 
-  virtual ~CFRefCount() {
-    for (llvm::DenseMap<SymbolRef, const SimpleProgramPointTag *>::iterator
-         it = DeadSymbolTags.begin(), ei = DeadSymbolTags.end(); it != ei; ++it)
-      delete it->second;
-  }
-
   void RegisterChecks(ExprEngine &Eng);
 
   virtual void RegisterPrinters(std::vector<ProgramState::Printer*>& Printers) {
@@ -1723,18 +1704,6 @@
 
   // End-of-path.
 
-  virtual void evalEndPath(ExprEngine& Engine,
-                           EndOfFunctionNodeBuilder& Builder);
-
-  virtual void evalDeadSymbols(ExplodedNodeSet &Dst,
-                               ExprEngine& Engine,
-                               StmtNodeBuilder& Builder,
-                               ExplodedNode *Pred,
-                               const ProgramState *state,
-                               SymbolReaper& SymReaper);
-
-  const ProgramPointTag *getDeadSymbolTag(SymbolRef sym);
-  
   std::pair<ExplodedNode*, const ProgramState *>
   HandleAutoreleaseCounts(const ProgramState * state,
                           GenericNodeBuilderRefCount Bd,
@@ -3062,142 +3031,6 @@
   return std::make_pair((ExplodedNode*)0, state);
 }
 
-const ProgramState *
-CFRefCount::HandleSymbolDeath(const ProgramState *state,
-                              SymbolRef sid,
-                              RefVal V,
-                              SmallVectorImpl<SymbolRef> &Leaked) {
-
-  bool hasLeak = V.isOwned() ||
-  ((V.isNotOwned() || V.isReturnedOwned()) && V.getCount() > 0);
-
-  if (!hasLeak)
-    return state->remove<RefBindings>(sid);
-
-  Leaked.push_back(sid);
-  return state->set<RefBindings>(sid, V ^ RefVal::ErrorLeak);
-}
-
-ExplodedNode*
-CFRefCount::ProcessLeaks(const ProgramState * state,
-                         SmallVectorImpl<SymbolRef> &Leaked,
-                         GenericNodeBuilderRefCount &Builder,
-                         ExprEngine& Eng,
-                         ExplodedNode *Pred) {
-
-  if (Leaked.empty())
-    return Pred;
-
-  // Generate an intermediate node representing the leak point.
-  ExplodedNode *N = Builder.MakeNode(state, Pred);
-
-  if (N) {
-    for (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(ExprEngine& Eng,
-                             EndOfFunctionNodeBuilder& Builder) {
-
-  const ProgramState *state = Builder.getState();
-  GenericNodeBuilderRefCount Bd(Builder);
-  RefBindings B = state->get<RefBindings>();
-  ExplodedNode *Pred = 0;
-
-  for (RefBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) {
-    bool stop = false;
-    llvm::tie(Pred, state) = HandleAutoreleaseCounts(state, Bd, Pred, Eng,
-                                                     (*I).first,
-                                                     (*I).second, stop);
-
-    if (stop)
-      return;
-  }
-
-  B = state->get<RefBindings>();
-  SmallVector<SymbolRef, 10> Leaked;
-
-  for (RefBindings::iterator I = B.begin(), E = B.end(); I != E; ++I)
-    state = HandleSymbolDeath(state, (*I).first, (*I).second, Leaked);
-
-  ProcessLeaks(state, Leaked, Bd, Eng, Pred);
-}
-
-const ProgramPointTag *CFRefCount::getDeadSymbolTag(SymbolRef sym) {
-  const SimpleProgramPointTag *&tag = DeadSymbolTags[sym];
-  if (!tag) {
-    llvm::SmallString<128> buf;
-    llvm::raw_svector_ostream out(buf);
-    out << "CFRefCount : Dead Symbol : " << sym->getSymbolID();
-    tag = new SimpleProgramPointTag(out.str());
-  }
-  return tag;  
-}
-
-void CFRefCount::evalDeadSymbols(ExplodedNodeSet &Dst,
-                                 ExprEngine& Eng,
-                                 StmtNodeBuilder& Builder,
-                                 ExplodedNode *Pred,
-                                 const ProgramState *state,
-                                 SymbolReaper& SymReaper) {
-  const Stmt *S = Builder.getStmt();
-  RefBindings B = state->get<RefBindings>();
-
-  // Update counts from autorelease pools
-  for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(),
-       E = SymReaper.dead_end(); I != E; ++I) {
-    SymbolRef Sym = *I;
-    if (const RefVal* T = B.lookup(Sym)){
-      // Use the symbol as the tag.
-      // FIXME: This might not be as unique as we would like.
-      GenericNodeBuilderRefCount Bd(Builder, S, getDeadSymbolTag(Sym));
-      bool stop = false;
-      llvm::tie(Pred, state) = HandleAutoreleaseCounts(state, Bd, Pred, Eng,
-                                                       Sym, *T, stop);
-      if (stop)
-        return;
-    }
-  }
-
-  B = state->get<RefBindings>();
-  SmallVector<SymbolRef, 10> Leaked;
-
-  for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(),
-       E = SymReaper.dead_end(); I != E; ++I) {
-      if (const RefVal* T = B.lookup(*I))
-        state = HandleSymbolDeath(state, *I, *T, Leaked);
-  }
-
-  static SimpleProgramPointTag LeakPPTag("CFRefCount : Leak");
-  {
-    GenericNodeBuilderRefCount Bd(Builder, S, &LeakPPTag);
-    Pred = ProcessLeaks(state, Leaked, Bd, Eng, Pred);
-  }
-
-  // Did we cache out?
-  if (!Pred)
-    return;
-
-  // Now generate a new node that nukes the old bindings.
-  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);
-
-  state = state->set<RefBindings>(B);
-  Builder.MakeNode(Dst, S, Pred, state);
-}
-
 //===----------------------------------------------------------------------===//
 // Pieces of the retain/release checker implemented using a CheckerVisitor.
 // More pieces of the retain/release checker will be migrated to this interface
@@ -3207,6 +3040,8 @@
 namespace {
 class RetainReleaseChecker
   : public Checker< check::Bind,
+                    check::DeadSymbols,
+                    check::EndPath,
                     check::PostStmt<BlockExpr>,
                     check::PostStmt<CastExpr>,
                     check::PostStmt<CallExpr>,
@@ -3214,7 +3049,18 @@
                     check::RegionChanges,
                     eval::Assume,
                     eval::Call > {
+
+  typedef llvm::DenseMap<SymbolRef, const SimpleProgramPointTag *> SymbolTagMap;
+
+  // This map is only used to ensure proper deletion of any allocated tags.
+  mutable SymbolTagMap DeadSymbolTags;
+
 public:  
+
+  virtual ~RetainReleaseChecker() {
+    DeleteContainerSeconds(DeadSymbolTags);
+  }
+
   void checkBind(SVal loc, SVal val, CheckerContext &C) const;
   void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const;
   void checkPostStmt(const CastExpr *CE, CheckerContext &C) const;
@@ -3238,10 +3084,24 @@
     return true;
   }
 
+  void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
+  void checkEndPath(EndOfFunctionNodeBuilder &Builder, ExprEngine &Eng) const;
+
   void processNonLeakError(const ProgramState *St, SourceRange ErrorRange,
                            RefVal::Kind ErrorKind, SymbolRef Sym,
                            CheckerContext &C) const;
 
+  const ProgramPointTag *getDeadSymbolTag(SymbolRef sym) const;
+
+  const ProgramState *handleSymbolDeath(const ProgramState *state,
+                                        SymbolRef sid, RefVal V,
+                                      SmallVectorImpl<SymbolRef> &Leaked) const;
+
+  ExplodedNode *processLeaks(const ProgramState *state,
+                             SmallVectorImpl<SymbolRef> &Leaked,
+                             GenericNodeBuilderRefCount &Builder,
+                             ExprEngine &Eng,
+                             ExplodedNode *Pred = 0) const;
 };
 } // end anonymous namespace
 
@@ -3727,6 +3587,155 @@
   return true;
 }
 
+// Handle dead symbols (potential leaks).
+
+const ProgramState *
+RetainReleaseChecker::handleSymbolDeath(const ProgramState *state,
+                                        SymbolRef sid, RefVal V,
+                                    SmallVectorImpl<SymbolRef> &Leaked) const {
+  bool hasLeak;
+  if (V.isOwned())
+    hasLeak = true;
+  else if (V.isNotOwned() || V.isReturnedOwned())
+    hasLeak = (V.getCount() > 0);
+
+  if (!hasLeak)
+    return state->remove<RefBindings>(sid);
+
+  Leaked.push_back(sid);
+  return state->set<RefBindings>(sid, V ^ RefVal::ErrorLeak);
+}
+
+ExplodedNode *
+RetainReleaseChecker::processLeaks(const ProgramState *state,
+                                   SmallVectorImpl<SymbolRef> &Leaked,
+                                   GenericNodeBuilderRefCount &Builder,
+                                   ExprEngine &Eng,
+                                   ExplodedNode *Pred) const {
+
+  if (Leaked.empty())
+    return Pred;
+
+  // Generate an intermediate node representing the leak point.
+  ExplodedNode *N = Builder.MakeNode(state, Pred);
+
+  if (N) {
+    for (SmallVectorImpl<SymbolRef>::iterator
+         I = Leaked.begin(), E = Leaked.end(); I != E; ++I) {
+
+      // FIXME: This goes away once the these bug types move to the checker,
+      // and CFRefReport no longer depends on CFRefCount.
+      CFRefCount &TF = static_cast<CFRefCount&>(Eng.getTF());
+      CFRefBug *BT = static_cast<CFRefBug*>(Pred ? TF.leakWithinFunction
+                                                 : TF.leakAtReturn);
+      assert(BT && "BugType not initialized.");
+      CFRefLeakReport *report = new CFRefLeakReport(*BT, TF, N, *I, Eng);
+      Eng.getBugReporter().EmitReport(report);
+    }
+  }
+
+  return N;
+}
+
+void RetainReleaseChecker::checkEndPath(EndOfFunctionNodeBuilder &Builder,
+                                        ExprEngine &Eng) const {
+  // FIXME: This goes away once HandleAutoreleaseCounts moves to the checker.
+  CFRefCount &TF = static_cast<CFRefCount&>(Eng.getTF());
+
+  const ProgramState *state = Builder.getState();
+  GenericNodeBuilderRefCount Bd(Builder);
+  RefBindings B = state->get<RefBindings>();
+  ExplodedNode *Pred = 0;
+
+  for (RefBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) {
+    bool stop = false;
+    llvm::tie(Pred, state) = TF.HandleAutoreleaseCounts(state, Bd, Pred, Eng,
+                                                        (*I).first,
+                                                        (*I).second, stop);
+
+    if (stop)
+      return;
+  }
+
+  B = state->get<RefBindings>();
+  SmallVector<SymbolRef, 10> Leaked;
+
+  for (RefBindings::iterator I = B.begin(), E = B.end(); I != E; ++I)
+    state = handleSymbolDeath(state, (*I).first, (*I).second, Leaked);
+
+  processLeaks(state, Leaked, Bd, Eng, Pred);
+}
+
+const ProgramPointTag *
+RetainReleaseChecker::getDeadSymbolTag(SymbolRef sym) const {
+  const SimpleProgramPointTag *&tag = DeadSymbolTags[sym];
+  if (!tag) {
+    llvm::SmallString<64> buf;
+    llvm::raw_svector_ostream out(buf);
+    out << "RetainReleaseChecker : Dead Symbol : " << sym->getSymbolID();
+    tag = new SimpleProgramPointTag(out.str());
+  }
+  return tag;  
+}
+
+void RetainReleaseChecker::checkDeadSymbols(SymbolReaper &SymReaper,
+                                            CheckerContext &C) const {
+  StmtNodeBuilder &Builder = C.getNodeBuilder();
+  ExprEngine &Eng = C.getEngine();
+  const Stmt *S = C.getStmt();
+  ExplodedNode *Pred = C.getPredecessor();
+
+  // FIXME: This goes away once HandleAutoreleaseCounts moves to the checker.
+  CFRefCount &TF = static_cast<CFRefCount&>(Eng.getTF());
+
+  const ProgramState *state = C.getState();
+  RefBindings B = state->get<RefBindings>();
+
+  // Update counts from autorelease pools
+  for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(),
+       E = SymReaper.dead_end(); I != E; ++I) {
+    SymbolRef Sym = *I;
+    if (const RefVal *T = B.lookup(Sym)){
+      // Use the symbol as the tag.
+      // FIXME: This might not be as unique as we would like.
+      GenericNodeBuilderRefCount Bd(Builder, S, getDeadSymbolTag(Sym));
+      bool stop = false;
+      llvm::tie(Pred, state) = TF.HandleAutoreleaseCounts(state, Bd, Pred, Eng,
+                                                          Sym, *T, stop);
+      if (stop)
+        return;
+    }
+  }
+
+  B = state->get<RefBindings>();
+  SmallVector<SymbolRef, 10> Leaked;
+
+  for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(),
+       E = SymReaper.dead_end(); I != E; ++I) {
+    if (const RefVal *T = B.lookup(*I))
+      state = handleSymbolDeath(state, *I, *T, Leaked);
+  }
+
+  {
+    GenericNodeBuilderRefCount Bd(Builder, S, this);
+    Pred = processLeaks(state, Leaked, Bd, Eng, Pred);
+  }
+
+  // Did we cache out?
+  if (!Pred)
+    return;
+
+  // Now generate a new node that nukes the old bindings.
+  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);
+
+  state = state->set<RefBindings>(B);
+  C.generateNode(state, Pred);
+}
+
 //===----------------------------------------------------------------------===//
 // Transfer function creation for external clients.
 //===----------------------------------------------------------------------===//

Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp?rev=138353&r1=138352&r2=138353&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp Tue Aug 23 14:01:07 2011
@@ -283,6 +283,9 @@
     ExplodedNodeSet Tmp2;
     getTF().evalDeadSymbols(Tmp2, *this, *Builder, EntryNode,
                             EntryState, SymReaper);
+    if (Tmp2.empty()) {
+      Builder->MakeNode(Tmp2, currentStmt, EntryNode, EntryState);
+    }
 
     ExplodedNodeSet Tmp3;
     getCheckerManager().runCheckersForDeadSymbols(Tmp3, Tmp2,





More information about the cfe-commits mailing list