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

Ted Kremenek kremenek at apple.com
Tue Apr 15 21:28:54 PDT 2008


Author: kremenek
Date: Tue Apr 15 23:28:53 2008
New Revision: 49771

URL: http://llvm.org/viewvc/llvm-project?rev=49771&view=rev
Log:
Implemented toll-free bridging support for CF Reference count checker.

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=49771&r1=49770&r2=49771&view=diff

==============================================================================
--- cfe/trunk/lib/Analysis/CFRefCount.cpp (original)
+++ cfe/trunk/lib/Analysis/CFRefCount.cpp Tue Apr 15 23:28:53 2008
@@ -458,6 +458,11 @@
 // Transfer functions.
 //===----------------------------------------------------------------------===//
 
+static inline Selector GetUnarySelector(const char* name, ASTContext& Ctx) {
+  IdentifierInfo* II = &Ctx.Idents.get(name);
+  return Ctx.Selectors.getSelector(0, &II);
+}
+
 namespace {
   
 class VISIBILITY_HIDDEN RefVal {
@@ -564,26 +569,39 @@
   
   BindingsPrinter Printer;
   
+  Selector RetainSelector;
+  Selector ReleaseSelector;
+
   // Private methods.
-    
+
   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, RefVal V, ArgEffect E,
-                     RefVal::Kind& hasError);
- 
+                     RefVal::Kind& hasErr);
+  
+  void ProcessError(ExplodedNodeSet<ValueState>& Dst,
+                    GRStmtNodeBuilder<ValueState>& Builder,
+                    Expr* NodeExpr, Expr* ErrorExpr,                        
+                    ExplodedNode<ValueState>* Pred,
+                    ValueState* St,
+                    RefVal::Kind hasErr);
   
 public:
-  CFRefCount(ASTContext& Ctx) : Summaries(Ctx) {}
+  CFRefCount(ASTContext& Ctx)
+    : Summaries(Ctx),
+      RetainSelector(GetUnarySelector("retain", Ctx)),
+      ReleaseSelector(GetUnarySelector("release", Ctx)) {}
+  
   virtual ~CFRefCount() {}
   
   virtual void RegisterChecks(GRExprEngine& Eng);
@@ -661,6 +679,29 @@
   return Summ ? Summ->getRet() : RetEffect::MakeNoRet();
 }
 
+void CFRefCount::ProcessError(ExplodedNodeSet<ValueState>& Dst,
+                              GRStmtNodeBuilder<ValueState>& Builder,
+                              Expr* NodeExpr, Expr* ErrorExpr,                        
+                              ExplodedNode<ValueState>* Pred,
+                              ValueState* St,
+                              RefVal::Kind hasErr) {
+  Builder.BuildSinks = true;
+  GRExprEngine::NodeTy* N  = Builder.MakeNode(Dst, NodeExpr, Pred, St);
+
+  if (!N) return;
+    
+  switch (hasErr) {
+    default: assert(false);
+    case RefVal::ErrorUseAfterRelease:
+      UseAfterReleases[N] = ErrorExpr;
+      break;
+      
+    case RefVal::ErrorReleaseNotOwned:
+      ReleasesNotOwned[N] = ErrorExpr;
+      break;
+  }
+}
+
 void CFRefCount::EvalCall(ExplodedNodeSet<ValueState>& Dst,
                           GRExprEngine& Eng,
                           GRStmtNodeBuilder<ValueState>& Builder,
@@ -686,7 +727,7 @@
   // Evaluate the effects of the call.
   
   ValueState StVals = *St;
-  RefVal::Kind hasError = (RefVal::Kind) 0;
+  RefVal::Kind hasErr = (RefVal::Kind) 0;
  
   // This function has a summary.  Evaluate the effect of the arguments.
   
@@ -704,10 +745,10 @@
       RefBindings B = GetRefBindings(StVals);      
       
       if (RefBindings::TreeTy* T = B.SlimFind(Sym)) {
-        B = Update(B, Sym, T->getValue().second, GetArgE(Summ, idx), hasError);
+        B = Update(B, Sym, T->getValue().second, GetArgE(Summ, idx), hasErr);
         SetRefBindings(StVals, B);
         
-        if (hasError) {
+        if (hasErr) {
           ErrorExpr = *I;
           break;
         }
@@ -720,34 +761,17 @@
       StateMgr.Unbind(StVals, cast<LVal>(V));
     }
   }    
+  
+  St = StateMgr.getPersistentState(StVals);
     
-  if (hasError) {
-    St = StateMgr.getPersistentState(StVals);
-    
-    Builder.BuildSinks = true;
-    GRExprEngine::NodeTy* N  = Builder.MakeNode(Dst, CE, Pred, St);
-
-    if (N) {
-      switch (hasError) {
-        default: assert(false);
-        case RefVal::ErrorUseAfterRelease:
-          UseAfterReleases[N] = ErrorExpr;
-          break;
-          
-        case RefVal::ErrorReleaseNotOwned:
-          ReleasesNotOwned[N] = ErrorExpr;
-          break;
-      }
-    }
-    
+  if (hasErr) {
+    ProcessError(Dst, Builder, CE, ErrorExpr, Pred, St, hasErr);
     return;
   }
-
+    
   // Finally, consult the summary for the return value.
   
   RetEffect RE = GetRetE(Summ);
-  St = StateMgr.getPersistentState(StVals);
-
   
   switch (RE.getKind()) {
     default:
@@ -831,15 +855,65 @@
                                         ObjCMessageExpr* ME,
                                         ExplodedNode<ValueState>* Pred) {
     
-  // Handle "toll-free bridging."  Eventually we will want to track the
-  // underlying object type associated.
+  // Handle "toll-free bridging" of calls to "Release" and "Retain".
+  
+  // FIXME: track the underlying object type associated so that we can
+  //  flag illegal uses of toll-free bridging (or at least handle it
+  //  at casts).
   
   Selector S = ME->getSelector();
   
   if (!S.isUnarySelector())
     return true;
 
-  return true; // FIXME: change to return false when more is implemented.
+  Expr* Receiver = ME->getReceiver();
+  
+  if (!Receiver)
+    return true;
+
+  // Check if we are calling "Retain" or "Release".
+  
+  bool isRetain = false;
+  
+  if (S == RetainSelector)
+    isRetain = true;
+  else if (S != ReleaseSelector)
+    return true;
+  
+  // We have "Retain" or "Release".  Get the reference binding.
+  
+  ValueStateManager& StateMgr = Eng.getStateManager();
+  ValueState* St = Builder.GetState(Pred);
+  RVal V = StateMgr.GetRVal(St, Receiver);
+  
+  if (!isa<lval::SymbolVal>(V))
+    return true;
+
+  SymbolID Sym = cast<lval::SymbolVal>(V).getSymbol();
+  RefBindings B = GetRefBindings(*St);
+  
+  RefBindings::TreeTy* T = B.SlimFind(Sym);
+  
+  if (!T)
+    return true;
+  
+  RefVal::Kind hasErr = (RefVal::Kind) 0;
+  B = Update(B, Sym, T->getValue().second, isRetain ? IncRef : DecRef, hasErr);
+
+  // Create a new state with the updated bindings.
+  
+  ValueState StVals = *St;
+  SetRefBindings(StVals, B);
+  St = StateMgr.getPersistentState(StVals);
+  
+  // Create an error node if it exists.
+  
+  if (hasErr)
+    ProcessError(Dst, Builder, ME, Receiver, Pred, St, hasErr);
+  else
+    Builder.MakeNode(Dst, ME, Pred, St);
+
+  return false;
 }
 
 // End-of-path.
@@ -864,7 +938,7 @@
 
 CFRefCount::RefBindings CFRefCount::Update(RefBindings B, SymbolID sym,
                                            RefVal V, ArgEffect E,
-                                           RefVal::Kind& hasError) {
+                                           RefVal::Kind& hasErr) {
   
   // FIXME: This dispatch can potentially be sped up by unifiying it into
   //  a single switch statement.  Opt for simplicity for now.
@@ -876,7 +950,7 @@
     case DoNothing:
       if (V.getKind() == RefVal::Released) {
         V = RefVal::makeUseAfterRelease();        
-        hasError = V.getKind();
+        hasErr = V.getKind();
         break;
       }
       
@@ -897,7 +971,7 @@
           
         case RefVal::Released:
           V = RefVal::makeUseAfterRelease();
-          hasError = V.getKind();
+          hasErr = V.getKind();
           break;
       }
       
@@ -921,7 +995,7 @@
             V = RefVal::makeNotOwned(Count);
           else {
             V = RefVal::makeReleaseNotOwned();
-            hasError = V.getKind();
+            hasErr = V.getKind();
           }
           
           break;
@@ -929,7 +1003,7 @@
 
         case RefVal::Released:
           V = RefVal::makeUseAfterRelease();
-          hasError = V.getKind();
+          hasErr = V.getKind();
           break;          
       }
       





More information about the cfe-commits mailing list