[cfe-commits] r138309 - in /cfe/trunk: include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h lib/StaticAnalyzer/Core/CFRefCount.cpp

Jordy Rose jediknil at belkadan.com
Mon Aug 22 16:48:23 PDT 2011


Author: jrose
Date: Mon Aug 22 18:48:23 2011
New Revision: 138309

URL: http://llvm.org/viewvc/llvm-project?rev=138309&view=rev
Log:
[analyzer] Migrate the handling of retain-count-related RetEffects and ArgEffects from CFRefCount to RetainReleaseChecker. No intended functionality change.

Modified:
    cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h
    cfe/trunk/lib/StaticAnalyzer/Core/CFRefCount.cpp

Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h?rev=138309&r1=138308&r2=138309&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h Mon Aug 22 18:48:23 2011
@@ -186,6 +186,12 @@
   bool isCXXCall() const {
     return CallE && isa<CXXMemberCallExpr>(CallE);
   }
+
+  const Expr *getOriginExpr() const {
+    if (isFunctionCall())
+      return CallE;
+    return Msg.getOriginExpr();
+  }
   
   SVal getFunctionCallee() const;
   SVal getCXXCallee() const;

Modified: cfe/trunk/lib/StaticAnalyzer/Core/CFRefCount.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/CFRefCount.cpp?rev=138309&r1=138308&r2=138309&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/CFRefCount.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/CFRefCount.cpp Mon Aug 22 18:48:23 2011
@@ -1633,15 +1633,6 @@
                              ArgEffect E,
                              RefVal::Kind& hasErr);
 
-  void ProcessNonLeakError(ExplodedNodeSet &Dst,
-                           StmtNodeBuilder& Builder,
-                           const Expr *NodeExpr,
-                           SourceRange ErrorRange,
-                           ExplodedNode *Pred,
-                           const ProgramState *St,
-                           RefVal::Kind hasErr,
-                           SymbolRef Sym);
-
   const ProgramState *HandleSymbolDeath(const ProgramState * state,
                                         SymbolRef sid,
                                         RefVal V,
@@ -2547,11 +2538,6 @@
                              ExplodedNode *Pred,
                              const ProgramState *state) {
 
-  // Evaluate the effect of the arguments.
-  RefVal::Kind hasErr = (RefVal::Kind) 0;
-  SourceRange ErrorRange;
-  SymbolRef ErrorSym = 0;
-
   SmallVector<const MemRegion*, 10> RegionsToInvalidate;
   
   // Use RAII to make sure the whitelist is properly cleared.
@@ -2579,80 +2565,62 @@
   
   for (unsigned idx = 0, e = callOrMsg.getNumArgs(); idx != e; ++idx) {
     SVal V = callOrMsg.getArgSValAsScalarOrLoc(idx);
-    SymbolRef Sym = V.getAsLocSymbol();
 
-    if (Sym)
-      if (RefBindings::data_type* T = state->get<RefBindings>(Sym)) {
-        WhitelistedSymbols.insert(Sym);
-        state = Update(state, Sym, *T, Summ.getArg(idx), hasErr);
-        if (hasErr) {
-          ErrorRange = callOrMsg.getArgSourceRange(idx);
-          ErrorSym = Sym;
-          break;
-        }
-      }
+    // If we are passing a location wrapped as an integer, unwrap it and
+    // invalidate the values referred by the location.
+    if (nonloc::LocAsInteger *Wrapped = dyn_cast<nonloc::LocAsInteger>(&V))
+      V = Wrapped->getLoc();
+    else if (!isa<Loc>(V))
+      continue;
 
-  tryAgain:
-    if (isa<Loc>(V)) {
-      if (loc::MemRegionVal* MR = dyn_cast<loc::MemRegionVal>(&V)) {
-        if (Summ.getArg(idx) == DoNothingByRef)
-          continue;
+    if (SymbolRef Sym = V.getAsLocSymbol())
+      if (state->get<RefBindings>(Sym))
+        WhitelistedSymbols.insert(Sym);
 
-        // Invalidate the value of the variable passed by reference.
-        const MemRegion *R = MR->getRegion();
+    if (const MemRegion *R = V.getAsRegion()) {
+      // Invalidate the value of the variable passed by reference.
 
-        // Are we dealing with an ElementRegion?  If the element type is
-        // a basic integer type (e.g., char, int) and the underying region
-        // is a variable region then strip off the ElementRegion.
-        // FIXME: We really need to think about this for the general case
-        //   as sometimes we are reasoning about arrays and other times
-        //   about (char*), etc., is just a form of passing raw bytes.
-        //   e.g., void *p = alloca(); foo((char*)p);
-        if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
-          // Checking for 'integral type' is probably too promiscuous, but
-          // we'll leave it in for now until we have a systematic way of
-          // handling all of these cases.  Eventually we need to come up
-          // with an interface to StoreManager so that this logic can be
-          // approriately delegated to the respective StoreManagers while
-          // still allowing us to do checker-specific logic (e.g.,
-          // invalidating reference counts), probably via callbacks.
-          if (ER->getElementType()->isIntegralOrEnumerationType()) {
-            const MemRegion *superReg = ER->getSuperRegion();
-            if (isa<VarRegion>(superReg) || isa<FieldRegion>(superReg) ||
-                isa<ObjCIvarRegion>(superReg))
-              R = cast<TypedRegion>(superReg);
-          }
-          // FIXME: What about layers of ElementRegions?
+      // Are we dealing with an ElementRegion?  If the element type is
+      // a basic integer type (e.g., char, int) and the underying region
+      // is a variable region then strip off the ElementRegion.
+      // FIXME: We really need to think about this for the general case
+      //   as sometimes we are reasoning about arrays and other times
+      //   about (char*), etc., is just a form of passing raw bytes.
+      //   e.g., void *p = alloca(); foo((char*)p);
+      if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
+        // Checking for 'integral type' is probably too promiscuous, but
+        // we'll leave it in for now until we have a systematic way of
+        // handling all of these cases.  Eventually we need to come up
+        // with an interface to StoreManager so that this logic can be
+        // approriately delegated to the respective StoreManagers while
+        // still allowing us to do checker-specific logic (e.g.,
+        // invalidating reference counts), probably via callbacks.
+        if (ER->getElementType()->isIntegralOrEnumerationType()) {
+          const MemRegion *superReg = ER->getSuperRegion();
+          if (isa<VarRegion>(superReg) || isa<FieldRegion>(superReg) ||
+              isa<ObjCIvarRegion>(superReg))
+            R = cast<TypedRegion>(superReg);
         }
-
-        // Mark this region for invalidation.  We batch invalidate regions
-        // below for efficiency.
-        RegionsToInvalidate.push_back(R);
-        continue;
-      }
-      else {
-        // Nuke all other arguments passed by reference.
-        // FIXME: is this necessary or correct? This handles the non-Region
-        //  cases.  Is it ever valid to store to these?
-        state = state->unbindLoc(cast<Loc>(V));
+        // FIXME: What about layers of ElementRegions?
       }
-    }
-    else if (isa<nonloc::LocAsInteger>(V)) {
-      // If we are passing a location wrapped as an integer, unwrap it and
-      // invalidate the values referred by the location.
-      V = cast<nonloc::LocAsInteger>(V).getLoc();
-      goto tryAgain;
+
+      // Mark this region for invalidation.  We batch invalidate regions
+      // below for efficiency.
+      RegionsToInvalidate.push_back(R);
+    } else {
+      // Nuke all other arguments passed by reference.
+      // FIXME: is this necessary or correct? This handles the non-Region
+      //  cases.  Is it ever valid to store to these?
+      state = state->unbindLoc(cast<Loc>(V));
     }
   }
 
   // Block calls result in all captured values passed-via-reference to be
   // invalidated.
-  if (const BlockDataRegion *BR = dyn_cast_or_null<BlockDataRegion>(Callee)) {
+  if (const BlockDataRegion *BR = dyn_cast_or_null<BlockDataRegion>(Callee))
     RegionsToInvalidate.push_back(BR);
-  }
 
-  // Invalidate regions we designed for invalidation use the batch invalidation
-  // API.
+  // Invalidate designated regions using the batch invalidation API.
 
   // FIXME: We can have collisions on the conjured symbol if the
   //  expression *I also creates conjured symbols.  We probably want
@@ -2673,92 +2641,7 @@
                              /* invalidateGlobals = */
                              Eng.doesInvalidateGlobals(callOrMsg));
 
-  // Evaluate the effect on the message receiver.
-  if (!ErrorRange.isValid() && Receiver) {
-    SymbolRef Sym = Receiver.getSValAsScalarOrLoc(state).getAsLocSymbol();
-    if (Sym) {
-      if (const RefVal* T = state->get<RefBindings>(Sym)) {
-        state = Update(state, Sym, *T, Summ.getReceiverEffect(), hasErr);
-        if (hasErr) {
-          ErrorRange = Receiver.getSourceRange();
-          ErrorSym = Sym;
-        }
-      }
-    }
-  }
-
-  // Process any errors.
-  if (hasErr) {
-    ProcessNonLeakError(Dst, Builder, Ex, ErrorRange, Pred, state,
-                        hasErr, ErrorSym);
-    return;
-  }
-
-  // Consult the summary for the return value.
-  RetEffect RE = Summ.getRetEffect();
-
-  if (RE.getKind() == RetEffect::OwnedWhenTrackedReceiver) {
-    bool found = false;
-    if (Receiver) {
-      SVal V = Receiver.getSValAsScalarOrLoc(state);
-      if (SymbolRef Sym = V.getAsLocSymbol())
-        if (state->get<RefBindings>(Sym)) {
-          found = true;
-          RE = Summaries.getObjAllocRetEffect();
-        }
-    } // FIXME: Otherwise, this is a send-to-super instance message.
-    if (!found)
-      RE = RetEffect::MakeNoRet();
-  }
-
-  switch (RE.getKind()) {
-    default:
-      llvm_unreachable("Unhandled RetEffect."); break;
-
-    case RetEffect::NoRet:
-      // No work necessary.
-      break;
-
-    case RetEffect::OwnedAllocatedSymbol:
-    case RetEffect::OwnedSymbol:
-      if (SymbolRef Sym = state->getSVal(Ex).getAsSymbol()) {
-        // Use the result type from callOrMsg as it automatically adjusts
-        // for methods/functions that return references.
-        QualType ResultTy = callOrMsg.getResultType(Eng.getContext());
-        state = state->set<RefBindings>(Sym, RefVal::makeOwned(RE.getObjKind(),
-                                                               ResultTy));
-      }
-
-      // FIXME: Add a flag to the checker where allocations are assumed to
-      // *not* fail. (The code below is out-of-date, though.)
-#if 0
-      if (RE.getKind() == RetEffect::OwnedAllocatedSymbol) {
-        bool isFeasible;
-        state = state.assume(loc::SymbolVal(Sym), true, isFeasible);
-        assert(isFeasible && "Cannot assume fresh symbol is non-null.");
-      }
-#endif
-
-      break;
-
-    case RetEffect::GCNotOwnedSymbol:
-    case RetEffect::ARCNotOwnedSymbol:
-    case RetEffect::NotOwnedSymbol: {
-      if (SymbolRef Sym = state->getSVal(Ex).getAsSymbol()) {
-        // Use GetReturnType in order to give [NSFoo alloc] the type NSFoo *.
-        QualType ResultTy = GetReturnType(Ex, Eng.getContext());
-        state =
-          state->set<RefBindings>(Sym, RefVal::makeNotOwned(RE.getObjKind(),
-                                                            ResultTy));
-      }
-      break;
-    }
-  }
-
-  ExplodedNode *NewNode = Builder.MakeNode(Dst, Ex, Pred, state);
-
-  // Annotate the edge with summary we used.
-  if (NewNode) SummaryLog[NewNode] = &Summ;
+  Builder.MakeNode(Dst, Ex, Pred, state);
 }
 
 
@@ -3320,44 +3203,6 @@
   Builder.MakeNode(Dst, S, Pred, state);
 }
 
-void CFRefCount::ProcessNonLeakError(ExplodedNodeSet &Dst,
-                                     StmtNodeBuilder& Builder,
-                                     const Expr *NodeExpr, 
-                                     SourceRange ErrorRange,
-                                     ExplodedNode *Pred,
-                                     const ProgramState *St,
-                                     RefVal::Kind hasErr, SymbolRef Sym) {
-  Builder.BuildSinks = true;
-  ExplodedNode *N  = Builder.MakeNode(Dst, NodeExpr, Pred, St);
-
-  if (!N)
-    return;
-
-  CFRefBug *BT = 0;
-
-  switch (hasErr) {
-    default:
-      assert(false && "Unhandled error.");
-      return;
-    case RefVal::ErrorUseAfterRelease:
-      BT = static_cast<CFRefBug*>(useAfterRelease);
-      break;
-    case RefVal::ErrorReleaseNotOwned:
-      BT = static_cast<CFRefBug*>(releaseNotOwned);
-      break;
-    case RefVal::ErrorDeallocGC:
-      BT = static_cast<CFRefBug*>(deallocGC);
-      break;
-    case RefVal::ErrorDeallocNotOwned:
-      BT = static_cast<CFRefBug*>(deallocNotOwned);
-      break;
-  }
-
-  CFRefReport *report = new CFRefReport(*BT, *this, N, Sym);
-  report->addRange(ErrorRange);
-  BR->EmitReport(report);
-}
-
 //===----------------------------------------------------------------------===//
 // Pieces of the retain/release checker implemented using a CheckerVisitor.
 // More pieces of the retain/release checker will be migrated to this interface
@@ -3369,6 +3214,8 @@
   : public Checker< check::Bind,
                     check::PostStmt<BlockExpr>,
                     check::PostStmt<CastExpr>,
+                    check::PostStmt<CallExpr>,
+                    check::PostObjCMessage,
                     check::RegionChanges,
                     eval::Assume,
                     eval::Call > {
@@ -3377,6 +3224,11 @@
   void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const;
   void checkPostStmt(const CastExpr *CE, CheckerContext &C) const;
 
+  void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
+  void checkPostObjCMessage(const ObjCMessage &Msg, CheckerContext &C) const;
+  void checkSummary(const RetainSummary &Summ, const CallOrObjCMessage &Call,
+                    InstanceReceiver Receiver, CheckerContext &C) const;
+
   bool evalCall(const CallExpr *CE, CheckerContext &C) const;
 
   const ProgramState *evalAssume(const ProgramState *state, SVal Cond,
@@ -3390,6 +3242,11 @@
   bool wantsRegionChangeUpdate(const ProgramState *state) const {
     return true;
   }
+
+  void processNonLeakError(const ProgramState *St, SourceRange ErrorRange,
+                           RefVal::Kind ErrorKind, SymbolRef Sym,
+                           CheckerContext &C) const;
+
 };
 } // end anonymous namespace
 
@@ -3579,6 +3436,224 @@
   C.generateNode(state);
 }
 
+void RetainReleaseChecker::checkPostStmt(const CallExpr *CE,
+                                         CheckerContext &C) const {
+  // FIXME: This goes away once the RetainSummaryManager moves to the checker.
+  CFRefCount &TF = static_cast<CFRefCount&>(C.getEngine().getTF());
+  RetainSummaryManager &Summaries = TF.Summaries;
+
+  // Get the callee.
+  const ProgramState *state = C.getState();
+  const Expr *Callee = CE->getCallee();
+  SVal L = state->getSVal(Callee);
+
+  RetainSummary *Summ = 0;
+
+  // FIXME: Better support for blocks.  For now we stop tracking anything
+  // that is passed to blocks.
+  // FIXME: Need to handle variables that are "captured" by the block.
+  if (dyn_cast_or_null<BlockDataRegion>(L.getAsRegion())) {
+    Summ = Summaries.getPersistentStopSummary();
+  } else if (const FunctionDecl *FD = L.getAsFunctionDecl()) {
+    Summ = Summaries.getSummary(FD);
+  } else if (const CXXMemberCallExpr *me = dyn_cast<CXXMemberCallExpr>(CE)) {
+    if (const CXXMethodDecl *MD = me->getMethodDecl())
+      Summ = Summaries.getSummary(MD);
+  }
+
+  // If we didn't get a summary, this function doesn't affect retain counts.
+  if (!Summ)
+    return;
+
+  checkSummary(*Summ, CallOrObjCMessage(CE, state), InstanceReceiver(), C);
+}
+
+void RetainReleaseChecker::checkPostObjCMessage(const ObjCMessage &Msg, 
+                                                CheckerContext &C) const {
+  // FIXME: This goes away once the RetainSummaryManager moves to the checker.
+  CFRefCount &TF = static_cast<CFRefCount&>(C.getEngine().getTF());
+  RetainSummaryManager &Summaries = TF.Summaries;
+
+  const ProgramState *state = C.getState();
+  ExplodedNode *Pred = C.getPredecessor();
+
+  RetainSummary *Summ;
+  if (Msg.isInstanceMessage()) {
+    const LocationContext *LC = Pred->getLocationContext();
+    Summ = Summaries.getInstanceMethodSummary(Msg, state, LC);
+  } else {
+    Summ = Summaries.getClassMethodSummary(Msg);    
+  }
+
+  // If we didn't get a summary, this message doesn't affect retain counts.
+  if (!Summ)
+    return;
+
+  checkSummary(*Summ, CallOrObjCMessage(Msg, state),
+               InstanceReceiver(Msg, Pred->getLocationContext()), C);
+}
+
+void RetainReleaseChecker::checkSummary(const RetainSummary &Summ,
+                                        const CallOrObjCMessage &CallOrMsg,
+                                        InstanceReceiver Receiver,
+                                        CheckerContext &C) const {
+  // FIXME: This goes away once the Update() method moves to the checker.
+  CFRefCount &TF = static_cast<CFRefCount&>(C.getEngine().getTF());
+
+  const ProgramState *state = C.getState();
+
+  // Evaluate the effect of the arguments.
+  RefVal::Kind hasErr = (RefVal::Kind) 0;
+  SourceRange ErrorRange;
+  SymbolRef ErrorSym = 0;
+
+  for (unsigned idx = 0, e = CallOrMsg.getNumArgs(); idx != e; ++idx) {
+    SVal V = CallOrMsg.getArgSValAsScalarOrLoc(idx);
+
+    if (SymbolRef Sym = V.getAsLocSymbol()) {
+      if (RefBindings::data_type *T = state->get<RefBindings>(Sym)) {
+        state = TF.Update(state, Sym, *T, Summ.getArg(idx), hasErr);
+        if (hasErr) {
+          ErrorRange = CallOrMsg.getArgSourceRange(idx);
+          ErrorSym = Sym;
+          break;
+        }
+      }
+    }
+  }
+
+  // Evaluate the effect on the message receiver.
+  bool ReceiverIsTracked = false;
+  if (!hasErr && Receiver) {
+    if (SymbolRef Sym = Receiver.getSValAsScalarOrLoc(state).getAsLocSymbol()) {
+      if (const RefVal *T = state->get<RefBindings>(Sym)) {
+        ReceiverIsTracked = true;
+        state = TF.Update(state, Sym, *T, Summ.getReceiverEffect(), hasErr);
+        if (hasErr) {
+          ErrorRange = Receiver.getSourceRange();
+          ErrorSym = Sym;
+        }
+      }
+    }
+  }
+
+  // Process any errors.
+  if (hasErr) {
+    processNonLeakError(state, ErrorRange, hasErr, ErrorSym, C);
+    return;
+  }
+
+  // Consult the summary for the return value.
+  RetEffect RE = Summ.getRetEffect();
+
+  if (RE.getKind() == RetEffect::OwnedWhenTrackedReceiver) {
+    if (ReceiverIsTracked)
+      RE = TF.Summaries.getObjAllocRetEffect();
+    else
+      RE = RetEffect::MakeNoRet();
+  }
+
+  switch (RE.getKind()) {
+    default:
+      llvm_unreachable("Unhandled RetEffect."); break;
+
+    case RetEffect::NoRet:
+      // No work necessary.
+      break;
+
+    case RetEffect::OwnedAllocatedSymbol:
+    case RetEffect::OwnedSymbol: {
+      SymbolRef Sym = state->getSVal(CallOrMsg.getOriginExpr()).getAsSymbol();
+      if (!Sym)
+        break;
+
+      // Use the result type from callOrMsg as it automatically adjusts
+      // for methods/functions that return references.
+      QualType ResultTy = CallOrMsg.getResultType(C.getASTContext());
+      state = state->set<RefBindings>(Sym, RefVal::makeOwned(RE.getObjKind(),
+                                                             ResultTy));
+
+      // FIXME: Add a flag to the checker where allocations are assumed to
+      // *not* fail. (The code below is out-of-date, though.)
+#if 0
+      if (RE.getKind() == RetEffect::OwnedAllocatedSymbol) {
+        bool isFeasible;
+        state = state.assume(loc::SymbolVal(Sym), true, isFeasible);
+        assert(isFeasible && "Cannot assume fresh symbol is non-null.");
+      }
+#endif
+
+      break;
+    }
+
+    case RetEffect::GCNotOwnedSymbol:
+    case RetEffect::ARCNotOwnedSymbol:
+    case RetEffect::NotOwnedSymbol: {
+      const Expr *Ex = CallOrMsg.getOriginExpr();
+      SymbolRef Sym = state->getSVal(Ex).getAsSymbol();
+      if (!Sym)
+        break;
+
+      // Use GetReturnType in order to give [NSFoo alloc] the type NSFoo *.
+      QualType ResultTy = GetReturnType(Ex, C.getASTContext());
+      state = state->set<RefBindings>(Sym, RefVal::makeNotOwned(RE.getObjKind(),
+                                                                ResultTy));
+      break;
+    }
+  }
+
+  // This check is actually necessary; otherwise the statement builder thinks
+  // we've hit a previously-found path.
+  // Normally addTransition takes care of this, but we want the node pointer.
+  ExplodedNode *NewNode;
+  if (state == C.getState()) {
+    NewNode = C.getPredecessor();
+  } else {
+    NewNode = C.generateNode(state);
+  }
+
+  // Annotate the edge with summary we used.
+  // FIXME: The summary log should live on RetainReleaseChecker.
+  if (NewNode) TF.SummaryLog[NewNode] = &Summ;
+}
+
+void RetainReleaseChecker::processNonLeakError(const ProgramState *St,
+                                               SourceRange ErrorRange,
+                                               RefVal::Kind ErrorKind,
+                                               SymbolRef Sym,
+                                               CheckerContext &C) const {
+  ExplodedNode *N = C.generateSink(St);
+  if (!N)
+    return;
+
+  // 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&>(C.getEngine().getTF());
+
+  CFRefBug *BT;
+  switch (ErrorKind) {
+    default:
+      llvm_unreachable("Unhandled error.");
+      return;
+    case RefVal::ErrorUseAfterRelease:
+      BT = static_cast<CFRefBug*>(TF.useAfterRelease);
+      break;
+    case RefVal::ErrorReleaseNotOwned:
+      BT = static_cast<CFRefBug*>(TF.releaseNotOwned);
+      break;
+    case RefVal::ErrorDeallocGC:
+      BT = static_cast<CFRefBug*>(TF.deallocGC);
+      break;
+    case RefVal::ErrorDeallocNotOwned:
+      BT = static_cast<CFRefBug*>(TF.deallocNotOwned);
+      break;
+  }
+
+  CFRefReport *report = new CFRefReport(*BT, TF, N, Sym);
+  report->addRange(ErrorRange);
+  C.EmitReport(report);
+}
+
 bool RetainReleaseChecker::evalCall(const CallExpr *CE,
                                     CheckerContext &C) const {
   // Get the callee. We're only interested in simple C functions.
@@ -3635,19 +3710,25 @@
   }
   state = state->BindExpr(CE, RetVal, false);
 
-  // FIXME: This will improve when RetainSummariesManager moves to the checker.
-  // Really we only want to handle ArgEffects and RetEffects; the arguments to
-  // CFRetain and CFMakeCollectable don't need to be invalidated.
-  // All of this can go away once the effects are handled in a post-call check.
-  CFRefCount &TF = static_cast<CFRefCount&>(C.getEngine().getTF());
-  RetainSummary *Summ = TF.Summaries.getSummary(FD);
-  assert(Summ);
+  // FIXME: This should not be necessary, but otherwise the argument seems to be
+  // considered alive during the next statement.
+  if (const MemRegion *ArgRegion = RetVal.getAsRegion()) {
+    // Save the refcount status of the argument.
+    SymbolRef Sym = RetVal.getAsLocSymbol();
+    RefBindings::data_type *Binding = 0;
+    if (Sym)
+      Binding = state->get<RefBindings>(Sym);
 
-  TF.evalSummary(C.getNodeSet(), C.getEngine(), C.getNodeBuilder(), CE,
-                 CallOrObjCMessage(CE, C.getState()),
-                 InstanceReceiver(), *Summ, L.getAsRegion(),
-                 C.getPredecessor(), state);
+    // Invalidate the argument region.
+    unsigned Count = C.getNodeBuilder().getCurrentBlockCount();
+    state = state->invalidateRegion(ArgRegion, CE, Count);
 
+    // Restore the refcount status of the argument.
+    if (Binding)
+      state = state->set<RefBindings>(Sym, *Binding);
+  }
+
+  C.addTransition(state);
   return true;
 }
 





More information about the cfe-commits mailing list