[cfe-commits] r48214 - in /cfe/trunk: Analysis/CFRefCount.cpp Analysis/CFRefCount.h Analysis/ValueState.cpp include/clang/Analysis/PathSensitive/ValueState.h

Ted Kremenek kremenek at apple.com
Mon Mar 10 23:39:12 PDT 2008


Author: kremenek
Date: Tue Mar 11 01:39:11 2008
New Revision: 48214

URL: http://llvm.org/viewvc/llvm-project?rev=48214&view=rev
Log:
Added main skeleton for CFRetain transfer function logic.

Removed:
    cfe/trunk/Analysis/CFRefCount.h
Modified:
    cfe/trunk/Analysis/CFRefCount.cpp
    cfe/trunk/Analysis/ValueState.cpp
    cfe/trunk/include/clang/Analysis/PathSensitive/ValueState.h

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

==============================================================================
--- cfe/trunk/Analysis/CFRefCount.cpp (original)
+++ cfe/trunk/Analysis/CFRefCount.cpp Tue Mar 11 01:39:11 2008
@@ -12,35 +12,188 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "CFRefCount.h"
+#include "GRSimpleVals.h"
 #include "clang/Analysis/PathSensitive/ValueState.h"
 #include "clang/Basic/Diagnostic.h"
 #include "clang/Analysis/LocalCheckers.h"
-
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/ImmutableMap.h"
 
 using namespace clang;
 
+namespace {  
+  enum ArgEffect { IncRef, DecRef, DoNothing };
+  typedef std::vector<ArgEffect> ArgEffects;
+}
 
-namespace clang {
+namespace llvm {
+  template <> struct FoldingSetTrait<ArgEffects> {
+    static void Profile(const ArgEffects& X, FoldingSetNodeID ID) {
+      for (ArgEffects::const_iterator I = X.begin(), E = X.end(); I!= E; ++I)
+        ID.AddInteger((unsigned) *I);
+    }
+    
+    static void Profile(ArgEffects& X, FoldingSetNodeID ID) {
+      Profile(X, ID);
+    }
+  };
+} // end llvm namespace
+
+namespace {
+  
+class RetEffect {
+public:
+  enum Kind { Alias = 0x0, OwnedSymbol = 0x1, NotOwnedSymbol = 0x2 };
+
+private:
+  unsigned Data;
+  RetEffect(Kind k, unsigned D) { Data = (Data << 2) | (unsigned) k; }
+  
+public:
+
+  Kind getKind() const { return (Kind) (Data & 0x3); }
+
+  unsigned getValue() const { 
+    assert(getKind() == Alias);
+    return Data & ~0x3;
+  }
+  
+  static RetEffect MakeAlias(unsigned Idx) { return RetEffect(Alias, Idx); }
+  
+  static RetEffect MakeOwned() { return RetEffect(OwnedSymbol, 0); }
+  
+  static RetEffect MakeNotOwned() { return RetEffect(NotOwnedSymbol, 0); }
+  
+  operator Kind() const { return getKind(); }
+  
+  void Profile(llvm::FoldingSetNodeID& ID) const { ID.AddInteger(Data); }
+};
+
+  
+class CFRefSummary : public llvm::FoldingSetNode {
+  ArgEffects* Args;
+  RetEffect   Ret;
+public:
+  
+  CFRefSummary(ArgEffects* A, RetEffect R) : Args(A), Ret(R) {}
+  
+  unsigned getNumArgs() const { return Args->size(); }
+  
+  typedef ArgEffects::const_iterator arg_iterator;
+  
+  arg_iterator begin_args() const { return Args->begin(); }
+  arg_iterator end_args()   const { return Args->end(); }
   
-void CheckCFRefCount(CFG& cfg, FunctionDecl& FD, ASTContext& Ctx,
-                     Diagnostic& Diag) {
+  static void Profile(llvm::FoldingSetNodeID& ID, ArgEffects* A, RetEffect R) {
+    ID.AddPointer(A);
+    ID.Add(R);
+  }
+      
+  void Profile(llvm::FoldingSetNodeID& ID) const {
+    Profile(ID, Args, Ret);
+  }
+};
+
   
-  if (Diag.hasErrorOccurred())
-    return;
+class CFRefSummaryManager {
+  typedef llvm::FoldingSet<llvm::FoldingSetNodeWrapper<ArgEffects> > AESetTy;
+  typedef llvm::FoldingSet<CFRefSummary>                SummarySetTy;
+  typedef llvm::DenseMap<FunctionDecl*, CFRefSummary*>  SummaryMapTy;
+  
+  SummarySetTy           SummarySet;
+  SummaryMapTy           SummaryMap;  
+  AESetTy                AESet;  
+  llvm::BumpPtrAllocator BPAlloc;
+  
+  ArgEffects             ScratchArgs;
+
+public:
+  CFRefSummaryManager() {}
+  ~CFRefSummaryManager();
   
-  // FIXME: Refactor some day so this becomes a single function invocation.
+  CFRefSummary* getSummary(FunctionDecl* FD);
+};
+  
+} // end anonymous namespace
+
+//===----------------------------------------------------------------------===//
+// Implementation of checker data structures.
+//===----------------------------------------------------------------------===//
+
+CFRefSummaryManager::~CFRefSummaryManager() {
   
-  GRCoreEngine<GRExprEngine> Engine(cfg, FD, Ctx);
-  GRExprEngine* CS = &Engine.getCheckerState();
-  CFRefCount TF;
-  CS->setTransferFunctions(TF);
-  Engine.ExecuteWorkList(20000);
+  // FIXME: The ArgEffects could eventually be allocated from BPAlloc, 
+  //   mitigating the need to do explicit cleanup of the
+  //   Argument-Effect summaries.
   
+  for (AESetTy::iterator I = AESet.begin(), E = AESet.end(); I!=E; ++I)
+    I->getValue().~ArgEffects();
 }
+
+CFRefSummary* CFRefSummaryManager::getSummary(FunctionDecl* FD) {
+  
+  { // Look into our cache of summaries to see if we have already computed
+    // a summary for this FunctionDecl.
+      
+    SummaryMapTy::iterator I = SummaryMap.find(FD);
+    
+    if (I != SummaryMap.end())
+      return I->second;
+  }
+  
+  //
+  
   
+  return NULL;  
 }
 
+//===----------------------------------------------------------------------===//
+// Transfer functions.
+//===----------------------------------------------------------------------===//
+
+typedef unsigned RefState; // FIXME
+
+namespace {
+  
+class CFRefCount : public GRSimpleVals {
+  typedef llvm::ImmutableMap<SymbolID, RefState> RefBindings;
+  typedef RefBindings::Factory RefBFactoryTy;
+
+  CFRefSummaryManager Summaries;
+  RefBFactoryTy  RefBFactory;
+    
+  static RefBindings GetRefBindings(ValueState& StImpl) {
+    return RefBindings((RefBindings::TreeTy*) StImpl.CheckerState);
+  }
+  
+  static void SetRefBindings(ValueState& StImpl, RefBindings B) {
+    StImpl.CheckerState = B.getRoot();
+  }
+  
+  RefBindings Remove(RefBindings B, SymbolID sym) {
+    return RefBFactory.Remove(B, sym);
+  }
+  
+  RefBindings Update(RefBindings B, SymbolID sym,
+                     CFRefSummary* Summ, unsigned ArgIdx);
+  
+public:
+  CFRefCount() {}
+  virtual ~CFRefCount() {}
+  
+  // Calls.
+  
+  virtual void EvalCall(ExplodedNodeSet<ValueState>& Dst,
+                        ValueStateManager& StateMgr,
+                        GRStmtNodeBuilder<ValueState>& Builder,
+                        BasicValueFactory& BasicVals,
+                        CallExpr* CE, LVal L,
+                        ExplodedNode<ValueState>* Pred);  
+};
+
+} // end anonymous namespace
+
 void CFRefCount::EvalCall(ExplodedNodeSet<ValueState>& Dst,
                             ValueStateManager& StateMgr,
                             GRStmtNodeBuilder<ValueState>& Builder,
@@ -48,18 +201,104 @@
                             CallExpr* CE, LVal L,
                             ExplodedNode<ValueState>* Pred) {
   
-  ValueState* St = Pred->getState();
+  // FIXME: Support calls to things other than lval::FuncVal.  At the very
+  //  least we should stop tracking ref-state for ref-counted objects passed
+  //  to these functions.
+  
+  assert (isa<lval::FuncVal>(L) && "Not yet implemented.");
   
-  // Invalidate all arguments passed in by reference (LVals).
+  // Get the summary.
 
-  for (CallExpr::arg_iterator I = CE->arg_begin(), E = CE->arg_end();
-        I != E; ++I) {
+  lval::FuncVal FV = cast<lval::FuncVal>(L);
+  FunctionDecl* FD = FV.getDecl();
+  CFRefSummary* Summ = Summaries.getSummary(FD);
 
-    RVal V = StateMgr.GetRVal(St, *I);
+  // Get the state.
+  
+  ValueState* St = Builder.GetState(Pred);
+  
+  // Evaluate the effects of the call.
+  
+  ValueState StVals = *St;
+  
+  if (!Summ) {
+    
+    // This function has no summary.  Invalidate all reference-count state
+    // for arguments passed to this function, and also nuke the values of
+    // arguments passed-by-reference.
+    
+    ValueState StVals = *St;
     
-    if (isa<LVal>(V))
-      St = StateMgr.SetRVal(St, cast<LVal>(V), UnknownVal());
+    for (CallExpr::arg_iterator I = CE->arg_begin(), E = CE->arg_end();
+         I != E; ++I) {
+      
+      RVal V = StateMgr.GetRVal(St, *I);
+      
+      if (isa<lval::SymbolVal>(V)) {
+        SymbolID Sym = cast<lval::SymbolVal>(V).getSymbol();
+        RefBindings B = GetRefBindings(StVals);
+        SetRefBindings(StVals, Remove(B, Sym));
+      }
+            
+      if (isa<LVal>(V))
+        StateMgr.Unbind(StVals, cast<LVal>(V));
+    }    
   }
+  else {
+    
+    // This function has a summary.  Evaluate the effect of the arguments.
+    
+    unsigned idx = 0;
+    
+    for (CallExpr::arg_iterator I=CE->arg_begin(), E=CE->arg_end();
+          I!=E; ++I, ++idx) {
+      
+      RVal V = StateMgr.GetRVal(St, *I);
+      
+      if (isa<lval::SymbolVal>(V)) {
+        SymbolID Sym = cast<lval::SymbolVal>(V).getSymbol();
+        RefBindings B = GetRefBindings(StVals);
+        SetRefBindings(StVals, Update(B, Sym, Summ, idx));
+      }
+    }    
+  }
+  
+  St = StateMgr.getPersistentState(StVals);
     
   Builder.Nodify(Dst, CE, Pred, St);
 }
+
+
+CFRefCount::RefBindings CFRefCount::Update(RefBindings B, SymbolID sym,
+                                           CFRefSummary* Summ, unsigned ArgIdx){
+  
+  assert (Summ);
+  
+  // FIXME: Implement.
+  
+  return B;
+}
+
+//===----------------------------------------------------------------------===//
+// Driver for the CFRefCount Checker.
+//===----------------------------------------------------------------------===//
+
+namespace clang {
+  
+  void CheckCFRefCount(CFG& cfg, FunctionDecl& FD, ASTContext& Ctx,
+                       Diagnostic& Diag) {
+    
+    if (Diag.hasErrorOccurred())
+      return;
+    
+    // FIXME: Refactor some day so this becomes a single function invocation.
+    
+    GRCoreEngine<GRExprEngine> Engine(cfg, FD, Ctx);
+    GRExprEngine* CS = &Engine.getCheckerState();
+    CFRefCount TF;
+    CS->setTransferFunctions(TF);
+    Engine.ExecuteWorkList(20000);
+    
+  }
+  
+} // end clang namespace

Removed: cfe/trunk/Analysis/CFRefCount.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/Analysis/CFRefCount.h?rev=48213&view=auto

==============================================================================
--- cfe/trunk/Analysis/CFRefCount.h (original)
+++ cfe/trunk/Analysis/CFRefCount.h (removed)
@@ -1,39 +0,0 @@
-// CFRefCount.h - Transfer functions for the CF Ref. Count checker -*- C++ -*---
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-//  This file defines CFRefCount, which defines the transfer functions
-//  to implement the Core Foundation reference count checker.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_ANALYSIS_GRREFCOUNT
-#define LLVM_CLANG_ANALYSIS_GRREFCOUNT
-
-#include "GRSimpleVals.h"
-
-namespace clang {
-  
-class CFRefCount : public GRSimpleVals {
-public:
-  CFRefCount() {}
-  virtual ~CFRefCount() {}
-    
-  // Calls.
-  
-  virtual void EvalCall(ExplodedNodeSet<ValueState>& Dst,
-                        ValueStateManager& StateMgr,
-                        GRStmtNodeBuilder<ValueState>& Builder,
-                        BasicValueFactory& BasicVals,
-                        CallExpr* CE, LVal L,
-                        ExplodedNode<ValueState>* Pred);  
-};
-  
-} // end clang namespace
-
-#endif

Modified: cfe/trunk/Analysis/ValueState.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/Analysis/ValueState.cpp?rev=48214&r1=48213&r2=48214&view=diff

==============================================================================
--- cfe/trunk/Analysis/ValueState.cpp (original)
+++ cfe/trunk/Analysis/ValueState.cpp Tue Mar 11 01:39:11 2008
@@ -442,6 +442,14 @@
   return getPersistentState(NewSt);
 }
 
+void ValueStateManager::Unbind(ValueState& StImpl, LVal LV) {
+  
+  if (isa<lval::DeclVal>(LV))
+    StImpl.VarBindings = VBFactory.Remove(StImpl.VarBindings,
+                                          cast<lval::DeclVal>(LV).getDecl());
+  
+}
+
 ValueState* ValueStateManager::getInitialState() {
 
   // Create a state with empty variable bindings.

Modified: cfe/trunk/include/clang/Analysis/PathSensitive/ValueState.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/PathSensitive/ValueState.h?rev=48214&r1=48213&r2=48214&view=diff

==============================================================================
--- cfe/trunk/include/clang/Analysis/PathSensitive/ValueState.h (original)
+++ cfe/trunk/include/clang/Analysis/PathSensitive/ValueState.h Tue Mar 11 01:39:11 2008
@@ -234,6 +234,9 @@
   RVal GetBlkExprRVal(ValueState* St, Expr* Ex);
   
   void BindVar(ValueState& StImpl, VarDecl* D, RVal V);
+  
+  void Unbind(ValueState& StImpl, LVal LV);
+  
   ValueState* getPersistentState(ValueState& Impl);
   
   ValueState* AddEQ(ValueState* St, SymbolID sym, const llvm::APSInt& V);





More information about the cfe-commits mailing list