]> granicus.if.org Git - clang/commitdiff
Added "GetErrorNodes()" to BugType so that -trim-egraph can recognize errors
authorTed Kremenek <kremenek@apple.com>
Fri, 18 Apr 2008 19:23:43 +0000 (19:23 +0000)
committerTed Kremenek <kremenek@apple.com>
Fri, 18 Apr 2008 19:23:43 +0000 (19:23 +0000)
from registered BugTypes.  This helps with debugging.

Add detection of NULL values in ref count checker; this suppresses false positives.

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

include/clang/Analysis/PathSensitive/BugReporter.h
include/clang/Analysis/PathSensitive/GRTransferFuncs.h
lib/Analysis/CFRefCount.cpp
lib/Analysis/GRExprEngine.cpp

index b209a3296bd3f7eee3321df01a064f45b878ebee..f2f2e0316610a11f29b14c041a6d5bd24d32ab93 100644 (file)
@@ -19,6 +19,7 @@
 #include "clang/Analysis/PathSensitive/ValueState.h"
 #include "clang/Analysis/PathSensitive/ExplodedGraph.h"
 #include "llvm/ADT/SmallPtrSet.h"
+#include <vector>
 
 namespace clang {
   
@@ -41,6 +42,7 @@ public:
   virtual const char* getDescription() const { return getName(); }
       
   virtual void EmitWarnings(BugReporter& BR) {}
+  virtual void GetErrorNodes(std::vector<ExplodedNode<ValueState>*>& Nodes) {}
 };
   
 class BugReport {
index 60492b5eeab156e458caef763c96bed0865428e8..33199a574c4c40959ba7cac5ad3fc8faa7ee92a7 100644 (file)
@@ -99,11 +99,8 @@ public:
 
   // Assumptions.
   
-  virtual ValueState* EvalAssume(ValueState* St, NonLVal Cond, bool Assumption){
-    return St;
-  }
-  
-  virtual ValueState* EvalAssume(ValueState* St, LVal Cond, bool Assumption) {
+  virtual ValueState* EvalAssume(GRExprEngine& Engine, ValueState* St,
+                                 RVal Cond, bool Assumption, bool& isFeasible) {
     return St;
   }
 };
index 1618f04359d1c23e3e893a3a45c0da41eac2f130..3eb037978a1d29375fa27159ece81eb8e9aef138 100644 (file)
@@ -693,7 +693,12 @@ public:
                           GRStmtNodeBuilder<ValueState>& Builder,
                           ReturnStmt* S,
                           ExplodedNode<ValueState>* Pred);
-  
+
+  // Assumptions.
+
+  virtual ValueState* EvalAssume(GRExprEngine& Engine, ValueState* St,
+                                 RVal Cond, bool Assumption, bool& isFeasible);
+
   // Error iterators.
 
   typedef UseAfterReleasesTy::iterator use_after_iterator;  
@@ -1029,8 +1034,6 @@ ValueState* CFRefCount::NukeBinding(ValueStateManager& VMgr, ValueState* St,
 
 // End-of-path.
 
-
-
 ValueState* CFRefCount::HandleSymbolDeath(ValueStateManager& VMgr,
                                           ValueState* St, SymbolID sid,
                                           RefVal V, bool& hasLeak) {
@@ -1066,9 +1069,9 @@ void CFRefCount::EvalEndPath(GRExprEngine& Eng,
       
   ExplodedNode<ValueState>* N = Builder.MakeNode(St);  
   
-  if (!N)
+  if (!N || Leaked.empty())
     return;
-  
+    
   std::vector<SymbolID>*& LeaksAtNode = Leaks[N];
   assert (!LeaksAtNode);
   LeaksAtNode = new std::vector<SymbolID>();
@@ -1138,6 +1141,44 @@ void CFRefCount::EvalReturn(ExplodedNodeSet<ValueState>& Dst,
   Builder.MakeNode(Dst, S, Pred, StateMgr.getPersistentState(StImpl));
 }
 
+// Assumptions.
+
+ValueState* CFRefCount::EvalAssume(GRExprEngine& Eng, ValueState* St,
+                                   RVal Cond, bool Assumption,
+                                   bool& isFeasible) {
+
+  // FIXME: We may add to the interface of EvalAssume the list of symbols
+  //  whose assumptions have changed.  For now we just iterate through the
+  //  bindings and check if any of the tracked symbols are NULL.  This isn't
+  //  too bad since the number of symbols we will track in practice are 
+  //  probably small and EvalAssume is only called at branches and a few
+  //  other places.
+    
+  RefBindings B = GetRefBindings(*St);
+  
+  if (B.isEmpty())
+    return St;
+  
+  bool changed = false;
+
+  for (RefBindings::iterator I=B.begin(), E=B.end(); I!=E; ++I) {    
+
+    // Check if the symbol is null (or equal to any constant).
+    // If this is the case, stop tracking the symbol.
+  
+    if (St->getSymVal(I.getKey())) {
+      changed = true;
+      B = RefBFactory.Remove(B, I.getKey());
+    }
+  }
+  
+  if (!changed)
+    return St;
+  
+  ValueState StImpl = *St;
+  StImpl.CheckerState = B.getRoot();
+  return Eng.getStateManager().getPersistentState(StImpl);
+}
 
 CFRefCount::RefBindings CFRefCount::Update(RefBindings B, SymbolID sym,
                                            RefVal V, ArgEffect E,
@@ -1280,6 +1321,7 @@ namespace {
     }
     
     virtual void EmitWarnings(BugReporter& BR);
+    virtual void GetErrorNodes(std::vector<ExplodedNode<ValueState>*>& Nodes);    
   };
   
   //===---------===//
@@ -1465,6 +1507,12 @@ void Leak::EmitWarnings(BugReporter& BR) {
   }  
 }
 
+void Leak::GetErrorNodes(std::vector<ExplodedNode<ValueState>*>& Nodes) {
+  for (CFRefCount::leaks_iterator I=TF.leaks_begin(), E=TF.leaks_end();
+       I!=E; ++I)
+    Nodes.push_back(I->first);
+}
+
 //===----------------------------------------------------------------------===//
 // Transfer function creation for external clients.
 //===----------------------------------------------------------------------===//
index e3fe2395535c1f89214a99a50adc14c7134698aa..63986fb38a50584117e923b2bfbb03c32a001e88 100644 (file)
@@ -1843,7 +1843,9 @@ ValueState* GRExprEngine::Assume(ValueState* St, LVal Cond,
                                  bool Assumption, bool& isFeasible) {
                                              
   St = AssumeAux(St, Cond, Assumption, isFeasible);
-  return isFeasible ? St : TF->EvalAssume(St, Cond, Assumption);
+  
+  return isFeasible ? TF->EvalAssume(*this, St, Cond, Assumption, isFeasible)
+                    : St;
 }
 
 ValueState* GRExprEngine::AssumeAux(ValueState* St, LVal Cond,
@@ -1881,7 +1883,9 @@ ValueState* GRExprEngine::Assume(ValueState* St, NonLVal Cond,
                                  bool Assumption, bool& isFeasible) {
 
   St = AssumeAux(St, Cond, Assumption, isFeasible);
-  return isFeasible ? St : TF->EvalAssume(St, Cond, Assumption);
+
+  return isFeasible ? TF->EvalAssume(*this, St, Cond, Assumption, isFeasible)
+                    : St;
 }
 
 ValueState* GRExprEngine::AssumeAux(ValueState* St, NonLVal Cond,
@@ -2258,7 +2262,7 @@ GetGraphNode<llvm::DenseMap<GRExprEngine::NodeTy*, Expr*>::iterator>
 }
 
 template <typename ITERATOR>
-static void AddSources(llvm::SmallVector<GRExprEngine::NodeTy*, 10>& Sources,
+static void AddSources(std::vector<GRExprEngine::NodeTy*>& Sources,
                        ITERATOR I, ITERATOR E) {
   
   llvm::SmallPtrSet<void*,10> CachedSources;
@@ -2280,7 +2284,9 @@ static void AddSources(llvm::SmallVector<GRExprEngine::NodeTy*, 10>& Sources,
 void GRExprEngine::ViewGraph(bool trim) {
 #ifndef NDEBUG  
   if (trim) {
-    llvm::SmallVector<NodeTy*, 10> Src;
+    std::vector<NodeTy*> Src;
+    
+    // Fixme: Migrate over to the new way of adding nodes.
     AddSources(Src, null_derefs_begin(), null_derefs_end());
     AddSources(Src, undef_derefs_begin(), undef_derefs_end());
     AddSources(Src, explicit_bad_divides_begin(), explicit_bad_divides_end());
@@ -2289,6 +2295,11 @@ void GRExprEngine::ViewGraph(bool trim) {
     AddSources(Src, undef_arg_begin(), undef_arg_end());
     AddSources(Src, undef_branches_begin(), undef_branches_end());
     
+    // The new way.
+    for (BugTypeSet::iterator I=BugTypes.begin(), E=BugTypes.end(); I!=E; ++I)
+      (*I)->GetErrorNodes(Src);
+      
+    
     ViewGraph(&Src[0], &Src[0]+Src.size());
   }
   else {