| // CFRefCount.cpp - Transfer functions for tracking simple values -*- 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 the methods for CFRefCount, which implements | 
 | //  a reference count checker for Core Foundation (Mac OS X). | 
 | // | 
 | //===----------------------------------------------------------------------===// | 
 |  | 
 | #include "clang/AST/DeclObjC.h" | 
 | #include "clang/AST/StmtVisitor.h" | 
 | #include "clang/Basic/LangOptions.h" | 
 | #include "clang/Basic/SourceManager.h" | 
 | #include "clang/Checker/BugReporter/BugType.h" | 
 | #include "clang/Checker/BugReporter/PathDiagnostic.h" | 
 | #include "clang/Checker/Checkers/LocalCheckers.h" | 
 | #include "clang/Checker/DomainSpecific/CocoaConventions.h" | 
 | #include "clang/Checker/PathSensitive/CheckerVisitor.h" | 
 | #include "clang/Checker/PathSensitive/GRExprEngineBuilders.h" | 
 | #include "clang/Checker/PathSensitive/GRStateTrait.h" | 
 | #include "clang/Checker/PathSensitive/GRTransferFuncs.h" | 
 | #include "clang/Checker/PathSensitive/SymbolManager.h" | 
 | #include "llvm/ADT/DenseMap.h" | 
 | #include "llvm/ADT/FoldingSet.h" | 
 | #include "llvm/ADT/ImmutableList.h" | 
 | #include "llvm/ADT/ImmutableMap.h" | 
 | #include "llvm/ADT/STLExtras.h" | 
 | #include "llvm/ADT/StringExtras.h" | 
 | #include <stdarg.h> | 
 |  | 
 | using namespace clang; | 
 | using llvm::StringRef; | 
 | using llvm::StrInStrNoCase; | 
 |  | 
 | static const ObjCMethodDecl* | 
 | ResolveToInterfaceMethodDecl(const ObjCMethodDecl *MD) { | 
 |   ObjCInterfaceDecl *ID = | 
 |     const_cast<ObjCInterfaceDecl*>(MD->getClassInterface()); | 
 |  | 
 |   return MD->isInstanceMethod() | 
 |          ? ID->lookupInstanceMethod(MD->getSelector()) | 
 |          : ID->lookupClassMethod(MD->getSelector()); | 
 | } | 
 |  | 
 | namespace { | 
 | class GenericNodeBuilder { | 
 |   GRStmtNodeBuilder *SNB; | 
 |   Stmt *S; | 
 |   const void *tag; | 
 |   GREndPathNodeBuilder *ENB; | 
 | public: | 
 |   GenericNodeBuilder(GRStmtNodeBuilder &snb, Stmt *s, | 
 |                      const void *t) | 
 |   : SNB(&snb), S(s), tag(t), ENB(0) {} | 
 |  | 
 |   GenericNodeBuilder(GREndPathNodeBuilder &enb) | 
 |   : SNB(0), S(0), tag(0), ENB(&enb) {} | 
 |  | 
 |   ExplodedNode *MakeNode(const GRState *state, ExplodedNode *Pred) { | 
 |     if (SNB) | 
 |       return SNB->generateNode(PostStmt(S, Pred->getLocationContext(), tag), | 
 |                                state, Pred); | 
 |  | 
 |     assert(ENB); | 
 |     return ENB->generateNode(state, Pred); | 
 |   } | 
 | }; | 
 | } // end anonymous namespace | 
 |  | 
 | //===----------------------------------------------------------------------===// | 
 | // Primitives used for constructing summaries for function/method calls. | 
 | //===----------------------------------------------------------------------===// | 
 |  | 
 | /// ArgEffect is used to summarize a function/method call's effect on a | 
 | /// particular argument. | 
 | enum ArgEffect { Autorelease, Dealloc, DecRef, DecRefMsg, DoNothing, | 
 |                  DoNothingByRef, IncRefMsg, IncRef, MakeCollectable, MayEscape, | 
 |                  NewAutoreleasePool, SelfOwn, StopTracking }; | 
 |  | 
 | namespace llvm { | 
 | template <> struct FoldingSetTrait<ArgEffect> { | 
 | static inline void Profile(const ArgEffect X, FoldingSetNodeID& ID) { | 
 |   ID.AddInteger((unsigned) X); | 
 | } | 
 | }; | 
 | } // end llvm namespace | 
 |  | 
 | /// ArgEffects summarizes the effects of a function/method call on all of | 
 | /// its arguments. | 
 | typedef llvm::ImmutableMap<unsigned,ArgEffect> ArgEffects; | 
 |  | 
 | namespace { | 
 |  | 
 | ///  RetEffect is used to summarize a function/method call's behavior with | 
 | ///  respect to its return value. | 
 | class RetEffect { | 
 | public: | 
 |   enum Kind { NoRet, Alias, OwnedSymbol, OwnedAllocatedSymbol, | 
 |               NotOwnedSymbol, GCNotOwnedSymbol, ReceiverAlias, | 
 |               OwnedWhenTrackedReceiver }; | 
 |  | 
 |   enum ObjKind { CF, ObjC, AnyObj }; | 
 |  | 
 | private: | 
 |   Kind K; | 
 |   ObjKind O; | 
 |   unsigned index; | 
 |  | 
 |   RetEffect(Kind k, unsigned idx = 0) : K(k), O(AnyObj), index(idx) {} | 
 |   RetEffect(Kind k, ObjKind o) : K(k), O(o), index(0) {} | 
 |  | 
 | public: | 
 |   Kind getKind() const { return K; } | 
 |  | 
 |   ObjKind getObjKind() const { return O; } | 
 |  | 
 |   unsigned getIndex() const { | 
 |     assert(getKind() == Alias); | 
 |     return index; | 
 |   } | 
 |  | 
 |   bool isOwned() const { | 
 |     return K == OwnedSymbol || K == OwnedAllocatedSymbol || | 
 |            K == OwnedWhenTrackedReceiver; | 
 |   } | 
 |  | 
 |   static RetEffect MakeOwnedWhenTrackedReceiver() { | 
 |     return RetEffect(OwnedWhenTrackedReceiver, ObjC); | 
 |   } | 
 |  | 
 |   static RetEffect MakeAlias(unsigned Idx) { | 
 |     return RetEffect(Alias, Idx); | 
 |   } | 
 |   static RetEffect MakeReceiverAlias() { | 
 |     return RetEffect(ReceiverAlias); | 
 |   } | 
 |   static RetEffect MakeOwned(ObjKind o, bool isAllocated = false) { | 
 |     return RetEffect(isAllocated ? OwnedAllocatedSymbol : OwnedSymbol, o); | 
 |   } | 
 |   static RetEffect MakeNotOwned(ObjKind o) { | 
 |     return RetEffect(NotOwnedSymbol, o); | 
 |   } | 
 |   static RetEffect MakeGCNotOwned() { | 
 |     return RetEffect(GCNotOwnedSymbol, ObjC); | 
 |   } | 
 |  | 
 |   static RetEffect MakeNoRet() { | 
 |     return RetEffect(NoRet); | 
 |   } | 
 |  | 
 |   void Profile(llvm::FoldingSetNodeID& ID) const { | 
 |     ID.AddInteger((unsigned)K); | 
 |     ID.AddInteger((unsigned)O); | 
 |     ID.AddInteger(index); | 
 |   } | 
 | }; | 
 |  | 
 | //===----------------------------------------------------------------------===// | 
 | // Reference-counting logic (typestate + counts). | 
 | //===----------------------------------------------------------------------===// | 
 |  | 
 | class RefVal { | 
 | public: | 
 |   enum Kind { | 
 |     Owned = 0, // Owning reference. | 
 |     NotOwned,  // Reference is not owned by still valid (not freed). | 
 |     Released,  // Object has been released. | 
 |     ReturnedOwned, // Returned object passes ownership to caller. | 
 |     ReturnedNotOwned, // Return object does not pass ownership to caller. | 
 |     ERROR_START, | 
 |     ErrorDeallocNotOwned, // -dealloc called on non-owned object. | 
 |     ErrorDeallocGC, // Calling -dealloc with GC enabled. | 
 |     ErrorUseAfterRelease, // Object used after released. | 
 |     ErrorReleaseNotOwned, // Release of an object that was not owned. | 
 |     ERROR_LEAK_START, | 
 |     ErrorLeak,  // A memory leak due to excessive reference counts. | 
 |     ErrorLeakReturned, // A memory leak due to the returning method not having | 
 |                        // the correct naming conventions. | 
 |     ErrorGCLeakReturned, | 
 |     ErrorOverAutorelease, | 
 |     ErrorReturnedNotOwned | 
 |   }; | 
 |    | 
 | private: | 
 |   Kind kind; | 
 |   RetEffect::ObjKind okind; | 
 |   unsigned Cnt; | 
 |   unsigned ACnt; | 
 |   QualType T; | 
 |    | 
 |   RefVal(Kind k, RetEffect::ObjKind o, unsigned cnt, unsigned acnt, QualType t) | 
 |   : kind(k), okind(o), Cnt(cnt), ACnt(acnt), T(t) {} | 
 |    | 
 |   RefVal(Kind k, unsigned cnt = 0) | 
 |   : kind(k), okind(RetEffect::AnyObj), Cnt(cnt), ACnt(0) {} | 
 |    | 
 | public: | 
 |   Kind getKind() const { return kind; } | 
 |    | 
 |   RetEffect::ObjKind getObjKind() const { return okind; } | 
 |    | 
 |   unsigned getCount() const { return Cnt; } | 
 |   unsigned getAutoreleaseCount() const { return ACnt; } | 
 |   unsigned getCombinedCounts() const { return Cnt + ACnt; } | 
 |   void clearCounts() { Cnt = 0; ACnt = 0; } | 
 |   void setCount(unsigned i) { Cnt = i; } | 
 |   void setAutoreleaseCount(unsigned i) { ACnt = i; } | 
 |    | 
 |   QualType getType() const { return T; } | 
 |    | 
 |   // Useful predicates. | 
 |    | 
 |   static bool isError(Kind k) { return k >= ERROR_START; } | 
 |    | 
 |   static bool isLeak(Kind k) { return k >= ERROR_LEAK_START; } | 
 |    | 
 |   bool isOwned() const { | 
 |     return getKind() == Owned; | 
 |   } | 
 |    | 
 |   bool isNotOwned() const { | 
 |     return getKind() == NotOwned; | 
 |   } | 
 |    | 
 |   bool isReturnedOwned() const { | 
 |     return getKind() == ReturnedOwned; | 
 |   } | 
 |    | 
 |   bool isReturnedNotOwned() const { | 
 |     return getKind() == ReturnedNotOwned; | 
 |   } | 
 |    | 
 |   bool isNonLeakError() const { | 
 |     Kind k = getKind(); | 
 |     return isError(k) && !isLeak(k); | 
 |   } | 
 |    | 
 |   static RefVal makeOwned(RetEffect::ObjKind o, QualType t, | 
 |                           unsigned Count = 1) { | 
 |     return RefVal(Owned, o, Count, 0, t); | 
 |   } | 
 |    | 
 |   static RefVal makeNotOwned(RetEffect::ObjKind o, QualType t, | 
 |                              unsigned Count = 0) { | 
 |     return RefVal(NotOwned, o, Count, 0, t); | 
 |   } | 
 |    | 
 |   // Comparison, profiling, and pretty-printing. | 
 |    | 
 |   bool operator==(const RefVal& X) const { | 
 |     return kind == X.kind && Cnt == X.Cnt && T == X.T && ACnt == X.ACnt; | 
 |   } | 
 |    | 
 |   RefVal operator-(size_t i) const { | 
 |     return RefVal(getKind(), getObjKind(), getCount() - i, | 
 |                   getAutoreleaseCount(), getType()); | 
 |   } | 
 |    | 
 |   RefVal operator+(size_t i) const { | 
 |     return RefVal(getKind(), getObjKind(), getCount() + i, | 
 |                   getAutoreleaseCount(), getType()); | 
 |   } | 
 |    | 
 |   RefVal operator^(Kind k) const { | 
 |     return RefVal(k, getObjKind(), getCount(), getAutoreleaseCount(), | 
 |                   getType()); | 
 |   } | 
 |    | 
 |   RefVal autorelease() const { | 
 |     return RefVal(getKind(), getObjKind(), getCount(), getAutoreleaseCount()+1, | 
 |                   getType()); | 
 |   } | 
 |    | 
 |   void Profile(llvm::FoldingSetNodeID& ID) const { | 
 |     ID.AddInteger((unsigned) kind); | 
 |     ID.AddInteger(Cnt); | 
 |     ID.AddInteger(ACnt); | 
 |     ID.Add(T); | 
 |   } | 
 |    | 
 |   void print(llvm::raw_ostream& Out) const; | 
 | }; | 
 |  | 
 | void RefVal::print(llvm::raw_ostream& Out) const { | 
 |   if (!T.isNull()) | 
 |     Out << "Tracked Type:" << T.getAsString() << '\n'; | 
 |    | 
 |   switch (getKind()) { | 
 |     default: assert(false); | 
 |     case Owned: { | 
 |       Out << "Owned"; | 
 |       unsigned cnt = getCount(); | 
 |       if (cnt) Out << " (+ " << cnt << ")"; | 
 |       break; | 
 |     } | 
 |        | 
 |     case NotOwned: { | 
 |       Out << "NotOwned"; | 
 |       unsigned cnt = getCount(); | 
 |       if (cnt) Out << " (+ " << cnt << ")"; | 
 |       break; | 
 |     } | 
 |        | 
 |     case ReturnedOwned: { | 
 |       Out << "ReturnedOwned"; | 
 |       unsigned cnt = getCount(); | 
 |       if (cnt) Out << " (+ " << cnt << ")"; | 
 |       break; | 
 |     } | 
 |        | 
 |     case ReturnedNotOwned: { | 
 |       Out << "ReturnedNotOwned"; | 
 |       unsigned cnt = getCount(); | 
 |       if (cnt) Out << " (+ " << cnt << ")"; | 
 |       break; | 
 |     } | 
 |        | 
 |     case Released: | 
 |       Out << "Released"; | 
 |       break; | 
 |        | 
 |     case ErrorDeallocGC: | 
 |       Out << "-dealloc (GC)"; | 
 |       break; | 
 |        | 
 |     case ErrorDeallocNotOwned: | 
 |       Out << "-dealloc (not-owned)"; | 
 |       break; | 
 |        | 
 |     case ErrorLeak: | 
 |       Out << "Leaked"; | 
 |       break; | 
 |        | 
 |     case ErrorLeakReturned: | 
 |       Out << "Leaked (Bad naming)"; | 
 |       break; | 
 |        | 
 |     case ErrorGCLeakReturned: | 
 |       Out << "Leaked (GC-ed at return)"; | 
 |       break; | 
 |        | 
 |     case ErrorUseAfterRelease: | 
 |       Out << "Use-After-Release [ERROR]"; | 
 |       break; | 
 |        | 
 |     case ErrorReleaseNotOwned: | 
 |       Out << "Release of Not-Owned [ERROR]"; | 
 |       break; | 
 |        | 
 |     case RefVal::ErrorOverAutorelease: | 
 |       Out << "Over autoreleased"; | 
 |       break; | 
 |        | 
 |     case RefVal::ErrorReturnedNotOwned: | 
 |       Out << "Non-owned object returned instead of owned"; | 
 |       break; | 
 |   } | 
 |    | 
 |   if (ACnt) { | 
 |     Out << " [ARC +" << ACnt << ']'; | 
 |   } | 
 | } | 
 | } //end anonymous namespace | 
 |  | 
 | //===----------------------------------------------------------------------===// | 
 | // RefBindings - State used to track object reference counts. | 
 | //===----------------------------------------------------------------------===// | 
 |  | 
 | typedef llvm::ImmutableMap<SymbolRef, RefVal> RefBindings; | 
 |  | 
 | namespace clang { | 
 |   template<> | 
 |   struct GRStateTrait<RefBindings> : public GRStatePartialTrait<RefBindings> { | 
 |     static void* GDMIndex() { | 
 |       static int RefBIndex = 0; | 
 |       return &RefBIndex; | 
 |     } | 
 |   }; | 
 | } | 
 |  | 
 | //===----------------------------------------------------------------------===// | 
 | // Summaries | 
 | //===----------------------------------------------------------------------===// | 
 |  | 
 | namespace { | 
 | class RetainSummary { | 
 |   /// Args - an ordered vector of (index, ArgEffect) pairs, where index | 
 |   ///  specifies the argument (starting from 0).  This can be sparsely | 
 |   ///  populated; arguments with no entry in Args use 'DefaultArgEffect'. | 
 |   ArgEffects Args; | 
 |  | 
 |   /// DefaultArgEffect - The default ArgEffect to apply to arguments that | 
 |   ///  do not have an entry in Args. | 
 |   ArgEffect   DefaultArgEffect; | 
 |  | 
 |   /// Receiver - If this summary applies to an Objective-C message expression, | 
 |   ///  this is the effect applied to the state of the receiver. | 
 |   ArgEffect   Receiver; | 
 |  | 
 |   /// Ret - The effect on the return value.  Used to indicate if the | 
 |   ///  function/method call returns a new tracked symbol, returns an | 
 |   ///  alias of one of the arguments in the call, and so on. | 
 |   RetEffect   Ret; | 
 |  | 
 |   /// EndPath - Indicates that execution of this method/function should | 
 |   ///  terminate the simulation of a path. | 
 |   bool EndPath; | 
 |  | 
 | public: | 
 |   RetainSummary(ArgEffects A, RetEffect R, ArgEffect defaultEff, | 
 |                 ArgEffect ReceiverEff, bool endpath = false) | 
 |     : Args(A), DefaultArgEffect(defaultEff), Receiver(ReceiverEff), Ret(R), | 
 |       EndPath(endpath) {} | 
 |  | 
 |   /// getArg - Return the argument effect on the argument specified by | 
 |   ///  idx (starting from 0). | 
 |   ArgEffect getArg(unsigned idx) const { | 
 |     if (const ArgEffect *AE = Args.lookup(idx)) | 
 |       return *AE; | 
 |  | 
 |     return DefaultArgEffect; | 
 |   } | 
 |  | 
 |   /// setDefaultArgEffect - Set the default argument effect. | 
 |   void setDefaultArgEffect(ArgEffect E) { | 
 |     DefaultArgEffect = E; | 
 |   } | 
 |  | 
 |   /// setArg - Set the argument effect on the argument specified by idx. | 
 |   void setArgEffect(ArgEffects::Factory& AF, unsigned idx, ArgEffect E) { | 
 |     Args = AF.Add(Args, idx, E); | 
 |   } | 
 |  | 
 |   /// getRetEffect - Returns the effect on the return value of the call. | 
 |   RetEffect getRetEffect() const { return Ret; } | 
 |  | 
 |   /// setRetEffect - Set the effect of the return value of the call. | 
 |   void setRetEffect(RetEffect E) { Ret = E; } | 
 |  | 
 |   /// isEndPath - Returns true if executing the given method/function should | 
 |   ///  terminate the path. | 
 |   bool isEndPath() const { return EndPath; } | 
 |  | 
 |   /// getReceiverEffect - Returns the effect on the receiver of the call. | 
 |   ///  This is only meaningful if the summary applies to an ObjCMessageExpr*. | 
 |   ArgEffect getReceiverEffect() const { return Receiver; } | 
 |  | 
 |   /// setReceiverEffect - Set the effect on the receiver of the call. | 
 |   void setReceiverEffect(ArgEffect E) { Receiver = E; } | 
 |  | 
 |   typedef ArgEffects::iterator ExprIterator; | 
 |  | 
 |   ExprIterator begin_args() const { return Args.begin(); } | 
 |   ExprIterator end_args()   const { return Args.end(); } | 
 |  | 
 |   static void Profile(llvm::FoldingSetNodeID& ID, ArgEffects A, | 
 |                       RetEffect RetEff, ArgEffect DefaultEff, | 
 |                       ArgEffect ReceiverEff, bool EndPath) { | 
 |     ID.Add(A); | 
 |     ID.Add(RetEff); | 
 |     ID.AddInteger((unsigned) DefaultEff); | 
 |     ID.AddInteger((unsigned) ReceiverEff); | 
 |     ID.AddInteger((unsigned) EndPath); | 
 |   } | 
 |  | 
 |   void Profile(llvm::FoldingSetNodeID& ID) const { | 
 |     Profile(ID, Args, Ret, DefaultArgEffect, Receiver, EndPath); | 
 |   } | 
 | }; | 
 | } // end anonymous namespace | 
 |  | 
 | //===----------------------------------------------------------------------===// | 
 | // Data structures for constructing summaries. | 
 | //===----------------------------------------------------------------------===// | 
 |  | 
 | namespace { | 
 | class ObjCSummaryKey { | 
 |   IdentifierInfo* II; | 
 |   Selector S; | 
 | public: | 
 |   ObjCSummaryKey(IdentifierInfo* ii, Selector s) | 
 |     : II(ii), S(s) {} | 
 |  | 
 |   ObjCSummaryKey(const ObjCInterfaceDecl* d, Selector s) | 
 |     : II(d ? d->getIdentifier() : 0), S(s) {} | 
 |  | 
 |   ObjCSummaryKey(const ObjCInterfaceDecl* d, IdentifierInfo *ii, Selector s) | 
 |     : II(d ? d->getIdentifier() : ii), S(s) {} | 
 |  | 
 |   ObjCSummaryKey(Selector s) | 
 |     : II(0), S(s) {} | 
 |  | 
 |   IdentifierInfo* getIdentifier() const { return II; } | 
 |   Selector getSelector() const { return S; } | 
 | }; | 
 | } | 
 |  | 
 | namespace llvm { | 
 | template <> struct DenseMapInfo<ObjCSummaryKey> { | 
 |   static inline ObjCSummaryKey getEmptyKey() { | 
 |     return ObjCSummaryKey(DenseMapInfo<IdentifierInfo*>::getEmptyKey(), | 
 |                           DenseMapInfo<Selector>::getEmptyKey()); | 
 |   } | 
 |  | 
 |   static inline ObjCSummaryKey getTombstoneKey() { | 
 |     return ObjCSummaryKey(DenseMapInfo<IdentifierInfo*>::getTombstoneKey(), | 
 |                           DenseMapInfo<Selector>::getTombstoneKey()); | 
 |   } | 
 |  | 
 |   static unsigned getHashValue(const ObjCSummaryKey &V) { | 
 |     return (DenseMapInfo<IdentifierInfo*>::getHashValue(V.getIdentifier()) | 
 |             & 0x88888888) | 
 |         | (DenseMapInfo<Selector>::getHashValue(V.getSelector()) | 
 |             & 0x55555555); | 
 |   } | 
 |  | 
 |   static bool isEqual(const ObjCSummaryKey& LHS, const ObjCSummaryKey& RHS) { | 
 |     return DenseMapInfo<IdentifierInfo*>::isEqual(LHS.getIdentifier(), | 
 |                                                   RHS.getIdentifier()) && | 
 |            DenseMapInfo<Selector>::isEqual(LHS.getSelector(), | 
 |                                            RHS.getSelector()); | 
 |   } | 
 |  | 
 | }; | 
 | template <> | 
 | struct isPodLike<ObjCSummaryKey> { static const bool value = true; }; | 
 | } // end llvm namespace | 
 |  | 
 | namespace { | 
 | class ObjCSummaryCache { | 
 |   typedef llvm::DenseMap<ObjCSummaryKey, RetainSummary*> MapTy; | 
 |   MapTy M; | 
 | public: | 
 |   ObjCSummaryCache() {} | 
 |  | 
 |   RetainSummary* find(const ObjCInterfaceDecl* D, IdentifierInfo *ClsName, | 
 |                 Selector S) { | 
 |     // Lookup the method using the decl for the class @interface.  If we | 
 |     // have no decl, lookup using the class name. | 
 |     return D ? find(D, S) : find(ClsName, S); | 
 |   } | 
 |  | 
 |   RetainSummary* find(const ObjCInterfaceDecl* D, Selector S) { | 
 |     // Do a lookup with the (D,S) pair.  If we find a match return | 
 |     // the iterator. | 
 |     ObjCSummaryKey K(D, S); | 
 |     MapTy::iterator I = M.find(K); | 
 |  | 
 |     if (I != M.end() || !D) | 
 |       return I->second; | 
 |  | 
 |     // Walk the super chain.  If we find a hit with a parent, we'll end | 
 |     // up returning that summary.  We actually allow that key (null,S), as | 
 |     // we cache summaries for the null ObjCInterfaceDecl* to allow us to | 
 |     // generate initial summaries without having to worry about NSObject | 
 |     // being declared. | 
 |     // FIXME: We may change this at some point. | 
 |     for (ObjCInterfaceDecl* C=D->getSuperClass() ;; C=C->getSuperClass()) { | 
 |       if ((I = M.find(ObjCSummaryKey(C, S))) != M.end()) | 
 |         break; | 
 |  | 
 |       if (!C) | 
 |         return NULL; | 
 |     } | 
 |  | 
 |     // Cache the summary with original key to make the next lookup faster | 
 |     // and return the iterator. | 
 |     RetainSummary *Summ = I->second; | 
 |     M[K] = Summ; | 
 |     return Summ; | 
 |   } | 
 |  | 
 |  | 
 |   RetainSummary* find(Expr* Receiver, Selector S) { | 
 |     return find(getReceiverDecl(Receiver), S); | 
 |   } | 
 |  | 
 |   RetainSummary* find(IdentifierInfo* II, Selector S) { | 
 |     // FIXME: Class method lookup.  Right now we dont' have a good way | 
 |     // of going between IdentifierInfo* and the class hierarchy. | 
 |     MapTy::iterator I = M.find(ObjCSummaryKey(II, S)); | 
 |  | 
 |     if (I == M.end()) | 
 |       I = M.find(ObjCSummaryKey(S)); | 
 |  | 
 |     return I == M.end() ? NULL : I->second; | 
 |   } | 
 |  | 
 |   const ObjCInterfaceDecl* getReceiverDecl(Expr* E) { | 
 |     if (const ObjCObjectPointerType* PT = | 
 |         E->getType()->getAs<ObjCObjectPointerType>()) | 
 |       return PT->getInterfaceDecl(); | 
 |  | 
 |     return NULL; | 
 |   } | 
 |  | 
 |   RetainSummary*& operator[](ObjCMessageExpr* ME) { | 
 |  | 
 |     Selector S = ME->getSelector(); | 
 |  | 
 |     const ObjCInterfaceDecl* OD = 0; | 
 |     bool IsInstanceMessage = false; | 
 |     switch (ME->getReceiverKind()) { | 
 |     case ObjCMessageExpr::Instance: | 
 |       OD = getReceiverDecl(ME->getInstanceReceiver()); | 
 |       IsInstanceMessage = true; | 
 |       break; | 
 |  | 
 |     case ObjCMessageExpr::SuperInstance: | 
 |       IsInstanceMessage = true; | 
 |       OD = ME->getSuperType()->getAs<ObjCObjectPointerType>() | 
 |                                                         ->getInterfaceDecl(); | 
 |       break; | 
 |  | 
 |     case ObjCMessageExpr::Class: | 
 |       OD = ME->getClassReceiver()->getAs<ObjCInterfaceType>()->getDecl(); | 
 |       break; | 
 |  | 
 |     case ObjCMessageExpr::SuperClass: | 
 |       OD = ME->getSuperType()->getAs<ObjCInterfaceType>()->getDecl(); | 
 |       break; | 
 |     } | 
 |  | 
 |     if (IsInstanceMessage) | 
 |       return OD ? M[ObjCSummaryKey(OD->getIdentifier(), S)] : M[S]; | 
 |  | 
 |     return M[ObjCSummaryKey(OD->getIdentifier(), S)]; | 
 |   } | 
 |  | 
 |   RetainSummary*& operator[](ObjCSummaryKey K) { | 
 |     return M[K]; | 
 |   } | 
 |  | 
 |   RetainSummary*& operator[](Selector S) { | 
 |     return M[ ObjCSummaryKey(S) ]; | 
 |   } | 
 | }; | 
 | } // end anonymous namespace | 
 |  | 
 | //===----------------------------------------------------------------------===// | 
 | // Data structures for managing collections of summaries. | 
 | //===----------------------------------------------------------------------===// | 
 |  | 
 | namespace { | 
 | class RetainSummaryManager { | 
 |  | 
 |   //==-----------------------------------------------------------------==// | 
 |   //  Typedefs. | 
 |   //==-----------------------------------------------------------------==// | 
 |  | 
 |   typedef llvm::DenseMap<FunctionDecl*, RetainSummary*> | 
 |           FuncSummariesTy; | 
 |  | 
 |   typedef ObjCSummaryCache ObjCMethodSummariesTy; | 
 |  | 
 |   //==-----------------------------------------------------------------==// | 
 |   //  Data. | 
 |   //==-----------------------------------------------------------------==// | 
 |  | 
 |   /// Ctx - The ASTContext object for the analyzed ASTs. | 
 |   ASTContext& Ctx; | 
 |  | 
 |   /// CFDictionaryCreateII - An IdentifierInfo* representing the indentifier | 
 |   ///  "CFDictionaryCreate". | 
 |   IdentifierInfo* CFDictionaryCreateII; | 
 |  | 
 |   /// GCEnabled - Records whether or not the analyzed code runs in GC mode. | 
 |   const bool GCEnabled; | 
 |  | 
 |   /// FuncSummaries - A map from FunctionDecls to summaries. | 
 |   FuncSummariesTy FuncSummaries; | 
 |  | 
 |   /// ObjCClassMethodSummaries - A map from selectors (for instance methods) | 
 |   ///  to summaries. | 
 |   ObjCMethodSummariesTy ObjCClassMethodSummaries; | 
 |  | 
 |   /// ObjCMethodSummaries - A map from selectors to summaries. | 
 |   ObjCMethodSummariesTy ObjCMethodSummaries; | 
 |  | 
 |   /// BPAlloc - A BumpPtrAllocator used for allocating summaries, ArgEffects, | 
 |   ///  and all other data used by the checker. | 
 |   llvm::BumpPtrAllocator BPAlloc; | 
 |  | 
 |   /// AF - A factory for ArgEffects objects. | 
 |   ArgEffects::Factory AF; | 
 |  | 
 |   /// ScratchArgs - A holding buffer for construct ArgEffects. | 
 |   ArgEffects ScratchArgs; | 
 |  | 
 |   /// ObjCAllocRetE - Default return effect for methods returning Objective-C | 
 |   ///  objects. | 
 |   RetEffect ObjCAllocRetE; | 
 |  | 
 |   /// ObjCInitRetE - Default return effect for init methods returning | 
 |   ///   Objective-C objects. | 
 |   RetEffect ObjCInitRetE; | 
 |  | 
 |   RetainSummary DefaultSummary; | 
 |   RetainSummary* StopSummary; | 
 |  | 
 |   //==-----------------------------------------------------------------==// | 
 |   //  Methods. | 
 |   //==-----------------------------------------------------------------==// | 
 |  | 
 |   /// getArgEffects - Returns a persistent ArgEffects object based on the | 
 |   ///  data in ScratchArgs. | 
 |   ArgEffects getArgEffects(); | 
 |  | 
 |   enum UnaryFuncKind { cfretain, cfrelease, cfmakecollectable }; | 
 |  | 
 | public: | 
 |   RetEffect getObjAllocRetEffect() const { return ObjCAllocRetE; } | 
 |  | 
 |   RetainSummary *getDefaultSummary() { | 
 |     RetainSummary *Summ = (RetainSummary*) BPAlloc.Allocate<RetainSummary>(); | 
 |     return new (Summ) RetainSummary(DefaultSummary); | 
 |   } | 
 |  | 
 |   RetainSummary* getUnarySummary(const FunctionType* FT, UnaryFuncKind func); | 
 |  | 
 |   RetainSummary* getCFSummaryCreateRule(FunctionDecl* FD); | 
 |   RetainSummary* getCFSummaryGetRule(FunctionDecl* FD); | 
 |   RetainSummary* getCFCreateGetRuleSummary(FunctionDecl* FD, StringRef FName); | 
 |  | 
 |   RetainSummary* getPersistentSummary(ArgEffects AE, RetEffect RetEff, | 
 |                                       ArgEffect ReceiverEff = DoNothing, | 
 |                                       ArgEffect DefaultEff = MayEscape, | 
 |                                       bool isEndPath = false); | 
 |  | 
 |   RetainSummary* getPersistentSummary(RetEffect RE, | 
 |                                       ArgEffect ReceiverEff = DoNothing, | 
 |                                       ArgEffect DefaultEff = MayEscape) { | 
 |     return getPersistentSummary(getArgEffects(), RE, ReceiverEff, DefaultEff); | 
 |   } | 
 |  | 
 |   RetainSummary *getPersistentStopSummary() { | 
 |     if (StopSummary) | 
 |       return StopSummary; | 
 |  | 
 |     StopSummary = getPersistentSummary(RetEffect::MakeNoRet(), | 
 |                                        StopTracking, StopTracking); | 
 |  | 
 |     return StopSummary; | 
 |   } | 
 |  | 
 |   RetainSummary *getInitMethodSummary(QualType RetTy); | 
 |  | 
 |   void InitializeClassMethodSummaries(); | 
 |   void InitializeMethodSummaries(); | 
 | private: | 
 |  | 
 |   void addClsMethSummary(IdentifierInfo* ClsII, Selector S, | 
 |                          RetainSummary* Summ) { | 
 |     ObjCClassMethodSummaries[ObjCSummaryKey(ClsII, S)] = Summ; | 
 |   } | 
 |  | 
 |   void addNSObjectClsMethSummary(Selector S, RetainSummary *Summ) { | 
 |     ObjCClassMethodSummaries[S] = Summ; | 
 |   } | 
 |  | 
 |   void addNSObjectMethSummary(Selector S, RetainSummary *Summ) { | 
 |     ObjCMethodSummaries[S] = Summ; | 
 |   } | 
 |  | 
 |   void addClassMethSummary(const char* Cls, const char* nullaryName, | 
 |                            RetainSummary *Summ) { | 
 |     IdentifierInfo* ClsII = &Ctx.Idents.get(Cls); | 
 |     Selector S = GetNullarySelector(nullaryName, Ctx); | 
 |     ObjCClassMethodSummaries[ObjCSummaryKey(ClsII, S)]  = Summ; | 
 |   } | 
 |  | 
 |   void addInstMethSummary(const char* Cls, const char* nullaryName, | 
 |                           RetainSummary *Summ) { | 
 |     IdentifierInfo* ClsII = &Ctx.Idents.get(Cls); | 
 |     Selector S = GetNullarySelector(nullaryName, Ctx); | 
 |     ObjCMethodSummaries[ObjCSummaryKey(ClsII, S)]  = Summ; | 
 |   } | 
 |  | 
 |   Selector generateSelector(va_list argp) { | 
 |     llvm::SmallVector<IdentifierInfo*, 10> II; | 
 |  | 
 |     while (const char* s = va_arg(argp, const char*)) | 
 |       II.push_back(&Ctx.Idents.get(s)); | 
 |  | 
 |     return Ctx.Selectors.getSelector(II.size(), &II[0]); | 
 |   } | 
 |  | 
 |   void addMethodSummary(IdentifierInfo *ClsII, ObjCMethodSummariesTy& Summaries, | 
 |                         RetainSummary* Summ, va_list argp) { | 
 |     Selector S = generateSelector(argp); | 
 |     Summaries[ObjCSummaryKey(ClsII, S)] = Summ; | 
 |   } | 
 |  | 
 |   void addInstMethSummary(const char* Cls, RetainSummary* Summ, ...) { | 
 |     va_list argp; | 
 |     va_start(argp, Summ); | 
 |     addMethodSummary(&Ctx.Idents.get(Cls), ObjCMethodSummaries, Summ, argp); | 
 |     va_end(argp); | 
 |   } | 
 |  | 
 |   void addClsMethSummary(const char* Cls, RetainSummary* Summ, ...) { | 
 |     va_list argp; | 
 |     va_start(argp, Summ); | 
 |     addMethodSummary(&Ctx.Idents.get(Cls),ObjCClassMethodSummaries, Summ, argp); | 
 |     va_end(argp); | 
 |   } | 
 |  | 
 |   void addClsMethSummary(IdentifierInfo *II, RetainSummary* Summ, ...) { | 
 |     va_list argp; | 
 |     va_start(argp, Summ); | 
 |     addMethodSummary(II, ObjCClassMethodSummaries, Summ, argp); | 
 |     va_end(argp); | 
 |   } | 
 |  | 
 |   void addPanicSummary(const char* Cls, ...) { | 
 |     RetainSummary* Summ = getPersistentSummary(AF.GetEmptyMap(), | 
 |                                                RetEffect::MakeNoRet(), | 
 |                                                DoNothing,  DoNothing, true); | 
 |     va_list argp; | 
 |     va_start (argp, Cls); | 
 |     addMethodSummary(&Ctx.Idents.get(Cls), ObjCMethodSummaries, Summ, argp); | 
 |     va_end(argp); | 
 |   } | 
 |  | 
 | public: | 
 |  | 
 |   RetainSummaryManager(ASTContext& ctx, bool gcenabled) | 
 |    : Ctx(ctx), | 
 |      CFDictionaryCreateII(&ctx.Idents.get("CFDictionaryCreate")), | 
 |      GCEnabled(gcenabled), AF(BPAlloc), ScratchArgs(AF.GetEmptyMap()), | 
 |      ObjCAllocRetE(gcenabled ? RetEffect::MakeGCNotOwned() | 
 |                              : RetEffect::MakeOwned(RetEffect::ObjC, true)), | 
 |      ObjCInitRetE(gcenabled ? RetEffect::MakeGCNotOwned() | 
 |                             : RetEffect::MakeOwnedWhenTrackedReceiver()), | 
 |      DefaultSummary(AF.GetEmptyMap() /* per-argument effects (none) */, | 
 |                     RetEffect::MakeNoRet() /* return effect */, | 
 |                     MayEscape, /* default argument effect */ | 
 |                     DoNothing /* receiver effect */), | 
 |      StopSummary(0) { | 
 |  | 
 |     InitializeClassMethodSummaries(); | 
 |     InitializeMethodSummaries(); | 
 |   } | 
 |  | 
 |   ~RetainSummaryManager(); | 
 |  | 
 |   RetainSummary* getSummary(FunctionDecl* FD); | 
 |  | 
 |   RetainSummary *getInstanceMethodSummary(const ObjCMessageExpr *ME, | 
 |                                           const GRState *state, | 
 |                                           const LocationContext *LC); | 
 |    | 
 |   RetainSummary* getInstanceMethodSummary(const ObjCMessageExpr* ME, | 
 |                                           const ObjCInterfaceDecl* ID) { | 
 |     return getInstanceMethodSummary(ME->getSelector(), 0, | 
 |                             ID, ME->getMethodDecl(), ME->getType()); | 
 |   } | 
 |  | 
 |   RetainSummary* getInstanceMethodSummary(Selector S, IdentifierInfo *ClsName, | 
 |                                           const ObjCInterfaceDecl* ID, | 
 |                                           const ObjCMethodDecl *MD, | 
 |                                           QualType RetTy); | 
 |  | 
 |   RetainSummary *getClassMethodSummary(Selector S, IdentifierInfo *ClsName, | 
 |                                        const ObjCInterfaceDecl *ID, | 
 |                                        const ObjCMethodDecl *MD, | 
 |                                        QualType RetTy); | 
 |  | 
 |   RetainSummary *getClassMethodSummary(const ObjCMessageExpr *ME) { | 
 |     ObjCInterfaceDecl *Class = 0; | 
 |     switch (ME->getReceiverKind()) { | 
 |     case ObjCMessageExpr::Class: | 
 |     case ObjCMessageExpr::SuperClass: | 
 |       Class = ME->getReceiverInterface(); | 
 |       break; | 
 |  | 
 |     case ObjCMessageExpr::Instance: | 
 |     case ObjCMessageExpr::SuperInstance: | 
 |       break; | 
 |     } | 
 |  | 
 |     return getClassMethodSummary(ME->getSelector(),  | 
 |                                  Class? Class->getIdentifier() : 0, | 
 |                                  Class, | 
 |                                  ME->getMethodDecl(), ME->getType()); | 
 |   } | 
 |  | 
 |   /// getMethodSummary - This version of getMethodSummary is used to query | 
 |   ///  the summary for the current method being analyzed. | 
 |   RetainSummary *getMethodSummary(const ObjCMethodDecl *MD) { | 
 |     // FIXME: Eventually this should be unneeded. | 
 |     const ObjCInterfaceDecl *ID = MD->getClassInterface(); | 
 |     Selector S = MD->getSelector(); | 
 |     IdentifierInfo *ClsName = ID->getIdentifier(); | 
 |     QualType ResultTy = MD->getResultType(); | 
 |  | 
 |     // Resolve the method decl last. | 
 |     if (const ObjCMethodDecl *InterfaceMD = ResolveToInterfaceMethodDecl(MD)) | 
 |       MD = InterfaceMD; | 
 |  | 
 |     if (MD->isInstanceMethod()) | 
 |       return getInstanceMethodSummary(S, ClsName, ID, MD, ResultTy); | 
 |     else | 
 |       return getClassMethodSummary(S, ClsName, ID, MD, ResultTy); | 
 |   } | 
 |  | 
 |   RetainSummary* getCommonMethodSummary(const ObjCMethodDecl* MD, | 
 |                                         Selector S, QualType RetTy); | 
 |  | 
 |   void updateSummaryFromAnnotations(RetainSummary &Summ, | 
 |                                     const ObjCMethodDecl *MD); | 
 |  | 
 |   void updateSummaryFromAnnotations(RetainSummary &Summ, | 
 |                                     const FunctionDecl *FD); | 
 |  | 
 |   bool isGCEnabled() const { return GCEnabled; } | 
 |  | 
 |   RetainSummary *copySummary(RetainSummary *OldSumm) { | 
 |     RetainSummary *Summ = (RetainSummary*) BPAlloc.Allocate<RetainSummary>(); | 
 |     new (Summ) RetainSummary(*OldSumm); | 
 |     return Summ; | 
 |   } | 
 | }; | 
 |  | 
 | } // end anonymous namespace | 
 |  | 
 | //===----------------------------------------------------------------------===// | 
 | // Implementation of checker data structures. | 
 | //===----------------------------------------------------------------------===// | 
 |  | 
 | RetainSummaryManager::~RetainSummaryManager() {} | 
 |  | 
 | ArgEffects RetainSummaryManager::getArgEffects() { | 
 |   ArgEffects AE = ScratchArgs; | 
 |   ScratchArgs = AF.GetEmptyMap(); | 
 |   return AE; | 
 | } | 
 |  | 
 | RetainSummary* | 
 | RetainSummaryManager::getPersistentSummary(ArgEffects AE, RetEffect RetEff, | 
 |                                            ArgEffect ReceiverEff, | 
 |                                            ArgEffect DefaultEff, | 
 |                                            bool isEndPath) { | 
 |   // Create the summary and return it. | 
 |   RetainSummary *Summ = (RetainSummary*) BPAlloc.Allocate<RetainSummary>(); | 
 |   new (Summ) RetainSummary(AE, RetEff, DefaultEff, ReceiverEff, isEndPath); | 
 |   return Summ; | 
 | } | 
 |  | 
 | //===----------------------------------------------------------------------===// | 
 | // Summary creation for functions (largely uses of Core Foundation). | 
 | //===----------------------------------------------------------------------===// | 
 |  | 
 | static bool isRetain(FunctionDecl* FD, StringRef FName) { | 
 |   return FName.endswith("Retain"); | 
 | } | 
 |  | 
 | static bool isRelease(FunctionDecl* FD, StringRef FName) { | 
 |   return FName.endswith("Release"); | 
 | } | 
 |  | 
 | RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) { | 
 |   // Look up a summary in our cache of FunctionDecls -> Summaries. | 
 |   FuncSummariesTy::iterator I = FuncSummaries.find(FD); | 
 |   if (I != FuncSummaries.end()) | 
 |     return I->second; | 
 |  | 
 |   // No summary?  Generate one. | 
 |   RetainSummary *S = 0; | 
 |  | 
 |   do { | 
 |     // We generate "stop" summaries for implicitly defined functions. | 
 |     if (FD->isImplicit()) { | 
 |       S = getPersistentStopSummary(); | 
 |       break; | 
 |     } | 
 |  | 
 |     // [PR 3337] Use 'getAs<FunctionType>' to strip away any typedefs on the | 
 |     // function's type. | 
 |     const FunctionType* FT = FD->getType()->getAs<FunctionType>(); | 
 |     const IdentifierInfo *II = FD->getIdentifier(); | 
 |     if (!II) | 
 |       break; | 
 |  | 
 |     StringRef FName = II->getName(); | 
 |  | 
 |     // Strip away preceding '_'.  Doing this here will effect all the checks | 
 |     // down below. | 
 |     FName = FName.substr(FName.find_first_not_of('_')); | 
 |  | 
 |     // Inspect the result type. | 
 |     QualType RetTy = FT->getResultType(); | 
 |  | 
 |     // FIXME: This should all be refactored into a chain of "summary lookup" | 
 |     //  filters. | 
 |     assert(ScratchArgs.isEmpty()); | 
 |  | 
 |     if (FName == "pthread_create") { | 
 |       // Part of: <rdar://problem/7299394>.  This will be addressed | 
 |       // better with IPA. | 
 |       S = getPersistentStopSummary(); | 
 |     } else if (FName == "NSMakeCollectable") { | 
 |       // Handle: id NSMakeCollectable(CFTypeRef) | 
 |       S = (RetTy->isObjCIdType()) | 
 |           ? getUnarySummary(FT, cfmakecollectable) | 
 |           : getPersistentStopSummary(); | 
 |     } else if (FName == "IOBSDNameMatching" || | 
 |                FName == "IOServiceMatching" || | 
 |                FName == "IOServiceNameMatching" || | 
 |                FName == "IORegistryEntryIDMatching" || | 
 |                FName == "IOOpenFirmwarePathMatching") { | 
 |       // Part of <rdar://problem/6961230>. (IOKit) | 
 |       // This should be addressed using a API table. | 
 |       S = getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF, true), | 
 |                                DoNothing, DoNothing); | 
 |     } else if (FName == "IOServiceGetMatchingService" || | 
 |                FName == "IOServiceGetMatchingServices") { | 
 |       // FIXES: <rdar://problem/6326900> | 
 |       // This should be addressed using a API table.  This strcmp is also | 
 |       // a little gross, but there is no need to super optimize here. | 
 |       ScratchArgs = AF.Add(ScratchArgs, 1, DecRef); | 
 |       S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing); | 
 |     } else if (FName == "IOServiceAddNotification" || | 
 |                FName == "IOServiceAddMatchingNotification") { | 
 |       // Part of <rdar://problem/6961230>. (IOKit) | 
 |       // This should be addressed using a API table. | 
 |       ScratchArgs = AF.Add(ScratchArgs, 2, DecRef); | 
 |       S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing); | 
 |     } else if (FName == "CVPixelBufferCreateWithBytes") { | 
 |       // FIXES: <rdar://problem/7283567> | 
 |       // Eventually this can be improved by recognizing that the pixel | 
 |       // buffer passed to CVPixelBufferCreateWithBytes is released via | 
 |       // a callback and doing full IPA to make sure this is done correctly. | 
 |       // FIXME: This function has an out parameter that returns an | 
 |       // allocated object. | 
 |       ScratchArgs = AF.Add(ScratchArgs, 7, StopTracking); | 
 |       S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing); | 
 |     } else if (FName == "CGBitmapContextCreateWithData") { | 
 |       // FIXES: <rdar://problem/7358899> | 
 |       // Eventually this can be improved by recognizing that 'releaseInfo' | 
 |       // passed to CGBitmapContextCreateWithData is released via | 
 |       // a callback and doing full IPA to make sure this is done correctly. | 
 |       ScratchArgs = AF.Add(ScratchArgs, 8, StopTracking); | 
 |       S = getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF, true), | 
 |                                DoNothing, DoNothing); | 
 |     } else if (FName == "CVPixelBufferCreateWithPlanarBytes") { | 
 |       // FIXES: <rdar://problem/7283567> | 
 |       // Eventually this can be improved by recognizing that the pixel | 
 |       // buffer passed to CVPixelBufferCreateWithPlanarBytes is released | 
 |       // via a callback and doing full IPA to make sure this is done | 
 |       // correctly. | 
 |       ScratchArgs = AF.Add(ScratchArgs, 12, StopTracking); | 
 |       S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing); | 
 |     } | 
 |  | 
 |     // Did we get a summary? | 
 |     if (S) | 
 |       break; | 
 |  | 
 |     // Enable this code once the semantics of NSDeallocateObject are resolved | 
 |     // for GC.  <rdar://problem/6619988> | 
 | #if 0 | 
 |     // Handle: NSDeallocateObject(id anObject); | 
 |     // This method does allow 'nil' (although we don't check it now). | 
 |     if (strcmp(FName, "NSDeallocateObject") == 0) { | 
 |       return RetTy == Ctx.VoidTy | 
 |         ? getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, Dealloc) | 
 |         : getPersistentStopSummary(); | 
 |     } | 
 | #endif | 
 |  | 
 |     if (RetTy->isPointerType()) { | 
 |       // For CoreFoundation ('CF') types. | 
 |       if (cocoa::isRefType(RetTy, "CF", FName)) { | 
 |         if (isRetain(FD, FName)) | 
 |           S = getUnarySummary(FT, cfretain); | 
 |         else if (FName.find("MakeCollectable") != StringRef::npos) | 
 |           S = getUnarySummary(FT, cfmakecollectable); | 
 |         else | 
 |           S = getCFCreateGetRuleSummary(FD, FName); | 
 |  | 
 |         break; | 
 |       } | 
 |  | 
 |       // For CoreGraphics ('CG') types. | 
 |       if (cocoa::isRefType(RetTy, "CG", FName)) { | 
 |         if (isRetain(FD, FName)) | 
 |           S = getUnarySummary(FT, cfretain); | 
 |         else | 
 |           S = getCFCreateGetRuleSummary(FD, FName); | 
 |  | 
 |         break; | 
 |       } | 
 |  | 
 |       // For the Disk Arbitration API (DiskArbitration/DADisk.h) | 
 |       if (cocoa::isRefType(RetTy, "DADisk") || | 
 |           cocoa::isRefType(RetTy, "DADissenter") || | 
 |           cocoa::isRefType(RetTy, "DASessionRef")) { | 
 |         S = getCFCreateGetRuleSummary(FD, FName); | 
 |         break; | 
 |       } | 
 |  | 
 |       break; | 
 |     } | 
 |  | 
 |     // Check for release functions, the only kind of functions that we care | 
 |     // about that don't return a pointer type. | 
 |     if (FName[0] == 'C' && (FName[1] == 'F' || FName[1] == 'G')) { | 
 |       // Test for 'CGCF'. | 
 |       FName = FName.substr(FName.startswith("CGCF") ? 4 : 2); | 
 |  | 
 |       if (isRelease(FD, FName)) | 
 |         S = getUnarySummary(FT, cfrelease); | 
 |       else { | 
 |         assert (ScratchArgs.isEmpty()); | 
 |         // Remaining CoreFoundation and CoreGraphics functions. | 
 |         // We use to assume that they all strictly followed the ownership idiom | 
 |         // and that ownership cannot be transferred.  While this is technically | 
 |         // correct, many methods allow a tracked object to escape.  For example: | 
 |         // | 
 |         //   CFMutableDictionaryRef x = CFDictionaryCreateMutable(...); | 
 |         //   CFDictionaryAddValue(y, key, x); | 
 |         //   CFRelease(x); | 
 |         //   ... it is okay to use 'x' since 'y' has a reference to it | 
 |         // | 
 |         // We handle this and similar cases with the follow heuristic.  If the | 
 |         // function name contains "InsertValue", "SetValue", "AddValue", | 
 |         // "AppendValue", or "SetAttribute", then we assume that arguments may | 
 |         // "escape."  This means that something else holds on to the object, | 
 |         // allowing it be used even after its local retain count drops to 0. | 
 |         ArgEffect E = (StrInStrNoCase(FName, "InsertValue") != StringRef::npos|| | 
 |                        StrInStrNoCase(FName, "AddValue") != StringRef::npos || | 
 |                        StrInStrNoCase(FName, "SetValue") != StringRef::npos || | 
 |                        StrInStrNoCase(FName, "AppendValue") != StringRef::npos|| | 
 |                        StrInStrNoCase(FName, "SetAttribute") != StringRef::npos) | 
 |                       ? MayEscape : DoNothing; | 
 |  | 
 |         S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, E); | 
 |       } | 
 |     } | 
 |   } | 
 |   while (0); | 
 |  | 
 |   if (!S) | 
 |     S = getDefaultSummary(); | 
 |  | 
 |   // Annotations override defaults. | 
 |   assert(S); | 
 |   updateSummaryFromAnnotations(*S, FD); | 
 |  | 
 |   FuncSummaries[FD] = S; | 
 |   return S; | 
 | } | 
 |  | 
 | RetainSummary* | 
 | RetainSummaryManager::getCFCreateGetRuleSummary(FunctionDecl* FD, | 
 |                                                 StringRef FName) { | 
 |  | 
 |   if (FName.find("Create") != StringRef::npos || | 
 |       FName.find("Copy") != StringRef::npos) | 
 |     return getCFSummaryCreateRule(FD); | 
 |  | 
 |   if (FName.find("Get") != StringRef::npos) | 
 |     return getCFSummaryGetRule(FD); | 
 |  | 
 |   return getDefaultSummary(); | 
 | } | 
 |  | 
 | RetainSummary* | 
 | RetainSummaryManager::getUnarySummary(const FunctionType* FT, | 
 |                                       UnaryFuncKind func) { | 
 |  | 
 |   // Sanity check that this is *really* a unary function.  This can | 
 |   // happen if people do weird things. | 
 |   const FunctionProtoType* FTP = dyn_cast<FunctionProtoType>(FT); | 
 |   if (!FTP || FTP->getNumArgs() != 1) | 
 |     return getPersistentStopSummary(); | 
 |  | 
 |   assert (ScratchArgs.isEmpty()); | 
 |  | 
 |   switch (func) { | 
 |     case cfretain: { | 
 |       ScratchArgs = AF.Add(ScratchArgs, 0, IncRef); | 
 |       return getPersistentSummary(RetEffect::MakeAlias(0), | 
 |                                   DoNothing, DoNothing); | 
 |     } | 
 |  | 
 |     case cfrelease: { | 
 |       ScratchArgs = AF.Add(ScratchArgs, 0, DecRef); | 
 |       return getPersistentSummary(RetEffect::MakeNoRet(), | 
 |                                   DoNothing, DoNothing); | 
 |     } | 
 |  | 
 |     case cfmakecollectable: { | 
 |       ScratchArgs = AF.Add(ScratchArgs, 0, MakeCollectable); | 
 |       return getPersistentSummary(RetEffect::MakeAlias(0),DoNothing, DoNothing); | 
 |     } | 
 |  | 
 |     default: | 
 |       assert (false && "Not a supported unary function."); | 
 |       return getDefaultSummary(); | 
 |   } | 
 | } | 
 |  | 
 | RetainSummary* RetainSummaryManager::getCFSummaryCreateRule(FunctionDecl* FD) { | 
 |   assert (ScratchArgs.isEmpty()); | 
 |  | 
 |   if (FD->getIdentifier() == CFDictionaryCreateII) { | 
 |     ScratchArgs = AF.Add(ScratchArgs, 1, DoNothingByRef); | 
 |     ScratchArgs = AF.Add(ScratchArgs, 2, DoNothingByRef); | 
 |   } | 
 |  | 
 |   return getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF, true)); | 
 | } | 
 |  | 
 | RetainSummary* RetainSummaryManager::getCFSummaryGetRule(FunctionDecl* FD) { | 
 |   assert (ScratchArgs.isEmpty()); | 
 |   return getPersistentSummary(RetEffect::MakeNotOwned(RetEffect::CF), | 
 |                               DoNothing, DoNothing); | 
 | } | 
 |  | 
 | //===----------------------------------------------------------------------===// | 
 | // Summary creation for Selectors. | 
 | //===----------------------------------------------------------------------===// | 
 |  | 
 | RetainSummary* | 
 | RetainSummaryManager::getInitMethodSummary(QualType RetTy) { | 
 |   assert(ScratchArgs.isEmpty()); | 
 |   // 'init' methods conceptually return a newly allocated object and claim | 
 |   // the receiver. | 
 |   if (cocoa::isCocoaObjectRef(RetTy) || cocoa::isCFObjectRef(RetTy)) | 
 |     return getPersistentSummary(ObjCInitRetE, DecRefMsg); | 
 |  | 
 |   return getDefaultSummary(); | 
 | } | 
 |  | 
 | void | 
 | RetainSummaryManager::updateSummaryFromAnnotations(RetainSummary &Summ, | 
 |                                                    const FunctionDecl *FD) { | 
 |   if (!FD) | 
 |     return; | 
 |  | 
 |   QualType RetTy = FD->getResultType(); | 
 |  | 
 |   // Determine if there is a special return effect for this method. | 
 |   if (cocoa::isCocoaObjectRef(RetTy)) { | 
 |     if (FD->getAttr<NSReturnsRetainedAttr>()) { | 
 |       Summ.setRetEffect(ObjCAllocRetE); | 
 |     } | 
 |     else if (FD->getAttr<CFReturnsRetainedAttr>()) { | 
 |       Summ.setRetEffect(RetEffect::MakeOwned(RetEffect::CF, true)); | 
 |     } | 
 |     else if (FD->getAttr<NSReturnsNotRetainedAttr>()) { | 
 |       Summ.setRetEffect(RetEffect::MakeNotOwned(RetEffect::ObjC)); | 
 |     } | 
 |     else if (FD->getAttr<CFReturnsNotRetainedAttr>()) { | 
 |       Summ.setRetEffect(RetEffect::MakeNotOwned(RetEffect::CF)); | 
 |     } | 
 |   } | 
 |   else if (RetTy->getAs<PointerType>()) { | 
 |     if (FD->getAttr<CFReturnsRetainedAttr>()) { | 
 |       Summ.setRetEffect(RetEffect::MakeOwned(RetEffect::CF, true)); | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | void | 
 | RetainSummaryManager::updateSummaryFromAnnotations(RetainSummary &Summ, | 
 |                                                   const ObjCMethodDecl *MD) { | 
 |   if (!MD) | 
 |     return; | 
 |  | 
 |   bool isTrackedLoc = false; | 
 |  | 
 |   // Determine if there is a special return effect for this method. | 
 |   if (cocoa::isCocoaObjectRef(MD->getResultType())) { | 
 |     if (MD->getAttr<NSReturnsRetainedAttr>()) { | 
 |       Summ.setRetEffect(ObjCAllocRetE); | 
 |       return; | 
 |     } | 
 |     if (MD->getAttr<NSReturnsNotRetainedAttr>()) { | 
 |       Summ.setRetEffect(RetEffect::MakeNotOwned(RetEffect::ObjC)); | 
 |       return; | 
 |     } | 
 |  | 
 |     isTrackedLoc = true; | 
 |   } | 
 |  | 
 |   if (!isTrackedLoc) | 
 |     isTrackedLoc = MD->getResultType()->getAs<PointerType>() != NULL; | 
 |  | 
 |   if (isTrackedLoc) { | 
 |     if (MD->getAttr<CFReturnsRetainedAttr>()) | 
 |       Summ.setRetEffect(RetEffect::MakeOwned(RetEffect::CF, true)); | 
 |     else if (MD->getAttr<CFReturnsNotRetainedAttr>()) | 
 |       Summ.setRetEffect(RetEffect::MakeNotOwned(RetEffect::CF)); | 
 |   } | 
 | } | 
 |  | 
 | RetainSummary* | 
 | RetainSummaryManager::getCommonMethodSummary(const ObjCMethodDecl* MD, | 
 |                                              Selector S, QualType RetTy) { | 
 |  | 
 |   if (MD) { | 
 |     // Scan the method decl for 'void*' arguments.  These should be treated | 
 |     // as 'StopTracking' because they are often used with delegates. | 
 |     // Delegates are a frequent form of false positives with the retain | 
 |     // count checker. | 
 |     unsigned i = 0; | 
 |     for (ObjCMethodDecl::param_iterator I = MD->param_begin(), | 
 |          E = MD->param_end(); I != E; ++I, ++i) | 
 |       if (ParmVarDecl *PD = *I) { | 
 |         QualType Ty = Ctx.getCanonicalType(PD->getType()); | 
 |         if (Ty.getLocalUnqualifiedType() == Ctx.VoidPtrTy) | 
 |           ScratchArgs = AF.Add(ScratchArgs, i, StopTracking); | 
 |       } | 
 |   } | 
 |  | 
 |   // Any special effect for the receiver? | 
 |   ArgEffect ReceiverEff = DoNothing; | 
 |  | 
 |   // If one of the arguments in the selector has the keyword 'delegate' we | 
 |   // should stop tracking the reference count for the receiver.  This is | 
 |   // because the reference count is quite possibly handled by a delegate | 
 |   // method. | 
 |   if (S.isKeywordSelector()) { | 
 |     const std::string &str = S.getAsString(); | 
 |     assert(!str.empty()); | 
 |     if (StrInStrNoCase(str, "delegate:") != StringRef::npos) | 
 |       ReceiverEff = StopTracking; | 
 |   } | 
 |  | 
 |   // Look for methods that return an owned object. | 
 |   if (cocoa::isCocoaObjectRef(RetTy)) { | 
 |     // EXPERIMENTAL: Assume the Cocoa conventions for all objects returned | 
 |     //  by instance methods. | 
 |     RetEffect E = cocoa::followsFundamentalRule(S) | 
 |                   ? ObjCAllocRetE : RetEffect::MakeNotOwned(RetEffect::ObjC); | 
 |  | 
 |     return getPersistentSummary(E, ReceiverEff, MayEscape); | 
 |   } | 
 |  | 
 |   // Look for methods that return an owned core foundation object. | 
 |   if (cocoa::isCFObjectRef(RetTy)) { | 
 |     RetEffect E = cocoa::followsFundamentalRule(S) | 
 |       ? RetEffect::MakeOwned(RetEffect::CF, true) | 
 |       : RetEffect::MakeNotOwned(RetEffect::CF); | 
 |  | 
 |     return getPersistentSummary(E, ReceiverEff, MayEscape); | 
 |   } | 
 |  | 
 |   if (ScratchArgs.isEmpty() && ReceiverEff == DoNothing) | 
 |     return getDefaultSummary(); | 
 |  | 
 |   return getPersistentSummary(RetEffect::MakeNoRet(), ReceiverEff, MayEscape); | 
 | } | 
 |  | 
 | RetainSummary* | 
 | RetainSummaryManager::getInstanceMethodSummary(const ObjCMessageExpr *ME, | 
 |                                                const GRState *state, | 
 |                                                const LocationContext *LC) { | 
 |  | 
 |   // We need the type-information of the tracked receiver object | 
 |   // Retrieve it from the state. | 
 |   const Expr *Receiver = ME->getInstanceReceiver(); | 
 |   const ObjCInterfaceDecl* ID = 0; | 
 |  | 
 |   // FIXME: Is this really working as expected?  There are cases where | 
 |   //  we just use the 'ID' from the message expression. | 
 |   SVal receiverV; | 
 |  | 
 |   if (const Expr *Receiver = ME->getInstanceReceiver()) { | 
 |     receiverV = state->getSValAsScalarOrLoc(Receiver); | 
 |    | 
 |     // FIXME: Eventually replace the use of state->get<RefBindings> with | 
 |     // a generic API for reasoning about the Objective-C types of symbolic | 
 |     // objects. | 
 |     if (SymbolRef Sym = receiverV.getAsLocSymbol()) | 
 |       if (const RefVal *T = state->get<RefBindings>(Sym)) | 
 |         if (const ObjCObjectPointerType* PT =  | 
 |             T->getType()->getAs<ObjCObjectPointerType>()) | 
 |           ID = PT->getInterfaceDecl(); | 
 |    | 
 |     // FIXME: this is a hack.  This may or may not be the actual method | 
 |     //  that is called. | 
 |     if (!ID) { | 
 |       if (const ObjCObjectPointerType *PT = | 
 |           Receiver->getType()->getAs<ObjCObjectPointerType>()) | 
 |         ID = PT->getInterfaceDecl(); | 
 |     } | 
 |   } else { | 
 |     // FIXME: Hack for 'super'. | 
 |     ID = ME->getReceiverInterface(); | 
 |   } | 
 |  | 
 |   // FIXME: The receiver could be a reference to a class, meaning that | 
 |   //  we should use the class method. | 
 |   RetainSummary *Summ = getInstanceMethodSummary(ME, ID); | 
 |    | 
 |   // Special-case: are we sending a mesage to "self"? | 
 |   //  This is a hack.  When we have full-IP this should be removed. | 
 |   if (isa<ObjCMethodDecl>(LC->getDecl()) && Receiver) { | 
 |     if (const loc::MemRegionVal *L = dyn_cast<loc::MemRegionVal>(&receiverV)) { | 
 |       // Get the region associated with 'self'. | 
 |       if (const ImplicitParamDecl *SelfDecl = LC->getSelfDecl()) { | 
 |         SVal SelfVal = state->getSVal(state->getRegion(SelfDecl, LC)); | 
 |         if (L->StripCasts() == SelfVal.getAsRegion()) { | 
 |           // Update the summary to make the default argument effect | 
 |           // 'StopTracking'. | 
 |           Summ = copySummary(Summ); | 
 |           Summ->setDefaultArgEffect(StopTracking); | 
 |         } | 
 |       } | 
 |     } | 
 |   } | 
 |    | 
 |   return Summ ? Summ : getDefaultSummary(); | 
 | } | 
 |  | 
 | RetainSummary* | 
 | RetainSummaryManager::getInstanceMethodSummary(Selector S, | 
 |                                                IdentifierInfo *ClsName, | 
 |                                                const ObjCInterfaceDecl* ID, | 
 |                                                const ObjCMethodDecl *MD, | 
 |                                                QualType RetTy) { | 
 |  | 
 |   // Look up a summary in our summary cache. | 
 |   RetainSummary *Summ = ObjCMethodSummaries.find(ID, ClsName, S); | 
 |  | 
 |   if (!Summ) { | 
 |     assert(ScratchArgs.isEmpty()); | 
 |  | 
 |     // "initXXX": pass-through for receiver. | 
 |     if (cocoa::deriveNamingConvention(S) == cocoa::InitRule) | 
 |       Summ = getInitMethodSummary(RetTy); | 
 |     else | 
 |       Summ = getCommonMethodSummary(MD, S, RetTy); | 
 |  | 
 |     // Annotations override defaults. | 
 |     updateSummaryFromAnnotations(*Summ, MD); | 
 |  | 
 |     // Memoize the summary. | 
 |     ObjCMethodSummaries[ObjCSummaryKey(ID, ClsName, S)] = Summ; | 
 |   } | 
 |  | 
 |   return Summ; | 
 | } | 
 |  | 
 | RetainSummary* | 
 | RetainSummaryManager::getClassMethodSummary(Selector S, IdentifierInfo *ClsName, | 
 |                                             const ObjCInterfaceDecl *ID, | 
 |                                             const ObjCMethodDecl *MD, | 
 |                                             QualType RetTy) { | 
 |  | 
 |   assert(ClsName && "Class name must be specified."); | 
 |   RetainSummary *Summ = ObjCClassMethodSummaries.find(ID, ClsName, S); | 
 |  | 
 |   if (!Summ) { | 
 |     Summ = getCommonMethodSummary(MD, S, RetTy); | 
 |     // Annotations override defaults. | 
 |     updateSummaryFromAnnotations(*Summ, MD); | 
 |     // Memoize the summary. | 
 |     ObjCClassMethodSummaries[ObjCSummaryKey(ID, ClsName, S)] = Summ; | 
 |   } | 
 |  | 
 |   return Summ; | 
 | } | 
 |  | 
 | void RetainSummaryManager::InitializeClassMethodSummaries() { | 
 |   assert(ScratchArgs.isEmpty()); | 
 |   RetainSummary* Summ = getPersistentSummary(ObjCAllocRetE); | 
 |  | 
 |   // Create the summaries for "alloc", "new", and "allocWithZone:" for | 
 |   // NSObject and its derivatives. | 
 |   addNSObjectClsMethSummary(GetNullarySelector("alloc", Ctx), Summ); | 
 |   addNSObjectClsMethSummary(GetNullarySelector("new", Ctx), Summ); | 
 |   addNSObjectClsMethSummary(GetUnarySelector("allocWithZone", Ctx), Summ); | 
 |  | 
 |   // Create the [NSAssertionHandler currentHander] summary. | 
 |   addClassMethSummary("NSAssertionHandler", "currentHandler", | 
 |                 getPersistentSummary(RetEffect::MakeNotOwned(RetEffect::ObjC))); | 
 |  | 
 |   // Create the [NSAutoreleasePool addObject:] summary. | 
 |   ScratchArgs = AF.Add(ScratchArgs, 0, Autorelease); | 
 |   addClassMethSummary("NSAutoreleasePool", "addObject", | 
 |                       getPersistentSummary(RetEffect::MakeNoRet(), | 
 |                                            DoNothing, Autorelease)); | 
 |  | 
 |   // Create a summary for [NSCursor dragCopyCursor]. | 
 |   addClassMethSummary("NSCursor", "dragCopyCursor", | 
 |                       getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, | 
 |                                            DoNothing)); | 
 |  | 
 |   // Create the summaries for [NSObject performSelector...].  We treat | 
 |   // these as 'stop tracking' for the arguments because they are often | 
 |   // used for delegates that can release the object.  When we have better | 
 |   // inter-procedural analysis we can potentially do something better.  This | 
 |   // workaround is to remove false positives. | 
 |   Summ = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, StopTracking); | 
 |   IdentifierInfo *NSObjectII = &Ctx.Idents.get("NSObject"); | 
 |   addClsMethSummary(NSObjectII, Summ, "performSelector", "withObject", | 
 |                     "afterDelay", NULL); | 
 |   addClsMethSummary(NSObjectII, Summ, "performSelector", "withObject", | 
 |                     "afterDelay", "inModes", NULL); | 
 |   addClsMethSummary(NSObjectII, Summ, "performSelectorOnMainThread", | 
 |                     "withObject", "waitUntilDone", NULL); | 
 |   addClsMethSummary(NSObjectII, Summ, "performSelectorOnMainThread", | 
 |                     "withObject", "waitUntilDone", "modes", NULL); | 
 |   addClsMethSummary(NSObjectII, Summ, "performSelector", "onThread", | 
 |                     "withObject", "waitUntilDone", NULL); | 
 |   addClsMethSummary(NSObjectII, Summ, "performSelector", "onThread", | 
 |                     "withObject", "waitUntilDone", "modes", NULL); | 
 |   addClsMethSummary(NSObjectII, Summ, "performSelectorInBackground", | 
 |                     "withObject", NULL); | 
 |  | 
 |   // Specially handle NSData. | 
 |   RetainSummary *dataWithBytesNoCopySumm = | 
 |     getPersistentSummary(RetEffect::MakeNotOwned(RetEffect::ObjC), DoNothing, | 
 |                          DoNothing); | 
 |   addClsMethSummary("NSData", dataWithBytesNoCopySumm, | 
 |                     "dataWithBytesNoCopy", "length", NULL); | 
 |   addClsMethSummary("NSData", dataWithBytesNoCopySumm, | 
 |                     "dataWithBytesNoCopy", "length", "freeWhenDone", NULL); | 
 | } | 
 |  | 
 | void RetainSummaryManager::InitializeMethodSummaries() { | 
 |  | 
 |   assert (ScratchArgs.isEmpty()); | 
 |  | 
 |   // Create the "init" selector.  It just acts as a pass-through for the | 
 |   // receiver. | 
 |   RetainSummary *InitSumm = getPersistentSummary(ObjCInitRetE, DecRefMsg); | 
 |   addNSObjectMethSummary(GetNullarySelector("init", Ctx), InitSumm); | 
 |  | 
 |   // awakeAfterUsingCoder: behaves basically like an 'init' method.  It | 
 |   // claims the receiver and returns a retained object. | 
 |   addNSObjectMethSummary(GetUnarySelector("awakeAfterUsingCoder", Ctx), | 
 |                          InitSumm); | 
 |  | 
 |   // The next methods are allocators. | 
 |   RetainSummary *AllocSumm = getPersistentSummary(ObjCAllocRetE); | 
 |   RetainSummary *CFAllocSumm = | 
 |     getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF, true)); | 
 |  | 
 |   // Create the "copy" selector. | 
 |   addNSObjectMethSummary(GetNullarySelector("copy", Ctx), AllocSumm); | 
 |  | 
 |   // Create the "mutableCopy" selector. | 
 |   addNSObjectMethSummary(GetNullarySelector("mutableCopy", Ctx), AllocSumm); | 
 |  | 
 |   // Create the "retain" selector. | 
 |   RetEffect E = RetEffect::MakeReceiverAlias(); | 
 |   RetainSummary *Summ = getPersistentSummary(E, IncRefMsg); | 
 |   addNSObjectMethSummary(GetNullarySelector("retain", Ctx), Summ); | 
 |  | 
 |   // Create the "release" selector. | 
 |   Summ = getPersistentSummary(E, DecRefMsg); | 
 |   addNSObjectMethSummary(GetNullarySelector("release", Ctx), Summ); | 
 |  | 
 |   // Create the "drain" selector. | 
 |   Summ = getPersistentSummary(E, isGCEnabled() ? DoNothing : DecRef); | 
 |   addNSObjectMethSummary(GetNullarySelector("drain", Ctx), Summ); | 
 |  | 
 |   // Create the -dealloc summary. | 
 |   Summ = getPersistentSummary(RetEffect::MakeNoRet(), Dealloc); | 
 |   addNSObjectMethSummary(GetNullarySelector("dealloc", Ctx), Summ); | 
 |  | 
 |   // Create the "autorelease" selector. | 
 |   Summ = getPersistentSummary(E, Autorelease); | 
 |   addNSObjectMethSummary(GetNullarySelector("autorelease", Ctx), Summ); | 
 |  | 
 |   // Specially handle NSAutoreleasePool. | 
 |   addInstMethSummary("NSAutoreleasePool", "init", | 
 |                      getPersistentSummary(RetEffect::MakeReceiverAlias(), | 
 |                                           NewAutoreleasePool)); | 
 |  | 
 |   // For NSWindow, allocated objects are (initially) self-owned. | 
 |   // FIXME: For now we opt for false negatives with NSWindow, as these objects | 
 |   //  self-own themselves.  However, they only do this once they are displayed. | 
 |   //  Thus, we need to track an NSWindow's display status. | 
 |   //  This is tracked in <rdar://problem/6062711>. | 
 |   //  See also http://llvm.org/bugs/show_bug.cgi?id=3714. | 
 |   RetainSummary *NoTrackYet = getPersistentSummary(RetEffect::MakeNoRet(), | 
 |                                                    StopTracking, | 
 |                                                    StopTracking); | 
 |  | 
 |   addClassMethSummary("NSWindow", "alloc", NoTrackYet); | 
 |  | 
 | #if 0 | 
 |   addInstMethSummary("NSWindow", NoTrackYet, "initWithContentRect", | 
 |                      "styleMask", "backing", "defer", NULL); | 
 |  | 
 |   addInstMethSummary("NSWindow", NoTrackYet, "initWithContentRect", | 
 |                      "styleMask", "backing", "defer", "screen", NULL); | 
 | #endif | 
 |  | 
 |   // For NSPanel (which subclasses NSWindow), allocated objects are not | 
 |   //  self-owned. | 
 |   // FIXME: For now we don't track NSPanels. object for the same reason | 
 |   //   as for NSWindow objects. | 
 |   addClassMethSummary("NSPanel", "alloc", NoTrackYet); | 
 |  | 
 | #if 0 | 
 |   addInstMethSummary("NSPanel", NoTrackYet, "initWithContentRect", | 
 |                      "styleMask", "backing", "defer", NULL); | 
 |  | 
 |   addInstMethSummary("NSPanel", NoTrackYet, "initWithContentRect", | 
 |                      "styleMask", "backing", "defer", "screen", NULL); | 
 | #endif | 
 |  | 
 |   // Don't track allocated autorelease pools yet, as it is okay to prematurely | 
 |   // exit a method. | 
 |   addClassMethSummary("NSAutoreleasePool", "alloc", NoTrackYet); | 
 |  | 
 |   // Create NSAssertionHandler summaries. | 
 |   addPanicSummary("NSAssertionHandler", "handleFailureInFunction", "file", | 
 |                   "lineNumber", "description", NULL); | 
 |  | 
 |   addPanicSummary("NSAssertionHandler", "handleFailureInMethod", "object", | 
 |                   "file", "lineNumber", "description", NULL); | 
 |  | 
 |   // Create summaries QCRenderer/QCView -createSnapShotImageOfType: | 
 |   addInstMethSummary("QCRenderer", AllocSumm, | 
 |                      "createSnapshotImageOfType", NULL); | 
 |   addInstMethSummary("QCView", AllocSumm, | 
 |                      "createSnapshotImageOfType", NULL); | 
 |  | 
 |   // Create summaries for CIContext, 'createCGImage' and | 
 |   // 'createCGLayerWithSize'.  These objects are CF objects, and are not | 
 |   // automatically garbage collected. | 
 |   addInstMethSummary("CIContext", CFAllocSumm, | 
 |                      "createCGImage", "fromRect", NULL); | 
 |   addInstMethSummary("CIContext", CFAllocSumm, | 
 |                      "createCGImage", "fromRect", "format", "colorSpace", NULL); | 
 |   addInstMethSummary("CIContext", CFAllocSumm, "createCGLayerWithSize", | 
 |            "info", NULL); | 
 | } | 
 |  | 
 | //===----------------------------------------------------------------------===// | 
 | // AutoreleaseBindings - State used to track objects in autorelease pools. | 
 | //===----------------------------------------------------------------------===// | 
 |  | 
 | typedef llvm::ImmutableMap<SymbolRef, unsigned> ARCounts; | 
 | typedef llvm::ImmutableMap<SymbolRef, ARCounts> ARPoolContents; | 
 | typedef llvm::ImmutableList<SymbolRef> ARStack; | 
 |  | 
 | static int AutoRCIndex = 0; | 
 | static int AutoRBIndex = 0; | 
 |  | 
 | namespace { class AutoreleasePoolContents {}; } | 
 | namespace { class AutoreleaseStack {}; } | 
 |  | 
 | namespace clang { | 
 | template<> struct GRStateTrait<AutoreleaseStack> | 
 |   : public GRStatePartialTrait<ARStack> { | 
 |   static inline void* GDMIndex() { return &AutoRBIndex; } | 
 | }; | 
 |  | 
 | template<> struct GRStateTrait<AutoreleasePoolContents> | 
 |   : public GRStatePartialTrait<ARPoolContents> { | 
 |   static inline void* GDMIndex() { return &AutoRCIndex; } | 
 | }; | 
 | } // end clang namespace | 
 |  | 
 | static SymbolRef GetCurrentAutoreleasePool(const GRState* state) { | 
 |   ARStack stack = state->get<AutoreleaseStack>(); | 
 |   return stack.isEmpty() ? SymbolRef() : stack.getHead(); | 
 | } | 
 |  | 
 | static const GRState * SendAutorelease(const GRState *state, | 
 |                                        ARCounts::Factory &F, SymbolRef sym) { | 
 |  | 
 |   SymbolRef pool = GetCurrentAutoreleasePool(state); | 
 |   const ARCounts *cnts = state->get<AutoreleasePoolContents>(pool); | 
 |   ARCounts newCnts(0); | 
 |  | 
 |   if (cnts) { | 
 |     const unsigned *cnt = (*cnts).lookup(sym); | 
 |     newCnts = F.Add(*cnts, sym, cnt ? *cnt  + 1 : 1); | 
 |   } | 
 |   else | 
 |     newCnts = F.Add(F.GetEmptyMap(), sym, 1); | 
 |  | 
 |   return state->set<AutoreleasePoolContents>(pool, newCnts); | 
 | } | 
 |  | 
 | //===----------------------------------------------------------------------===// | 
 | // Transfer functions. | 
 | //===----------------------------------------------------------------------===// | 
 |  | 
 | namespace { | 
 |  | 
 | class CFRefCount : public GRTransferFuncs { | 
 | public: | 
 |   class BindingsPrinter : public GRState::Printer { | 
 |   public: | 
 |     virtual void Print(llvm::raw_ostream& Out, const GRState* state, | 
 |                        const char* nl, const char* sep); | 
 |   }; | 
 |  | 
 | private: | 
 |   typedef llvm::DenseMap<const ExplodedNode*, const RetainSummary*> | 
 |     SummaryLogTy; | 
 |  | 
 |   RetainSummaryManager Summaries; | 
 |   SummaryLogTy SummaryLog; | 
 |   const LangOptions&   LOpts; | 
 |   ARCounts::Factory    ARCountFactory; | 
 |  | 
 |   BugType *useAfterRelease, *releaseNotOwned; | 
 |   BugType *deallocGC, *deallocNotOwned; | 
 |   BugType *leakWithinFunction, *leakAtReturn; | 
 |   BugType *overAutorelease; | 
 |   BugType *returnNotOwnedForOwned; | 
 |   BugReporter *BR; | 
 |  | 
 |   const GRState * Update(const GRState * state, SymbolRef sym, RefVal V, ArgEffect E, | 
 |                     RefVal::Kind& hasErr); | 
 |  | 
 |   void ProcessNonLeakError(ExplodedNodeSet& Dst, | 
 |                            GRStmtNodeBuilder& Builder, | 
 |                            Expr* NodeExpr, Expr* ErrorExpr, | 
 |                            ExplodedNode* Pred, | 
 |                            const GRState* St, | 
 |                            RefVal::Kind hasErr, SymbolRef Sym); | 
 |  | 
 |   const GRState * HandleSymbolDeath(const GRState * state, SymbolRef sid, RefVal V, | 
 |                                llvm::SmallVectorImpl<SymbolRef> &Leaked); | 
 |  | 
 |   ExplodedNode* ProcessLeaks(const GRState * state, | 
 |                                       llvm::SmallVectorImpl<SymbolRef> &Leaked, | 
 |                                       GenericNodeBuilder &Builder, | 
 |                                       GRExprEngine &Eng, | 
 |                                       ExplodedNode *Pred = 0); | 
 |  | 
 | public: | 
 |   CFRefCount(ASTContext& Ctx, bool gcenabled, const LangOptions& lopts) | 
 |     : Summaries(Ctx, gcenabled), | 
 |       LOpts(lopts), useAfterRelease(0), releaseNotOwned(0), | 
 |       deallocGC(0), deallocNotOwned(0), | 
 |       leakWithinFunction(0), leakAtReturn(0), overAutorelease(0), | 
 |       returnNotOwnedForOwned(0), BR(0) {} | 
 |  | 
 |   virtual ~CFRefCount() {} | 
 |  | 
 |   void RegisterChecks(GRExprEngine &Eng); | 
 |  | 
 |   virtual void RegisterPrinters(std::vector<GRState::Printer*>& Printers) { | 
 |     Printers.push_back(new BindingsPrinter()); | 
 |   } | 
 |  | 
 |   bool isGCEnabled() const { return Summaries.isGCEnabled(); } | 
 |   const LangOptions& getLangOptions() const { return LOpts; } | 
 |  | 
 |   const RetainSummary *getSummaryOfNode(const ExplodedNode *N) const { | 
 |     SummaryLogTy::const_iterator I = SummaryLog.find(N); | 
 |     return I == SummaryLog.end() ? 0 : I->second; | 
 |   } | 
 |  | 
 |   // Calls. | 
 |  | 
 |   void EvalSummary(ExplodedNodeSet& Dst, | 
 |                    GRExprEngine& Eng, | 
 |                    GRStmtNodeBuilder& Builder, | 
 |                    Expr* Ex, | 
 |                    Expr* Receiver, | 
 |                    const RetainSummary& Summ, | 
 |                    const MemRegion *Callee, | 
 |                    ExprIterator arg_beg, ExprIterator arg_end, | 
 |                    ExplodedNode* Pred, const GRState *state); | 
 |  | 
 |   virtual void EvalCall(ExplodedNodeSet& Dst, | 
 |                         GRExprEngine& Eng, | 
 |                         GRStmtNodeBuilder& Builder, | 
 |                         CallExpr* CE, SVal L, | 
 |                         ExplodedNode* Pred); | 
 |  | 
 |  | 
 |   virtual void EvalObjCMessageExpr(ExplodedNodeSet& Dst, | 
 |                                    GRExprEngine& Engine, | 
 |                                    GRStmtNodeBuilder& Builder, | 
 |                                    ObjCMessageExpr* ME, | 
 |                                    ExplodedNode* Pred, | 
 |                                    const GRState *state); | 
 |  | 
 |   bool EvalObjCMessageExprAux(ExplodedNodeSet& Dst, | 
 |                               GRExprEngine& Engine, | 
 |                               GRStmtNodeBuilder& Builder, | 
 |                               ObjCMessageExpr* ME, | 
 |                               ExplodedNode* Pred); | 
 |  | 
 |   // Stores. | 
 |   virtual void EvalBind(GRStmtNodeBuilderRef& B, SVal location, SVal val); | 
 |  | 
 |   // End-of-path. | 
 |  | 
 |   virtual void EvalEndPath(GRExprEngine& Engine, | 
 |                            GREndPathNodeBuilder& Builder); | 
 |  | 
 |   virtual void EvalDeadSymbols(ExplodedNodeSet& Dst, | 
 |                                GRExprEngine& Engine, | 
 |                                GRStmtNodeBuilder& Builder, | 
 |                                ExplodedNode* Pred, | 
 |                                Stmt* S, const GRState* state, | 
 |                                SymbolReaper& SymReaper); | 
 |  | 
 |   std::pair<ExplodedNode*, const GRState *> | 
 |   HandleAutoreleaseCounts(const GRState * state, GenericNodeBuilder Bd, | 
 |                           ExplodedNode* Pred, GRExprEngine &Eng, | 
 |                           SymbolRef Sym, RefVal V, bool &stop); | 
 |   // Return statements. | 
 |  | 
 |   virtual void EvalReturn(ExplodedNodeSet& Dst, | 
 |                           GRExprEngine& Engine, | 
 |                           GRStmtNodeBuilder& Builder, | 
 |                           ReturnStmt* S, | 
 |                           ExplodedNode* Pred); | 
 |  | 
 |   // Assumptions. | 
 |  | 
 |   virtual const GRState *EvalAssume(const GRState* state, SVal condition, | 
 |                                     bool assumption); | 
 | }; | 
 |  | 
 | } // end anonymous namespace | 
 |  | 
 | static void PrintPool(llvm::raw_ostream &Out, SymbolRef Sym, | 
 |                       const GRState *state) { | 
 |   Out << ' '; | 
 |   if (Sym) | 
 |     Out << Sym->getSymbolID(); | 
 |   else | 
 |     Out << "<pool>"; | 
 |   Out << ":{"; | 
 |  | 
 |   // Get the contents of the pool. | 
 |   if (const ARCounts *cnts = state->get<AutoreleasePoolContents>(Sym)) | 
 |     for (ARCounts::iterator J=cnts->begin(), EJ=cnts->end(); J != EJ; ++J) | 
 |       Out << '(' << J.getKey() << ',' << J.getData() << ')'; | 
 |  | 
 |   Out << '}'; | 
 | } | 
 |  | 
 | void CFRefCount::BindingsPrinter::Print(llvm::raw_ostream& Out, | 
 |                                         const GRState* state, | 
 |                                         const char* nl, const char* sep) { | 
 |  | 
 |   RefBindings B = state->get<RefBindings>(); | 
 |  | 
 |   if (!B.isEmpty()) | 
 |     Out << sep << nl; | 
 |  | 
 |   for (RefBindings::iterator I=B.begin(), E=B.end(); I!=E; ++I) { | 
 |     Out << (*I).first << " : "; | 
 |     (*I).second.print(Out); | 
 |     Out << nl; | 
 |   } | 
 |  | 
 |   // Print the autorelease stack. | 
 |   Out << sep << nl << "AR pool stack:"; | 
 |   ARStack stack = state->get<AutoreleaseStack>(); | 
 |  | 
 |   PrintPool(Out, SymbolRef(), state);  // Print the caller's pool. | 
 |   for (ARStack::iterator I=stack.begin(), E=stack.end(); I!=E; ++I) | 
 |     PrintPool(Out, *I, state); | 
 |  | 
 |   Out << nl; | 
 | } | 
 |  | 
 | //===----------------------------------------------------------------------===// | 
 | // Error reporting. | 
 | //===----------------------------------------------------------------------===// | 
 |  | 
 | namespace { | 
 |  | 
 |   //===-------------===// | 
 |   // Bug Descriptions. // | 
 |   //===-------------===// | 
 |  | 
 |   class CFRefBug : public BugType { | 
 |   protected: | 
 |     CFRefCount& TF; | 
 |  | 
 |     CFRefBug(CFRefCount* tf, llvm::StringRef name) | 
 |     : BugType(name, "Memory (Core Foundation/Objective-C)"), TF(*tf) {} | 
 |   public: | 
 |  | 
 |     CFRefCount& getTF() { return TF; } | 
 |     const CFRefCount& getTF() const { return TF; } | 
 |  | 
 |     // FIXME: Eventually remove. | 
 |     virtual const char* getDescription() const = 0; | 
 |  | 
 |     virtual bool isLeak() const { return false; } | 
 |   }; | 
 |  | 
 |   class UseAfterRelease : public CFRefBug { | 
 |   public: | 
 |     UseAfterRelease(CFRefCount* tf) | 
 |     : CFRefBug(tf, "Use-after-release") {} | 
 |  | 
 |     const char* getDescription() const { | 
 |       return "Reference-counted object is used after it is released"; | 
 |     } | 
 |   }; | 
 |  | 
 |   class BadRelease : public CFRefBug { | 
 |   public: | 
 |     BadRelease(CFRefCount* tf) : CFRefBug(tf, "Bad release") {} | 
 |  | 
 |     const char* getDescription() const { | 
 |       return "Incorrect decrement of the reference count of an object that is " | 
 |              "not owned at this point by the caller"; | 
 |     } | 
 |   }; | 
 |  | 
 |   class DeallocGC : public CFRefBug { | 
 |   public: | 
 |     DeallocGC(CFRefCount *tf) | 
 |       : CFRefBug(tf, "-dealloc called while using garbage collection") {} | 
 |  | 
 |     const char *getDescription() const { | 
 |       return "-dealloc called while using garbage collection"; | 
 |     } | 
 |   }; | 
 |  | 
 |   class DeallocNotOwned : public CFRefBug { | 
 |   public: | 
 |     DeallocNotOwned(CFRefCount *tf) | 
 |       : CFRefBug(tf, "-dealloc sent to non-exclusively owned object") {} | 
 |  | 
 |     const char *getDescription() const { | 
 |       return "-dealloc sent to object that may be referenced elsewhere"; | 
 |     } | 
 |   }; | 
 |  | 
 |   class OverAutorelease : public CFRefBug { | 
 |   public: | 
 |     OverAutorelease(CFRefCount *tf) : | 
 |       CFRefBug(tf, "Object sent -autorelease too many times") {} | 
 |  | 
 |     const char *getDescription() const { | 
 |       return "Object sent -autorelease too many times"; | 
 |     } | 
 |   }; | 
 |  | 
 |   class ReturnedNotOwnedForOwned : public CFRefBug { | 
 |   public: | 
 |     ReturnedNotOwnedForOwned(CFRefCount *tf) : | 
 |       CFRefBug(tf, "Method should return an owned object") {} | 
 |  | 
 |     const char *getDescription() const { | 
 |       return "Object with +0 retain counts returned to caller where a +1 " | 
 |              "(owning) retain count is expected"; | 
 |     } | 
 |   }; | 
 |  | 
 |   class Leak : public CFRefBug { | 
 |     const bool isReturn; | 
 |   protected: | 
 |     Leak(CFRefCount* tf, llvm::StringRef name, bool isRet) | 
 |     : CFRefBug(tf, name), isReturn(isRet) {} | 
 |   public: | 
 |  | 
 |     const char* getDescription() const { return ""; } | 
 |  | 
 |     bool isLeak() const { return true; } | 
 |   }; | 
 |  | 
 |   class LeakAtReturn : public Leak { | 
 |   public: | 
 |     LeakAtReturn(CFRefCount* tf, llvm::StringRef name) | 
 |     : Leak(tf, name, true) {} | 
 |   }; | 
 |  | 
 |   class LeakWithinFunction : public Leak { | 
 |   public: | 
 |     LeakWithinFunction(CFRefCount* tf, llvm::StringRef name) | 
 |     : Leak(tf, name, false) {} | 
 |   }; | 
 |  | 
 |   //===---------===// | 
 |   // Bug Reports.  // | 
 |   //===---------===// | 
 |  | 
 |   class CFRefReport : public RangedBugReport { | 
 |   protected: | 
 |     SymbolRef Sym; | 
 |     const CFRefCount &TF; | 
 |   public: | 
 |     CFRefReport(CFRefBug& D, const CFRefCount &tf, | 
 |                 ExplodedNode *n, SymbolRef sym) | 
 |       : RangedBugReport(D, D.getDescription(), n), Sym(sym), TF(tf) {} | 
 |  | 
 |     CFRefReport(CFRefBug& D, const CFRefCount &tf, | 
 |                 ExplodedNode *n, SymbolRef sym, llvm::StringRef endText) | 
 |       : RangedBugReport(D, D.getDescription(), endText, n), Sym(sym), TF(tf) {} | 
 |  | 
 |     virtual ~CFRefReport() {} | 
 |  | 
 |     CFRefBug& getBugType() { | 
 |       return (CFRefBug&) RangedBugReport::getBugType(); | 
 |     } | 
 |     const CFRefBug& getBugType() const { | 
 |       return (const CFRefBug&) RangedBugReport::getBugType(); | 
 |     } | 
 |  | 
 |     virtual void getRanges(const SourceRange*& beg, const SourceRange*& end) { | 
 |       if (!getBugType().isLeak()) | 
 |         RangedBugReport::getRanges(beg, end); | 
 |       else | 
 |         beg = end = 0; | 
 |     } | 
 |  | 
 |     SymbolRef getSymbol() const { return Sym; } | 
 |  | 
 |     PathDiagnosticPiece* getEndPath(BugReporterContext& BRC, | 
 |                                     const ExplodedNode* N); | 
 |  | 
 |     std::pair<const char**,const char**> getExtraDescriptiveText(); | 
 |  | 
 |     PathDiagnosticPiece* VisitNode(const ExplodedNode* N, | 
 |                                    const ExplodedNode* PrevN, | 
 |                                    BugReporterContext& BRC); | 
 |   }; | 
 |  | 
 |   class CFRefLeakReport : public CFRefReport { | 
 |     SourceLocation AllocSite; | 
 |     const MemRegion* AllocBinding; | 
 |   public: | 
 |     CFRefLeakReport(CFRefBug& D, const CFRefCount &tf, | 
 |                     ExplodedNode *n, SymbolRef sym, | 
 |                     GRExprEngine& Eng); | 
 |  | 
 |     PathDiagnosticPiece* getEndPath(BugReporterContext& BRC, | 
 |                                     const ExplodedNode* N); | 
 |  | 
 |     SourceLocation getLocation() const { return AllocSite; } | 
 |   }; | 
 | } // end anonymous namespace | 
 |  | 
 |  | 
 |  | 
 | static const char* Msgs[] = { | 
 |   // GC only | 
 |   "Code is compiled to only use garbage collection", | 
 |   // No GC. | 
 |   "Code is compiled to use reference counts", | 
 |   // Hybrid, with GC. | 
 |   "Code is compiled to use either garbage collection (GC) or reference counts" | 
 |   " (non-GC).  The bug occurs with GC enabled", | 
 |   // Hybrid, without GC | 
 |   "Code is compiled to use either garbage collection (GC) or reference counts" | 
 |   " (non-GC).  The bug occurs in non-GC mode" | 
 | }; | 
 |  | 
 | std::pair<const char**,const char**> CFRefReport::getExtraDescriptiveText() { | 
 |   CFRefCount& TF = static_cast<CFRefBug&>(getBugType()).getTF(); | 
 |  | 
 |   switch (TF.getLangOptions().getGCMode()) { | 
 |     default: | 
 |       assert(false); | 
 |  | 
 |     case LangOptions::GCOnly: | 
 |       assert (TF.isGCEnabled()); | 
 |       return std::make_pair(&Msgs[0], &Msgs[0]+1); | 
 |  | 
 |     case LangOptions::NonGC: | 
 |       assert (!TF.isGCEnabled()); | 
 |       return std::make_pair(&Msgs[1], &Msgs[1]+1); | 
 |  | 
 |     case LangOptions::HybridGC: | 
 |       if (TF.isGCEnabled()) | 
 |         return std::make_pair(&Msgs[2], &Msgs[2]+1); | 
 |       else | 
 |         return std::make_pair(&Msgs[3], &Msgs[3]+1); | 
 |   } | 
 | } | 
 |  | 
 | static inline bool contains(const llvm::SmallVectorImpl<ArgEffect>& V, | 
 |                             ArgEffect X) { | 
 |   for (llvm::SmallVectorImpl<ArgEffect>::const_iterator I=V.begin(), E=V.end(); | 
 |        I!=E; ++I) | 
 |     if (*I == X) return true; | 
 |  | 
 |   return false; | 
 | } | 
 |  | 
 | PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N, | 
 |                                             const ExplodedNode* PrevN, | 
 |                                             BugReporterContext& BRC) { | 
 |  | 
 |   if (!isa<PostStmt>(N->getLocation())) | 
 |     return NULL; | 
 |  | 
 |   // Check if the type state has changed. | 
 |   const GRState *PrevSt = PrevN->getState(); | 
 |   const GRState *CurrSt = N->getState(); | 
 |  | 
 |   const RefVal* CurrT = CurrSt->get<RefBindings>(Sym); | 
 |   if (!CurrT) return NULL; | 
 |  | 
 |   const RefVal &CurrV = *CurrT; | 
 |   const RefVal *PrevT = PrevSt->get<RefBindings>(Sym); | 
 |  | 
 |   // Create a string buffer to constain all the useful things we want | 
 |   // to tell the user. | 
 |   std::string sbuf; | 
 |   llvm::raw_string_ostream os(sbuf); | 
 |  | 
 |   // This is the allocation site since the previous node had no bindings | 
 |   // for this symbol. | 
 |   if (!PrevT) { | 
 |     const Stmt* S = cast<PostStmt>(N->getLocation()).getStmt(); | 
 |  | 
 |     if (const CallExpr *CE = dyn_cast<CallExpr>(S)) { | 
 |       // Get the name of the callee (if it is available). | 
 |       SVal X = CurrSt->getSValAsScalarOrLoc(CE->getCallee()); | 
 |       if (const FunctionDecl* FD = X.getAsFunctionDecl()) | 
 |         os << "Call to function '" << FD << '\''; | 
 |       else | 
 |         os << "function call"; | 
 |     } | 
 |     else { | 
 |       assert (isa<ObjCMessageExpr>(S)); | 
 |       os << "Method"; | 
 |     } | 
 |  | 
 |     if (CurrV.getObjKind() == RetEffect::CF) { | 
 |       os << " returns a Core Foundation object with a "; | 
 |     } | 
 |     else { | 
 |       assert (CurrV.getObjKind() == RetEffect::ObjC); | 
 |       os << " returns an Objective-C object with a "; | 
 |     } | 
 |  | 
 |     if (CurrV.isOwned()) { | 
 |       os << "+1 retain count (owning reference)."; | 
 |  | 
 |       if (static_cast<CFRefBug&>(getBugType()).getTF().isGCEnabled()) { | 
 |         assert(CurrV.getObjKind() == RetEffect::CF); | 
 |         os << "  " | 
 |         "Core Foundation objects are not automatically garbage collected."; | 
 |       } | 
 |     } | 
 |     else { | 
 |       assert (CurrV.isNotOwned()); | 
 |       os << "+0 retain count (non-owning reference)."; | 
 |     } | 
 |  | 
 |     PathDiagnosticLocation Pos(S, BRC.getSourceManager()); | 
 |     return new PathDiagnosticEventPiece(Pos, os.str()); | 
 |   } | 
 |  | 
 |   // Gather up the effects that were performed on the object at this | 
 |   // program point | 
 |   llvm::SmallVector<ArgEffect, 2> AEffects; | 
 |  | 
 |   if (const RetainSummary *Summ = | 
 |         TF.getSummaryOfNode(BRC.getNodeResolver().getOriginalNode(N))) { | 
 |     // We only have summaries attached to nodes after evaluating CallExpr and | 
 |     // ObjCMessageExprs. | 
 |     const Stmt* S = cast<PostStmt>(N->getLocation()).getStmt(); | 
 |  | 
 |     if (const CallExpr *CE = dyn_cast<CallExpr>(S)) { | 
 |       // Iterate through the parameter expressions and see if the symbol | 
 |       // was ever passed as an argument. | 
 |       unsigned i = 0; | 
 |  | 
 |       for (CallExpr::const_arg_iterator AI=CE->arg_begin(), AE=CE->arg_end(); | 
 |            AI!=AE; ++AI, ++i) { | 
 |  | 
 |         // Retrieve the value of the argument.  Is it the symbol | 
 |         // we are interested in? | 
 |         if (CurrSt->getSValAsScalarOrLoc(*AI).getAsLocSymbol() != Sym) | 
 |           continue; | 
 |  | 
 |         // We have an argument.  Get the effect! | 
 |         AEffects.push_back(Summ->getArg(i)); | 
 |       } | 
 |     } | 
 |     else if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S)) { | 
 |       if (const Expr *receiver = ME->getInstanceReceiver()) | 
 |         if (CurrSt->getSValAsScalarOrLoc(receiver).getAsLocSymbol() == Sym) { | 
 |           // The symbol we are tracking is the receiver. | 
 |           AEffects.push_back(Summ->getReceiverEffect()); | 
 |         } | 
 |     } | 
 |   } | 
 |  | 
 |   do { | 
 |     // Get the previous type state. | 
 |     RefVal PrevV = *PrevT; | 
 |  | 
 |     // Specially handle -dealloc. | 
 |     if (!TF.isGCEnabled() && contains(AEffects, Dealloc)) { | 
 |       // Determine if the object's reference count was pushed to zero. | 
 |       assert(!(PrevV == CurrV) && "The typestate *must* have changed."); | 
 |       // We may not have transitioned to 'release' if we hit an error. | 
 |       // This case is handled elsewhere. | 
 |       if (CurrV.getKind() == RefVal::Released) { | 
 |         assert(CurrV.getCombinedCounts() == 0); | 
 |         os << "Object released by directly sending the '-dealloc' message"; | 
 |         break; | 
 |       } | 
 |     } | 
 |  | 
 |     // Specially handle CFMakeCollectable and friends. | 
 |     if (contains(AEffects, MakeCollectable)) { | 
 |       // Get the name of the function. | 
 |       const Stmt* S = cast<PostStmt>(N->getLocation()).getStmt(); | 
 |       SVal X = CurrSt->getSValAsScalarOrLoc(cast<CallExpr>(S)->getCallee()); | 
 |       const FunctionDecl* FD = X.getAsFunctionDecl(); | 
 |       const std::string& FName = FD->getNameAsString(); | 
 |  | 
 |       if (TF.isGCEnabled()) { | 
 |         // Determine if the object's reference count was pushed to zero. | 
 |         assert(!(PrevV == CurrV) && "The typestate *must* have changed."); | 
 |  | 
 |         os << "In GC mode a call to '" << FName | 
 |         <<  "' decrements an object's retain count and registers the " | 
 |         "object with the garbage collector. "; | 
 |  | 
 |         if (CurrV.getKind() == RefVal::Released) { | 
 |           assert(CurrV.getCount() == 0); | 
 |           os << "Since it now has a 0 retain count the object can be " | 
 |           "automatically collected by the garbage collector."; | 
 |         } | 
 |         else | 
 |           os << "An object must have a 0 retain count to be garbage collected. " | 
 |           "After this call its retain count is +" << CurrV.getCount() | 
 |           << '.'; | 
 |       } | 
 |       else | 
 |         os << "When GC is not enabled a call to '" << FName | 
 |         << "' has no effect on its argument."; | 
 |  | 
 |       // Nothing more to say. | 
 |       break; | 
 |     } | 
 |  | 
 |     // Determine if the typestate has changed. | 
 |     if (!(PrevV == CurrV)) | 
 |       switch (CurrV.getKind()) { | 
 |         case RefVal::Owned: | 
 |         case RefVal::NotOwned: | 
 |  | 
 |           if (PrevV.getCount() == CurrV.getCount()) { | 
 |             // Did an autorelease message get sent? | 
 |             if (PrevV.getAutoreleaseCount() == CurrV.getAutoreleaseCount()) | 
 |               return 0; | 
 |  | 
 |             assert(PrevV.getAutoreleaseCount() < CurrV.getAutoreleaseCount()); | 
 |             os << "Object sent -autorelease message"; | 
 |             break; | 
 |           } | 
 |  | 
 |           if (PrevV.getCount() > CurrV.getCount()) | 
 |             os << "Reference count decremented."; | 
 |           else | 
 |             os << "Reference count incremented."; | 
 |  | 
 |           if (unsigned Count = CurrV.getCount()) | 
 |             os << " The object now has a +" << Count << " retain count."; | 
 |  | 
 |           if (PrevV.getKind() == RefVal::Released) { | 
 |             assert(TF.isGCEnabled() && CurrV.getCount() > 0); | 
 |             os << " The object is not eligible for garbage collection until the " | 
 |             "retain count reaches 0 again."; | 
 |           } | 
 |  | 
 |           break; | 
 |  | 
 |         case RefVal::Released: | 
 |           os << "Object released."; | 
 |           break; | 
 |  | 
 |         case RefVal::ReturnedOwned: | 
 |           os << "Object returned to caller as an owning reference (single retain " | 
 |           "count transferred to caller)."; | 
 |           break; | 
 |  | 
 |         case RefVal::ReturnedNotOwned: | 
 |           os << "Object returned to caller with a +0 (non-owning) retain count."; | 
 |           break; | 
 |  | 
 |         default: | 
 |           return NULL; | 
 |       } | 
 |  | 
 |     // Emit any remaining diagnostics for the argument effects (if any). | 
 |     for (llvm::SmallVectorImpl<ArgEffect>::iterator I=AEffects.begin(), | 
 |          E=AEffects.end(); I != E; ++I) { | 
 |  | 
 |       // A bunch of things have alternate behavior under GC. | 
 |       if (TF.isGCEnabled()) | 
 |         switch (*I) { | 
 |           default: break; | 
 |           case Autorelease: | 
 |             os << "In GC mode an 'autorelease' has no effect."; | 
 |             continue; | 
 |           case IncRefMsg: | 
 |             os << "In GC mode the 'retain' message has no effect."; | 
 |             continue; | 
 |           case DecRefMsg: | 
 |             os << "In GC mode the 'release' message has no effect."; | 
 |             continue; | 
 |         } | 
 |     } | 
 |   } while (0); | 
 |  | 
 |   if (os.str().empty()) | 
 |     return 0; // We have nothing to say! | 
 |  | 
 |   const Stmt* S = cast<PostStmt>(N->getLocation()).getStmt(); | 
 |   PathDiagnosticLocation Pos(S, BRC.getSourceManager()); | 
 |   PathDiagnosticPiece* P = new PathDiagnosticEventPiece(Pos, os.str()); | 
 |  | 
 |   // Add the range by scanning the children of the statement for any bindings | 
 |   // to Sym. | 
 |   for (Stmt::const_child_iterator I = S->child_begin(), E = S->child_end(); | 
 |        I!=E; ++I) | 
 |     if (const Expr* Exp = dyn_cast_or_null<Expr>(*I)) | 
 |       if (CurrSt->getSValAsScalarOrLoc(Exp).getAsLocSymbol() == Sym) { | 
 |         P->addRange(Exp->getSourceRange()); | 
 |         break; | 
 |       } | 
 |  | 
 |   return P; | 
 | } | 
 |  | 
 | namespace { | 
 |   class FindUniqueBinding : | 
 |   public StoreManager::BindingsHandler { | 
 |     SymbolRef Sym; | 
 |     const MemRegion* Binding; | 
 |     bool First; | 
 |  | 
 |   public: | 
 |     FindUniqueBinding(SymbolRef sym) : Sym(sym), Binding(0), First(true) {} | 
 |  | 
 |     bool HandleBinding(StoreManager& SMgr, Store store, const MemRegion* R, | 
 |                        SVal val) { | 
 |  | 
 |       SymbolRef SymV = val.getAsSymbol(); | 
 |       if (!SymV || SymV != Sym) | 
 |         return true; | 
 |  | 
 |       if (Binding) { | 
 |         First = false; | 
 |         return false; | 
 |       } | 
 |       else | 
 |         Binding = R; | 
 |  | 
 |       return true; | 
 |     } | 
 |  | 
 |     operator bool() { return First && Binding; } | 
 |     const MemRegion* getRegion() { return Binding; } | 
 |   }; | 
 | } | 
 |  | 
 | static std::pair<const ExplodedNode*,const MemRegion*> | 
 | GetAllocationSite(GRStateManager& StateMgr, const ExplodedNode* N, | 
 |                   SymbolRef Sym) { | 
 |  | 
 |   // Find both first node that referred to the tracked symbol and the | 
 |   // memory location that value was store to. | 
 |   const ExplodedNode* Last = N; | 
 |   const MemRegion* FirstBinding = 0; | 
 |  | 
 |   while (N) { | 
 |     const GRState* St = N->getState(); | 
 |     RefBindings B = St->get<RefBindings>(); | 
 |  | 
 |     if (!B.lookup(Sym)) | 
 |       break; | 
 |  | 
 |     FindUniqueBinding FB(Sym); | 
 |     StateMgr.iterBindings(St, FB); | 
 |     if (FB) FirstBinding = FB.getRegion(); | 
 |  | 
 |     Last = N; | 
 |     N = N->pred_empty() ? NULL : *(N->pred_begin()); | 
 |   } | 
 |  | 
 |   return std::make_pair(Last, FirstBinding); | 
 | } | 
 |  | 
 | PathDiagnosticPiece* | 
 | CFRefReport::getEndPath(BugReporterContext& BRC, | 
 |                         const ExplodedNode* EndN) { | 
 |   // Tell the BugReporterContext to report cases when the tracked symbol is | 
 |   // assigned to different variables, etc. | 
 |   BRC.addNotableSymbol(Sym); | 
 |   return RangedBugReport::getEndPath(BRC, EndN); | 
 | } | 
 |  | 
 | PathDiagnosticPiece* | 
 | CFRefLeakReport::getEndPath(BugReporterContext& BRC, | 
 |                             const ExplodedNode* EndN){ | 
 |  | 
 |   // Tell the BugReporterContext to report cases when the tracked symbol is | 
 |   // assigned to different variables, etc. | 
 |   BRC.addNotableSymbol(Sym); | 
 |  | 
 |   // We are reporting a leak.  Walk up the graph to get to the first node where | 
 |   // the symbol appeared, and also get the first VarDecl that tracked object | 
 |   // is stored to. | 
 |   const ExplodedNode* AllocNode = 0; | 
 |   const MemRegion* FirstBinding = 0; | 
 |  | 
 |   llvm::tie(AllocNode, FirstBinding) = | 
 |     GetAllocationSite(BRC.getStateManager(), EndN, Sym); | 
 |  | 
 |   // Get the allocate site. | 
 |   assert(AllocNode); | 
 |   const Stmt* FirstStmt = cast<PostStmt>(AllocNode->getLocation()).getStmt(); | 
 |  | 
 |   SourceManager& SMgr = BRC.getSourceManager(); | 
 |   unsigned AllocLine =SMgr.getInstantiationLineNumber(FirstStmt->getLocStart()); | 
 |  | 
 |   // Compute an actual location for the leak.  Sometimes a leak doesn't | 
 |   // occur at an actual statement (e.g., transition between blocks; end | 
 |   // of function) so we need to walk the graph and compute a real location. | 
 |   const ExplodedNode* LeakN = EndN; | 
 |   PathDiagnosticLocation L; | 
 |  | 
 |   while (LeakN) { | 
 |     ProgramPoint P = LeakN->getLocation(); | 
 |  | 
 |     if (const PostStmt *PS = dyn_cast<PostStmt>(&P)) { | 
 |       L = PathDiagnosticLocation(PS->getStmt()->getLocStart(), SMgr); | 
 |       break; | 
 |     } | 
 |     else if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) { | 
 |       if (const Stmt* Term = BE->getSrc()->getTerminator()) { | 
 |         L = PathDiagnosticLocation(Term->getLocStart(), SMgr); | 
 |         break; | 
 |       } | 
 |     } | 
 |  | 
 |     LeakN = LeakN->succ_empty() ? 0 : *(LeakN->succ_begin()); | 
 |   } | 
 |  | 
 |   if (!L.isValid()) { | 
 |     const Decl &D = EndN->getCodeDecl(); | 
 |     L = PathDiagnosticLocation(D.getBodyRBrace(), SMgr); | 
 |   } | 
 |  | 
 |   std::string sbuf; | 
 |   llvm::raw_string_ostream os(sbuf); | 
 |  | 
 |   os << "Object allocated on line " << AllocLine; | 
 |  | 
 |   if (FirstBinding) | 
 |     os << " and stored into '" << FirstBinding->getString() << '\''; | 
 |  | 
 |   // Get the retain count. | 
 |   const RefVal* RV = EndN->getState()->get<RefBindings>(Sym); | 
 |  | 
 |   if (RV->getKind() == RefVal::ErrorLeakReturned) { | 
 |     // FIXME: Per comments in rdar://6320065, "create" only applies to CF | 
 |     // ojbects.  Only "copy", "alloc", "retain" and "new" transfer ownership | 
 |     // to the caller for NS objects. | 
 |     ObjCMethodDecl& MD = cast<ObjCMethodDecl>(EndN->getCodeDecl()); | 
 |     os << " is returned from a method whose name ('" | 
 |        << MD.getSelector().getAsString() | 
 |     << "') does not contain 'copy' or otherwise starts with" | 
 |     " 'new' or 'alloc'.  This violates the naming convention rules given" | 
 |     " in the Memory Management Guide for Cocoa (object leaked)"; | 
 |   } | 
 |   else if (RV->getKind() == RefVal::ErrorGCLeakReturned) { | 
 |     ObjCMethodDecl& MD = cast<ObjCMethodDecl>(EndN->getCodeDecl()); | 
 |     os << " and returned from method '" << MD.getSelector().getAsString() | 
 |        << "' is potentially leaked when using garbage collection.  Callers " | 
 |           "of this method do not expect a returned object with a +1 retain " | 
 |           "count since they expect the object to be managed by the garbage " | 
 |           "collector"; | 
 |   } | 
 |   else | 
 |     os << " is no longer referenced after this point and has a retain count of" | 
 |           " +" << RV->getCount() << " (object leaked)"; | 
 |  | 
 |   return new PathDiagnosticEventPiece(L, os.str()); | 
 | } | 
 |  | 
 | CFRefLeakReport::CFRefLeakReport(CFRefBug& D, const CFRefCount &tf, | 
 |                                  ExplodedNode *n, | 
 |                                  SymbolRef sym, GRExprEngine& Eng) | 
 | : CFRefReport(D, tf, n, sym) { | 
 |  | 
 |   // Most bug reports are cached at the location where they occured. | 
 |   // With leaks, we want to unique them by the location where they were | 
 |   // allocated, and only report a single path.  To do this, we need to find | 
 |   // the allocation site of a piece of tracked memory, which we do via a | 
 |   // call to GetAllocationSite.  This will walk the ExplodedGraph backwards. | 
 |   // Note that this is *not* the trimmed graph; we are guaranteed, however, | 
 |   // that all ancestor nodes that represent the allocation site have the | 
 |   // same SourceLocation. | 
 |   const ExplodedNode* AllocNode = 0; | 
 |  | 
 |   llvm::tie(AllocNode, AllocBinding) =  // Set AllocBinding. | 
 |     GetAllocationSite(Eng.getStateManager(), getEndNode(), getSymbol()); | 
 |  | 
 |   // Get the SourceLocation for the allocation site. | 
 |   ProgramPoint P = AllocNode->getLocation(); | 
 |   AllocSite = cast<PostStmt>(P).getStmt()->getLocStart(); | 
 |  | 
 |   // Fill in the description of the bug. | 
 |   Description.clear(); | 
 |   llvm::raw_string_ostream os(Description); | 
 |   SourceManager& SMgr = Eng.getContext().getSourceManager(); | 
 |   unsigned AllocLine = SMgr.getInstantiationLineNumber(AllocSite); | 
 |   os << "Potential leak "; | 
 |   if (tf.isGCEnabled()) { | 
 |     os << "(when using garbage collection) "; | 
 |   } | 
 |   os << "of an object allocated on line " << AllocLine; | 
 |  | 
 |   // FIXME: AllocBinding doesn't get populated for RegionStore yet. | 
 |   if (AllocBinding) | 
 |     os << " and stored into '" << AllocBinding->getString() << '\''; | 
 | } | 
 |  | 
 | //===----------------------------------------------------------------------===// | 
 | // Main checker logic. | 
 | //===----------------------------------------------------------------------===// | 
 |  | 
 | /// GetReturnType - Used to get the return type of a message expression or | 
 | ///  function call with the intention of affixing that type to a tracked symbol. | 
 | ///  While the the return type can be queried directly from RetEx, when | 
 | ///  invoking class methods we augment to the return type to be that of | 
 | ///  a pointer to the class (as opposed it just being id). | 
 | static QualType GetReturnType(const Expr* RetE, ASTContext& Ctx) { | 
 |   QualType RetTy = RetE->getType(); | 
 |   // If RetE is not a message expression just return its type. | 
 |   // If RetE is a message expression, return its types if it is something | 
 |   /// more specific than id. | 
 |   if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(RetE)) | 
 |     if (const ObjCObjectPointerType *PT = RetTy->getAs<ObjCObjectPointerType>()) | 
 |       if (PT->isObjCQualifiedIdType() || PT->isObjCIdType() || | 
 |           PT->isObjCClassType()) { | 
 |         // At this point we know the return type of the message expression is | 
 |         // id, id<...>, or Class. If we have an ObjCInterfaceDecl, we know this | 
 |         // is a call to a class method whose type we can resolve.  In such | 
 |         // cases, promote the return type to XXX* (where XXX is the class). | 
 |         const ObjCInterfaceDecl *D = ME->getReceiverInterface(); | 
 |         return !D ? RetTy : Ctx.getPointerType(Ctx.getObjCInterfaceType(D)); | 
 |       } | 
 |  | 
 |   return RetTy; | 
 | } | 
 |  | 
 | void CFRefCount::EvalSummary(ExplodedNodeSet& Dst, | 
 |                              GRExprEngine& Eng, | 
 |                              GRStmtNodeBuilder& Builder, | 
 |                              Expr* Ex, | 
 |                              Expr* Receiver, | 
 |                              const RetainSummary& Summ, | 
 |                              const MemRegion *Callee, | 
 |                              ExprIterator arg_beg, ExprIterator arg_end, | 
 |                              ExplodedNode* Pred, const GRState *state) { | 
 |  | 
 |   // Evaluate the effect of the arguments. | 
 |   RefVal::Kind hasErr = (RefVal::Kind) 0; | 
 |   unsigned idx = 0; | 
 |   Expr* ErrorExpr = NULL; | 
 |   SymbolRef ErrorSym = 0; | 
 |  | 
 |   llvm::SmallVector<const MemRegion*, 10> RegionsToInvalidate; | 
 |    | 
 |   for (ExprIterator I = arg_beg; I != arg_end; ++I, ++idx) { | 
 |     SVal V = state->getSValAsScalarOrLoc(*I); | 
 |     SymbolRef Sym = V.getAsLocSymbol(); | 
 |  | 
 |     if (Sym) | 
 |       if (RefBindings::data_type* T = state->get<RefBindings>(Sym)) { | 
 |         state = Update(state, Sym, *T, Summ.getArg(idx), hasErr); | 
 |         if (hasErr) { | 
 |           ErrorExpr = *I; | 
 |           ErrorSym = Sym; | 
 |           break; | 
 |         } | 
 |         continue; | 
 |       } | 
 |  | 
 |   tryAgain: | 
 |     if (isa<Loc>(V)) { | 
 |       if (loc::MemRegionVal* MR = dyn_cast<loc::MemRegionVal>(&V)) { | 
 |         if (Summ.getArg(idx) == DoNothingByRef) | 
 |           continue; | 
 |  | 
 |         // Invalidate the value of the variable passed by reference. | 
 |         const MemRegion *R = MR->getRegion(); | 
 |  | 
 |         // 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()->isIntegralType()) { | 
 |             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? | 
 |         } | 
 |          | 
 |         // 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)); | 
 |       } | 
 |     } | 
 |     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; | 
 |     } | 
 |   } | 
 |    | 
 |   // Block calls result in all captured values passed-via-reference to be | 
 |   // invalidated. | 
 |   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. | 
 |   if (!RegionsToInvalidate.empty()) {     | 
 |     // FIXME: We can have collisions on the conjured symbol if the | 
 |     //  expression *I also creates conjured symbols.  We probably want | 
 |     //  to identify conjured symbols by an expression pair: the enclosing | 
 |     //  expression (the context) and the expression itself.  This should | 
 |     //  disambiguate conjured symbols. | 
 |     unsigned Count = Builder.getCurrentBlockCount(); | 
 |     StoreManager& StoreMgr = Eng.getStateManager().getStoreManager(); | 
 |  | 
 |      | 
 |     StoreManager::InvalidatedSymbols IS; | 
 |     Store store = state->getStore(); | 
 |     store = StoreMgr.InvalidateRegions(store, RegionsToInvalidate.data(), | 
 |                                        RegionsToInvalidate.data() + | 
 |                                        RegionsToInvalidate.size(), | 
 |                                        Ex, Count, &IS); | 
 |     state = state->makeWithStore(store); | 
 |     for (StoreManager::InvalidatedSymbols::iterator I = IS.begin(), | 
 |          E = IS.end(); I!=E; ++I) { | 
 |         // Remove any existing reference-count binding. | 
 |       state = state->remove<RefBindings>(*I); | 
 |     } | 
 |   } | 
 |  | 
 |   // Evaluate the effect on the message receiver. | 
 |   if (!ErrorExpr && Receiver) { | 
 |     SymbolRef Sym = state->getSValAsScalarOrLoc(Receiver).getAsLocSymbol(); | 
 |     if (Sym) { | 
 |       if (const RefVal* T = state->get<RefBindings>(Sym)) { | 
 |         state = Update(state, Sym, *T, Summ.getReceiverEffect(), hasErr); | 
 |         if (hasErr) { | 
 |           ErrorExpr = Receiver; | 
 |           ErrorSym = Sym; | 
 |         } | 
 |       } | 
 |     } | 
 |   } | 
 |  | 
 |   // Process any errors. | 
 |   if (hasErr) { | 
 |     ProcessNonLeakError(Dst, Builder, Ex, ErrorExpr, 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 = state->getSValAsScalarOrLoc(Receiver); | 
 |       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: | 
 |       assert (false && "Unhandled RetEffect."); break; | 
 |  | 
 |     case RetEffect::NoRet: { | 
 |       // Make up a symbol for the return value (not reference counted). | 
 |       // FIXME: Most of this logic is not specific to the retain/release | 
 |       // checker. | 
 |  | 
 |       // FIXME: We eventually should handle structs and other compound types | 
 |       // that are returned by value. | 
 |  | 
 |       QualType T = Ex->getType(); | 
 |  | 
 |       // For CallExpr, use the result type to know if it returns a reference. | 
 |       if (const CallExpr *CE = dyn_cast<CallExpr>(Ex)) { | 
 |         const Expr *Callee = CE->getCallee(); | 
 |         if (const FunctionDecl *FD = state->getSVal(Callee).getAsFunctionDecl()) | 
 |           T = FD->getResultType(); | 
 |       } | 
 |       else if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(Ex)) { | 
 |         if (const ObjCMethodDecl *MD = ME->getMethodDecl()) | 
 |           T = MD->getResultType(); | 
 |       } | 
 |  | 
 |       if (Loc::IsLocType(T) || (T->isIntegerType() && T->isScalarType())) { | 
 |         unsigned Count = Builder.getCurrentBlockCount(); | 
 |         ValueManager &ValMgr = Eng.getValueManager(); | 
 |         SVal X = ValMgr.getConjuredSymbolVal(NULL, Ex, T, Count); | 
 |         state = state->BindExpr(Ex, X, false); | 
 |       } | 
 |  | 
 |       break; | 
 |     } | 
 |  | 
 |     case RetEffect::Alias: { | 
 |       unsigned idx = RE.getIndex(); | 
 |       assert (arg_end >= arg_beg); | 
 |       assert (idx < (unsigned) (arg_end - arg_beg)); | 
 |       SVal V = state->getSValAsScalarOrLoc(*(arg_beg+idx)); | 
 |       state = state->BindExpr(Ex, V, false); | 
 |       break; | 
 |     } | 
 |  | 
 |     case RetEffect::ReceiverAlias: { | 
 |       assert (Receiver); | 
 |       SVal V = state->getSValAsScalarOrLoc(Receiver); | 
 |       state = state->BindExpr(Ex, V, false); | 
 |       break; | 
 |     } | 
 |  | 
 |     case RetEffect::OwnedAllocatedSymbol: | 
 |     case RetEffect::OwnedSymbol: { | 
 |       unsigned Count = Builder.getCurrentBlockCount(); | 
 |       ValueManager &ValMgr = Eng.getValueManager(); | 
 |       SymbolRef Sym = ValMgr.getConjuredSymbol(Ex, Count); | 
 |       QualType RetT = GetReturnType(Ex, ValMgr.getContext()); | 
 |       state = state->set<RefBindings>(Sym, RefVal::makeOwned(RE.getObjKind(), | 
 |                                                             RetT)); | 
 |       state = state->BindExpr(Ex, ValMgr.makeLoc(Sym), false); | 
 |  | 
 |       // FIXME: Add a flag to the checker where allocations are assumed to | 
 |       // *not fail. | 
 | #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::NotOwnedSymbol: { | 
 |       unsigned Count = Builder.getCurrentBlockCount(); | 
 |       ValueManager &ValMgr = Eng.getValueManager(); | 
 |       SymbolRef Sym = ValMgr.getConjuredSymbol(Ex, Count); | 
 |       QualType RetT = GetReturnType(Ex, ValMgr.getContext()); | 
 |       state = state->set<RefBindings>(Sym, RefVal::makeNotOwned(RE.getObjKind(), | 
 |                                                                RetT)); | 
 |       state = state->BindExpr(Ex, ValMgr.makeLoc(Sym), false); | 
 |       break; | 
 |     } | 
 |   } | 
 |  | 
 |   // Generate a sink node if we are at the end of a path. | 
 |   ExplodedNode *NewNode = | 
 |     Summ.isEndPath() ? Builder.MakeSinkNode(Dst, Ex, Pred, state) | 
 |                      : Builder.MakeNode(Dst, Ex, Pred, state); | 
 |  | 
 |   // Annotate the edge with summary we used. | 
 |   if (NewNode) SummaryLog[NewNode] = &Summ; | 
 | } | 
 |  | 
 |  | 
 | void CFRefCount::EvalCall(ExplodedNodeSet& Dst, | 
 |                           GRExprEngine& Eng, | 
 |                           GRStmtNodeBuilder& Builder, | 
 |                           CallExpr* CE, SVal L, | 
 |                           ExplodedNode* Pred) { | 
 |  | 
 |   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 { | 
 |     const FunctionDecl* FD = L.getAsFunctionDecl(); | 
 |     Summ = !FD ? Summaries.getDefaultSummary() : | 
 |                  Summaries.getSummary(const_cast<FunctionDecl*>(FD)); | 
 |   } | 
 |  | 
 |   assert(Summ); | 
 |   EvalSummary(Dst, Eng, Builder, CE, 0, *Summ, L.getAsRegion(), | 
 |               CE->arg_begin(), CE->arg_end(), Pred, Builder.GetState(Pred)); | 
 | } | 
 |  | 
 | void CFRefCount::EvalObjCMessageExpr(ExplodedNodeSet& Dst, | 
 |                                      GRExprEngine& Eng, | 
 |                                      GRStmtNodeBuilder& Builder, | 
 |                                      ObjCMessageExpr* ME, | 
 |                                      ExplodedNode* Pred, | 
 |                                      const GRState *state) { | 
 |   RetainSummary *Summ = | 
 |     ME->isInstanceMessage() | 
 |       ? Summaries.getInstanceMethodSummary(ME, state,Pred->getLocationContext()) | 
 |       : Summaries.getClassMethodSummary(ME); | 
 |  | 
 |   assert(Summ && "RetainSummary is null"); | 
 |   EvalSummary(Dst, Eng, Builder, ME, ME->getInstanceReceiver(), *Summ, NULL, | 
 |               ME->arg_begin(), ME->arg_end(), Pred, state); | 
 | } | 
 |  | 
 | namespace { | 
 | class StopTrackingCallback : public SymbolVisitor { | 
 |   const GRState *state; | 
 | public: | 
 |   StopTrackingCallback(const GRState *st) : state(st) {} | 
 |   const GRState *getState() const { return state; } | 
 |  | 
 |   bool VisitSymbol(SymbolRef sym) { | 
 |     state = state->remove<RefBindings>(sym); | 
 |     return true; | 
 |   } | 
 | }; | 
 | } // end anonymous namespace | 
 |  | 
 |  | 
 | void CFRefCount::EvalBind(GRStmtNodeBuilderRef& B, SVal location, SVal val) { | 
 |   // Are we storing to something that causes the value to "escape"? | 
 |   bool escapes = false; | 
 |  | 
 |   // A value escapes in three possible cases (this may change): | 
 |   // | 
 |   // (1) we are binding to something that is not a memory region. | 
 |   // (2) we are binding to a memregion that does not have stack storage | 
 |   // (3) we are binding to a memregion with stack storage that the store | 
 |   //     does not understand. | 
 |   const GRState *state = B.getState(); | 
 |  | 
 |   if (!isa<loc::MemRegionVal>(location)) | 
 |     escapes = true; | 
 |   else { | 
 |     const MemRegion* R = cast<loc::MemRegionVal>(location).getRegion(); | 
 |     escapes = !R->hasStackStorage(); | 
 |  | 
 |     if (!escapes) { | 
 |       // To test (3), generate a new state with the binding removed.  If it is | 
 |       // the same state, then it escapes (since the store cannot represent | 
 |       // the binding). | 
 |       escapes = (state == (state->bindLoc(cast<Loc>(location), UnknownVal()))); | 
 |     } | 
 |   } | 
 |  | 
 |   // If our store can represent the binding and we aren't storing to something | 
 |   // that doesn't have local storage then just return and have the simulation | 
 |   // state continue as is. | 
 |   if (!escapes) | 
 |       return; | 
 |  | 
 |   // Otherwise, find all symbols referenced by 'val' that we are tracking | 
 |   // and stop tracking them. | 
 |   B.MakeNode(state->scanReachableSymbols<StopTrackingCallback>(val).getState()); | 
 | } | 
 |  | 
 |  // Return statements. | 
 |  | 
 | void CFRefCount::EvalReturn(ExplodedNodeSet& Dst, | 
 |                             GRExprEngine& Eng, | 
 |                             GRStmtNodeBuilder& Builder, | 
 |                             ReturnStmt* S, | 
 |                             ExplodedNode* Pred) { | 
 |  | 
 |   Expr* RetE = S->getRetValue(); | 
 |   if (!RetE) | 
 |     return; | 
 |  | 
 |   const GRState *state = Builder.GetState(Pred); | 
 |   SymbolRef Sym = state->getSValAsScalarOrLoc(RetE).getAsLocSymbol(); | 
 |  | 
 |   if (!Sym) | 
 |     return; | 
 |  | 
 |   // Get the reference count binding (if any). | 
 |   const RefVal* T = state->get<RefBindings>(Sym); | 
 |  | 
 |   if (!T) | 
 |     return; | 
 |  | 
 |   // Change the reference count. | 
 |   RefVal X = *T; | 
 |  | 
 |   switch (X.getKind()) { | 
 |     case RefVal::Owned: { | 
 |       unsigned cnt = X.getCount(); | 
 |       assert (cnt > 0); | 
 |       X.setCount(cnt - 1); | 
 |       X = X ^ RefVal::ReturnedOwned; | 
 |       break; | 
 |     } | 
 |  | 
 |     case RefVal::NotOwned: { | 
 |       unsigned cnt = X.getCount(); | 
 |       if (cnt) { | 
 |         X.setCount(cnt - 1); | 
 |         X = X ^ RefVal::ReturnedOwned; | 
 |       } | 
 |       else { | 
 |         X = X ^ RefVal::ReturnedNotOwned; | 
 |       } | 
 |       break; | 
 |     } | 
 |  | 
 |     default: | 
 |       return; | 
 |   } | 
 |  | 
 |   // Update the binding. | 
 |   state = state->set<RefBindings>(Sym, X); | 
 |   Pred = Builder.MakeNode(Dst, S, Pred, state); | 
 |  | 
 |   // Did we cache out? | 
 |   if (!Pred) | 
 |     return; | 
 |  | 
 |   // Update the autorelease counts. | 
 |   static unsigned autoreleasetag = 0; | 
 |   GenericNodeBuilder Bd(Builder, S, &autoreleasetag); | 
 |   bool stop = false; | 
 |   llvm::tie(Pred, state) = HandleAutoreleaseCounts(state , Bd, Pred, Eng, Sym, | 
 |                                                    X, stop); | 
 |  | 
 |   // Did we cache out? | 
 |   if (!Pred || stop) | 
 |     return; | 
 |  | 
 |   // Get the updated binding. | 
 |   T = state->get<RefBindings>(Sym); | 
 |   assert(T); | 
 |   X = *T; | 
 |  | 
 |   // Any leaks or other errors? | 
 |   if (X.isReturnedOwned() && X.getCount() == 0) { | 
 |     Decl const *CD = &Pred->getCodeDecl(); | 
 |     if (const ObjCMethodDecl* MD = dyn_cast<ObjCMethodDecl>(CD)) { | 
 |       const RetainSummary &Summ = *Summaries.getMethodSummary(MD); | 
 |       RetEffect RE = Summ.getRetEffect(); | 
 |       bool hasError = false; | 
 |  | 
 |       if (RE.getKind() != RetEffect::NoRet) { | 
 |         if (isGCEnabled() && RE.getObjKind() == RetEffect::ObjC) { | 
 |           // Things are more complicated with garbage collection.  If the | 
 |           // returned object is suppose to be an Objective-C object, we have | 
 |           // a leak (as the caller expects a GC'ed object) because no | 
 |           // method should return ownership unless it returns a CF object. | 
 |           hasError = true; | 
 |           X = X ^ RefVal::ErrorGCLeakReturned; | 
 |         } | 
 |         else if (!RE.isOwned()) { | 
 |           // Either we are using GC and the returned object is a CF type | 
 |           // or we aren't using GC.  In either case, we expect that the | 
 |           // enclosing method is expected to return ownership. | 
 |           hasError = true; | 
 |           X = X ^ RefVal::ErrorLeakReturned; | 
 |         } | 
 |       } | 
 |  | 
 |       if (hasError) { | 
 |         // Generate an error node. | 
 |         static int ReturnOwnLeakTag = 0; | 
 |         state = state->set<RefBindings>(Sym, X); | 
 |         ExplodedNode *N = | 
 |           Builder.generateNode(PostStmt(S, Pred->getLocationContext(), | 
 |                                         &ReturnOwnLeakTag), state, Pred); | 
 |         if (N) { | 
 |           CFRefReport *report = | 
 |             new CFRefLeakReport(*static_cast<CFRefBug*>(leakAtReturn), *this, | 
 |                                 N, Sym, Eng); | 
 |           BR->EmitReport(report); | 
 |         } | 
 |       } | 
 |     } | 
 |   } | 
 |   else if (X.isReturnedNotOwned()) { | 
 |     Decl const *CD = &Pred->getCodeDecl(); | 
 |     if (const ObjCMethodDecl* MD = dyn_cast<ObjCMethodDecl>(CD)) { | 
 |       const RetainSummary &Summ = *Summaries.getMethodSummary(MD); | 
 |       if (Summ.getRetEffect().isOwned()) { | 
 |         // Trying to return a not owned object to a caller expecting an | 
 |         // owned object. | 
 |  | 
 |         static int ReturnNotOwnedForOwnedTag = 0; | 
 |         state = state->set<RefBindings>(Sym, X ^ RefVal::ErrorReturnedNotOwned); | 
 |         if (ExplodedNode *N = | 
 |             Builder.generateNode(PostStmt(S, Pred->getLocationContext(), | 
 |                                           &ReturnNotOwnedForOwnedTag), | 
 |                                  state, Pred)) { | 
 |             CFRefReport *report = | 
 |                 new CFRefReport(*static_cast<CFRefBug*>(returnNotOwnedForOwned), | 
 |                                 *this, N, Sym); | 
 |             BR->EmitReport(report); | 
 |         } | 
 |       } | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | // Assumptions. | 
 |  | 
 | const GRState* CFRefCount::EvalAssume(const GRState *state, | 
 |                                       SVal Cond, bool Assumption) { | 
 |  | 
 |   // 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 = state->get<RefBindings>(); | 
 |  | 
 |   if (B.isEmpty()) | 
 |     return state; | 
 |  | 
 |   bool changed = false; | 
 |   RefBindings::Factory& RefBFactory = state->get_context<RefBindings>(); | 
 |  | 
 |   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 (state->getSymVal(I.getKey())) { | 
 |       changed = true; | 
 |       B = RefBFactory.Remove(B, I.getKey()); | 
 |     } | 
 |   } | 
 |  | 
 |   if (changed) | 
 |     state = state->set<RefBindings>(B); | 
 |  | 
 |   return state; | 
 | } | 
 |  | 
 | const GRState * CFRefCount::Update(const GRState * state, SymbolRef sym, | 
 |                               RefVal V, ArgEffect E, | 
 |                               RefVal::Kind& hasErr) { | 
 |  | 
 |   // In GC mode [... release] and [... retain] do nothing. | 
 |   switch (E) { | 
 |     default: break; | 
 |     case IncRefMsg: E = isGCEnabled() ? DoNothing : IncRef; break; | 
 |     case DecRefMsg: E = isGCEnabled() ? DoNothing : DecRef; break; | 
 |     case MakeCollectable: E = isGCEnabled() ? DecRef : DoNothing; break; | 
 |     case NewAutoreleasePool: E = isGCEnabled() ? DoNothing : | 
 |                                                  NewAutoreleasePool; break; | 
 |   } | 
 |  | 
 |   // Handle all use-after-releases. | 
 |   if (!isGCEnabled() && V.getKind() == RefVal::Released) { | 
 |     V = V ^ RefVal::ErrorUseAfterRelease; | 
 |     hasErr = V.getKind(); | 
 |     return state->set<RefBindings>(sym, V); | 
 |   } | 
 |  | 
 |   switch (E) { | 
 |     default: | 
 |       assert (false && "Unhandled CFRef transition."); | 
 |  | 
 |     case Dealloc: | 
 |       // Any use of -dealloc in GC is *bad*. | 
 |       if (isGCEnabled()) { | 
 |         V = V ^ RefVal::ErrorDeallocGC; | 
 |         hasErr = V.getKind(); | 
 |         break; | 
 |       } | 
 |  | 
 |       switch (V.getKind()) { | 
 |         default: | 
 |           assert(false && "Invalid case."); | 
 |         case RefVal::Owned: | 
 |           // The object immediately transitions to the released state. | 
 |           V = V ^ RefVal::Released; | 
 |           V.clearCounts(); | 
 |           return state->set<RefBindings>(sym, V); | 
 |         case RefVal::NotOwned: | 
 |           V = V ^ RefVal::ErrorDeallocNotOwned; | 
 |           hasErr = V.getKind(); | 
 |           break; | 
 |       } | 
 |       break; | 
 |  | 
 |     case NewAutoreleasePool: | 
 |       assert(!isGCEnabled()); | 
 |       return state->add<AutoreleaseStack>(sym); | 
 |  | 
 |     case MayEscape: | 
 |       if (V.getKind() == RefVal::Owned) { | 
 |         V = V ^ RefVal::NotOwned; | 
 |         break; | 
 |       } | 
 |  | 
 |       // Fall-through. | 
 |  | 
 |     case DoNothingByRef: | 
 |     case DoNothing: | 
 |       return state; | 
 |  | 
 |     case Autorelease: | 
 |       if (isGCEnabled()) | 
 |         return state; | 
 |  | 
 |       // Update the autorelease counts. | 
 |       state = SendAutorelease(state, ARCountFactory, sym); | 
 |       V = V.autorelease(); | 
 |       break; | 
 |  | 
 |     case StopTracking: | 
 |       return state->remove<RefBindings>(sym); | 
 |  | 
 |     case IncRef: | 
 |       switch (V.getKind()) { | 
 |         default: | 
 |           assert(false); | 
 |  | 
 |         case RefVal::Owned: | 
 |         case RefVal::NotOwned: | 
 |           V = V + 1; | 
 |           break; | 
 |         case RefVal::Released: | 
 |           // Non-GC cases are handled above. | 
 |           assert(isGCEnabled()); | 
 |           V = (V ^ RefVal::Owned) + 1; | 
 |           break; | 
 |       } | 
 |       break; | 
 |  | 
 |     case SelfOwn: | 
 |       V = V ^ RefVal::NotOwned; | 
 |       // Fall-through. | 
 |     case DecRef: | 
 |       switch (V.getKind()) { | 
 |         default: | 
 |           // case 'RefVal::Released' handled above. | 
 |           assert (false); | 
 |  | 
 |         case RefVal::Owned: | 
 |           assert(V.getCount() > 0); | 
 |           if (V.getCount() == 1) V = V ^ RefVal::Released; | 
 |           V = V - 1; | 
 |           break; | 
 |  | 
 |         case RefVal::NotOwned: | 
 |           if (V.getCount() > 0) | 
 |             V = V - 1; | 
 |           else { | 
 |             V = V ^ RefVal::ErrorReleaseNotOwned; | 
 |             hasErr = V.getKind(); | 
 |           } | 
 |           break; | 
 |  | 
 |         case RefVal::Released: | 
 |           // Non-GC cases are handled above. | 
 |           assert(isGCEnabled()); | 
 |           V = V ^ RefVal::ErrorUseAfterRelease; | 
 |           hasErr = V.getKind(); | 
 |           break; | 
 |       } | 
 |       break; | 
 |   } | 
 |   return state->set<RefBindings>(sym, V); | 
 | } | 
 |  | 
 | //===----------------------------------------------------------------------===// | 
 | // Handle dead symbols and end-of-path. | 
 | //===----------------------------------------------------------------------===// | 
 |  | 
 | std::pair<ExplodedNode*, const GRState *> | 
 | CFRefCount::HandleAutoreleaseCounts(const GRState * state, GenericNodeBuilder Bd, | 
 |                                     ExplodedNode* Pred, | 
 |                                     GRExprEngine &Eng, | 
 |                                     SymbolRef Sym, RefVal V, bool &stop) { | 
 |  | 
 |   unsigned ACnt = V.getAutoreleaseCount(); | 
 |   stop = false; | 
 |  | 
 |   // No autorelease counts?  Nothing to be done. | 
 |   if (!ACnt) | 
 |     return std::make_pair(Pred, state); | 
 |  | 
 |   assert(!isGCEnabled() && "Autorelease counts in GC mode?"); | 
 |   unsigned Cnt = V.getCount(); | 
 |  | 
 |   // FIXME: Handle sending 'autorelease' to already released object. | 
 |  | 
 |   if (V.getKind() == RefVal::ReturnedOwned) | 
 |     ++Cnt; | 
 |  | 
 |   if (ACnt <= Cnt) { | 
 |     if (ACnt == Cnt) { | 
 |       V.clearCounts(); | 
 |       if (V.getKind() == RefVal::ReturnedOwned) | 
 |         V = V ^ RefVal::ReturnedNotOwned; | 
 |       else | 
 |         V = V ^ RefVal::NotOwned; | 
 |     } | 
 |     else { | 
 |       V.setCount(Cnt - ACnt); | 
 |       V.setAutoreleaseCount(0); | 
 |     } | 
 |     state = state->set<RefBindings>(Sym, V); | 
 |     ExplodedNode *N = Bd.MakeNode(state, Pred); | 
 |     stop = (N == 0); | 
 |     return std::make_pair(N, state); | 
 |   } | 
 |  | 
 |   // Woah!  More autorelease counts then retain counts left. | 
 |   // Emit hard error. | 
 |   stop = true; | 
 |   V = V ^ RefVal::ErrorOverAutorelease; | 
 |   state = state->set<RefBindings>(Sym, V); | 
 |  | 
 |   if (ExplodedNode *N = Bd.MakeNode(state, Pred)) { | 
 |     N->markAsSink(); | 
 |  | 
 |     std::string sbuf; | 
 |     llvm::raw_string_ostream os(sbuf); | 
 |     os << "Object over-autoreleased: object was sent -autorelease"; | 
 |     if (V.getAutoreleaseCount() > 1) | 
 |       os << V.getAutoreleaseCount() << " times"; | 
 |     os << " but the object has "; | 
 |     if (V.getCount() == 0) | 
 |       os << "zero (locally visible)"; | 
 |     else | 
 |       os << "+" << V.getCount(); | 
 |     os << " retain counts"; | 
 |  | 
 |     CFRefReport *report = | 
 |       new CFRefReport(*static_cast<CFRefBug*>(overAutorelease), | 
 |                       *this, N, Sym, os.str()); | 
 |     BR->EmitReport(report); | 
 |   } | 
 |  | 
 |   return std::make_pair((ExplodedNode*)0, state); | 
 | } | 
 |  | 
 | const GRState * | 
 | CFRefCount::HandleSymbolDeath(const GRState * state, SymbolRef sid, RefVal V, | 
 |                               llvm::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 GRState * state, | 
 |                          llvm::SmallVectorImpl<SymbolRef> &Leaked, | 
 |                          GenericNodeBuilder &Builder, | 
 |                          GRExprEngine& 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 (llvm::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(GRExprEngine& Eng, | 
 |                              GREndPathNodeBuilder& Builder) { | 
 |  | 
 |   const GRState *state = Builder.getState(); | 
 |   GenericNodeBuilder 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>(); | 
 |   llvm::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); | 
 | } | 
 |  | 
 | void CFRefCount::EvalDeadSymbols(ExplodedNodeSet& Dst, | 
 |                                  GRExprEngine& Eng, | 
 |                                  GRStmtNodeBuilder& Builder, | 
 |                                  ExplodedNode* Pred, | 
 |                                  Stmt* S, | 
 |                                  const GRState* state, | 
 |                                  SymbolReaper& SymReaper) { | 
 |  | 
 |   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. | 
 |       GenericNodeBuilder Bd(Builder, S, Sym); | 
 |       bool stop = false; | 
 |       llvm::tie(Pred, state) = HandleAutoreleaseCounts(state, Bd, Pred, Eng, | 
 |                                                        Sym, *T, stop); | 
 |       if (stop) | 
 |         return; | 
 |     } | 
 |   } | 
 |  | 
 |   B = state->get<RefBindings>(); | 
 |   llvm::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 unsigned LeakPPTag = 0; | 
 |   { | 
 |     GenericNodeBuilder 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); | 
 | } | 
 |  | 
 | void CFRefCount::ProcessNonLeakError(ExplodedNodeSet& Dst, | 
 |                                      GRStmtNodeBuilder& Builder, | 
 |                                      Expr* NodeExpr, Expr* ErrorExpr, | 
 |                                      ExplodedNode* Pred, | 
 |                                      const GRState* 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(ErrorExpr->getSourceRange()); | 
 |   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 | 
 | // (ideally, all of it some day). | 
 | //===----------------------------------------------------------------------===// | 
 |  | 
 | namespace { | 
 | class RetainReleaseChecker | 
 |   : public CheckerVisitor<RetainReleaseChecker> { | 
 |   CFRefCount *TF; | 
 | public: | 
 |     RetainReleaseChecker(CFRefCount *tf) : TF(tf) {} | 
 |     static void* getTag() { static int x = 0; return &x; } | 
 |      | 
 |     void PostVisitBlockExpr(CheckerContext &C, const BlockExpr *BE); | 
 | }; | 
 | } // end anonymous namespace | 
 |  | 
 |  | 
 | void RetainReleaseChecker::PostVisitBlockExpr(CheckerContext &C, | 
 |                                               const BlockExpr *BE) { | 
 |    | 
 |   // Scan the BlockDecRefExprs for any object the retain/release checker | 
 |   // may be tracking.   | 
 |   if (!BE->hasBlockDeclRefExprs()) | 
 |     return; | 
 |    | 
 |   const GRState *state = C.getState(); | 
 |   const BlockDataRegion *R = | 
 |     cast<BlockDataRegion>(state->getSVal(BE).getAsRegion()); | 
 |    | 
 |   BlockDataRegion::referenced_vars_iterator I = R->referenced_vars_begin(), | 
 |                                             E = R->referenced_vars_end(); | 
 |    | 
 |   if (I == E) | 
 |     return; | 
 |    | 
 |   // FIXME: For now we invalidate the tracking of all symbols passed to blocks | 
 |   // via captured variables, even though captured variables result in a copy | 
 |   // and in implicit increment/decrement of a retain count. | 
 |   llvm::SmallVector<const MemRegion*, 10> Regions; | 
 |   const LocationContext *LC = C.getPredecessor()->getLocationContext(); | 
 |   MemRegionManager &MemMgr = C.getValueManager().getRegionManager(); | 
 |    | 
 |   for ( ; I != E; ++I) { | 
 |     const VarRegion *VR = *I; | 
 |     if (VR->getSuperRegion() == R) { | 
 |       VR = MemMgr.getVarRegion(VR->getDecl(), LC); | 
 |     } | 
 |     Regions.push_back(VR); | 
 |   } | 
 |    | 
 |   state = | 
 |     state->scanReachableSymbols<StopTrackingCallback>(Regions.data(), | 
 |                                     Regions.data() + Regions.size()).getState(); | 
 |   C.addTransition(state); | 
 | } | 
 |  | 
 | //===----------------------------------------------------------------------===// | 
 | // Transfer function creation for external clients. | 
 | //===----------------------------------------------------------------------===// | 
 |  | 
 | void CFRefCount::RegisterChecks(GRExprEngine& Eng) { | 
 |   BugReporter &BR = Eng.getBugReporter(); | 
 |    | 
 |   useAfterRelease = new UseAfterRelease(this); | 
 |   BR.Register(useAfterRelease); | 
 |    | 
 |   releaseNotOwned = new BadRelease(this); | 
 |   BR.Register(releaseNotOwned); | 
 |    | 
 |   deallocGC = new DeallocGC(this); | 
 |   BR.Register(deallocGC); | 
 |    | 
 |   deallocNotOwned = new DeallocNotOwned(this); | 
 |   BR.Register(deallocNotOwned); | 
 |    | 
 |   overAutorelease = new OverAutorelease(this); | 
 |   BR.Register(overAutorelease); | 
 |    | 
 |   returnNotOwnedForOwned = new ReturnedNotOwnedForOwned(this); | 
 |   BR.Register(returnNotOwnedForOwned); | 
 |    | 
 |   // First register "return" leaks. | 
 |   const char* name = 0; | 
 |    | 
 |   if (isGCEnabled()) | 
 |     name = "Leak of returned object when using garbage collection"; | 
 |   else if (getLangOptions().getGCMode() == LangOptions::HybridGC) | 
 |     name = "Leak of returned object when not using garbage collection (GC) in " | 
 |     "dual GC/non-GC code"; | 
 |   else { | 
 |     assert(getLangOptions().getGCMode() == LangOptions::NonGC); | 
 |     name = "Leak of returned object"; | 
 |   } | 
 |    | 
 |   // Leaks should not be reported if they are post-dominated by a sink. | 
 |   leakAtReturn = new LeakAtReturn(this, name); | 
 |   leakAtReturn->setSuppressOnSink(true); | 
 |   BR.Register(leakAtReturn); | 
 |    | 
 |   // Second, register leaks within a function/method. | 
 |   if (isGCEnabled()) | 
 |     name = "Leak of object when using garbage collection"; | 
 |   else if (getLangOptions().getGCMode() == LangOptions::HybridGC) | 
 |     name = "Leak of object when not using garbage collection (GC) in " | 
 |     "dual GC/non-GC code"; | 
 |   else { | 
 |     assert(getLangOptions().getGCMode() == LangOptions::NonGC); | 
 |     name = "Leak"; | 
 |   } | 
 |    | 
 |   // Leaks should not be reported if they are post-dominated by sinks. | 
 |   leakWithinFunction = new LeakWithinFunction(this, name); | 
 |   leakWithinFunction->setSuppressOnSink(true); | 
 |   BR.Register(leakWithinFunction); | 
 |    | 
 |   // Save the reference to the BugReporter. | 
 |   this->BR = &BR; | 
 |    | 
 |   // Register the RetainReleaseChecker with the GRExprEngine object. | 
 |   // Functionality in CFRefCount will be migrated to RetainReleaseChecker | 
 |   // over time. | 
 |   Eng.registerCheck(new RetainReleaseChecker(this)); | 
 | } | 
 |  | 
 | GRTransferFuncs* clang::MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled, | 
 |                                          const LangOptions& lopts) { | 
 |   return new CFRefCount(Ctx, GCEnabled, lopts); | 
 | } |