1226586Sdim//==-- RetainCountChecker.cpp - Checks for leaks and other issues -*- C++ -*--// 2226586Sdim// 3226586Sdim// The LLVM Compiler Infrastructure 4226586Sdim// 5226586Sdim// This file is distributed under the University of Illinois Open Source 6226586Sdim// License. See LICENSE.TXT for details. 7226586Sdim// 8226586Sdim//===----------------------------------------------------------------------===// 9226586Sdim// 10226586Sdim// This file defines the methods for RetainCountChecker, which implements 11226586Sdim// a reference count checker for Core Foundation and Cocoa on (Mac OS X). 12226586Sdim// 13226586Sdim//===----------------------------------------------------------------------===// 14226586Sdim 15226586Sdim#include "ClangSACheckers.h" 16249423Sdim#include "clang/AST/Attr.h" 17249423Sdim#include "clang/AST/DeclCXX.h" 18226586Sdim#include "clang/AST/DeclObjC.h" 19249423Sdim#include "clang/AST/ParentMap.h" 20249423Sdim#include "clang/Analysis/DomainSpecific/CocoaConventions.h" 21226586Sdim#include "clang/Basic/LangOptions.h" 22226586Sdim#include "clang/Basic/SourceManager.h" 23249423Sdim#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 24249423Sdim#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" 25226586Sdim#include "clang/StaticAnalyzer/Core/Checker.h" 26226586Sdim#include "clang/StaticAnalyzer/Core/CheckerManager.h" 27239462Sdim#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" 28226586Sdim#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 29226586Sdim#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" 30226586Sdim#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h" 31226586Sdim#include "llvm/ADT/DenseMap.h" 32226586Sdim#include "llvm/ADT/FoldingSet.h" 33226586Sdim#include "llvm/ADT/ImmutableList.h" 34226586Sdim#include "llvm/ADT/ImmutableMap.h" 35249423Sdim#include "llvm/ADT/STLExtras.h" 36234353Sdim#include "llvm/ADT/SmallString.h" 37226586Sdim#include "llvm/ADT/StringExtras.h" 38226586Sdim#include <cstdarg> 39226586Sdim 40251662Sdim#include "AllocationDiagnostics.h" 41251662Sdim 42226586Sdimusing namespace clang; 43226586Sdimusing namespace ento; 44226586Sdimusing llvm::StrInStrNoCase; 45226586Sdim 46226586Sdim//===----------------------------------------------------------------------===// 47226586Sdim// Primitives used for constructing summaries for function/method calls. 48226586Sdim//===----------------------------------------------------------------------===// 49226586Sdim 50226586Sdim/// ArgEffect is used to summarize a function/method call's effect on a 51226586Sdim/// particular argument. 52226586Sdimenum ArgEffect { DoNothing, Autorelease, Dealloc, DecRef, DecRefMsg, 53226586Sdim DecRefBridgedTransfered, 54226586Sdim IncRefMsg, IncRef, MakeCollectable, MayEscape, 55226586Sdim 56243830Sdim // Stop tracking the argument - the effect of the call is 57243830Sdim // unknown. 58243830Sdim StopTracking, 59243830Sdim 60243830Sdim // In some cases, we obtain a better summary for this checker 61243830Sdim // by looking at the call site than by inlining the function. 62243830Sdim // Signifies that we should stop tracking the symbol even if 63243830Sdim // the function is inlined. 64243830Sdim StopTrackingHard, 65243830Sdim 66243830Sdim // The function decrements the reference count and the checker 67243830Sdim // should stop tracking the argument. 68243830Sdim DecRefAndStopTrackingHard, DecRefMsgAndStopTrackingHard 69243830Sdim }; 70243830Sdim 71226586Sdimnamespace llvm { 72226586Sdimtemplate <> struct FoldingSetTrait<ArgEffect> { 73226586Sdimstatic inline void Profile(const ArgEffect X, FoldingSetNodeID& ID) { 74226586Sdim ID.AddInteger((unsigned) X); 75226586Sdim} 76226586Sdim}; 77226586Sdim} // end llvm namespace 78226586Sdim 79226586Sdim/// ArgEffects summarizes the effects of a function/method call on all of 80226586Sdim/// its arguments. 81226586Sdimtypedef llvm::ImmutableMap<unsigned,ArgEffect> ArgEffects; 82226586Sdim 83226586Sdimnamespace { 84226586Sdim 85226586Sdim/// RetEffect is used to summarize a function/method call's behavior with 86226586Sdim/// respect to its return value. 87226586Sdimclass RetEffect { 88226586Sdimpublic: 89226586Sdim enum Kind { NoRet, OwnedSymbol, OwnedAllocatedSymbol, 90226586Sdim NotOwnedSymbol, GCNotOwnedSymbol, ARCNotOwnedSymbol, 91243830Sdim OwnedWhenTrackedReceiver, 92243830Sdim // Treat this function as returning a non-tracked symbol even if 93243830Sdim // the function has been inlined. This is used where the call 94243830Sdim // site summary is more presise than the summary indirectly produced 95243830Sdim // by inlining the function 96243830Sdim NoRetHard 97243830Sdim }; 98226586Sdim 99226586Sdim enum ObjKind { CF, ObjC, AnyObj }; 100226586Sdim 101226586Sdimprivate: 102226586Sdim Kind K; 103226586Sdim ObjKind O; 104226586Sdim 105226586Sdim RetEffect(Kind k, ObjKind o = AnyObj) : K(k), O(o) {} 106226586Sdim 107226586Sdimpublic: 108226586Sdim Kind getKind() const { return K; } 109226586Sdim 110226586Sdim ObjKind getObjKind() const { return O; } 111226586Sdim 112226586Sdim bool isOwned() const { 113226586Sdim return K == OwnedSymbol || K == OwnedAllocatedSymbol || 114226586Sdim K == OwnedWhenTrackedReceiver; 115226586Sdim } 116226586Sdim 117226586Sdim bool operator==(const RetEffect &Other) const { 118226586Sdim return K == Other.K && O == Other.O; 119226586Sdim } 120226586Sdim 121226586Sdim static RetEffect MakeOwnedWhenTrackedReceiver() { 122226586Sdim return RetEffect(OwnedWhenTrackedReceiver, ObjC); 123226586Sdim } 124226586Sdim 125226586Sdim static RetEffect MakeOwned(ObjKind o, bool isAllocated = false) { 126226586Sdim return RetEffect(isAllocated ? OwnedAllocatedSymbol : OwnedSymbol, o); 127226586Sdim } 128226586Sdim static RetEffect MakeNotOwned(ObjKind o) { 129226586Sdim return RetEffect(NotOwnedSymbol, o); 130226586Sdim } 131226586Sdim static RetEffect MakeGCNotOwned() { 132226586Sdim return RetEffect(GCNotOwnedSymbol, ObjC); 133226586Sdim } 134226586Sdim static RetEffect MakeARCNotOwned() { 135226586Sdim return RetEffect(ARCNotOwnedSymbol, ObjC); 136226586Sdim } 137226586Sdim static RetEffect MakeNoRet() { 138226586Sdim return RetEffect(NoRet); 139226586Sdim } 140243830Sdim static RetEffect MakeNoRetHard() { 141243830Sdim return RetEffect(NoRetHard); 142243830Sdim } 143234353Sdim 144234353Sdim void Profile(llvm::FoldingSetNodeID& ID) const { 145234353Sdim ID.AddInteger((unsigned) K); 146234353Sdim ID.AddInteger((unsigned) O); 147234353Sdim } 148226586Sdim}; 149226586Sdim 150226586Sdim//===----------------------------------------------------------------------===// 151226586Sdim// Reference-counting logic (typestate + counts). 152226586Sdim//===----------------------------------------------------------------------===// 153226586Sdim 154226586Sdimclass RefVal { 155226586Sdimpublic: 156226586Sdim enum Kind { 157226586Sdim Owned = 0, // Owning reference. 158226586Sdim NotOwned, // Reference is not owned by still valid (not freed). 159226586Sdim Released, // Object has been released. 160226586Sdim ReturnedOwned, // Returned object passes ownership to caller. 161226586Sdim ReturnedNotOwned, // Return object does not pass ownership to caller. 162226586Sdim ERROR_START, 163226586Sdim ErrorDeallocNotOwned, // -dealloc called on non-owned object. 164226586Sdim ErrorDeallocGC, // Calling -dealloc with GC enabled. 165226586Sdim ErrorUseAfterRelease, // Object used after released. 166226586Sdim ErrorReleaseNotOwned, // Release of an object that was not owned. 167226586Sdim ERROR_LEAK_START, 168226586Sdim ErrorLeak, // A memory leak due to excessive reference counts. 169226586Sdim ErrorLeakReturned, // A memory leak due to the returning method not having 170226586Sdim // the correct naming conventions. 171226586Sdim ErrorGCLeakReturned, 172226586Sdim ErrorOverAutorelease, 173226586Sdim ErrorReturnedNotOwned 174226586Sdim }; 175226586Sdim 176226586Sdimprivate: 177226586Sdim Kind kind; 178226586Sdim RetEffect::ObjKind okind; 179226586Sdim unsigned Cnt; 180226586Sdim unsigned ACnt; 181226586Sdim QualType T; 182226586Sdim 183226586Sdim RefVal(Kind k, RetEffect::ObjKind o, unsigned cnt, unsigned acnt, QualType t) 184226586Sdim : kind(k), okind(o), Cnt(cnt), ACnt(acnt), T(t) {} 185226586Sdim 186226586Sdimpublic: 187226586Sdim Kind getKind() const { return kind; } 188226586Sdim 189226586Sdim RetEffect::ObjKind getObjKind() const { return okind; } 190226586Sdim 191226586Sdim unsigned getCount() const { return Cnt; } 192226586Sdim unsigned getAutoreleaseCount() const { return ACnt; } 193226586Sdim unsigned getCombinedCounts() const { return Cnt + ACnt; } 194226586Sdim void clearCounts() { Cnt = 0; ACnt = 0; } 195226586Sdim void setCount(unsigned i) { Cnt = i; } 196226586Sdim void setAutoreleaseCount(unsigned i) { ACnt = i; } 197226586Sdim 198226586Sdim QualType getType() const { return T; } 199226586Sdim 200226586Sdim bool isOwned() const { 201226586Sdim return getKind() == Owned; 202226586Sdim } 203226586Sdim 204226586Sdim bool isNotOwned() const { 205226586Sdim return getKind() == NotOwned; 206226586Sdim } 207226586Sdim 208226586Sdim bool isReturnedOwned() const { 209226586Sdim return getKind() == ReturnedOwned; 210226586Sdim } 211226586Sdim 212226586Sdim bool isReturnedNotOwned() const { 213226586Sdim return getKind() == ReturnedNotOwned; 214226586Sdim } 215226586Sdim 216226586Sdim static RefVal makeOwned(RetEffect::ObjKind o, QualType t, 217226586Sdim unsigned Count = 1) { 218226586Sdim return RefVal(Owned, o, Count, 0, t); 219226586Sdim } 220226586Sdim 221226586Sdim static RefVal makeNotOwned(RetEffect::ObjKind o, QualType t, 222226586Sdim unsigned Count = 0) { 223226586Sdim return RefVal(NotOwned, o, Count, 0, t); 224226586Sdim } 225226586Sdim 226226586Sdim // Comparison, profiling, and pretty-printing. 227226586Sdim 228226586Sdim bool operator==(const RefVal& X) const { 229226586Sdim return kind == X.kind && Cnt == X.Cnt && T == X.T && ACnt == X.ACnt; 230226586Sdim } 231226586Sdim 232226586Sdim RefVal operator-(size_t i) const { 233226586Sdim return RefVal(getKind(), getObjKind(), getCount() - i, 234226586Sdim getAutoreleaseCount(), getType()); 235226586Sdim } 236226586Sdim 237226586Sdim RefVal operator+(size_t i) const { 238226586Sdim return RefVal(getKind(), getObjKind(), getCount() + i, 239226586Sdim getAutoreleaseCount(), getType()); 240226586Sdim } 241226586Sdim 242226586Sdim RefVal operator^(Kind k) const { 243226586Sdim return RefVal(k, getObjKind(), getCount(), getAutoreleaseCount(), 244226586Sdim getType()); 245226586Sdim } 246226586Sdim 247226586Sdim RefVal autorelease() const { 248226586Sdim return RefVal(getKind(), getObjKind(), getCount(), getAutoreleaseCount()+1, 249226586Sdim getType()); 250226586Sdim } 251226586Sdim 252226586Sdim void Profile(llvm::FoldingSetNodeID& ID) const { 253226586Sdim ID.AddInteger((unsigned) kind); 254226586Sdim ID.AddInteger(Cnt); 255226586Sdim ID.AddInteger(ACnt); 256226586Sdim ID.Add(T); 257226586Sdim } 258226586Sdim 259226586Sdim void print(raw_ostream &Out) const; 260226586Sdim}; 261226586Sdim 262226586Sdimvoid RefVal::print(raw_ostream &Out) const { 263226586Sdim if (!T.isNull()) 264226586Sdim Out << "Tracked " << T.getAsString() << '/'; 265226586Sdim 266226586Sdim switch (getKind()) { 267226586Sdim default: llvm_unreachable("Invalid RefVal kind"); 268226586Sdim case Owned: { 269226586Sdim Out << "Owned"; 270226586Sdim unsigned cnt = getCount(); 271226586Sdim if (cnt) Out << " (+ " << cnt << ")"; 272226586Sdim break; 273226586Sdim } 274226586Sdim 275226586Sdim case NotOwned: { 276226586Sdim Out << "NotOwned"; 277226586Sdim unsigned cnt = getCount(); 278226586Sdim if (cnt) Out << " (+ " << cnt << ")"; 279226586Sdim break; 280226586Sdim } 281226586Sdim 282226586Sdim case ReturnedOwned: { 283226586Sdim Out << "ReturnedOwned"; 284226586Sdim unsigned cnt = getCount(); 285226586Sdim if (cnt) Out << " (+ " << cnt << ")"; 286226586Sdim break; 287226586Sdim } 288226586Sdim 289226586Sdim case ReturnedNotOwned: { 290226586Sdim Out << "ReturnedNotOwned"; 291226586Sdim unsigned cnt = getCount(); 292226586Sdim if (cnt) Out << " (+ " << cnt << ")"; 293226586Sdim break; 294226586Sdim } 295226586Sdim 296226586Sdim case Released: 297226586Sdim Out << "Released"; 298226586Sdim break; 299226586Sdim 300226586Sdim case ErrorDeallocGC: 301226586Sdim Out << "-dealloc (GC)"; 302226586Sdim break; 303226586Sdim 304226586Sdim case ErrorDeallocNotOwned: 305226586Sdim Out << "-dealloc (not-owned)"; 306226586Sdim break; 307226586Sdim 308226586Sdim case ErrorLeak: 309226586Sdim Out << "Leaked"; 310226586Sdim break; 311226586Sdim 312226586Sdim case ErrorLeakReturned: 313226586Sdim Out << "Leaked (Bad naming)"; 314226586Sdim break; 315226586Sdim 316226586Sdim case ErrorGCLeakReturned: 317226586Sdim Out << "Leaked (GC-ed at return)"; 318226586Sdim break; 319226586Sdim 320226586Sdim case ErrorUseAfterRelease: 321226586Sdim Out << "Use-After-Release [ERROR]"; 322226586Sdim break; 323226586Sdim 324226586Sdim case ErrorReleaseNotOwned: 325226586Sdim Out << "Release of Not-Owned [ERROR]"; 326226586Sdim break; 327226586Sdim 328226586Sdim case RefVal::ErrorOverAutorelease: 329251662Sdim Out << "Over-autoreleased"; 330226586Sdim break; 331226586Sdim 332226586Sdim case RefVal::ErrorReturnedNotOwned: 333226586Sdim Out << "Non-owned object returned instead of owned"; 334226586Sdim break; 335226586Sdim } 336226586Sdim 337226586Sdim if (ACnt) { 338226586Sdim Out << " [ARC +" << ACnt << ']'; 339226586Sdim } 340226586Sdim} 341226586Sdim} //end anonymous namespace 342226586Sdim 343226586Sdim//===----------------------------------------------------------------------===// 344226586Sdim// RefBindings - State used to track object reference counts. 345226586Sdim//===----------------------------------------------------------------------===// 346226586Sdim 347243830SdimREGISTER_MAP_WITH_PROGRAMSTATE(RefBindings, SymbolRef, RefVal) 348226586Sdim 349239462Sdimstatic inline const RefVal *getRefBinding(ProgramStateRef State, 350239462Sdim SymbolRef Sym) { 351239462Sdim return State->get<RefBindings>(Sym); 352239462Sdim} 353239462Sdim 354239462Sdimstatic inline ProgramStateRef setRefBinding(ProgramStateRef State, 355239462Sdim SymbolRef Sym, RefVal Val) { 356239462Sdim return State->set<RefBindings>(Sym, Val); 357239462Sdim} 358239462Sdim 359239462Sdimstatic ProgramStateRef removeRefBinding(ProgramStateRef State, SymbolRef Sym) { 360239462Sdim return State->remove<RefBindings>(Sym); 361239462Sdim} 362239462Sdim 363226586Sdim//===----------------------------------------------------------------------===// 364226586Sdim// Function/Method behavior summaries. 365226586Sdim//===----------------------------------------------------------------------===// 366226586Sdim 367226586Sdimnamespace { 368226586Sdimclass RetainSummary { 369234353Sdim /// Args - a map of (index, ArgEffect) pairs, where index 370226586Sdim /// specifies the argument (starting from 0). This can be sparsely 371226586Sdim /// populated; arguments with no entry in Args use 'DefaultArgEffect'. 372226586Sdim ArgEffects Args; 373226586Sdim 374226586Sdim /// DefaultArgEffect - The default ArgEffect to apply to arguments that 375226586Sdim /// do not have an entry in Args. 376234353Sdim ArgEffect DefaultArgEffect; 377226586Sdim 378226586Sdim /// Receiver - If this summary applies to an Objective-C message expression, 379226586Sdim /// this is the effect applied to the state of the receiver. 380234353Sdim ArgEffect Receiver; 381226586Sdim 382226586Sdim /// Ret - The effect on the return value. Used to indicate if the 383226586Sdim /// function/method call returns a new tracked symbol. 384234353Sdim RetEffect Ret; 385226586Sdim 386226586Sdimpublic: 387226586Sdim RetainSummary(ArgEffects A, RetEffect R, ArgEffect defaultEff, 388226586Sdim ArgEffect ReceiverEff) 389226586Sdim : Args(A), DefaultArgEffect(defaultEff), Receiver(ReceiverEff), Ret(R) {} 390226586Sdim 391226586Sdim /// getArg - Return the argument effect on the argument specified by 392226586Sdim /// idx (starting from 0). 393226586Sdim ArgEffect getArg(unsigned idx) const { 394226586Sdim if (const ArgEffect *AE = Args.lookup(idx)) 395226586Sdim return *AE; 396226586Sdim 397226586Sdim return DefaultArgEffect; 398226586Sdim } 399226586Sdim 400226586Sdim void addArg(ArgEffects::Factory &af, unsigned idx, ArgEffect e) { 401226586Sdim Args = af.add(Args, idx, e); 402226586Sdim } 403226586Sdim 404226586Sdim /// setDefaultArgEffect - Set the default argument effect. 405226586Sdim void setDefaultArgEffect(ArgEffect E) { 406226586Sdim DefaultArgEffect = E; 407226586Sdim } 408226586Sdim 409226586Sdim /// getRetEffect - Returns the effect on the return value of the call. 410226586Sdim RetEffect getRetEffect() const { return Ret; } 411226586Sdim 412226586Sdim /// setRetEffect - Set the effect of the return value of the call. 413226586Sdim void setRetEffect(RetEffect E) { Ret = E; } 414226586Sdim 415226586Sdim 416226586Sdim /// Sets the effect on the receiver of the message. 417226586Sdim void setReceiverEffect(ArgEffect e) { Receiver = e; } 418226586Sdim 419226586Sdim /// getReceiverEffect - Returns the effect on the receiver of the call. 420226586Sdim /// This is only meaningful if the summary applies to an ObjCMessageExpr*. 421226586Sdim ArgEffect getReceiverEffect() const { return Receiver; } 422226586Sdim 423226586Sdim /// Test if two retain summaries are identical. Note that merely equivalent 424226586Sdim /// summaries are not necessarily identical (for example, if an explicit 425226586Sdim /// argument effect matches the default effect). 426226586Sdim bool operator==(const RetainSummary &Other) const { 427226586Sdim return Args == Other.Args && DefaultArgEffect == Other.DefaultArgEffect && 428226586Sdim Receiver == Other.Receiver && Ret == Other.Ret; 429226586Sdim } 430234353Sdim 431234353Sdim /// Profile this summary for inclusion in a FoldingSet. 432234353Sdim void Profile(llvm::FoldingSetNodeID& ID) const { 433234353Sdim ID.Add(Args); 434234353Sdim ID.Add(DefaultArgEffect); 435234353Sdim ID.Add(Receiver); 436234353Sdim ID.Add(Ret); 437234353Sdim } 438234353Sdim 439234353Sdim /// A retain summary is simple if it has no ArgEffects other than the default. 440234353Sdim bool isSimple() const { 441234353Sdim return Args.isEmpty(); 442234353Sdim } 443239462Sdim 444239462Sdimprivate: 445239462Sdim ArgEffects getArgEffects() const { return Args; } 446239462Sdim ArgEffect getDefaultArgEffect() const { return DefaultArgEffect; } 447239462Sdim 448239462Sdim friend class RetainSummaryManager; 449226586Sdim}; 450226586Sdim} // end anonymous namespace 451226586Sdim 452226586Sdim//===----------------------------------------------------------------------===// 453226586Sdim// Data structures for constructing summaries. 454226586Sdim//===----------------------------------------------------------------------===// 455226586Sdim 456226586Sdimnamespace { 457226586Sdimclass ObjCSummaryKey { 458226586Sdim IdentifierInfo* II; 459226586Sdim Selector S; 460226586Sdimpublic: 461226586Sdim ObjCSummaryKey(IdentifierInfo* ii, Selector s) 462226586Sdim : II(ii), S(s) {} 463226586Sdim 464226586Sdim ObjCSummaryKey(const ObjCInterfaceDecl *d, Selector s) 465226586Sdim : II(d ? d->getIdentifier() : 0), S(s) {} 466226586Sdim 467226586Sdim ObjCSummaryKey(Selector s) 468226586Sdim : II(0), S(s) {} 469226586Sdim 470234353Sdim IdentifierInfo *getIdentifier() const { return II; } 471226586Sdim Selector getSelector() const { return S; } 472226586Sdim}; 473226586Sdim} 474226586Sdim 475226586Sdimnamespace llvm { 476226586Sdimtemplate <> struct DenseMapInfo<ObjCSummaryKey> { 477226586Sdim static inline ObjCSummaryKey getEmptyKey() { 478226586Sdim return ObjCSummaryKey(DenseMapInfo<IdentifierInfo*>::getEmptyKey(), 479226586Sdim DenseMapInfo<Selector>::getEmptyKey()); 480226586Sdim } 481226586Sdim 482226586Sdim static inline ObjCSummaryKey getTombstoneKey() { 483226586Sdim return ObjCSummaryKey(DenseMapInfo<IdentifierInfo*>::getTombstoneKey(), 484226586Sdim DenseMapInfo<Selector>::getTombstoneKey()); 485226586Sdim } 486226586Sdim 487226586Sdim static unsigned getHashValue(const ObjCSummaryKey &V) { 488239462Sdim typedef std::pair<IdentifierInfo*, Selector> PairTy; 489239462Sdim return DenseMapInfo<PairTy>::getHashValue(PairTy(V.getIdentifier(), 490239462Sdim V.getSelector())); 491226586Sdim } 492226586Sdim 493226586Sdim static bool isEqual(const ObjCSummaryKey& LHS, const ObjCSummaryKey& RHS) { 494239462Sdim return LHS.getIdentifier() == RHS.getIdentifier() && 495239462Sdim LHS.getSelector() == RHS.getSelector(); 496226586Sdim } 497226586Sdim 498226586Sdim}; 499226586Sdimtemplate <> 500226586Sdimstruct isPodLike<ObjCSummaryKey> { static const bool value = true; }; 501226586Sdim} // end llvm namespace 502226586Sdim 503226586Sdimnamespace { 504226586Sdimclass ObjCSummaryCache { 505226586Sdim typedef llvm::DenseMap<ObjCSummaryKey, const RetainSummary *> MapTy; 506226586Sdim MapTy M; 507226586Sdimpublic: 508226586Sdim ObjCSummaryCache() {} 509226586Sdim 510226586Sdim const RetainSummary * find(const ObjCInterfaceDecl *D, Selector S) { 511226586Sdim // Do a lookup with the (D,S) pair. If we find a match return 512226586Sdim // the iterator. 513226586Sdim ObjCSummaryKey K(D, S); 514226586Sdim MapTy::iterator I = M.find(K); 515226586Sdim 516239462Sdim if (I != M.end()) 517226586Sdim return I->second; 518239462Sdim if (!D) 519239462Sdim return NULL; 520226586Sdim 521226586Sdim // Walk the super chain. If we find a hit with a parent, we'll end 522226586Sdim // up returning that summary. We actually allow that key (null,S), as 523226586Sdim // we cache summaries for the null ObjCInterfaceDecl* to allow us to 524226586Sdim // generate initial summaries without having to worry about NSObject 525226586Sdim // being declared. 526226586Sdim // FIXME: We may change this at some point. 527226586Sdim for (ObjCInterfaceDecl *C=D->getSuperClass() ;; C=C->getSuperClass()) { 528226586Sdim if ((I = M.find(ObjCSummaryKey(C, S))) != M.end()) 529226586Sdim break; 530226586Sdim 531226586Sdim if (!C) 532226586Sdim return NULL; 533226586Sdim } 534226586Sdim 535226586Sdim // Cache the summary with original key to make the next lookup faster 536226586Sdim // and return the iterator. 537226586Sdim const RetainSummary *Summ = I->second; 538226586Sdim M[K] = Summ; 539226586Sdim return Summ; 540226586Sdim } 541226586Sdim 542234353Sdim const RetainSummary *find(IdentifierInfo* II, Selector S) { 543226586Sdim // FIXME: Class method lookup. Right now we dont' have a good way 544226586Sdim // of going between IdentifierInfo* and the class hierarchy. 545226586Sdim MapTy::iterator I = M.find(ObjCSummaryKey(II, S)); 546226586Sdim 547226586Sdim if (I == M.end()) 548226586Sdim I = M.find(ObjCSummaryKey(S)); 549226586Sdim 550226586Sdim return I == M.end() ? NULL : I->second; 551226586Sdim } 552226586Sdim 553226586Sdim const RetainSummary *& operator[](ObjCSummaryKey K) { 554226586Sdim return M[K]; 555226586Sdim } 556226586Sdim 557226586Sdim const RetainSummary *& operator[](Selector S) { 558226586Sdim return M[ ObjCSummaryKey(S) ]; 559226586Sdim } 560226586Sdim}; 561226586Sdim} // end anonymous namespace 562226586Sdim 563226586Sdim//===----------------------------------------------------------------------===// 564226586Sdim// Data structures for managing collections of summaries. 565226586Sdim//===----------------------------------------------------------------------===// 566226586Sdim 567226586Sdimnamespace { 568226586Sdimclass RetainSummaryManager { 569226586Sdim 570226586Sdim //==-----------------------------------------------------------------==// 571226586Sdim // Typedefs. 572226586Sdim //==-----------------------------------------------------------------==// 573226586Sdim 574226586Sdim typedef llvm::DenseMap<const FunctionDecl*, const RetainSummary *> 575226586Sdim FuncSummariesTy; 576226586Sdim 577226586Sdim typedef ObjCSummaryCache ObjCMethodSummariesTy; 578226586Sdim 579234353Sdim typedef llvm::FoldingSetNodeWrapper<RetainSummary> CachedSummaryNode; 580234353Sdim 581226586Sdim //==-----------------------------------------------------------------==// 582226586Sdim // Data. 583226586Sdim //==-----------------------------------------------------------------==// 584226586Sdim 585226586Sdim /// Ctx - The ASTContext object for the analyzed ASTs. 586226586Sdim ASTContext &Ctx; 587226586Sdim 588226586Sdim /// GCEnabled - Records whether or not the analyzed code runs in GC mode. 589226586Sdim const bool GCEnabled; 590226586Sdim 591226586Sdim /// Records whether or not the analyzed code runs in ARC mode. 592226586Sdim const bool ARCEnabled; 593226586Sdim 594226586Sdim /// FuncSummaries - A map from FunctionDecls to summaries. 595226586Sdim FuncSummariesTy FuncSummaries; 596226586Sdim 597226586Sdim /// ObjCClassMethodSummaries - A map from selectors (for instance methods) 598226586Sdim /// to summaries. 599226586Sdim ObjCMethodSummariesTy ObjCClassMethodSummaries; 600226586Sdim 601226586Sdim /// ObjCMethodSummaries - A map from selectors to summaries. 602226586Sdim ObjCMethodSummariesTy ObjCMethodSummaries; 603226586Sdim 604226586Sdim /// BPAlloc - A BumpPtrAllocator used for allocating summaries, ArgEffects, 605226586Sdim /// and all other data used by the checker. 606226586Sdim llvm::BumpPtrAllocator BPAlloc; 607226586Sdim 608226586Sdim /// AF - A factory for ArgEffects objects. 609226586Sdim ArgEffects::Factory AF; 610226586Sdim 611226586Sdim /// ScratchArgs - A holding buffer for construct ArgEffects. 612234353Sdim ArgEffects ScratchArgs; 613226586Sdim 614226586Sdim /// ObjCAllocRetE - Default return effect for methods returning Objective-C 615226586Sdim /// objects. 616226586Sdim RetEffect ObjCAllocRetE; 617226586Sdim 618226586Sdim /// ObjCInitRetE - Default return effect for init methods returning 619226586Sdim /// Objective-C objects. 620226586Sdim RetEffect ObjCInitRetE; 621226586Sdim 622234353Sdim /// SimpleSummaries - Used for uniquing summaries that don't have special 623234353Sdim /// effects. 624234353Sdim llvm::FoldingSet<CachedSummaryNode> SimpleSummaries; 625226586Sdim 626226586Sdim //==-----------------------------------------------------------------==// 627226586Sdim // Methods. 628226586Sdim //==-----------------------------------------------------------------==// 629226586Sdim 630226586Sdim /// getArgEffects - Returns a persistent ArgEffects object based on the 631226586Sdim /// data in ScratchArgs. 632226586Sdim ArgEffects getArgEffects(); 633226586Sdim 634226586Sdim enum UnaryFuncKind { cfretain, cfrelease, cfmakecollectable }; 635226586Sdim 636234353Sdim const RetainSummary *getUnarySummary(const FunctionType* FT, 637226586Sdim UnaryFuncKind func); 638226586Sdim 639234353Sdim const RetainSummary *getCFSummaryCreateRule(const FunctionDecl *FD); 640234353Sdim const RetainSummary *getCFSummaryGetRule(const FunctionDecl *FD); 641234353Sdim const RetainSummary *getCFCreateGetRuleSummary(const FunctionDecl *FD); 642226586Sdim 643234353Sdim const RetainSummary *getPersistentSummary(const RetainSummary &OldSumm); 644226586Sdim 645234353Sdim const RetainSummary *getPersistentSummary(RetEffect RetEff, 646226586Sdim ArgEffect ReceiverEff = DoNothing, 647226586Sdim ArgEffect DefaultEff = MayEscape) { 648234353Sdim RetainSummary Summ(getArgEffects(), RetEff, DefaultEff, ReceiverEff); 649234353Sdim return getPersistentSummary(Summ); 650226586Sdim } 651226586Sdim 652239462Sdim const RetainSummary *getDoNothingSummary() { 653239462Sdim return getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing); 654239462Sdim } 655239462Sdim 656234353Sdim const RetainSummary *getDefaultSummary() { 657234353Sdim return getPersistentSummary(RetEffect::MakeNoRet(), 658234353Sdim DoNothing, MayEscape); 659234353Sdim } 660234353Sdim 661226586Sdim const RetainSummary *getPersistentStopSummary() { 662234353Sdim return getPersistentSummary(RetEffect::MakeNoRet(), 663234353Sdim StopTracking, StopTracking); 664226586Sdim } 665226586Sdim 666226586Sdim void InitializeClassMethodSummaries(); 667226586Sdim void InitializeMethodSummaries(); 668226586Sdimprivate: 669226586Sdim void addNSObjectClsMethSummary(Selector S, const RetainSummary *Summ) { 670226586Sdim ObjCClassMethodSummaries[S] = Summ; 671226586Sdim } 672226586Sdim 673226586Sdim void addNSObjectMethSummary(Selector S, const RetainSummary *Summ) { 674226586Sdim ObjCMethodSummaries[S] = Summ; 675226586Sdim } 676226586Sdim 677234353Sdim void addClassMethSummary(const char* Cls, const char* name, 678234353Sdim const RetainSummary *Summ, bool isNullary = true) { 679226586Sdim IdentifierInfo* ClsII = &Ctx.Idents.get(Cls); 680234353Sdim Selector S = isNullary ? GetNullarySelector(name, Ctx) 681234353Sdim : GetUnarySelector(name, Ctx); 682226586Sdim ObjCClassMethodSummaries[ObjCSummaryKey(ClsII, S)] = Summ; 683226586Sdim } 684226586Sdim 685226586Sdim void addInstMethSummary(const char* Cls, const char* nullaryName, 686226586Sdim const RetainSummary *Summ) { 687226586Sdim IdentifierInfo* ClsII = &Ctx.Idents.get(Cls); 688226586Sdim Selector S = GetNullarySelector(nullaryName, Ctx); 689226586Sdim ObjCMethodSummaries[ObjCSummaryKey(ClsII, S)] = Summ; 690226586Sdim } 691226586Sdim 692226586Sdim Selector generateSelector(va_list argp) { 693226586Sdim SmallVector<IdentifierInfo*, 10> II; 694226586Sdim 695226586Sdim while (const char* s = va_arg(argp, const char*)) 696226586Sdim II.push_back(&Ctx.Idents.get(s)); 697226586Sdim 698226586Sdim return Ctx.Selectors.getSelector(II.size(), &II[0]); 699226586Sdim } 700226586Sdim 701226586Sdim void addMethodSummary(IdentifierInfo *ClsII, ObjCMethodSummariesTy& Summaries, 702226586Sdim const RetainSummary * Summ, va_list argp) { 703226586Sdim Selector S = generateSelector(argp); 704226586Sdim Summaries[ObjCSummaryKey(ClsII, S)] = Summ; 705226586Sdim } 706226586Sdim 707226586Sdim void addInstMethSummary(const char* Cls, const RetainSummary * Summ, ...) { 708226586Sdim va_list argp; 709226586Sdim va_start(argp, Summ); 710226586Sdim addMethodSummary(&Ctx.Idents.get(Cls), ObjCMethodSummaries, Summ, argp); 711226586Sdim va_end(argp); 712226586Sdim } 713226586Sdim 714226586Sdim void addClsMethSummary(const char* Cls, const RetainSummary * Summ, ...) { 715226586Sdim va_list argp; 716226586Sdim va_start(argp, Summ); 717226586Sdim addMethodSummary(&Ctx.Idents.get(Cls),ObjCClassMethodSummaries, Summ, argp); 718226586Sdim va_end(argp); 719226586Sdim } 720226586Sdim 721226586Sdim void addClsMethSummary(IdentifierInfo *II, const RetainSummary * Summ, ...) { 722226586Sdim va_list argp; 723226586Sdim va_start(argp, Summ); 724226586Sdim addMethodSummary(II, ObjCClassMethodSummaries, Summ, argp); 725226586Sdim va_end(argp); 726226586Sdim } 727226586Sdim 728226586Sdimpublic: 729226586Sdim 730226586Sdim RetainSummaryManager(ASTContext &ctx, bool gcenabled, bool usesARC) 731226586Sdim : Ctx(ctx), 732226586Sdim GCEnabled(gcenabled), 733226586Sdim ARCEnabled(usesARC), 734226586Sdim AF(BPAlloc), ScratchArgs(AF.getEmptyMap()), 735226586Sdim ObjCAllocRetE(gcenabled 736226586Sdim ? RetEffect::MakeGCNotOwned() 737226586Sdim : (usesARC ? RetEffect::MakeARCNotOwned() 738226586Sdim : RetEffect::MakeOwned(RetEffect::ObjC, true))), 739226586Sdim ObjCInitRetE(gcenabled 740226586Sdim ? RetEffect::MakeGCNotOwned() 741226586Sdim : (usesARC ? RetEffect::MakeARCNotOwned() 742234353Sdim : RetEffect::MakeOwnedWhenTrackedReceiver())) { 743226586Sdim InitializeClassMethodSummaries(); 744226586Sdim InitializeMethodSummaries(); 745226586Sdim } 746226586Sdim 747239462Sdim const RetainSummary *getSummary(const CallEvent &Call, 748239462Sdim ProgramStateRef State = 0); 749226586Sdim 750239462Sdim const RetainSummary *getFunctionSummary(const FunctionDecl *FD); 751239462Sdim 752239462Sdim const RetainSummary *getMethodSummary(Selector S, const ObjCInterfaceDecl *ID, 753234353Sdim const ObjCMethodDecl *MD, 754234353Sdim QualType RetTy, 755234353Sdim ObjCMethodSummariesTy &CachedSummaries); 756234353Sdim 757239462Sdim const RetainSummary *getInstanceMethodSummary(const ObjCMethodCall &M, 758239462Sdim ProgramStateRef State); 759226586Sdim 760239462Sdim const RetainSummary *getClassMethodSummary(const ObjCMethodCall &M) { 761239462Sdim assert(!M.isInstanceMessage()); 762239462Sdim const ObjCInterfaceDecl *Class = M.getReceiverInterface(); 763226586Sdim 764239462Sdim return getMethodSummary(M.getSelector(), Class, M.getDecl(), 765239462Sdim M.getResultType(), ObjCClassMethodSummaries); 766226586Sdim } 767226586Sdim 768226586Sdim /// getMethodSummary - This version of getMethodSummary is used to query 769226586Sdim /// the summary for the current method being analyzed. 770226586Sdim const RetainSummary *getMethodSummary(const ObjCMethodDecl *MD) { 771226586Sdim const ObjCInterfaceDecl *ID = MD->getClassInterface(); 772226586Sdim Selector S = MD->getSelector(); 773226586Sdim QualType ResultTy = MD->getResultType(); 774226586Sdim 775234353Sdim ObjCMethodSummariesTy *CachedSummaries; 776226586Sdim if (MD->isInstanceMethod()) 777234353Sdim CachedSummaries = &ObjCMethodSummaries; 778226586Sdim else 779234353Sdim CachedSummaries = &ObjCClassMethodSummaries; 780234353Sdim 781239462Sdim return getMethodSummary(S, ID, MD, ResultTy, *CachedSummaries); 782226586Sdim } 783226586Sdim 784234353Sdim const RetainSummary *getStandardMethodSummary(const ObjCMethodDecl *MD, 785239462Sdim Selector S, QualType RetTy); 786226586Sdim 787249423Sdim /// Determine if there is a special return effect for this function or method. 788249423Sdim Optional<RetEffect> getRetEffectFromAnnotations(QualType RetTy, 789249423Sdim const Decl *D); 790249423Sdim 791226586Sdim void updateSummaryFromAnnotations(const RetainSummary *&Summ, 792226586Sdim const ObjCMethodDecl *MD); 793226586Sdim 794226586Sdim void updateSummaryFromAnnotations(const RetainSummary *&Summ, 795226586Sdim const FunctionDecl *FD); 796226586Sdim 797239462Sdim void updateSummaryForCall(const RetainSummary *&Summ, 798239462Sdim const CallEvent &Call); 799239462Sdim 800226586Sdim bool isGCEnabled() const { return GCEnabled; } 801226586Sdim 802226586Sdim bool isARCEnabled() const { return ARCEnabled; } 803226586Sdim 804226586Sdim bool isARCorGCEnabled() const { return GCEnabled || ARCEnabled; } 805239462Sdim 806239462Sdim RetEffect getObjAllocRetEffect() const { return ObjCAllocRetE; } 807239462Sdim 808239462Sdim friend class RetainSummaryTemplate; 809226586Sdim}; 810226586Sdim 811226586Sdim// Used to avoid allocating long-term (BPAlloc'd) memory for default retain 812226586Sdim// summaries. If a function or method looks like it has a default summary, but 813226586Sdim// it has annotations, the annotations are added to the stack-based template 814226586Sdim// and then copied into managed memory. 815226586Sdimclass RetainSummaryTemplate { 816226586Sdim RetainSummaryManager &Manager; 817226586Sdim const RetainSummary *&RealSummary; 818226586Sdim RetainSummary ScratchSummary; 819226586Sdim bool Accessed; 820226586Sdimpublic: 821239462Sdim RetainSummaryTemplate(const RetainSummary *&real, RetainSummaryManager &mgr) 822239462Sdim : Manager(mgr), RealSummary(real), ScratchSummary(*real), Accessed(false) {} 823226586Sdim 824226586Sdim ~RetainSummaryTemplate() { 825226586Sdim if (Accessed) 826234353Sdim RealSummary = Manager.getPersistentSummary(ScratchSummary); 827226586Sdim } 828226586Sdim 829226586Sdim RetainSummary &operator*() { 830226586Sdim Accessed = true; 831226586Sdim return ScratchSummary; 832226586Sdim } 833226586Sdim 834226586Sdim RetainSummary *operator->() { 835226586Sdim Accessed = true; 836226586Sdim return &ScratchSummary; 837226586Sdim } 838226586Sdim}; 839226586Sdim 840226586Sdim} // end anonymous namespace 841226586Sdim 842226586Sdim//===----------------------------------------------------------------------===// 843226586Sdim// Implementation of checker data structures. 844226586Sdim//===----------------------------------------------------------------------===// 845226586Sdim 846226586SdimArgEffects RetainSummaryManager::getArgEffects() { 847226586Sdim ArgEffects AE = ScratchArgs; 848226586Sdim ScratchArgs = AF.getEmptyMap(); 849226586Sdim return AE; 850226586Sdim} 851226586Sdim 852226586Sdimconst RetainSummary * 853234353SdimRetainSummaryManager::getPersistentSummary(const RetainSummary &OldSumm) { 854234353Sdim // Unique "simple" summaries -- those without ArgEffects. 855234353Sdim if (OldSumm.isSimple()) { 856234353Sdim llvm::FoldingSetNodeID ID; 857234353Sdim OldSumm.Profile(ID); 858234353Sdim 859234353Sdim void *Pos; 860234353Sdim CachedSummaryNode *N = SimpleSummaries.FindNodeOrInsertPos(ID, Pos); 861234353Sdim 862234353Sdim if (!N) { 863234353Sdim N = (CachedSummaryNode *) BPAlloc.Allocate<CachedSummaryNode>(); 864234353Sdim new (N) CachedSummaryNode(OldSumm); 865234353Sdim SimpleSummaries.InsertNode(N, Pos); 866234353Sdim } 867234353Sdim 868234353Sdim return &N->getValue(); 869234353Sdim } 870234353Sdim 871226586Sdim RetainSummary *Summ = (RetainSummary *) BPAlloc.Allocate<RetainSummary>(); 872234353Sdim new (Summ) RetainSummary(OldSumm); 873226586Sdim return Summ; 874226586Sdim} 875226586Sdim 876226586Sdim//===----------------------------------------------------------------------===// 877226586Sdim// Summary creation for functions (largely uses of Core Foundation). 878226586Sdim//===----------------------------------------------------------------------===// 879226586Sdim 880226586Sdimstatic bool isRetain(const FunctionDecl *FD, StringRef FName) { 881226586Sdim return FName.endswith("Retain"); 882226586Sdim} 883226586Sdim 884226586Sdimstatic bool isRelease(const FunctionDecl *FD, StringRef FName) { 885226586Sdim return FName.endswith("Release"); 886226586Sdim} 887226586Sdim 888226586Sdimstatic bool isMakeCollectable(const FunctionDecl *FD, StringRef FName) { 889226586Sdim // FIXME: Remove FunctionDecl parameter. 890226586Sdim // FIXME: Is it really okay if MakeCollectable isn't a suffix? 891226586Sdim return FName.find("MakeCollectable") != StringRef::npos; 892226586Sdim} 893226586Sdim 894243830Sdimstatic ArgEffect getStopTrackingHardEquivalent(ArgEffect E) { 895239462Sdim switch (E) { 896239462Sdim case DoNothing: 897239462Sdim case Autorelease: 898239462Sdim case DecRefBridgedTransfered: 899239462Sdim case IncRef: 900239462Sdim case IncRefMsg: 901239462Sdim case MakeCollectable: 902239462Sdim case MayEscape: 903239462Sdim case StopTracking: 904243830Sdim case StopTrackingHard: 905243830Sdim return StopTrackingHard; 906239462Sdim case DecRef: 907243830Sdim case DecRefAndStopTrackingHard: 908243830Sdim return DecRefAndStopTrackingHard; 909239462Sdim case DecRefMsg: 910243830Sdim case DecRefMsgAndStopTrackingHard: 911243830Sdim return DecRefMsgAndStopTrackingHard; 912239462Sdim case Dealloc: 913239462Sdim return Dealloc; 914239462Sdim } 915239462Sdim 916239462Sdim llvm_unreachable("Unknown ArgEffect kind"); 917239462Sdim} 918239462Sdim 919239462Sdimvoid RetainSummaryManager::updateSummaryForCall(const RetainSummary *&S, 920239462Sdim const CallEvent &Call) { 921239462Sdim if (Call.hasNonZeroCallbackArg()) { 922243830Sdim ArgEffect RecEffect = 923243830Sdim getStopTrackingHardEquivalent(S->getReceiverEffect()); 924243830Sdim ArgEffect DefEffect = 925243830Sdim getStopTrackingHardEquivalent(S->getDefaultArgEffect()); 926239462Sdim 927239462Sdim ArgEffects CustomArgEffects = S->getArgEffects(); 928239462Sdim for (ArgEffects::iterator I = CustomArgEffects.begin(), 929239462Sdim E = CustomArgEffects.end(); 930239462Sdim I != E; ++I) { 931243830Sdim ArgEffect Translated = getStopTrackingHardEquivalent(I->second); 932239462Sdim if (Translated != DefEffect) 933239462Sdim ScratchArgs = AF.add(ScratchArgs, I->first, Translated); 934239462Sdim } 935239462Sdim 936243830Sdim RetEffect RE = RetEffect::MakeNoRetHard(); 937239462Sdim 938239462Sdim // Special cases where the callback argument CANNOT free the return value. 939239462Sdim // This can generally only happen if we know that the callback will only be 940239462Sdim // called when the return value is already being deallocated. 941239462Sdim if (const FunctionCall *FC = dyn_cast<FunctionCall>(&Call)) { 942243830Sdim if (IdentifierInfo *Name = FC->getDecl()->getIdentifier()) { 943243830Sdim // When the CGBitmapContext is deallocated, the callback here will free 944243830Sdim // the associated data buffer. 945243830Sdim if (Name->isStr("CGBitmapContextCreateWithData")) 946243830Sdim RE = S->getRetEffect(); 947243830Sdim } 948239462Sdim } 949239462Sdim 950239462Sdim S = getPersistentSummary(RE, RecEffect, DefEffect); 951239462Sdim } 952243830Sdim 953243830Sdim // Special case '[super init];' and '[self init];' 954243830Sdim // 955243830Sdim // Even though calling '[super init]' without assigning the result to self 956243830Sdim // and checking if the parent returns 'nil' is a bad pattern, it is common. 957243830Sdim // Additionally, our Self Init checker already warns about it. To avoid 958243830Sdim // overwhelming the user with messages from both checkers, we model the case 959243830Sdim // of '[super init]' in cases when it is not consumed by another expression 960243830Sdim // as if the call preserves the value of 'self'; essentially, assuming it can 961243830Sdim // never fail and return 'nil'. 962243830Sdim // Note, we don't want to just stop tracking the value since we want the 963243830Sdim // RetainCount checker to report leaks and use-after-free if SelfInit checker 964243830Sdim // is turned off. 965243830Sdim if (const ObjCMethodCall *MC = dyn_cast<ObjCMethodCall>(&Call)) { 966243830Sdim if (MC->getMethodFamily() == OMF_init && MC->isReceiverSelfOrSuper()) { 967243830Sdim 968243830Sdim // Check if the message is not consumed, we know it will not be used in 969243830Sdim // an assignment, ex: "self = [super init]". 970243830Sdim const Expr *ME = MC->getOriginExpr(); 971243830Sdim const LocationContext *LCtx = MC->getLocationContext(); 972243830Sdim ParentMap &PM = LCtx->getAnalysisDeclContext()->getParentMap(); 973243830Sdim if (!PM.isConsumedExpr(ME)) { 974243830Sdim RetainSummaryTemplate ModifiableSummaryTemplate(S, *this); 975243830Sdim ModifiableSummaryTemplate->setReceiverEffect(DoNothing); 976243830Sdim ModifiableSummaryTemplate->setRetEffect(RetEffect::MakeNoRet()); 977243830Sdim } 978243830Sdim } 979243830Sdim 980243830Sdim } 981239462Sdim} 982239462Sdim 983239462Sdimconst RetainSummary * 984239462SdimRetainSummaryManager::getSummary(const CallEvent &Call, 985239462Sdim ProgramStateRef State) { 986239462Sdim const RetainSummary *Summ; 987239462Sdim switch (Call.getKind()) { 988239462Sdim case CE_Function: 989239462Sdim Summ = getFunctionSummary(cast<FunctionCall>(Call).getDecl()); 990239462Sdim break; 991239462Sdim case CE_CXXMember: 992239462Sdim case CE_CXXMemberOperator: 993239462Sdim case CE_Block: 994239462Sdim case CE_CXXConstructor: 995239462Sdim case CE_CXXDestructor: 996239462Sdim case CE_CXXAllocator: 997239462Sdim // FIXME: These calls are currently unsupported. 998239462Sdim return getPersistentStopSummary(); 999239462Sdim case CE_ObjCMessage: { 1000239462Sdim const ObjCMethodCall &Msg = cast<ObjCMethodCall>(Call); 1001239462Sdim if (Msg.isInstanceMessage()) 1002239462Sdim Summ = getInstanceMethodSummary(Msg, State); 1003239462Sdim else 1004239462Sdim Summ = getClassMethodSummary(Msg); 1005239462Sdim break; 1006239462Sdim } 1007239462Sdim } 1008239462Sdim 1009239462Sdim updateSummaryForCall(Summ, Call); 1010239462Sdim 1011239462Sdim assert(Summ && "Unknown call type?"); 1012239462Sdim return Summ; 1013239462Sdim} 1014239462Sdim 1015239462Sdimconst RetainSummary * 1016239462SdimRetainSummaryManager::getFunctionSummary(const FunctionDecl *FD) { 1017239462Sdim // If we don't know what function we're calling, use our default summary. 1018239462Sdim if (!FD) 1019239462Sdim return getDefaultSummary(); 1020239462Sdim 1021226586Sdim // Look up a summary in our cache of FunctionDecls -> Summaries. 1022226586Sdim FuncSummariesTy::iterator I = FuncSummaries.find(FD); 1023226586Sdim if (I != FuncSummaries.end()) 1024226586Sdim return I->second; 1025226586Sdim 1026226586Sdim // No summary? Generate one. 1027226586Sdim const RetainSummary *S = 0; 1028239462Sdim bool AllowAnnotations = true; 1029226586Sdim 1030226586Sdim do { 1031226586Sdim // We generate "stop" summaries for implicitly defined functions. 1032226586Sdim if (FD->isImplicit()) { 1033226586Sdim S = getPersistentStopSummary(); 1034226586Sdim break; 1035226586Sdim } 1036226586Sdim 1037226586Sdim // [PR 3337] Use 'getAs<FunctionType>' to strip away any typedefs on the 1038226586Sdim // function's type. 1039226586Sdim const FunctionType* FT = FD->getType()->getAs<FunctionType>(); 1040226586Sdim const IdentifierInfo *II = FD->getIdentifier(); 1041226586Sdim if (!II) 1042226586Sdim break; 1043226586Sdim 1044226586Sdim StringRef FName = II->getName(); 1045226586Sdim 1046226586Sdim // Strip away preceding '_'. Doing this here will effect all the checks 1047226586Sdim // down below. 1048226586Sdim FName = FName.substr(FName.find_first_not_of('_')); 1049226586Sdim 1050226586Sdim // Inspect the result type. 1051226586Sdim QualType RetTy = FT->getResultType(); 1052226586Sdim 1053226586Sdim // FIXME: This should all be refactored into a chain of "summary lookup" 1054226586Sdim // filters. 1055226586Sdim assert(ScratchArgs.isEmpty()); 1056226586Sdim 1057239462Sdim if (FName == "pthread_create" || FName == "pthread_setspecific") { 1058239462Sdim // Part of: <rdar://problem/7299394> and <rdar://problem/11282706>. 1059239462Sdim // This will be addressed better with IPA. 1060226586Sdim S = getPersistentStopSummary(); 1061226586Sdim } else if (FName == "NSMakeCollectable") { 1062226586Sdim // Handle: id NSMakeCollectable(CFTypeRef) 1063226586Sdim S = (RetTy->isObjCIdType()) 1064226586Sdim ? getUnarySummary(FT, cfmakecollectable) 1065226586Sdim : getPersistentStopSummary(); 1066239462Sdim // The headers on OS X 10.8 use cf_consumed/ns_returns_retained, 1067239462Sdim // but we can fully model NSMakeCollectable ourselves. 1068239462Sdim AllowAnnotations = false; 1069243830Sdim } else if (FName == "CFPlugInInstanceCreate") { 1070243830Sdim S = getPersistentSummary(RetEffect::MakeNoRet()); 1071226586Sdim } else if (FName == "IOBSDNameMatching" || 1072226586Sdim FName == "IOServiceMatching" || 1073226586Sdim FName == "IOServiceNameMatching" || 1074239462Sdim FName == "IORegistryEntrySearchCFProperty" || 1075226586Sdim FName == "IORegistryEntryIDMatching" || 1076226586Sdim FName == "IOOpenFirmwarePathMatching") { 1077226586Sdim // Part of <rdar://problem/6961230>. (IOKit) 1078226586Sdim // This should be addressed using a API table. 1079226586Sdim S = getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF, true), 1080226586Sdim DoNothing, DoNothing); 1081226586Sdim } else if (FName == "IOServiceGetMatchingService" || 1082226586Sdim FName == "IOServiceGetMatchingServices") { 1083226586Sdim // FIXES: <rdar://problem/6326900> 1084226586Sdim // This should be addressed using a API table. This strcmp is also 1085226586Sdim // a little gross, but there is no need to super optimize here. 1086226586Sdim ScratchArgs = AF.add(ScratchArgs, 1, DecRef); 1087226586Sdim S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing); 1088226586Sdim } else if (FName == "IOServiceAddNotification" || 1089226586Sdim FName == "IOServiceAddMatchingNotification") { 1090226586Sdim // Part of <rdar://problem/6961230>. (IOKit) 1091226586Sdim // This should be addressed using a API table. 1092226586Sdim ScratchArgs = AF.add(ScratchArgs, 2, DecRef); 1093226586Sdim S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing); 1094226586Sdim } else if (FName == "CVPixelBufferCreateWithBytes") { 1095226586Sdim // FIXES: <rdar://problem/7283567> 1096226586Sdim // Eventually this can be improved by recognizing that the pixel 1097226586Sdim // buffer passed to CVPixelBufferCreateWithBytes is released via 1098226586Sdim // a callback and doing full IPA to make sure this is done correctly. 1099226586Sdim // FIXME: This function has an out parameter that returns an 1100226586Sdim // allocated object. 1101226586Sdim ScratchArgs = AF.add(ScratchArgs, 7, StopTracking); 1102226586Sdim S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing); 1103226586Sdim } else if (FName == "CGBitmapContextCreateWithData") { 1104226586Sdim // FIXES: <rdar://problem/7358899> 1105226586Sdim // Eventually this can be improved by recognizing that 'releaseInfo' 1106226586Sdim // passed to CGBitmapContextCreateWithData is released via 1107226586Sdim // a callback and doing full IPA to make sure this is done correctly. 1108226586Sdim ScratchArgs = AF.add(ScratchArgs, 8, StopTracking); 1109226586Sdim S = getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF, true), 1110226586Sdim DoNothing, DoNothing); 1111226586Sdim } else if (FName == "CVPixelBufferCreateWithPlanarBytes") { 1112226586Sdim // FIXES: <rdar://problem/7283567> 1113226586Sdim // Eventually this can be improved by recognizing that the pixel 1114226586Sdim // buffer passed to CVPixelBufferCreateWithPlanarBytes is released 1115226586Sdim // via a callback and doing full IPA to make sure this is done 1116226586Sdim // correctly. 1117226586Sdim ScratchArgs = AF.add(ScratchArgs, 12, StopTracking); 1118226586Sdim S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing); 1119251662Sdim } else if (FName == "dispatch_set_context" || 1120251662Sdim FName == "xpc_connection_set_context") { 1121234353Sdim // <rdar://problem/11059275> - The analyzer currently doesn't have 1122234353Sdim // a good way to reason about the finalizer function for libdispatch. 1123234353Sdim // If we pass a context object that is memory managed, stop tracking it. 1124251662Sdim // <rdar://problem/13783514> - Same problem, but for XPC. 1125234353Sdim // FIXME: this hack should possibly go away once we can handle 1126251662Sdim // libdispatch and XPC finalizers. 1127234353Sdim ScratchArgs = AF.add(ScratchArgs, 1, StopTracking); 1128234353Sdim S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing); 1129239462Sdim } else if (FName.startswith("NSLog")) { 1130239462Sdim S = getDoNothingSummary(); 1131234353Sdim } else if (FName.startswith("NS") && 1132234353Sdim (FName.find("Insert") != StringRef::npos)) { 1133234353Sdim // Whitelist NSXXInsertXX, for example NSMapInsertIfAbsent, since they can 1134234353Sdim // be deallocated by NSMapRemove. (radar://11152419) 1135234353Sdim ScratchArgs = AF.add(ScratchArgs, 1, StopTracking); 1136234353Sdim ScratchArgs = AF.add(ScratchArgs, 2, StopTracking); 1137234353Sdim S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing); 1138226586Sdim } 1139226586Sdim 1140226586Sdim // Did we get a summary? 1141226586Sdim if (S) 1142226586Sdim break; 1143226586Sdim 1144249423Sdim if (RetTy->isPointerType()) { 1145226586Sdim // For CoreFoundation ('CF') types. 1146226586Sdim if (cocoa::isRefType(RetTy, "CF", FName)) { 1147226586Sdim if (isRetain(FD, FName)) 1148226586Sdim S = getUnarySummary(FT, cfretain); 1149226586Sdim else if (isMakeCollectable(FD, FName)) 1150226586Sdim S = getUnarySummary(FT, cfmakecollectable); 1151226586Sdim else 1152226586Sdim S = getCFCreateGetRuleSummary(FD); 1153226586Sdim 1154226586Sdim break; 1155226586Sdim } 1156226586Sdim 1157226586Sdim // For CoreGraphics ('CG') types. 1158226586Sdim if (cocoa::isRefType(RetTy, "CG", FName)) { 1159226586Sdim if (isRetain(FD, FName)) 1160226586Sdim S = getUnarySummary(FT, cfretain); 1161226586Sdim else 1162226586Sdim S = getCFCreateGetRuleSummary(FD); 1163226586Sdim 1164226586Sdim break; 1165226586Sdim } 1166226586Sdim 1167226586Sdim // For the Disk Arbitration API (DiskArbitration/DADisk.h) 1168226586Sdim if (cocoa::isRefType(RetTy, "DADisk") || 1169226586Sdim cocoa::isRefType(RetTy, "DADissenter") || 1170226586Sdim cocoa::isRefType(RetTy, "DASessionRef")) { 1171226586Sdim S = getCFCreateGetRuleSummary(FD); 1172226586Sdim break; 1173226586Sdim } 1174226586Sdim 1175249423Sdim if (FD->getAttr<CFAuditedTransferAttr>()) { 1176249423Sdim S = getCFCreateGetRuleSummary(FD); 1177249423Sdim break; 1178249423Sdim } 1179249423Sdim 1180226586Sdim break; 1181226586Sdim } 1182226586Sdim 1183226586Sdim // Check for release functions, the only kind of functions that we care 1184226586Sdim // about that don't return a pointer type. 1185226586Sdim if (FName[0] == 'C' && (FName[1] == 'F' || FName[1] == 'G')) { 1186226586Sdim // Test for 'CGCF'. 1187226586Sdim FName = FName.substr(FName.startswith("CGCF") ? 4 : 2); 1188226586Sdim 1189226586Sdim if (isRelease(FD, FName)) 1190226586Sdim S = getUnarySummary(FT, cfrelease); 1191226586Sdim else { 1192226586Sdim assert (ScratchArgs.isEmpty()); 1193226586Sdim // Remaining CoreFoundation and CoreGraphics functions. 1194226586Sdim // We use to assume that they all strictly followed the ownership idiom 1195226586Sdim // and that ownership cannot be transferred. While this is technically 1196226586Sdim // correct, many methods allow a tracked object to escape. For example: 1197226586Sdim // 1198226586Sdim // CFMutableDictionaryRef x = CFDictionaryCreateMutable(...); 1199226586Sdim // CFDictionaryAddValue(y, key, x); 1200226586Sdim // CFRelease(x); 1201226586Sdim // ... it is okay to use 'x' since 'y' has a reference to it 1202226586Sdim // 1203226586Sdim // We handle this and similar cases with the follow heuristic. If the 1204226586Sdim // function name contains "InsertValue", "SetValue", "AddValue", 1205226586Sdim // "AppendValue", or "SetAttribute", then we assume that arguments may 1206226586Sdim // "escape." This means that something else holds on to the object, 1207226586Sdim // allowing it be used even after its local retain count drops to 0. 1208226586Sdim ArgEffect E = (StrInStrNoCase(FName, "InsertValue") != StringRef::npos|| 1209226586Sdim StrInStrNoCase(FName, "AddValue") != StringRef::npos || 1210226586Sdim StrInStrNoCase(FName, "SetValue") != StringRef::npos || 1211226586Sdim StrInStrNoCase(FName, "AppendValue") != StringRef::npos|| 1212226586Sdim StrInStrNoCase(FName, "SetAttribute") != StringRef::npos) 1213226586Sdim ? MayEscape : DoNothing; 1214226586Sdim 1215226586Sdim S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, E); 1216226586Sdim } 1217226586Sdim } 1218226586Sdim } 1219226586Sdim while (0); 1220226586Sdim 1221239462Sdim // If we got all the way here without any luck, use a default summary. 1222239462Sdim if (!S) 1223239462Sdim S = getDefaultSummary(); 1224239462Sdim 1225226586Sdim // Annotations override defaults. 1226239462Sdim if (AllowAnnotations) 1227239462Sdim updateSummaryFromAnnotations(S, FD); 1228226586Sdim 1229226586Sdim FuncSummaries[FD] = S; 1230226586Sdim return S; 1231226586Sdim} 1232226586Sdim 1233226586Sdimconst RetainSummary * 1234226586SdimRetainSummaryManager::getCFCreateGetRuleSummary(const FunctionDecl *FD) { 1235226586Sdim if (coreFoundation::followsCreateRule(FD)) 1236226586Sdim return getCFSummaryCreateRule(FD); 1237226586Sdim 1238226586Sdim return getCFSummaryGetRule(FD); 1239226586Sdim} 1240226586Sdim 1241226586Sdimconst RetainSummary * 1242226586SdimRetainSummaryManager::getUnarySummary(const FunctionType* FT, 1243226586Sdim UnaryFuncKind func) { 1244226586Sdim 1245226586Sdim // Sanity check that this is *really* a unary function. This can 1246226586Sdim // happen if people do weird things. 1247226586Sdim const FunctionProtoType* FTP = dyn_cast<FunctionProtoType>(FT); 1248226586Sdim if (!FTP || FTP->getNumArgs() != 1) 1249226586Sdim return getPersistentStopSummary(); 1250226586Sdim 1251226586Sdim assert (ScratchArgs.isEmpty()); 1252226586Sdim 1253226586Sdim ArgEffect Effect; 1254226586Sdim switch (func) { 1255226586Sdim case cfretain: Effect = IncRef; break; 1256226586Sdim case cfrelease: Effect = DecRef; break; 1257226586Sdim case cfmakecollectable: Effect = MakeCollectable; break; 1258226586Sdim } 1259226586Sdim 1260226586Sdim ScratchArgs = AF.add(ScratchArgs, 0, Effect); 1261226586Sdim return getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing); 1262226586Sdim} 1263226586Sdim 1264226586Sdimconst RetainSummary * 1265226586SdimRetainSummaryManager::getCFSummaryCreateRule(const FunctionDecl *FD) { 1266226586Sdim assert (ScratchArgs.isEmpty()); 1267226586Sdim 1268226586Sdim return getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF, true)); 1269226586Sdim} 1270226586Sdim 1271226586Sdimconst RetainSummary * 1272226586SdimRetainSummaryManager::getCFSummaryGetRule(const FunctionDecl *FD) { 1273226586Sdim assert (ScratchArgs.isEmpty()); 1274226586Sdim return getPersistentSummary(RetEffect::MakeNotOwned(RetEffect::CF), 1275226586Sdim DoNothing, DoNothing); 1276226586Sdim} 1277226586Sdim 1278226586Sdim//===----------------------------------------------------------------------===// 1279226586Sdim// Summary creation for Selectors. 1280226586Sdim//===----------------------------------------------------------------------===// 1281226586Sdim 1282249423SdimOptional<RetEffect> 1283249423SdimRetainSummaryManager::getRetEffectFromAnnotations(QualType RetTy, 1284249423Sdim const Decl *D) { 1285249423Sdim if (cocoa::isCocoaObjectRef(RetTy)) { 1286249423Sdim if (D->getAttr<NSReturnsRetainedAttr>()) 1287249423Sdim return ObjCAllocRetE; 1288249423Sdim 1289249423Sdim if (D->getAttr<NSReturnsNotRetainedAttr>() || 1290249423Sdim D->getAttr<NSReturnsAutoreleasedAttr>()) 1291249423Sdim return RetEffect::MakeNotOwned(RetEffect::ObjC); 1292249423Sdim 1293249423Sdim } else if (!RetTy->isPointerType()) { 1294249423Sdim return None; 1295249423Sdim } 1296249423Sdim 1297249423Sdim if (D->getAttr<CFReturnsRetainedAttr>()) 1298249423Sdim return RetEffect::MakeOwned(RetEffect::CF, true); 1299249423Sdim 1300249423Sdim if (D->getAttr<CFReturnsNotRetainedAttr>()) 1301249423Sdim return RetEffect::MakeNotOwned(RetEffect::CF); 1302249423Sdim 1303249423Sdim return None; 1304249423Sdim} 1305249423Sdim 1306226586Sdimvoid 1307226586SdimRetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ, 1308226586Sdim const FunctionDecl *FD) { 1309226586Sdim if (!FD) 1310226586Sdim return; 1311226586Sdim 1312239462Sdim assert(Summ && "Must have a summary to add annotations to."); 1313239462Sdim RetainSummaryTemplate Template(Summ, *this); 1314226586Sdim 1315226586Sdim // Effects on the parameters. 1316226586Sdim unsigned parm_idx = 0; 1317226586Sdim for (FunctionDecl::param_const_iterator pi = FD->param_begin(), 1318226586Sdim pe = FD->param_end(); pi != pe; ++pi, ++parm_idx) { 1319226586Sdim const ParmVarDecl *pd = *pi; 1320249423Sdim if (pd->getAttr<NSConsumedAttr>()) 1321249423Sdim Template->addArg(AF, parm_idx, DecRefMsg); 1322249423Sdim else if (pd->getAttr<CFConsumedAttr>()) 1323226586Sdim Template->addArg(AF, parm_idx, DecRef); 1324226586Sdim } 1325226586Sdim 1326226586Sdim QualType RetTy = FD->getResultType(); 1327249423Sdim if (Optional<RetEffect> RetE = getRetEffectFromAnnotations(RetTy, FD)) 1328249423Sdim Template->setRetEffect(*RetE); 1329226586Sdim} 1330226586Sdim 1331226586Sdimvoid 1332226586SdimRetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ, 1333226586Sdim const ObjCMethodDecl *MD) { 1334226586Sdim if (!MD) 1335226586Sdim return; 1336226586Sdim 1337239462Sdim assert(Summ && "Must have a valid summary to add annotations to"); 1338239462Sdim RetainSummaryTemplate Template(Summ, *this); 1339226586Sdim 1340226586Sdim // Effects on the receiver. 1341249423Sdim if (MD->getAttr<NSConsumesSelfAttr>()) 1342249423Sdim Template->setReceiverEffect(DecRefMsg); 1343226586Sdim 1344226586Sdim // Effects on the parameters. 1345226586Sdim unsigned parm_idx = 0; 1346226586Sdim for (ObjCMethodDecl::param_const_iterator 1347226586Sdim pi=MD->param_begin(), pe=MD->param_end(); 1348226586Sdim pi != pe; ++pi, ++parm_idx) { 1349226586Sdim const ParmVarDecl *pd = *pi; 1350249423Sdim if (pd->getAttr<NSConsumedAttr>()) 1351249423Sdim Template->addArg(AF, parm_idx, DecRefMsg); 1352249423Sdim else if (pd->getAttr<CFConsumedAttr>()) { 1353226586Sdim Template->addArg(AF, parm_idx, DecRef); 1354226586Sdim } 1355226586Sdim } 1356226586Sdim 1357249423Sdim QualType RetTy = MD->getResultType(); 1358249423Sdim if (Optional<RetEffect> RetE = getRetEffectFromAnnotations(RetTy, MD)) 1359249423Sdim Template->setRetEffect(*RetE); 1360226586Sdim} 1361226586Sdim 1362226586Sdimconst RetainSummary * 1363234353SdimRetainSummaryManager::getStandardMethodSummary(const ObjCMethodDecl *MD, 1364234353Sdim Selector S, QualType RetTy) { 1365234353Sdim // Any special effects? 1366226586Sdim ArgEffect ReceiverEff = DoNothing; 1367234353Sdim RetEffect ResultEff = RetEffect::MakeNoRet(); 1368226586Sdim 1369234353Sdim // Check the method family, and apply any default annotations. 1370234353Sdim switch (MD ? MD->getMethodFamily() : S.getMethodFamily()) { 1371234353Sdim case OMF_None: 1372234353Sdim case OMF_performSelector: 1373234353Sdim // Assume all Objective-C methods follow Cocoa Memory Management rules. 1374234353Sdim // FIXME: Does the non-threaded performSelector family really belong here? 1375234353Sdim // The selector could be, say, @selector(copy). 1376234353Sdim if (cocoa::isCocoaObjectRef(RetTy)) 1377234353Sdim ResultEff = RetEffect::MakeNotOwned(RetEffect::ObjC); 1378234353Sdim else if (coreFoundation::isCFObjectRef(RetTy)) { 1379234353Sdim // ObjCMethodDecl currently doesn't consider CF objects as valid return 1380234353Sdim // values for alloc, new, copy, or mutableCopy, so we have to 1381234353Sdim // double-check with the selector. This is ugly, but there aren't that 1382234353Sdim // many Objective-C methods that return CF objects, right? 1383234353Sdim if (MD) { 1384234353Sdim switch (S.getMethodFamily()) { 1385234353Sdim case OMF_alloc: 1386234353Sdim case OMF_new: 1387234353Sdim case OMF_copy: 1388234353Sdim case OMF_mutableCopy: 1389234353Sdim ResultEff = RetEffect::MakeOwned(RetEffect::CF, true); 1390234353Sdim break; 1391234353Sdim default: 1392234353Sdim ResultEff = RetEffect::MakeNotOwned(RetEffect::CF); 1393234353Sdim break; 1394234353Sdim } 1395234353Sdim } else { 1396234353Sdim ResultEff = RetEffect::MakeNotOwned(RetEffect::CF); 1397234353Sdim } 1398234353Sdim } 1399234353Sdim break; 1400234353Sdim case OMF_init: 1401234353Sdim ResultEff = ObjCInitRetE; 1402234353Sdim ReceiverEff = DecRefMsg; 1403234353Sdim break; 1404234353Sdim case OMF_alloc: 1405234353Sdim case OMF_new: 1406234353Sdim case OMF_copy: 1407234353Sdim case OMF_mutableCopy: 1408234353Sdim if (cocoa::isCocoaObjectRef(RetTy)) 1409234353Sdim ResultEff = ObjCAllocRetE; 1410234353Sdim else if (coreFoundation::isCFObjectRef(RetTy)) 1411234353Sdim ResultEff = RetEffect::MakeOwned(RetEffect::CF, true); 1412234353Sdim break; 1413234353Sdim case OMF_autorelease: 1414234353Sdim ReceiverEff = Autorelease; 1415234353Sdim break; 1416234353Sdim case OMF_retain: 1417234353Sdim ReceiverEff = IncRefMsg; 1418234353Sdim break; 1419234353Sdim case OMF_release: 1420234353Sdim ReceiverEff = DecRefMsg; 1421234353Sdim break; 1422234353Sdim case OMF_dealloc: 1423234353Sdim ReceiverEff = Dealloc; 1424234353Sdim break; 1425234353Sdim case OMF_self: 1426234353Sdim // -self is handled specially by the ExprEngine to propagate the receiver. 1427234353Sdim break; 1428234353Sdim case OMF_retainCount: 1429234353Sdim case OMF_finalize: 1430234353Sdim // These methods don't return objects. 1431234353Sdim break; 1432234353Sdim } 1433234353Sdim 1434226586Sdim // If one of the arguments in the selector has the keyword 'delegate' we 1435226586Sdim // should stop tracking the reference count for the receiver. This is 1436226586Sdim // because the reference count is quite possibly handled by a delegate 1437226586Sdim // method. 1438226586Sdim if (S.isKeywordSelector()) { 1439239462Sdim for (unsigned i = 0, e = S.getNumArgs(); i != e; ++i) { 1440239462Sdim StringRef Slot = S.getNameForSlot(i); 1441239462Sdim if (Slot.substr(Slot.size() - 8).equals_lower("delegate")) { 1442239462Sdim if (ResultEff == ObjCInitRetE) 1443243830Sdim ResultEff = RetEffect::MakeNoRetHard(); 1444239462Sdim else 1445243830Sdim ReceiverEff = StopTrackingHard; 1446239462Sdim } 1447239462Sdim } 1448226586Sdim } 1449226586Sdim 1450234353Sdim if (ScratchArgs.isEmpty() && ReceiverEff == DoNothing && 1451234353Sdim ResultEff.getKind() == RetEffect::NoRet) 1452226586Sdim return getDefaultSummary(); 1453226586Sdim 1454234353Sdim return getPersistentSummary(ResultEff, ReceiverEff, MayEscape); 1455226586Sdim} 1456226586Sdim 1457226586Sdimconst RetainSummary * 1458239462SdimRetainSummaryManager::getInstanceMethodSummary(const ObjCMethodCall &Msg, 1459239462Sdim ProgramStateRef State) { 1460239462Sdim const ObjCInterfaceDecl *ReceiverClass = 0; 1461226586Sdim 1462239462Sdim // We do better tracking of the type of the object than the core ExprEngine. 1463239462Sdim // See if we have its type in our private state. 1464239462Sdim // FIXME: Eventually replace the use of state->get<RefBindings> with 1465239462Sdim // a generic API for reasoning about the Objective-C types of symbolic 1466239462Sdim // objects. 1467239462Sdim SVal ReceiverV = Msg.getReceiverSVal(); 1468239462Sdim if (SymbolRef Sym = ReceiverV.getAsLocSymbol()) 1469239462Sdim if (const RefVal *T = getRefBinding(State, Sym)) 1470239462Sdim if (const ObjCObjectPointerType *PT = 1471226586Sdim T->getType()->getAs<ObjCObjectPointerType>()) 1472239462Sdim ReceiverClass = PT->getInterfaceDecl(); 1473226586Sdim 1474239462Sdim // If we don't know what kind of object this is, fall back to its static type. 1475239462Sdim if (!ReceiverClass) 1476239462Sdim ReceiverClass = Msg.getReceiverInterface(); 1477226586Sdim 1478226586Sdim // FIXME: The receiver could be a reference to a class, meaning that 1479226586Sdim // we should use the class method. 1480239462Sdim // id x = [NSObject class]; 1481239462Sdim // [x performSelector:... withObject:... afterDelay:...]; 1482239462Sdim Selector S = Msg.getSelector(); 1483239462Sdim const ObjCMethodDecl *Method = Msg.getDecl(); 1484239462Sdim if (!Method && ReceiverClass) 1485239462Sdim Method = ReceiverClass->getInstanceMethod(S); 1486239462Sdim 1487239462Sdim return getMethodSummary(S, ReceiverClass, Method, Msg.getResultType(), 1488239462Sdim ObjCMethodSummaries); 1489226586Sdim} 1490226586Sdim 1491226586Sdimconst RetainSummary * 1492239462SdimRetainSummaryManager::getMethodSummary(Selector S, const ObjCInterfaceDecl *ID, 1493234353Sdim const ObjCMethodDecl *MD, QualType RetTy, 1494234353Sdim ObjCMethodSummariesTy &CachedSummaries) { 1495226586Sdim 1496226586Sdim // Look up a summary in our summary cache. 1497239462Sdim const RetainSummary *Summ = CachedSummaries.find(ID, S); 1498226586Sdim 1499226586Sdim if (!Summ) { 1500234353Sdim Summ = getStandardMethodSummary(MD, S, RetTy); 1501226586Sdim 1502226586Sdim // Annotations override defaults. 1503226586Sdim updateSummaryFromAnnotations(Summ, MD); 1504226586Sdim 1505226586Sdim // Memoize the summary. 1506239462Sdim CachedSummaries[ObjCSummaryKey(ID, S)] = Summ; 1507226586Sdim } 1508226586Sdim 1509226586Sdim return Summ; 1510226586Sdim} 1511226586Sdim 1512226586Sdimvoid RetainSummaryManager::InitializeClassMethodSummaries() { 1513226586Sdim assert(ScratchArgs.isEmpty()); 1514226586Sdim // Create the [NSAssertionHandler currentHander] summary. 1515226586Sdim addClassMethSummary("NSAssertionHandler", "currentHandler", 1516226586Sdim getPersistentSummary(RetEffect::MakeNotOwned(RetEffect::ObjC))); 1517226586Sdim 1518226586Sdim // Create the [NSAutoreleasePool addObject:] summary. 1519226586Sdim ScratchArgs = AF.add(ScratchArgs, 0, Autorelease); 1520226586Sdim addClassMethSummary("NSAutoreleasePool", "addObject", 1521226586Sdim getPersistentSummary(RetEffect::MakeNoRet(), 1522226586Sdim DoNothing, Autorelease)); 1523226586Sdim} 1524226586Sdim 1525226586Sdimvoid RetainSummaryManager::InitializeMethodSummaries() { 1526226586Sdim 1527226586Sdim assert (ScratchArgs.isEmpty()); 1528226586Sdim 1529226586Sdim // Create the "init" selector. It just acts as a pass-through for the 1530226586Sdim // receiver. 1531226586Sdim const RetainSummary *InitSumm = getPersistentSummary(ObjCInitRetE, DecRefMsg); 1532226586Sdim addNSObjectMethSummary(GetNullarySelector("init", Ctx), InitSumm); 1533226586Sdim 1534226586Sdim // awakeAfterUsingCoder: behaves basically like an 'init' method. It 1535226586Sdim // claims the receiver and returns a retained object. 1536226586Sdim addNSObjectMethSummary(GetUnarySelector("awakeAfterUsingCoder", Ctx), 1537226586Sdim InitSumm); 1538226586Sdim 1539226586Sdim // The next methods are allocators. 1540226586Sdim const RetainSummary *AllocSumm = getPersistentSummary(ObjCAllocRetE); 1541226586Sdim const RetainSummary *CFAllocSumm = 1542226586Sdim getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF, true)); 1543226586Sdim 1544226586Sdim // Create the "retain" selector. 1545226586Sdim RetEffect NoRet = RetEffect::MakeNoRet(); 1546226586Sdim const RetainSummary *Summ = getPersistentSummary(NoRet, IncRefMsg); 1547226586Sdim addNSObjectMethSummary(GetNullarySelector("retain", Ctx), Summ); 1548226586Sdim 1549226586Sdim // Create the "release" selector. 1550226586Sdim Summ = getPersistentSummary(NoRet, DecRefMsg); 1551226586Sdim addNSObjectMethSummary(GetNullarySelector("release", Ctx), Summ); 1552226586Sdim 1553226586Sdim // Create the -dealloc summary. 1554226586Sdim Summ = getPersistentSummary(NoRet, Dealloc); 1555226586Sdim addNSObjectMethSummary(GetNullarySelector("dealloc", Ctx), Summ); 1556226586Sdim 1557226586Sdim // Create the "autorelease" selector. 1558226586Sdim Summ = getPersistentSummary(NoRet, Autorelease); 1559226586Sdim addNSObjectMethSummary(GetNullarySelector("autorelease", Ctx), Summ); 1560226586Sdim 1561226586Sdim // For NSWindow, allocated objects are (initially) self-owned. 1562226586Sdim // FIXME: For now we opt for false negatives with NSWindow, as these objects 1563226586Sdim // self-own themselves. However, they only do this once they are displayed. 1564226586Sdim // Thus, we need to track an NSWindow's display status. 1565226586Sdim // This is tracked in <rdar://problem/6062711>. 1566226586Sdim // See also http://llvm.org/bugs/show_bug.cgi?id=3714. 1567226586Sdim const RetainSummary *NoTrackYet = getPersistentSummary(RetEffect::MakeNoRet(), 1568226586Sdim StopTracking, 1569226586Sdim StopTracking); 1570226586Sdim 1571226586Sdim addClassMethSummary("NSWindow", "alloc", NoTrackYet); 1572226586Sdim 1573226586Sdim // For NSPanel (which subclasses NSWindow), allocated objects are not 1574226586Sdim // self-owned. 1575226586Sdim // FIXME: For now we don't track NSPanels. object for the same reason 1576226586Sdim // as for NSWindow objects. 1577226586Sdim addClassMethSummary("NSPanel", "alloc", NoTrackYet); 1578226586Sdim 1579249423Sdim // Don't track allocated autorelease pools, as it is okay to prematurely 1580226586Sdim // exit a method. 1581226586Sdim addClassMethSummary("NSAutoreleasePool", "alloc", NoTrackYet); 1582234353Sdim addClassMethSummary("NSAutoreleasePool", "allocWithZone", NoTrackYet, false); 1583249423Sdim addClassMethSummary("NSAutoreleasePool", "new", NoTrackYet); 1584226586Sdim 1585226586Sdim // Create summaries QCRenderer/QCView -createSnapShotImageOfType: 1586226586Sdim addInstMethSummary("QCRenderer", AllocSumm, 1587226586Sdim "createSnapshotImageOfType", NULL); 1588226586Sdim addInstMethSummary("QCView", AllocSumm, 1589226586Sdim "createSnapshotImageOfType", NULL); 1590226586Sdim 1591226586Sdim // Create summaries for CIContext, 'createCGImage' and 1592226586Sdim // 'createCGLayerWithSize'. These objects are CF objects, and are not 1593226586Sdim // automatically garbage collected. 1594226586Sdim addInstMethSummary("CIContext", CFAllocSumm, 1595226586Sdim "createCGImage", "fromRect", NULL); 1596226586Sdim addInstMethSummary("CIContext", CFAllocSumm, 1597226586Sdim "createCGImage", "fromRect", "format", "colorSpace", NULL); 1598226586Sdim addInstMethSummary("CIContext", CFAllocSumm, "createCGLayerWithSize", 1599226586Sdim "info", NULL); 1600226586Sdim} 1601226586Sdim 1602226586Sdim//===----------------------------------------------------------------------===// 1603226586Sdim// Error reporting. 1604226586Sdim//===----------------------------------------------------------------------===// 1605226586Sdimnamespace { 1606226586Sdim typedef llvm::DenseMap<const ExplodedNode *, const RetainSummary *> 1607226586Sdim SummaryLogTy; 1608226586Sdim 1609226586Sdim //===-------------===// 1610226586Sdim // Bug Descriptions. // 1611226586Sdim //===-------------===// 1612226586Sdim 1613226586Sdim class CFRefBug : public BugType { 1614226586Sdim protected: 1615226586Sdim CFRefBug(StringRef name) 1616234353Sdim : BugType(name, categories::MemoryCoreFoundationObjectiveC) {} 1617226586Sdim public: 1618226586Sdim 1619226586Sdim // FIXME: Eventually remove. 1620226586Sdim virtual const char *getDescription() const = 0; 1621226586Sdim 1622226586Sdim virtual bool isLeak() const { return false; } 1623226586Sdim }; 1624226586Sdim 1625226586Sdim class UseAfterRelease : public CFRefBug { 1626226586Sdim public: 1627226586Sdim UseAfterRelease() : CFRefBug("Use-after-release") {} 1628226586Sdim 1629226586Sdim const char *getDescription() const { 1630226586Sdim return "Reference-counted object is used after it is released"; 1631226586Sdim } 1632226586Sdim }; 1633226586Sdim 1634226586Sdim class BadRelease : public CFRefBug { 1635226586Sdim public: 1636226586Sdim BadRelease() : CFRefBug("Bad release") {} 1637226586Sdim 1638226586Sdim const char *getDescription() const { 1639226586Sdim return "Incorrect decrement of the reference count of an object that is " 1640226586Sdim "not owned at this point by the caller"; 1641226586Sdim } 1642226586Sdim }; 1643226586Sdim 1644226586Sdim class DeallocGC : public CFRefBug { 1645226586Sdim public: 1646226586Sdim DeallocGC() 1647226586Sdim : CFRefBug("-dealloc called while using garbage collection") {} 1648226586Sdim 1649226586Sdim const char *getDescription() const { 1650226586Sdim return "-dealloc called while using garbage collection"; 1651226586Sdim } 1652226586Sdim }; 1653226586Sdim 1654226586Sdim class DeallocNotOwned : public CFRefBug { 1655226586Sdim public: 1656226586Sdim DeallocNotOwned() 1657226586Sdim : CFRefBug("-dealloc sent to non-exclusively owned object") {} 1658226586Sdim 1659226586Sdim const char *getDescription() const { 1660226586Sdim return "-dealloc sent to object that may be referenced elsewhere"; 1661226586Sdim } 1662226586Sdim }; 1663226586Sdim 1664226586Sdim class OverAutorelease : public CFRefBug { 1665226586Sdim public: 1666226586Sdim OverAutorelease() 1667251662Sdim : CFRefBug("Object autoreleased too many times") {} 1668226586Sdim 1669226586Sdim const char *getDescription() const { 1670251662Sdim return "Object autoreleased too many times"; 1671226586Sdim } 1672226586Sdim }; 1673226586Sdim 1674226586Sdim class ReturnedNotOwnedForOwned : public CFRefBug { 1675226586Sdim public: 1676226586Sdim ReturnedNotOwnedForOwned() 1677226586Sdim : CFRefBug("Method should return an owned object") {} 1678226586Sdim 1679226586Sdim const char *getDescription() const { 1680226586Sdim return "Object with a +0 retain count returned to caller where a +1 " 1681226586Sdim "(owning) retain count is expected"; 1682226586Sdim } 1683226586Sdim }; 1684226586Sdim 1685226586Sdim class Leak : public CFRefBug { 1686239462Sdim public: 1687239462Sdim Leak(StringRef name) 1688239462Sdim : CFRefBug(name) { 1689226586Sdim // Leaks should not be reported if they are post-dominated by a sink. 1690226586Sdim setSuppressOnSink(true); 1691226586Sdim } 1692226586Sdim 1693226586Sdim const char *getDescription() const { return ""; } 1694226586Sdim 1695226586Sdim bool isLeak() const { return true; } 1696226586Sdim }; 1697226586Sdim 1698226586Sdim //===---------===// 1699226586Sdim // Bug Reports. // 1700226586Sdim //===---------===// 1701226586Sdim 1702234353Sdim class CFRefReportVisitor : public BugReporterVisitorImpl<CFRefReportVisitor> { 1703226586Sdim protected: 1704226586Sdim SymbolRef Sym; 1705226586Sdim const SummaryLogTy &SummaryLog; 1706226586Sdim bool GCEnabled; 1707226586Sdim 1708226586Sdim public: 1709226586Sdim CFRefReportVisitor(SymbolRef sym, bool gcEnabled, const SummaryLogTy &log) 1710226586Sdim : Sym(sym), SummaryLog(log), GCEnabled(gcEnabled) {} 1711226586Sdim 1712226586Sdim virtual void Profile(llvm::FoldingSetNodeID &ID) const { 1713226586Sdim static int x = 0; 1714226586Sdim ID.AddPointer(&x); 1715226586Sdim ID.AddPointer(Sym); 1716226586Sdim } 1717226586Sdim 1718226586Sdim virtual PathDiagnosticPiece *VisitNode(const ExplodedNode *N, 1719226586Sdim const ExplodedNode *PrevN, 1720226586Sdim BugReporterContext &BRC, 1721226586Sdim BugReport &BR); 1722226586Sdim 1723226586Sdim virtual PathDiagnosticPiece *getEndPath(BugReporterContext &BRC, 1724226586Sdim const ExplodedNode *N, 1725226586Sdim BugReport &BR); 1726226586Sdim }; 1727226586Sdim 1728226586Sdim class CFRefLeakReportVisitor : public CFRefReportVisitor { 1729226586Sdim public: 1730226586Sdim CFRefLeakReportVisitor(SymbolRef sym, bool GCEnabled, 1731226586Sdim const SummaryLogTy &log) 1732226586Sdim : CFRefReportVisitor(sym, GCEnabled, log) {} 1733226586Sdim 1734226586Sdim PathDiagnosticPiece *getEndPath(BugReporterContext &BRC, 1735226586Sdim const ExplodedNode *N, 1736226586Sdim BugReport &BR); 1737234353Sdim 1738234353Sdim virtual BugReporterVisitor *clone() const { 1739234353Sdim // The curiously-recurring template pattern only works for one level of 1740234353Sdim // subclassing. Rather than make a new template base for 1741234353Sdim // CFRefReportVisitor, we simply override clone() to do the right thing. 1742234353Sdim // This could be trouble someday if BugReporterVisitorImpl is ever 1743234353Sdim // used for something else besides a convenient implementation of clone(). 1744234353Sdim return new CFRefLeakReportVisitor(*this); 1745234353Sdim } 1746226586Sdim }; 1747226586Sdim 1748226586Sdim class CFRefReport : public BugReport { 1749226586Sdim void addGCModeDescription(const LangOptions &LOpts, bool GCEnabled); 1750226586Sdim 1751226586Sdim public: 1752226586Sdim CFRefReport(CFRefBug &D, const LangOptions &LOpts, bool GCEnabled, 1753226586Sdim const SummaryLogTy &Log, ExplodedNode *n, SymbolRef sym, 1754226586Sdim bool registerVisitor = true) 1755226586Sdim : BugReport(D, D.getDescription(), n) { 1756226586Sdim if (registerVisitor) 1757226586Sdim addVisitor(new CFRefReportVisitor(sym, GCEnabled, Log)); 1758226586Sdim addGCModeDescription(LOpts, GCEnabled); 1759226586Sdim } 1760226586Sdim 1761226586Sdim CFRefReport(CFRefBug &D, const LangOptions &LOpts, bool GCEnabled, 1762226586Sdim const SummaryLogTy &Log, ExplodedNode *n, SymbolRef sym, 1763226586Sdim StringRef endText) 1764226586Sdim : BugReport(D, D.getDescription(), endText, n) { 1765226586Sdim addVisitor(new CFRefReportVisitor(sym, GCEnabled, Log)); 1766226586Sdim addGCModeDescription(LOpts, GCEnabled); 1767226586Sdim } 1768226586Sdim 1769226586Sdim virtual std::pair<ranges_iterator, ranges_iterator> getRanges() { 1770226586Sdim const CFRefBug& BugTy = static_cast<CFRefBug&>(getBugType()); 1771226586Sdim if (!BugTy.isLeak()) 1772226586Sdim return BugReport::getRanges(); 1773226586Sdim else 1774226586Sdim return std::make_pair(ranges_iterator(), ranges_iterator()); 1775226586Sdim } 1776226586Sdim }; 1777226586Sdim 1778226586Sdim class CFRefLeakReport : public CFRefReport { 1779226586Sdim const MemRegion* AllocBinding; 1780226586Sdim public: 1781226586Sdim CFRefLeakReport(CFRefBug &D, const LangOptions &LOpts, bool GCEnabled, 1782226586Sdim const SummaryLogTy &Log, ExplodedNode *n, SymbolRef sym, 1783251662Sdim CheckerContext &Ctx, 1784251662Sdim bool IncludeAllocationLine); 1785226586Sdim 1786226586Sdim PathDiagnosticLocation getLocation(const SourceManager &SM) const { 1787226586Sdim assert(Location.isValid()); 1788226586Sdim return Location; 1789226586Sdim } 1790226586Sdim }; 1791226586Sdim} // end anonymous namespace 1792226586Sdim 1793226586Sdimvoid CFRefReport::addGCModeDescription(const LangOptions &LOpts, 1794226586Sdim bool GCEnabled) { 1795226586Sdim const char *GCModeDescription = 0; 1796226586Sdim 1797226586Sdim switch (LOpts.getGC()) { 1798226586Sdim case LangOptions::GCOnly: 1799226586Sdim assert(GCEnabled); 1800226586Sdim GCModeDescription = "Code is compiled to only use garbage collection"; 1801226586Sdim break; 1802226586Sdim 1803226586Sdim case LangOptions::NonGC: 1804226586Sdim assert(!GCEnabled); 1805226586Sdim GCModeDescription = "Code is compiled to use reference counts"; 1806226586Sdim break; 1807226586Sdim 1808226586Sdim case LangOptions::HybridGC: 1809226586Sdim if (GCEnabled) { 1810226586Sdim GCModeDescription = "Code is compiled to use either garbage collection " 1811226586Sdim "(GC) or reference counts (non-GC). The bug occurs " 1812226586Sdim "with GC enabled"; 1813226586Sdim break; 1814226586Sdim } else { 1815226586Sdim GCModeDescription = "Code is compiled to use either garbage collection " 1816226586Sdim "(GC) or reference counts (non-GC). The bug occurs " 1817226586Sdim "in non-GC mode"; 1818226586Sdim break; 1819226586Sdim } 1820226586Sdim } 1821226586Sdim 1822226586Sdim assert(GCModeDescription && "invalid/unknown GC mode"); 1823226586Sdim addExtraText(GCModeDescription); 1824226586Sdim} 1825226586Sdim 1826226586Sdim// FIXME: This should be a method on SmallVector. 1827226586Sdimstatic inline bool contains(const SmallVectorImpl<ArgEffect>& V, 1828226586Sdim ArgEffect X) { 1829226586Sdim for (SmallVectorImpl<ArgEffect>::const_iterator I=V.begin(), E=V.end(); 1830226586Sdim I!=E; ++I) 1831226586Sdim if (*I == X) return true; 1832226586Sdim 1833226586Sdim return false; 1834226586Sdim} 1835226586Sdim 1836239462Sdimstatic bool isNumericLiteralExpression(const Expr *E) { 1837239462Sdim // FIXME: This set of cases was copied from SemaExprObjC. 1838239462Sdim return isa<IntegerLiteral>(E) || 1839239462Sdim isa<CharacterLiteral>(E) || 1840239462Sdim isa<FloatingLiteral>(E) || 1841239462Sdim isa<ObjCBoolLiteralExpr>(E) || 1842239462Sdim isa<CXXBoolLiteralExpr>(E); 1843234353Sdim} 1844234353Sdim 1845226586SdimPathDiagnosticPiece *CFRefReportVisitor::VisitNode(const ExplodedNode *N, 1846226586Sdim const ExplodedNode *PrevN, 1847226586Sdim BugReporterContext &BRC, 1848226586Sdim BugReport &BR) { 1849239462Sdim // FIXME: We will eventually need to handle non-statement-based events 1850239462Sdim // (__attribute__((cleanup))). 1851249423Sdim if (!N->getLocation().getAs<StmtPoint>()) 1852226586Sdim return NULL; 1853226586Sdim 1854226586Sdim // Check if the type state has changed. 1855234353Sdim ProgramStateRef PrevSt = PrevN->getState(); 1856234353Sdim ProgramStateRef CurrSt = N->getState(); 1857234353Sdim const LocationContext *LCtx = N->getLocationContext(); 1858226586Sdim 1859239462Sdim const RefVal* CurrT = getRefBinding(CurrSt, Sym); 1860226586Sdim if (!CurrT) return NULL; 1861226586Sdim 1862226586Sdim const RefVal &CurrV = *CurrT; 1863239462Sdim const RefVal *PrevT = getRefBinding(PrevSt, Sym); 1864226586Sdim 1865226586Sdim // Create a string buffer to constain all the useful things we want 1866226586Sdim // to tell the user. 1867226586Sdim std::string sbuf; 1868226586Sdim llvm::raw_string_ostream os(sbuf); 1869226586Sdim 1870226586Sdim // This is the allocation site since the previous node had no bindings 1871226586Sdim // for this symbol. 1872226586Sdim if (!PrevT) { 1873249423Sdim const Stmt *S = N->getLocation().castAs<StmtPoint>().getStmt(); 1874226586Sdim 1875234353Sdim if (isa<ObjCArrayLiteral>(S)) { 1876234353Sdim os << "NSArray literal is an object with a +0 retain count"; 1877226586Sdim } 1878234353Sdim else if (isa<ObjCDictionaryLiteral>(S)) { 1879234353Sdim os << "NSDictionary literal is an object with a +0 retain count"; 1880226586Sdim } 1881239462Sdim else if (const ObjCBoxedExpr *BL = dyn_cast<ObjCBoxedExpr>(S)) { 1882239462Sdim if (isNumericLiteralExpression(BL->getSubExpr())) 1883239462Sdim os << "NSNumber literal is an object with a +0 retain count"; 1884239462Sdim else { 1885239462Sdim const ObjCInterfaceDecl *BoxClass = 0; 1886239462Sdim if (const ObjCMethodDecl *Method = BL->getBoxingMethod()) 1887239462Sdim BoxClass = Method->getClassInterface(); 1888239462Sdim 1889239462Sdim // We should always be able to find the boxing class interface, 1890239462Sdim // but consider this future-proofing. 1891239462Sdim if (BoxClass) 1892239462Sdim os << *BoxClass << " b"; 1893239462Sdim else 1894239462Sdim os << "B"; 1895239462Sdim 1896239462Sdim os << "oxed expression produces an object with a +0 retain count"; 1897239462Sdim } 1898239462Sdim } 1899234353Sdim else { 1900234353Sdim if (const CallExpr *CE = dyn_cast<CallExpr>(S)) { 1901234353Sdim // Get the name of the callee (if it is available). 1902234353Sdim SVal X = CurrSt->getSValAsScalarOrLoc(CE->getCallee(), LCtx); 1903234353Sdim if (const FunctionDecl *FD = X.getAsFunctionDecl()) 1904234353Sdim os << "Call to function '" << *FD << '\''; 1905234353Sdim else 1906234353Sdim os << "function call"; 1907234353Sdim } 1908234353Sdim else { 1909239462Sdim assert(isa<ObjCMessageExpr>(S)); 1910239462Sdim CallEventManager &Mgr = CurrSt->getStateManager().getCallEventManager(); 1911239462Sdim CallEventRef<ObjCMethodCall> Call 1912239462Sdim = Mgr.getObjCMethodCall(cast<ObjCMessageExpr>(S), CurrSt, LCtx); 1913239462Sdim 1914239462Sdim switch (Call->getMessageKind()) { 1915239462Sdim case OCM_Message: 1916239462Sdim os << "Method"; 1917239462Sdim break; 1918239462Sdim case OCM_PropertyAccess: 1919239462Sdim os << "Property"; 1920239462Sdim break; 1921239462Sdim case OCM_Subscript: 1922239462Sdim os << "Subscript"; 1923239462Sdim break; 1924239462Sdim } 1925234353Sdim } 1926226586Sdim 1927234353Sdim if (CurrV.getObjKind() == RetEffect::CF) { 1928234353Sdim os << " returns a Core Foundation object with a "; 1929234353Sdim } 1930234353Sdim else { 1931234353Sdim assert (CurrV.getObjKind() == RetEffect::ObjC); 1932234353Sdim os << " returns an Objective-C object with a "; 1933234353Sdim } 1934226586Sdim 1935234353Sdim if (CurrV.isOwned()) { 1936234353Sdim os << "+1 retain count"; 1937226586Sdim 1938234353Sdim if (GCEnabled) { 1939234353Sdim assert(CurrV.getObjKind() == RetEffect::CF); 1940234353Sdim os << ". " 1941234353Sdim "Core Foundation objects are not automatically garbage collected."; 1942234353Sdim } 1943226586Sdim } 1944234353Sdim else { 1945234353Sdim assert (CurrV.isNotOwned()); 1946234353Sdim os << "+0 retain count"; 1947234353Sdim } 1948226586Sdim } 1949226586Sdim 1950226586Sdim PathDiagnosticLocation Pos(S, BRC.getSourceManager(), 1951226586Sdim N->getLocationContext()); 1952226586Sdim return new PathDiagnosticEventPiece(Pos, os.str()); 1953226586Sdim } 1954226586Sdim 1955226586Sdim // Gather up the effects that were performed on the object at this 1956226586Sdim // program point 1957226586Sdim SmallVector<ArgEffect, 2> AEffects; 1958226586Sdim 1959226586Sdim const ExplodedNode *OrigNode = BRC.getNodeResolver().getOriginalNode(N); 1960226586Sdim if (const RetainSummary *Summ = SummaryLog.lookup(OrigNode)) { 1961226586Sdim // We only have summaries attached to nodes after evaluating CallExpr and 1962226586Sdim // ObjCMessageExprs. 1963249423Sdim const Stmt *S = N->getLocation().castAs<StmtPoint>().getStmt(); 1964226586Sdim 1965226586Sdim if (const CallExpr *CE = dyn_cast<CallExpr>(S)) { 1966226586Sdim // Iterate through the parameter expressions and see if the symbol 1967226586Sdim // was ever passed as an argument. 1968226586Sdim unsigned i = 0; 1969226586Sdim 1970226586Sdim for (CallExpr::const_arg_iterator AI=CE->arg_begin(), AE=CE->arg_end(); 1971226586Sdim AI!=AE; ++AI, ++i) { 1972226586Sdim 1973226586Sdim // Retrieve the value of the argument. Is it the symbol 1974226586Sdim // we are interested in? 1975234353Sdim if (CurrSt->getSValAsScalarOrLoc(*AI, LCtx).getAsLocSymbol() != Sym) 1976226586Sdim continue; 1977226586Sdim 1978226586Sdim // We have an argument. Get the effect! 1979226586Sdim AEffects.push_back(Summ->getArg(i)); 1980226586Sdim } 1981226586Sdim } 1982226586Sdim else if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S)) { 1983226586Sdim if (const Expr *receiver = ME->getInstanceReceiver()) 1984234353Sdim if (CurrSt->getSValAsScalarOrLoc(receiver, LCtx) 1985234353Sdim .getAsLocSymbol() == Sym) { 1986226586Sdim // The symbol we are tracking is the receiver. 1987226586Sdim AEffects.push_back(Summ->getReceiverEffect()); 1988226586Sdim } 1989226586Sdim } 1990226586Sdim } 1991226586Sdim 1992226586Sdim do { 1993226586Sdim // Get the previous type state. 1994226586Sdim RefVal PrevV = *PrevT; 1995226586Sdim 1996226586Sdim // Specially handle -dealloc. 1997226586Sdim if (!GCEnabled && contains(AEffects, Dealloc)) { 1998226586Sdim // Determine if the object's reference count was pushed to zero. 1999226586Sdim assert(!(PrevV == CurrV) && "The typestate *must* have changed."); 2000226586Sdim // We may not have transitioned to 'release' if we hit an error. 2001226586Sdim // This case is handled elsewhere. 2002226586Sdim if (CurrV.getKind() == RefVal::Released) { 2003226586Sdim assert(CurrV.getCombinedCounts() == 0); 2004226586Sdim os << "Object released by directly sending the '-dealloc' message"; 2005226586Sdim break; 2006226586Sdim } 2007226586Sdim } 2008226586Sdim 2009226586Sdim // Specially handle CFMakeCollectable and friends. 2010226586Sdim if (contains(AEffects, MakeCollectable)) { 2011226586Sdim // Get the name of the function. 2012249423Sdim const Stmt *S = N->getLocation().castAs<StmtPoint>().getStmt(); 2013234353Sdim SVal X = 2014234353Sdim CurrSt->getSValAsScalarOrLoc(cast<CallExpr>(S)->getCallee(), LCtx); 2015226586Sdim const FunctionDecl *FD = X.getAsFunctionDecl(); 2016226586Sdim 2017226586Sdim if (GCEnabled) { 2018226586Sdim // Determine if the object's reference count was pushed to zero. 2019226586Sdim assert(!(PrevV == CurrV) && "The typestate *must* have changed."); 2020226586Sdim 2021226586Sdim os << "In GC mode a call to '" << *FD 2022226586Sdim << "' decrements an object's retain count and registers the " 2023226586Sdim "object with the garbage collector. "; 2024226586Sdim 2025226586Sdim if (CurrV.getKind() == RefVal::Released) { 2026226586Sdim assert(CurrV.getCount() == 0); 2027226586Sdim os << "Since it now has a 0 retain count the object can be " 2028226586Sdim "automatically collected by the garbage collector."; 2029226586Sdim } 2030226586Sdim else 2031226586Sdim os << "An object must have a 0 retain count to be garbage collected. " 2032226586Sdim "After this call its retain count is +" << CurrV.getCount() 2033226586Sdim << '.'; 2034226586Sdim } 2035226586Sdim else 2036226586Sdim os << "When GC is not enabled a call to '" << *FD 2037226586Sdim << "' has no effect on its argument."; 2038226586Sdim 2039226586Sdim // Nothing more to say. 2040226586Sdim break; 2041226586Sdim } 2042226586Sdim 2043226586Sdim // Determine if the typestate has changed. 2044226586Sdim if (!(PrevV == CurrV)) 2045226586Sdim switch (CurrV.getKind()) { 2046226586Sdim case RefVal::Owned: 2047226586Sdim case RefVal::NotOwned: 2048226586Sdim 2049226586Sdim if (PrevV.getCount() == CurrV.getCount()) { 2050226586Sdim // Did an autorelease message get sent? 2051226586Sdim if (PrevV.getAutoreleaseCount() == CurrV.getAutoreleaseCount()) 2052226586Sdim return 0; 2053226586Sdim 2054226586Sdim assert(PrevV.getAutoreleaseCount() < CurrV.getAutoreleaseCount()); 2055251662Sdim os << "Object autoreleased"; 2056226586Sdim break; 2057226586Sdim } 2058226586Sdim 2059226586Sdim if (PrevV.getCount() > CurrV.getCount()) 2060226586Sdim os << "Reference count decremented."; 2061226586Sdim else 2062226586Sdim os << "Reference count incremented."; 2063226586Sdim 2064226586Sdim if (unsigned Count = CurrV.getCount()) 2065226586Sdim os << " The object now has a +" << Count << " retain count."; 2066226586Sdim 2067226586Sdim if (PrevV.getKind() == RefVal::Released) { 2068226586Sdim assert(GCEnabled && CurrV.getCount() > 0); 2069234353Sdim os << " The object is not eligible for garbage collection until " 2070234353Sdim "the retain count reaches 0 again."; 2071226586Sdim } 2072226586Sdim 2073226586Sdim break; 2074226586Sdim 2075226586Sdim case RefVal::Released: 2076226586Sdim os << "Object released."; 2077226586Sdim break; 2078226586Sdim 2079226586Sdim case RefVal::ReturnedOwned: 2080234353Sdim // Autoreleases can be applied after marking a node ReturnedOwned. 2081234353Sdim if (CurrV.getAutoreleaseCount()) 2082234353Sdim return NULL; 2083234353Sdim 2084234353Sdim os << "Object returned to caller as an owning reference (single " 2085234353Sdim "retain count transferred to caller)"; 2086226586Sdim break; 2087226586Sdim 2088226586Sdim case RefVal::ReturnedNotOwned: 2089226586Sdim os << "Object returned to caller with a +0 retain count"; 2090226586Sdim break; 2091226586Sdim 2092226586Sdim default: 2093226586Sdim return NULL; 2094226586Sdim } 2095226586Sdim 2096226586Sdim // Emit any remaining diagnostics for the argument effects (if any). 2097226586Sdim for (SmallVectorImpl<ArgEffect>::iterator I=AEffects.begin(), 2098226586Sdim E=AEffects.end(); I != E; ++I) { 2099226586Sdim 2100226586Sdim // A bunch of things have alternate behavior under GC. 2101226586Sdim if (GCEnabled) 2102226586Sdim switch (*I) { 2103226586Sdim default: break; 2104226586Sdim case Autorelease: 2105226586Sdim os << "In GC mode an 'autorelease' has no effect."; 2106226586Sdim continue; 2107226586Sdim case IncRefMsg: 2108226586Sdim os << "In GC mode the 'retain' message has no effect."; 2109226586Sdim continue; 2110226586Sdim case DecRefMsg: 2111226586Sdim os << "In GC mode the 'release' message has no effect."; 2112226586Sdim continue; 2113226586Sdim } 2114226586Sdim } 2115226586Sdim } while (0); 2116226586Sdim 2117226586Sdim if (os.str().empty()) 2118226586Sdim return 0; // We have nothing to say! 2119226586Sdim 2120249423Sdim const Stmt *S = N->getLocation().castAs<StmtPoint>().getStmt(); 2121226586Sdim PathDiagnosticLocation Pos(S, BRC.getSourceManager(), 2122226586Sdim N->getLocationContext()); 2123226586Sdim PathDiagnosticPiece *P = new PathDiagnosticEventPiece(Pos, os.str()); 2124226586Sdim 2125226586Sdim // Add the range by scanning the children of the statement for any bindings 2126226586Sdim // to Sym. 2127226586Sdim for (Stmt::const_child_iterator I = S->child_begin(), E = S->child_end(); 2128226586Sdim I!=E; ++I) 2129226586Sdim if (const Expr *Exp = dyn_cast_or_null<Expr>(*I)) 2130234353Sdim if (CurrSt->getSValAsScalarOrLoc(Exp, LCtx).getAsLocSymbol() == Sym) { 2131226586Sdim P->addRange(Exp->getSourceRange()); 2132226586Sdim break; 2133226586Sdim } 2134226586Sdim 2135226586Sdim return P; 2136226586Sdim} 2137226586Sdim 2138234353Sdim// Find the first node in the current function context that referred to the 2139234353Sdim// tracked symbol and the memory location that value was stored to. Note, the 2140234353Sdim// value is only reported if the allocation occurred in the same function as 2141251662Sdim// the leak. The function can also return a location context, which should be 2142251662Sdim// treated as interesting. 2143251662Sdimstruct AllocationInfo { 2144251662Sdim const ExplodedNode* N; 2145251662Sdim const MemRegion *R; 2146251662Sdim const LocationContext *InterestingMethodContext; 2147251662Sdim AllocationInfo(const ExplodedNode *InN, 2148251662Sdim const MemRegion *InR, 2149251662Sdim const LocationContext *InInterestingMethodContext) : 2150251662Sdim N(InN), R(InR), InterestingMethodContext(InInterestingMethodContext) {} 2151251662Sdim}; 2152251662Sdim 2153251662Sdimstatic AllocationInfo 2154226586SdimGetAllocationSite(ProgramStateManager& StateMgr, const ExplodedNode *N, 2155226586Sdim SymbolRef Sym) { 2156251662Sdim const ExplodedNode *AllocationNode = N; 2157251662Sdim const ExplodedNode *AllocationNodeInCurrentContext = N; 2158226586Sdim const MemRegion* FirstBinding = 0; 2159234353Sdim const LocationContext *LeakContext = N->getLocationContext(); 2160226586Sdim 2161251662Sdim // The location context of the init method called on the leaked object, if 2162251662Sdim // available. 2163251662Sdim const LocationContext *InitMethodContext = 0; 2164251662Sdim 2165226586Sdim while (N) { 2166234353Sdim ProgramStateRef St = N->getState(); 2167251662Sdim const LocationContext *NContext = N->getLocationContext(); 2168226586Sdim 2169239462Sdim if (!getRefBinding(St, Sym)) 2170226586Sdim break; 2171226586Sdim 2172234353Sdim StoreManager::FindUniqueBinding FB(Sym); 2173226586Sdim StateMgr.iterBindings(St, FB); 2174251662Sdim 2175251662Sdim if (FB) { 2176251662Sdim const MemRegion *R = FB.getRegion(); 2177251662Sdim const VarRegion *VR = R->getBaseRegion()->getAs<VarRegion>(); 2178251662Sdim // Do not show local variables belonging to a function other than 2179251662Sdim // where the error is reported. 2180251662Sdim if (!VR || VR->getStackFrame() == LeakContext->getCurrentStackFrame()) 2181251662Sdim FirstBinding = R; 2182251662Sdim } 2183226586Sdim 2184251662Sdim // AllocationNode is the last node in which the symbol was tracked. 2185251662Sdim AllocationNode = N; 2186234353Sdim 2187251662Sdim // AllocationNodeInCurrentContext, is the last node in the current context 2188251662Sdim // in which the symbol was tracked. 2189251662Sdim if (NContext == LeakContext) 2190251662Sdim AllocationNodeInCurrentContext = N; 2191251662Sdim 2192251662Sdim // Find the last init that was called on the given symbol and store the 2193251662Sdim // init method's location context. 2194251662Sdim if (!InitMethodContext) 2195251662Sdim if (Optional<CallEnter> CEP = N->getLocation().getAs<CallEnter>()) { 2196251662Sdim const Stmt *CE = CEP->getCallExpr(); 2197251662Sdim if (const ObjCMessageExpr *ME = dyn_cast_or_null<ObjCMessageExpr>(CE)) { 2198251662Sdim const Stmt *RecExpr = ME->getInstanceReceiver(); 2199251662Sdim if (RecExpr) { 2200251662Sdim SVal RecV = St->getSVal(RecExpr, NContext); 2201251662Sdim if (ME->getMethodFamily() == OMF_init && RecV.getAsSymbol() == Sym) 2202251662Sdim InitMethodContext = CEP->getCalleeContext(); 2203251662Sdim } 2204251662Sdim } 2205251662Sdim } 2206251662Sdim 2207226586Sdim N = N->pred_empty() ? NULL : *(N->pred_begin()); 2208226586Sdim } 2209226586Sdim 2210251662Sdim // If we are reporting a leak of the object that was allocated with alloc, 2211251662Sdim // mark its init method as interesting. 2212251662Sdim const LocationContext *InterestingMethodContext = 0; 2213251662Sdim if (InitMethodContext) { 2214251662Sdim const ProgramPoint AllocPP = AllocationNode->getLocation(); 2215251662Sdim if (Optional<StmtPoint> SP = AllocPP.getAs<StmtPoint>()) 2216251662Sdim if (const ObjCMessageExpr *ME = SP->getStmtAs<ObjCMessageExpr>()) 2217251662Sdim if (ME->getMethodFamily() == OMF_alloc) 2218251662Sdim InterestingMethodContext = InitMethodContext; 2219251662Sdim } 2220251662Sdim 2221234353Sdim // If allocation happened in a function different from the leak node context, 2222234353Sdim // do not report the binding. 2223243830Sdim assert(N && "Could not find allocation node"); 2224234353Sdim if (N->getLocationContext() != LeakContext) { 2225234353Sdim FirstBinding = 0; 2226234353Sdim } 2227234353Sdim 2228251662Sdim return AllocationInfo(AllocationNodeInCurrentContext, 2229251662Sdim FirstBinding, 2230251662Sdim InterestingMethodContext); 2231226586Sdim} 2232226586Sdim 2233226586SdimPathDiagnosticPiece* 2234226586SdimCFRefReportVisitor::getEndPath(BugReporterContext &BRC, 2235226586Sdim const ExplodedNode *EndN, 2236226586Sdim BugReport &BR) { 2237234353Sdim BR.markInteresting(Sym); 2238226586Sdim return BugReporterVisitor::getDefaultEndPath(BRC, EndN, BR); 2239226586Sdim} 2240226586Sdim 2241226586SdimPathDiagnosticPiece* 2242226586SdimCFRefLeakReportVisitor::getEndPath(BugReporterContext &BRC, 2243226586Sdim const ExplodedNode *EndN, 2244226586Sdim BugReport &BR) { 2245226586Sdim 2246226586Sdim // Tell the BugReporterContext to report cases when the tracked symbol is 2247226586Sdim // assigned to different variables, etc. 2248234353Sdim BR.markInteresting(Sym); 2249226586Sdim 2250226586Sdim // We are reporting a leak. Walk up the graph to get to the first node where 2251226586Sdim // the symbol appeared, and also get the first VarDecl that tracked object 2252226586Sdim // is stored to. 2253251662Sdim AllocationInfo AllocI = 2254226586Sdim GetAllocationSite(BRC.getStateManager(), EndN, Sym); 2255226586Sdim 2256251662Sdim const MemRegion* FirstBinding = AllocI.R; 2257251662Sdim BR.markInteresting(AllocI.InterestingMethodContext); 2258251662Sdim 2259226586Sdim SourceManager& SM = BRC.getSourceManager(); 2260226586Sdim 2261226586Sdim // Compute an actual location for the leak. Sometimes a leak doesn't 2262226586Sdim // occur at an actual statement (e.g., transition between blocks; end 2263226586Sdim // of function) so we need to walk the graph and compute a real location. 2264226586Sdim const ExplodedNode *LeakN = EndN; 2265226586Sdim PathDiagnosticLocation L = PathDiagnosticLocation::createEndOfPath(LeakN, SM); 2266226586Sdim 2267226586Sdim std::string sbuf; 2268226586Sdim llvm::raw_string_ostream os(sbuf); 2269226586Sdim 2270226586Sdim os << "Object leaked: "; 2271226586Sdim 2272226586Sdim if (FirstBinding) { 2273226586Sdim os << "object allocated and stored into '" 2274226586Sdim << FirstBinding->getString() << '\''; 2275226586Sdim } 2276226586Sdim else 2277226586Sdim os << "allocated object"; 2278226586Sdim 2279226586Sdim // Get the retain count. 2280239462Sdim const RefVal* RV = getRefBinding(EndN->getState(), Sym); 2281243830Sdim assert(RV); 2282226586Sdim 2283226586Sdim if (RV->getKind() == RefVal::ErrorLeakReturned) { 2284226586Sdim // FIXME: Per comments in rdar://6320065, "create" only applies to CF 2285226586Sdim // objects. Only "copy", "alloc", "retain" and "new" transfer ownership 2286226586Sdim // to the caller for NS objects. 2287226586Sdim const Decl *D = &EndN->getCodeDecl(); 2288243830Sdim 2289243830Sdim os << (isa<ObjCMethodDecl>(D) ? " is returned from a method " 2290243830Sdim : " is returned from a function "); 2291243830Sdim 2292243830Sdim if (D->getAttr<CFReturnsNotRetainedAttr>()) 2293243830Sdim os << "that is annotated as CF_RETURNS_NOT_RETAINED"; 2294243830Sdim else if (D->getAttr<NSReturnsNotRetainedAttr>()) 2295243830Sdim os << "that is annotated as NS_RETURNS_NOT_RETAINED"; 2296243830Sdim else { 2297243830Sdim if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { 2298243830Sdim os << "whose name ('" << MD->getSelector().getAsString() 2299243830Sdim << "') does not start with 'copy', 'mutableCopy', 'alloc' or 'new'." 2300243830Sdim " This violates the naming convention rules" 2301243830Sdim " given in the Memory Management Guide for Cocoa"; 2302243830Sdim } 2303243830Sdim else { 2304243830Sdim const FunctionDecl *FD = cast<FunctionDecl>(D); 2305243830Sdim os << "whose name ('" << *FD 2306243830Sdim << "') does not contain 'Copy' or 'Create'. This violates the naming" 2307243830Sdim " convention rules given in the Memory Management Guide for Core" 2308243830Sdim " Foundation"; 2309243830Sdim } 2310226586Sdim } 2311226586Sdim } 2312226586Sdim else if (RV->getKind() == RefVal::ErrorGCLeakReturned) { 2313249423Sdim const ObjCMethodDecl &MD = cast<ObjCMethodDecl>(EndN->getCodeDecl()); 2314226586Sdim os << " and returned from method '" << MD.getSelector().getAsString() 2315226586Sdim << "' is potentially leaked when using garbage collection. Callers " 2316226586Sdim "of this method do not expect a returned object with a +1 retain " 2317226586Sdim "count since they expect the object to be managed by the garbage " 2318226586Sdim "collector"; 2319226586Sdim } 2320226586Sdim else 2321226586Sdim os << " is not referenced later in this execution path and has a retain " 2322226586Sdim "count of +" << RV->getCount(); 2323226586Sdim 2324226586Sdim return new PathDiagnosticEventPiece(L, os.str()); 2325226586Sdim} 2326226586Sdim 2327226586SdimCFRefLeakReport::CFRefLeakReport(CFRefBug &D, const LangOptions &LOpts, 2328226586Sdim bool GCEnabled, const SummaryLogTy &Log, 2329226586Sdim ExplodedNode *n, SymbolRef sym, 2330251662Sdim CheckerContext &Ctx, 2331251662Sdim bool IncludeAllocationLine) 2332251662Sdim : CFRefReport(D, LOpts, GCEnabled, Log, n, sym, false) { 2333226586Sdim 2334226586Sdim // Most bug reports are cached at the location where they occurred. 2335226586Sdim // With leaks, we want to unique them by the location where they were 2336226586Sdim // allocated, and only report a single path. To do this, we need to find 2337226586Sdim // the allocation site of a piece of tracked memory, which we do via a 2338226586Sdim // call to GetAllocationSite. This will walk the ExplodedGraph backwards. 2339226586Sdim // Note that this is *not* the trimmed graph; we are guaranteed, however, 2340226586Sdim // that all ancestor nodes that represent the allocation site have the 2341226586Sdim // same SourceLocation. 2342226586Sdim const ExplodedNode *AllocNode = 0; 2343226586Sdim 2344234353Sdim const SourceManager& SMgr = Ctx.getSourceManager(); 2345226586Sdim 2346251662Sdim AllocationInfo AllocI = 2347234353Sdim GetAllocationSite(Ctx.getStateManager(), getErrorNode(), sym); 2348226586Sdim 2349251662Sdim AllocNode = AllocI.N; 2350251662Sdim AllocBinding = AllocI.R; 2351251662Sdim markInteresting(AllocI.InterestingMethodContext); 2352251662Sdim 2353226586Sdim // Get the SourceLocation for the allocation site. 2354239462Sdim // FIXME: This will crash the analyzer if an allocation comes from an 2355239462Sdim // implicit call. (Currently there are no such allocations in Cocoa, though.) 2356239462Sdim const Stmt *AllocStmt; 2357226586Sdim ProgramPoint P = AllocNode->getLocation(); 2358249423Sdim if (Optional<CallExitEnd> Exit = P.getAs<CallExitEnd>()) 2359239462Sdim AllocStmt = Exit->getCalleeContext()->getCallSite(); 2360239462Sdim else 2361249423Sdim AllocStmt = P.castAs<PostStmt>().getStmt(); 2362239462Sdim assert(AllocStmt && "All allocations must come from explicit calls"); 2363251662Sdim 2364251662Sdim PathDiagnosticLocation AllocLocation = 2365251662Sdim PathDiagnosticLocation::createBegin(AllocStmt, SMgr, 2366251662Sdim AllocNode->getLocationContext()); 2367251662Sdim Location = AllocLocation; 2368251662Sdim 2369251662Sdim // Set uniqieing info, which will be used for unique the bug reports. The 2370251662Sdim // leaks should be uniqued on the allocation site. 2371251662Sdim UniqueingLocation = AllocLocation; 2372251662Sdim UniqueingDecl = AllocNode->getLocationContext()->getDecl(); 2373251662Sdim 2374226586Sdim // Fill in the description of the bug. 2375226586Sdim Description.clear(); 2376226586Sdim llvm::raw_string_ostream os(Description); 2377226586Sdim os << "Potential leak "; 2378226586Sdim if (GCEnabled) 2379226586Sdim os << "(when using garbage collection) "; 2380234353Sdim os << "of an object"; 2381226586Sdim 2382251662Sdim if (AllocBinding) { 2383234353Sdim os << " stored into '" << AllocBinding->getString() << '\''; 2384251662Sdim if (IncludeAllocationLine) { 2385251662Sdim FullSourceLoc SL(AllocStmt->getLocStart(), Ctx.getSourceManager()); 2386251662Sdim os << " (allocated on line " << SL.getSpellingLineNumber() << ")"; 2387251662Sdim } 2388251662Sdim } 2389226586Sdim 2390226586Sdim addVisitor(new CFRefLeakReportVisitor(sym, GCEnabled, Log)); 2391226586Sdim} 2392226586Sdim 2393226586Sdim//===----------------------------------------------------------------------===// 2394226586Sdim// Main checker logic. 2395226586Sdim//===----------------------------------------------------------------------===// 2396226586Sdim 2397226586Sdimnamespace { 2398226586Sdimclass RetainCountChecker 2399226586Sdim : public Checker< check::Bind, 2400226586Sdim check::DeadSymbols, 2401226586Sdim check::EndAnalysis, 2402249423Sdim check::EndFunction, 2403226586Sdim check::PostStmt<BlockExpr>, 2404226586Sdim check::PostStmt<CastExpr>, 2405234353Sdim check::PostStmt<ObjCArrayLiteral>, 2406234353Sdim check::PostStmt<ObjCDictionaryLiteral>, 2407239462Sdim check::PostStmt<ObjCBoxedExpr>, 2408239462Sdim check::PostCall, 2409226586Sdim check::PreStmt<ReturnStmt>, 2410226586Sdim check::RegionChanges, 2411226586Sdim eval::Assume, 2412226586Sdim eval::Call > { 2413234353Sdim mutable OwningPtr<CFRefBug> useAfterRelease, releaseNotOwned; 2414234353Sdim mutable OwningPtr<CFRefBug> deallocGC, deallocNotOwned; 2415234353Sdim mutable OwningPtr<CFRefBug> overAutorelease, returnNotOwnedForOwned; 2416234353Sdim mutable OwningPtr<CFRefBug> leakWithinFunction, leakAtReturn; 2417234353Sdim mutable OwningPtr<CFRefBug> leakWithinFunctionGC, leakAtReturnGC; 2418226586Sdim 2419226586Sdim typedef llvm::DenseMap<SymbolRef, const SimpleProgramPointTag *> SymbolTagMap; 2420226586Sdim 2421226586Sdim // This map is only used to ensure proper deletion of any allocated tags. 2422226586Sdim mutable SymbolTagMap DeadSymbolTags; 2423226586Sdim 2424234353Sdim mutable OwningPtr<RetainSummaryManager> Summaries; 2425234353Sdim mutable OwningPtr<RetainSummaryManager> SummariesGC; 2426226586Sdim mutable SummaryLogTy SummaryLog; 2427226586Sdim mutable bool ShouldResetSummaryLog; 2428226586Sdim 2429251662Sdim /// Optional setting to indicate if leak reports should include 2430251662Sdim /// the allocation line. 2431251662Sdim mutable bool IncludeAllocationLine; 2432251662Sdim 2433226586Sdimpublic: 2434251662Sdim RetainCountChecker(AnalyzerOptions &AO) 2435251662Sdim : ShouldResetSummaryLog(false), 2436251662Sdim IncludeAllocationLine(shouldIncludeAllocationSiteInLeakDiagnostics(AO)) {} 2437226586Sdim 2438226586Sdim virtual ~RetainCountChecker() { 2439226586Sdim DeleteContainerSeconds(DeadSymbolTags); 2440226586Sdim } 2441226586Sdim 2442226586Sdim void checkEndAnalysis(ExplodedGraph &G, BugReporter &BR, 2443226586Sdim ExprEngine &Eng) const { 2444226586Sdim // FIXME: This is a hack to make sure the summary log gets cleared between 2445226586Sdim // analyses of different code bodies. 2446226586Sdim // 2447226586Sdim // Why is this necessary? Because a checker's lifetime is tied to a 2448226586Sdim // translation unit, but an ExplodedGraph's lifetime is just a code body. 2449226586Sdim // Once in a blue moon, a new ExplodedNode will have the same address as an 2450226586Sdim // old one with an associated summary, and the bug report visitor gets very 2451226586Sdim // confused. (To make things worse, the summary lifetime is currently also 2452226586Sdim // tied to a code body, so we get a crash instead of incorrect results.) 2453226586Sdim // 2454226586Sdim // Why is this a bad solution? Because if the lifetime of the ExplodedGraph 2455226586Sdim // changes, things will start going wrong again. Really the lifetime of this 2456226586Sdim // log needs to be tied to either the specific nodes in it or the entire 2457226586Sdim // ExplodedGraph, not to a specific part of the code being analyzed. 2458226586Sdim // 2459226586Sdim // (Also, having stateful local data means that the same checker can't be 2460226586Sdim // used from multiple threads, but a lot of checkers have incorrect 2461226586Sdim // assumptions about that anyway. So that wasn't a priority at the time of 2462226586Sdim // this fix.) 2463226586Sdim // 2464226586Sdim // This happens at the end of analysis, but bug reports are emitted /after/ 2465226586Sdim // this point. So we can't just clear the summary log now. Instead, we mark 2466226586Sdim // that the next time we access the summary log, it should be cleared. 2467226586Sdim 2468226586Sdim // If we never reset the summary log during /this/ code body analysis, 2469226586Sdim // there were no new summaries. There might still have been summaries from 2470226586Sdim // the /last/ analysis, so clear them out to make sure the bug report 2471226586Sdim // visitors don't get confused. 2472226586Sdim if (ShouldResetSummaryLog) 2473226586Sdim SummaryLog.clear(); 2474226586Sdim 2475226586Sdim ShouldResetSummaryLog = !SummaryLog.empty(); 2476226586Sdim } 2477226586Sdim 2478226586Sdim CFRefBug *getLeakWithinFunctionBug(const LangOptions &LOpts, 2479226586Sdim bool GCEnabled) const { 2480226586Sdim if (GCEnabled) { 2481226586Sdim if (!leakWithinFunctionGC) 2482239462Sdim leakWithinFunctionGC.reset(new Leak("Leak of object when using " 2483239462Sdim "garbage collection")); 2484226586Sdim return leakWithinFunctionGC.get(); 2485226586Sdim } else { 2486226586Sdim if (!leakWithinFunction) { 2487226586Sdim if (LOpts.getGC() == LangOptions::HybridGC) { 2488239462Sdim leakWithinFunction.reset(new Leak("Leak of object when not using " 2489239462Sdim "garbage collection (GC) in " 2490239462Sdim "dual GC/non-GC code")); 2491226586Sdim } else { 2492239462Sdim leakWithinFunction.reset(new Leak("Leak")); 2493226586Sdim } 2494226586Sdim } 2495226586Sdim return leakWithinFunction.get(); 2496226586Sdim } 2497226586Sdim } 2498226586Sdim 2499226586Sdim CFRefBug *getLeakAtReturnBug(const LangOptions &LOpts, bool GCEnabled) const { 2500226586Sdim if (GCEnabled) { 2501226586Sdim if (!leakAtReturnGC) 2502239462Sdim leakAtReturnGC.reset(new Leak("Leak of returned object when using " 2503239462Sdim "garbage collection")); 2504226586Sdim return leakAtReturnGC.get(); 2505226586Sdim } else { 2506226586Sdim if (!leakAtReturn) { 2507226586Sdim if (LOpts.getGC() == LangOptions::HybridGC) { 2508239462Sdim leakAtReturn.reset(new Leak("Leak of returned object when not using " 2509239462Sdim "garbage collection (GC) in dual " 2510239462Sdim "GC/non-GC code")); 2511226586Sdim } else { 2512239462Sdim leakAtReturn.reset(new Leak("Leak of returned object")); 2513226586Sdim } 2514226586Sdim } 2515226586Sdim return leakAtReturn.get(); 2516226586Sdim } 2517226586Sdim } 2518226586Sdim 2519226586Sdim RetainSummaryManager &getSummaryManager(ASTContext &Ctx, 2520226586Sdim bool GCEnabled) const { 2521226586Sdim // FIXME: We don't support ARC being turned on and off during one analysis. 2522226586Sdim // (nor, for that matter, do we support changing ASTContexts) 2523234353Sdim bool ARCEnabled = (bool)Ctx.getLangOpts().ObjCAutoRefCount; 2524226586Sdim if (GCEnabled) { 2525226586Sdim if (!SummariesGC) 2526226586Sdim SummariesGC.reset(new RetainSummaryManager(Ctx, true, ARCEnabled)); 2527226586Sdim else 2528226586Sdim assert(SummariesGC->isARCEnabled() == ARCEnabled); 2529226586Sdim return *SummariesGC; 2530226586Sdim } else { 2531226586Sdim if (!Summaries) 2532226586Sdim Summaries.reset(new RetainSummaryManager(Ctx, false, ARCEnabled)); 2533226586Sdim else 2534226586Sdim assert(Summaries->isARCEnabled() == ARCEnabled); 2535226586Sdim return *Summaries; 2536226586Sdim } 2537226586Sdim } 2538226586Sdim 2539226586Sdim RetainSummaryManager &getSummaryManager(CheckerContext &C) const { 2540226586Sdim return getSummaryManager(C.getASTContext(), C.isObjCGCEnabled()); 2541226586Sdim } 2542226586Sdim 2543234353Sdim void printState(raw_ostream &Out, ProgramStateRef State, 2544226586Sdim const char *NL, const char *Sep) const; 2545226586Sdim 2546226586Sdim void checkBind(SVal loc, SVal val, const Stmt *S, CheckerContext &C) const; 2547226586Sdim void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const; 2548226586Sdim void checkPostStmt(const CastExpr *CE, CheckerContext &C) const; 2549226586Sdim 2550234353Sdim void checkPostStmt(const ObjCArrayLiteral *AL, CheckerContext &C) const; 2551234353Sdim void checkPostStmt(const ObjCDictionaryLiteral *DL, CheckerContext &C) const; 2552239462Sdim void checkPostStmt(const ObjCBoxedExpr *BE, CheckerContext &C) const; 2553239462Sdim 2554239462Sdim void checkPostCall(const CallEvent &Call, CheckerContext &C) const; 2555234353Sdim 2556239462Sdim void checkSummary(const RetainSummary &Summ, const CallEvent &Call, 2557226586Sdim CheckerContext &C) const; 2558226586Sdim 2559243830Sdim void processSummaryOfInlined(const RetainSummary &Summ, 2560243830Sdim const CallEvent &Call, 2561243830Sdim CheckerContext &C) const; 2562243830Sdim 2563226586Sdim bool evalCall(const CallExpr *CE, CheckerContext &C) const; 2564226586Sdim 2565234353Sdim ProgramStateRef evalAssume(ProgramStateRef state, SVal Cond, 2566226586Sdim bool Assumption) const; 2567226586Sdim 2568234353Sdim ProgramStateRef 2569234353Sdim checkRegionChanges(ProgramStateRef state, 2570249423Sdim const InvalidatedSymbols *invalidated, 2571226586Sdim ArrayRef<const MemRegion *> ExplicitRegions, 2572234353Sdim ArrayRef<const MemRegion *> Regions, 2573239462Sdim const CallEvent *Call) const; 2574226586Sdim 2575234353Sdim bool wantsRegionChangeUpdate(ProgramStateRef state) const { 2576226586Sdim return true; 2577226586Sdim } 2578226586Sdim 2579226586Sdim void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const; 2580226586Sdim void checkReturnWithRetEffect(const ReturnStmt *S, CheckerContext &C, 2581226586Sdim ExplodedNode *Pred, RetEffect RE, RefVal X, 2582234353Sdim SymbolRef Sym, ProgramStateRef state) const; 2583226586Sdim 2584226586Sdim void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const; 2585249423Sdim void checkEndFunction(CheckerContext &C) const; 2586226586Sdim 2587234353Sdim ProgramStateRef updateSymbol(ProgramStateRef state, SymbolRef sym, 2588243830Sdim RefVal V, ArgEffect E, RefVal::Kind &hasErr, 2589243830Sdim CheckerContext &C) const; 2590226586Sdim 2591234353Sdim void processNonLeakError(ProgramStateRef St, SourceRange ErrorRange, 2592226586Sdim RefVal::Kind ErrorKind, SymbolRef Sym, 2593226586Sdim CheckerContext &C) const; 2594234353Sdim 2595234353Sdim void processObjCLiterals(CheckerContext &C, const Expr *Ex) const; 2596226586Sdim 2597226586Sdim const ProgramPointTag *getDeadSymbolTag(SymbolRef sym) const; 2598226586Sdim 2599234353Sdim ProgramStateRef handleSymbolDeath(ProgramStateRef state, 2600239462Sdim SymbolRef sid, RefVal V, 2601239462Sdim SmallVectorImpl<SymbolRef> &Leaked) const; 2602226586Sdim 2603249423Sdim ProgramStateRef 2604243830Sdim handleAutoreleaseCounts(ProgramStateRef state, ExplodedNode *Pred, 2605243830Sdim const ProgramPointTag *Tag, CheckerContext &Ctx, 2606243830Sdim SymbolRef Sym, RefVal V) const; 2607226586Sdim 2608234353Sdim ExplodedNode *processLeaks(ProgramStateRef state, 2609226586Sdim SmallVectorImpl<SymbolRef> &Leaked, 2610234353Sdim CheckerContext &Ctx, 2611226586Sdim ExplodedNode *Pred = 0) const; 2612226586Sdim}; 2613226586Sdim} // end anonymous namespace 2614226586Sdim 2615226586Sdimnamespace { 2616226586Sdimclass StopTrackingCallback : public SymbolVisitor { 2617234353Sdim ProgramStateRef state; 2618226586Sdimpublic: 2619234353Sdim StopTrackingCallback(ProgramStateRef st) : state(st) {} 2620234353Sdim ProgramStateRef getState() const { return state; } 2621226586Sdim 2622226586Sdim bool VisitSymbol(SymbolRef sym) { 2623226586Sdim state = state->remove<RefBindings>(sym); 2624226586Sdim return true; 2625226586Sdim } 2626226586Sdim}; 2627226586Sdim} // end anonymous namespace 2628226586Sdim 2629226586Sdim//===----------------------------------------------------------------------===// 2630226586Sdim// Handle statements that may have an effect on refcounts. 2631226586Sdim//===----------------------------------------------------------------------===// 2632226586Sdim 2633226586Sdimvoid RetainCountChecker::checkPostStmt(const BlockExpr *BE, 2634226586Sdim CheckerContext &C) const { 2635226586Sdim 2636226586Sdim // Scan the BlockDecRefExprs for any object the retain count checker 2637226586Sdim // may be tracking. 2638226586Sdim if (!BE->getBlockDecl()->hasCaptures()) 2639226586Sdim return; 2640226586Sdim 2641234353Sdim ProgramStateRef state = C.getState(); 2642226586Sdim const BlockDataRegion *R = 2643234353Sdim cast<BlockDataRegion>(state->getSVal(BE, 2644234353Sdim C.getLocationContext()).getAsRegion()); 2645226586Sdim 2646226586Sdim BlockDataRegion::referenced_vars_iterator I = R->referenced_vars_begin(), 2647226586Sdim E = R->referenced_vars_end(); 2648226586Sdim 2649226586Sdim if (I == E) 2650226586Sdim return; 2651226586Sdim 2652226586Sdim // FIXME: For now we invalidate the tracking of all symbols passed to blocks 2653226586Sdim // via captured variables, even though captured variables result in a copy 2654226586Sdim // and in implicit increment/decrement of a retain count. 2655226586Sdim SmallVector<const MemRegion*, 10> Regions; 2656234353Sdim const LocationContext *LC = C.getLocationContext(); 2657226586Sdim MemRegionManager &MemMgr = C.getSValBuilder().getRegionManager(); 2658226586Sdim 2659226586Sdim for ( ; I != E; ++I) { 2660249423Sdim const VarRegion *VR = I.getCapturedRegion(); 2661226586Sdim if (VR->getSuperRegion() == R) { 2662226586Sdim VR = MemMgr.getVarRegion(VR->getDecl(), LC); 2663226586Sdim } 2664226586Sdim Regions.push_back(VR); 2665226586Sdim } 2666226586Sdim 2667226586Sdim state = 2668226586Sdim state->scanReachableSymbols<StopTrackingCallback>(Regions.data(), 2669226586Sdim Regions.data() + Regions.size()).getState(); 2670226586Sdim C.addTransition(state); 2671226586Sdim} 2672226586Sdim 2673226586Sdimvoid RetainCountChecker::checkPostStmt(const CastExpr *CE, 2674226586Sdim CheckerContext &C) const { 2675226586Sdim const ObjCBridgedCastExpr *BE = dyn_cast<ObjCBridgedCastExpr>(CE); 2676226586Sdim if (!BE) 2677226586Sdim return; 2678226586Sdim 2679226586Sdim ArgEffect AE = IncRef; 2680226586Sdim 2681226586Sdim switch (BE->getBridgeKind()) { 2682226586Sdim case clang::OBC_Bridge: 2683226586Sdim // Do nothing. 2684226586Sdim return; 2685226586Sdim case clang::OBC_BridgeRetained: 2686226586Sdim AE = IncRef; 2687226586Sdim break; 2688226586Sdim case clang::OBC_BridgeTransfer: 2689226586Sdim AE = DecRefBridgedTransfered; 2690226586Sdim break; 2691226586Sdim } 2692226586Sdim 2693234353Sdim ProgramStateRef state = C.getState(); 2694234353Sdim SymbolRef Sym = state->getSVal(CE, C.getLocationContext()).getAsLocSymbol(); 2695226586Sdim if (!Sym) 2696226586Sdim return; 2697239462Sdim const RefVal* T = getRefBinding(state, Sym); 2698226586Sdim if (!T) 2699226586Sdim return; 2700226586Sdim 2701226586Sdim RefVal::Kind hasErr = (RefVal::Kind) 0; 2702226586Sdim state = updateSymbol(state, Sym, *T, AE, hasErr, C); 2703226586Sdim 2704226586Sdim if (hasErr) { 2705226586Sdim // FIXME: If we get an error during a bridge cast, should we report it? 2706226586Sdim // Should we assert that there is no error? 2707226586Sdim return; 2708226586Sdim } 2709226586Sdim 2710234353Sdim C.addTransition(state); 2711226586Sdim} 2712226586Sdim 2713234353Sdimvoid RetainCountChecker::processObjCLiterals(CheckerContext &C, 2714234353Sdim const Expr *Ex) const { 2715234353Sdim ProgramStateRef state = C.getState(); 2716234353Sdim const ExplodedNode *pred = C.getPredecessor(); 2717234353Sdim for (Stmt::const_child_iterator it = Ex->child_begin(), et = Ex->child_end() ; 2718234353Sdim it != et ; ++it) { 2719234353Sdim const Stmt *child = *it; 2720234353Sdim SVal V = state->getSVal(child, pred->getLocationContext()); 2721234353Sdim if (SymbolRef sym = V.getAsSymbol()) 2722239462Sdim if (const RefVal* T = getRefBinding(state, sym)) { 2723234353Sdim RefVal::Kind hasErr = (RefVal::Kind) 0; 2724234353Sdim state = updateSymbol(state, sym, *T, MayEscape, hasErr, C); 2725234353Sdim if (hasErr) { 2726234353Sdim processNonLeakError(state, child->getSourceRange(), hasErr, sym, C); 2727234353Sdim return; 2728234353Sdim } 2729234353Sdim } 2730234353Sdim } 2731234353Sdim 2732234353Sdim // Return the object as autoreleased. 2733234353Sdim // RetEffect RE = RetEffect::MakeNotOwned(RetEffect::ObjC); 2734234353Sdim if (SymbolRef sym = 2735234353Sdim state->getSVal(Ex, pred->getLocationContext()).getAsSymbol()) { 2736234353Sdim QualType ResultTy = Ex->getType(); 2737239462Sdim state = setRefBinding(state, sym, 2738239462Sdim RefVal::makeNotOwned(RetEffect::ObjC, ResultTy)); 2739234353Sdim } 2740234353Sdim 2741234353Sdim C.addTransition(state); 2742234353Sdim} 2743234353Sdim 2744234353Sdimvoid RetainCountChecker::checkPostStmt(const ObjCArrayLiteral *AL, 2745234353Sdim CheckerContext &C) const { 2746234353Sdim // Apply the 'MayEscape' to all values. 2747234353Sdim processObjCLiterals(C, AL); 2748234353Sdim} 2749234353Sdim 2750234353Sdimvoid RetainCountChecker::checkPostStmt(const ObjCDictionaryLiteral *DL, 2751234353Sdim CheckerContext &C) const { 2752234353Sdim // Apply the 'MayEscape' to all keys and values. 2753234353Sdim processObjCLiterals(C, DL); 2754234353Sdim} 2755234353Sdim 2756239462Sdimvoid RetainCountChecker::checkPostStmt(const ObjCBoxedExpr *Ex, 2757239462Sdim CheckerContext &C) const { 2758239462Sdim const ExplodedNode *Pred = C.getPredecessor(); 2759239462Sdim const LocationContext *LCtx = Pred->getLocationContext(); 2760239462Sdim ProgramStateRef State = Pred->getState(); 2761226586Sdim 2762239462Sdim if (SymbolRef Sym = State->getSVal(Ex, LCtx).getAsSymbol()) { 2763239462Sdim QualType ResultTy = Ex->getType(); 2764239462Sdim State = setRefBinding(State, Sym, 2765239462Sdim RefVal::makeNotOwned(RetEffect::ObjC, ResultTy)); 2766226586Sdim } 2767226586Sdim 2768239462Sdim C.addTransition(State); 2769239462Sdim} 2770239462Sdim 2771239462Sdimvoid RetainCountChecker::checkPostCall(const CallEvent &Call, 2772239462Sdim CheckerContext &C) const { 2773239462Sdim RetainSummaryManager &Summaries = getSummaryManager(C); 2774239462Sdim const RetainSummary *Summ = Summaries.getSummary(Call, C.getState()); 2775243830Sdim 2776243830Sdim if (C.wasInlined) { 2777243830Sdim processSummaryOfInlined(*Summ, Call, C); 2778243830Sdim return; 2779243830Sdim } 2780239462Sdim checkSummary(*Summ, Call, C); 2781226586Sdim} 2782226586Sdim 2783226586Sdim/// GetReturnType - Used to get the return type of a message expression or 2784226586Sdim/// function call with the intention of affixing that type to a tracked symbol. 2785239462Sdim/// While the return type can be queried directly from RetEx, when 2786226586Sdim/// invoking class methods we augment to the return type to be that of 2787226586Sdim/// a pointer to the class (as opposed it just being id). 2788226586Sdim// FIXME: We may be able to do this with related result types instead. 2789226586Sdim// This function is probably overestimating. 2790226586Sdimstatic QualType GetReturnType(const Expr *RetE, ASTContext &Ctx) { 2791226586Sdim QualType RetTy = RetE->getType(); 2792226586Sdim // If RetE is not a message expression just return its type. 2793226586Sdim // If RetE is a message expression, return its types if it is something 2794226586Sdim /// more specific than id. 2795226586Sdim if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(RetE)) 2796226586Sdim if (const ObjCObjectPointerType *PT = RetTy->getAs<ObjCObjectPointerType>()) 2797226586Sdim if (PT->isObjCQualifiedIdType() || PT->isObjCIdType() || 2798226586Sdim PT->isObjCClassType()) { 2799226586Sdim // At this point we know the return type of the message expression is 2800226586Sdim // id, id<...>, or Class. If we have an ObjCInterfaceDecl, we know this 2801226586Sdim // is a call to a class method whose type we can resolve. In such 2802226586Sdim // cases, promote the return type to XXX* (where XXX is the class). 2803226586Sdim const ObjCInterfaceDecl *D = ME->getReceiverInterface(); 2804226586Sdim return !D ? RetTy : 2805226586Sdim Ctx.getObjCObjectPointerType(Ctx.getObjCInterfaceType(D)); 2806226586Sdim } 2807226586Sdim 2808226586Sdim return RetTy; 2809226586Sdim} 2810226586Sdim 2811243830Sdim// We don't always get the exact modeling of the function with regards to the 2812243830Sdim// retain count checker even when the function is inlined. For example, we need 2813243830Sdim// to stop tracking the symbols which were marked with StopTrackingHard. 2814243830Sdimvoid RetainCountChecker::processSummaryOfInlined(const RetainSummary &Summ, 2815243830Sdim const CallEvent &CallOrMsg, 2816243830Sdim CheckerContext &C) const { 2817243830Sdim ProgramStateRef state = C.getState(); 2818243830Sdim 2819243830Sdim // Evaluate the effect of the arguments. 2820243830Sdim for (unsigned idx = 0, e = CallOrMsg.getNumArgs(); idx != e; ++idx) { 2821243830Sdim if (Summ.getArg(idx) == StopTrackingHard) { 2822243830Sdim SVal V = CallOrMsg.getArgSVal(idx); 2823243830Sdim if (SymbolRef Sym = V.getAsLocSymbol()) { 2824243830Sdim state = removeRefBinding(state, Sym); 2825243830Sdim } 2826243830Sdim } 2827243830Sdim } 2828243830Sdim 2829243830Sdim // Evaluate the effect on the message receiver. 2830243830Sdim const ObjCMethodCall *MsgInvocation = dyn_cast<ObjCMethodCall>(&CallOrMsg); 2831243830Sdim if (MsgInvocation) { 2832243830Sdim if (SymbolRef Sym = MsgInvocation->getReceiverSVal().getAsLocSymbol()) { 2833243830Sdim if (Summ.getReceiverEffect() == StopTrackingHard) { 2834243830Sdim state = removeRefBinding(state, Sym); 2835243830Sdim } 2836243830Sdim } 2837243830Sdim } 2838243830Sdim 2839243830Sdim // Consult the summary for the return value. 2840243830Sdim RetEffect RE = Summ.getRetEffect(); 2841243830Sdim if (RE.getKind() == RetEffect::NoRetHard) { 2842243830Sdim SymbolRef Sym = CallOrMsg.getReturnValue().getAsSymbol(); 2843243830Sdim if (Sym) 2844243830Sdim state = removeRefBinding(state, Sym); 2845243830Sdim } 2846243830Sdim 2847243830Sdim C.addTransition(state); 2848243830Sdim} 2849243830Sdim 2850226586Sdimvoid RetainCountChecker::checkSummary(const RetainSummary &Summ, 2851239462Sdim const CallEvent &CallOrMsg, 2852226586Sdim CheckerContext &C) const { 2853234353Sdim ProgramStateRef state = C.getState(); 2854226586Sdim 2855226586Sdim // Evaluate the effect of the arguments. 2856226586Sdim RefVal::Kind hasErr = (RefVal::Kind) 0; 2857226586Sdim SourceRange ErrorRange; 2858226586Sdim SymbolRef ErrorSym = 0; 2859226586Sdim 2860226586Sdim for (unsigned idx = 0, e = CallOrMsg.getNumArgs(); idx != e; ++idx) { 2861226586Sdim SVal V = CallOrMsg.getArgSVal(idx); 2862226586Sdim 2863226586Sdim if (SymbolRef Sym = V.getAsLocSymbol()) { 2864239462Sdim if (const RefVal *T = getRefBinding(state, Sym)) { 2865226586Sdim state = updateSymbol(state, Sym, *T, Summ.getArg(idx), hasErr, C); 2866226586Sdim if (hasErr) { 2867226586Sdim ErrorRange = CallOrMsg.getArgSourceRange(idx); 2868226586Sdim ErrorSym = Sym; 2869226586Sdim break; 2870226586Sdim } 2871226586Sdim } 2872226586Sdim } 2873226586Sdim } 2874226586Sdim 2875226586Sdim // Evaluate the effect on the message receiver. 2876226586Sdim bool ReceiverIsTracked = false; 2877239462Sdim if (!hasErr) { 2878239462Sdim const ObjCMethodCall *MsgInvocation = dyn_cast<ObjCMethodCall>(&CallOrMsg); 2879239462Sdim if (MsgInvocation) { 2880239462Sdim if (SymbolRef Sym = MsgInvocation->getReceiverSVal().getAsLocSymbol()) { 2881239462Sdim if (const RefVal *T = getRefBinding(state, Sym)) { 2882239462Sdim ReceiverIsTracked = true; 2883239462Sdim state = updateSymbol(state, Sym, *T, Summ.getReceiverEffect(), 2884243830Sdim hasErr, C); 2885239462Sdim if (hasErr) { 2886239462Sdim ErrorRange = MsgInvocation->getOriginExpr()->getReceiverRange(); 2887239462Sdim ErrorSym = Sym; 2888239462Sdim } 2889226586Sdim } 2890226586Sdim } 2891226586Sdim } 2892226586Sdim } 2893226586Sdim 2894226586Sdim // Process any errors. 2895226586Sdim if (hasErr) { 2896226586Sdim processNonLeakError(state, ErrorRange, hasErr, ErrorSym, C); 2897226586Sdim return; 2898226586Sdim } 2899226586Sdim 2900226586Sdim // Consult the summary for the return value. 2901226586Sdim RetEffect RE = Summ.getRetEffect(); 2902226586Sdim 2903226586Sdim if (RE.getKind() == RetEffect::OwnedWhenTrackedReceiver) { 2904226586Sdim if (ReceiverIsTracked) 2905226586Sdim RE = getSummaryManager(C).getObjAllocRetEffect(); 2906226586Sdim else 2907226586Sdim RE = RetEffect::MakeNoRet(); 2908226586Sdim } 2909226586Sdim 2910226586Sdim switch (RE.getKind()) { 2911226586Sdim default: 2912234353Sdim llvm_unreachable("Unhandled RetEffect."); 2913226586Sdim 2914226586Sdim case RetEffect::NoRet: 2915243830Sdim case RetEffect::NoRetHard: 2916226586Sdim // No work necessary. 2917226586Sdim break; 2918226586Sdim 2919226586Sdim case RetEffect::OwnedAllocatedSymbol: 2920226586Sdim case RetEffect::OwnedSymbol: { 2921243830Sdim SymbolRef Sym = CallOrMsg.getReturnValue().getAsSymbol(); 2922226586Sdim if (!Sym) 2923226586Sdim break; 2924226586Sdim 2925239462Sdim // Use the result type from the CallEvent as it automatically adjusts 2926226586Sdim // for methods/functions that return references. 2927239462Sdim QualType ResultTy = CallOrMsg.getResultType(); 2928239462Sdim state = setRefBinding(state, Sym, RefVal::makeOwned(RE.getObjKind(), 2929239462Sdim ResultTy)); 2930226586Sdim 2931226586Sdim // FIXME: Add a flag to the checker where allocations are assumed to 2932239462Sdim // *not* fail. 2933226586Sdim break; 2934226586Sdim } 2935226586Sdim 2936226586Sdim case RetEffect::GCNotOwnedSymbol: 2937226586Sdim case RetEffect::ARCNotOwnedSymbol: 2938226586Sdim case RetEffect::NotOwnedSymbol: { 2939226586Sdim const Expr *Ex = CallOrMsg.getOriginExpr(); 2940243830Sdim SymbolRef Sym = CallOrMsg.getReturnValue().getAsSymbol(); 2941226586Sdim if (!Sym) 2942226586Sdim break; 2943243830Sdim assert(Ex); 2944226586Sdim // Use GetReturnType in order to give [NSFoo alloc] the type NSFoo *. 2945226586Sdim QualType ResultTy = GetReturnType(Ex, C.getASTContext()); 2946239462Sdim state = setRefBinding(state, Sym, RefVal::makeNotOwned(RE.getObjKind(), 2947239462Sdim ResultTy)); 2948226586Sdim break; 2949226586Sdim } 2950226586Sdim } 2951226586Sdim 2952226586Sdim // This check is actually necessary; otherwise the statement builder thinks 2953226586Sdim // we've hit a previously-found path. 2954226586Sdim // Normally addTransition takes care of this, but we want the node pointer. 2955226586Sdim ExplodedNode *NewNode; 2956226586Sdim if (state == C.getState()) { 2957226586Sdim NewNode = C.getPredecessor(); 2958226586Sdim } else { 2959234353Sdim NewNode = C.addTransition(state); 2960226586Sdim } 2961226586Sdim 2962226586Sdim // Annotate the node with summary we used. 2963226586Sdim if (NewNode) { 2964226586Sdim // FIXME: This is ugly. See checkEndAnalysis for why it's necessary. 2965226586Sdim if (ShouldResetSummaryLog) { 2966226586Sdim SummaryLog.clear(); 2967226586Sdim ShouldResetSummaryLog = false; 2968226586Sdim } 2969226586Sdim SummaryLog[NewNode] = &Summ; 2970226586Sdim } 2971226586Sdim} 2972226586Sdim 2973226586Sdim 2974234353SdimProgramStateRef 2975234353SdimRetainCountChecker::updateSymbol(ProgramStateRef state, SymbolRef sym, 2976226586Sdim RefVal V, ArgEffect E, RefVal::Kind &hasErr, 2977226586Sdim CheckerContext &C) const { 2978226586Sdim // In GC mode [... release] and [... retain] do nothing. 2979226586Sdim // In ARC mode they shouldn't exist at all, but we just ignore them. 2980226586Sdim bool IgnoreRetainMsg = C.isObjCGCEnabled(); 2981226586Sdim if (!IgnoreRetainMsg) 2982234353Sdim IgnoreRetainMsg = (bool)C.getASTContext().getLangOpts().ObjCAutoRefCount; 2983226586Sdim 2984226586Sdim switch (E) { 2985239462Sdim default: 2986239462Sdim break; 2987239462Sdim case IncRefMsg: 2988239462Sdim E = IgnoreRetainMsg ? DoNothing : IncRef; 2989239462Sdim break; 2990239462Sdim case DecRefMsg: 2991239462Sdim E = IgnoreRetainMsg ? DoNothing : DecRef; 2992239462Sdim break; 2993243830Sdim case DecRefMsgAndStopTrackingHard: 2994243830Sdim E = IgnoreRetainMsg ? StopTracking : DecRefAndStopTrackingHard; 2995239462Sdim break; 2996239462Sdim case MakeCollectable: 2997239462Sdim E = C.isObjCGCEnabled() ? DecRef : DoNothing; 2998239462Sdim break; 2999226586Sdim } 3000226586Sdim 3001226586Sdim // Handle all use-after-releases. 3002226586Sdim if (!C.isObjCGCEnabled() && V.getKind() == RefVal::Released) { 3003226586Sdim V = V ^ RefVal::ErrorUseAfterRelease; 3004226586Sdim hasErr = V.getKind(); 3005239462Sdim return setRefBinding(state, sym, V); 3006226586Sdim } 3007226586Sdim 3008226586Sdim switch (E) { 3009226586Sdim case DecRefMsg: 3010226586Sdim case IncRefMsg: 3011226586Sdim case MakeCollectable: 3012243830Sdim case DecRefMsgAndStopTrackingHard: 3013226586Sdim llvm_unreachable("DecRefMsg/IncRefMsg/MakeCollectable already converted"); 3014226586Sdim 3015226586Sdim case Dealloc: 3016226586Sdim // Any use of -dealloc in GC is *bad*. 3017226586Sdim if (C.isObjCGCEnabled()) { 3018226586Sdim V = V ^ RefVal::ErrorDeallocGC; 3019226586Sdim hasErr = V.getKind(); 3020226586Sdim break; 3021226586Sdim } 3022226586Sdim 3023226586Sdim switch (V.getKind()) { 3024226586Sdim default: 3025226586Sdim llvm_unreachable("Invalid RefVal state for an explicit dealloc."); 3026226586Sdim case RefVal::Owned: 3027226586Sdim // The object immediately transitions to the released state. 3028226586Sdim V = V ^ RefVal::Released; 3029226586Sdim V.clearCounts(); 3030239462Sdim return setRefBinding(state, sym, V); 3031226586Sdim case RefVal::NotOwned: 3032226586Sdim V = V ^ RefVal::ErrorDeallocNotOwned; 3033226586Sdim hasErr = V.getKind(); 3034226586Sdim break; 3035226586Sdim } 3036226586Sdim break; 3037226586Sdim 3038226586Sdim case MayEscape: 3039226586Sdim if (V.getKind() == RefVal::Owned) { 3040226586Sdim V = V ^ RefVal::NotOwned; 3041226586Sdim break; 3042226586Sdim } 3043226586Sdim 3044226586Sdim // Fall-through. 3045226586Sdim 3046226586Sdim case DoNothing: 3047226586Sdim return state; 3048226586Sdim 3049226586Sdim case Autorelease: 3050226586Sdim if (C.isObjCGCEnabled()) 3051226586Sdim return state; 3052226586Sdim // Update the autorelease counts. 3053226586Sdim V = V.autorelease(); 3054226586Sdim break; 3055226586Sdim 3056226586Sdim case StopTracking: 3057243830Sdim case StopTrackingHard: 3058239462Sdim return removeRefBinding(state, sym); 3059226586Sdim 3060226586Sdim case IncRef: 3061226586Sdim switch (V.getKind()) { 3062226586Sdim default: 3063226586Sdim llvm_unreachable("Invalid RefVal state for a retain."); 3064226586Sdim case RefVal::Owned: 3065226586Sdim case RefVal::NotOwned: 3066226586Sdim V = V + 1; 3067226586Sdim break; 3068226586Sdim case RefVal::Released: 3069226586Sdim // Non-GC cases are handled above. 3070226586Sdim assert(C.isObjCGCEnabled()); 3071226586Sdim V = (V ^ RefVal::Owned) + 1; 3072226586Sdim break; 3073226586Sdim } 3074226586Sdim break; 3075226586Sdim 3076226586Sdim case DecRef: 3077226586Sdim case DecRefBridgedTransfered: 3078243830Sdim case DecRefAndStopTrackingHard: 3079226586Sdim switch (V.getKind()) { 3080226586Sdim default: 3081226586Sdim // case 'RefVal::Released' handled above. 3082226586Sdim llvm_unreachable("Invalid RefVal state for a release."); 3083226586Sdim 3084226586Sdim case RefVal::Owned: 3085226586Sdim assert(V.getCount() > 0); 3086226586Sdim if (V.getCount() == 1) 3087226586Sdim V = V ^ (E == DecRefBridgedTransfered ? 3088226586Sdim RefVal::NotOwned : RefVal::Released); 3089243830Sdim else if (E == DecRefAndStopTrackingHard) 3090239462Sdim return removeRefBinding(state, sym); 3091239462Sdim 3092226586Sdim V = V - 1; 3093226586Sdim break; 3094226586Sdim 3095226586Sdim case RefVal::NotOwned: 3096239462Sdim if (V.getCount() > 0) { 3097243830Sdim if (E == DecRefAndStopTrackingHard) 3098239462Sdim return removeRefBinding(state, sym); 3099226586Sdim V = V - 1; 3100239462Sdim } else { 3101226586Sdim V = V ^ RefVal::ErrorReleaseNotOwned; 3102226586Sdim hasErr = V.getKind(); 3103226586Sdim } 3104226586Sdim break; 3105226586Sdim 3106226586Sdim case RefVal::Released: 3107226586Sdim // Non-GC cases are handled above. 3108226586Sdim assert(C.isObjCGCEnabled()); 3109226586Sdim V = V ^ RefVal::ErrorUseAfterRelease; 3110226586Sdim hasErr = V.getKind(); 3111226586Sdim break; 3112226586Sdim } 3113226586Sdim break; 3114226586Sdim } 3115239462Sdim return setRefBinding(state, sym, V); 3116226586Sdim} 3117226586Sdim 3118234353Sdimvoid RetainCountChecker::processNonLeakError(ProgramStateRef St, 3119226586Sdim SourceRange ErrorRange, 3120226586Sdim RefVal::Kind ErrorKind, 3121226586Sdim SymbolRef Sym, 3122226586Sdim CheckerContext &C) const { 3123226586Sdim ExplodedNode *N = C.generateSink(St); 3124226586Sdim if (!N) 3125226586Sdim return; 3126226586Sdim 3127226586Sdim CFRefBug *BT; 3128226586Sdim switch (ErrorKind) { 3129226586Sdim default: 3130226586Sdim llvm_unreachable("Unhandled error."); 3131226586Sdim case RefVal::ErrorUseAfterRelease: 3132226586Sdim if (!useAfterRelease) 3133226586Sdim useAfterRelease.reset(new UseAfterRelease()); 3134226586Sdim BT = &*useAfterRelease; 3135226586Sdim break; 3136226586Sdim case RefVal::ErrorReleaseNotOwned: 3137226586Sdim if (!releaseNotOwned) 3138226586Sdim releaseNotOwned.reset(new BadRelease()); 3139226586Sdim BT = &*releaseNotOwned; 3140226586Sdim break; 3141226586Sdim case RefVal::ErrorDeallocGC: 3142226586Sdim if (!deallocGC) 3143226586Sdim deallocGC.reset(new DeallocGC()); 3144226586Sdim BT = &*deallocGC; 3145226586Sdim break; 3146226586Sdim case RefVal::ErrorDeallocNotOwned: 3147226586Sdim if (!deallocNotOwned) 3148226586Sdim deallocNotOwned.reset(new DeallocNotOwned()); 3149226586Sdim BT = &*deallocNotOwned; 3150226586Sdim break; 3151226586Sdim } 3152226586Sdim 3153226586Sdim assert(BT); 3154234353Sdim CFRefReport *report = new CFRefReport(*BT, C.getASTContext().getLangOpts(), 3155226586Sdim C.isObjCGCEnabled(), SummaryLog, 3156226586Sdim N, Sym); 3157226586Sdim report->addRange(ErrorRange); 3158243830Sdim C.emitReport(report); 3159226586Sdim} 3160226586Sdim 3161226586Sdim//===----------------------------------------------------------------------===// 3162226586Sdim// Handle the return values of retain-count-related functions. 3163226586Sdim//===----------------------------------------------------------------------===// 3164226586Sdim 3165226586Sdimbool RetainCountChecker::evalCall(const CallExpr *CE, CheckerContext &C) const { 3166226586Sdim // Get the callee. We're only interested in simple C functions. 3167234353Sdim ProgramStateRef state = C.getState(); 3168234353Sdim const FunctionDecl *FD = C.getCalleeDecl(CE); 3169226586Sdim if (!FD) 3170226586Sdim return false; 3171226586Sdim 3172226586Sdim IdentifierInfo *II = FD->getIdentifier(); 3173226586Sdim if (!II) 3174226586Sdim return false; 3175226586Sdim 3176226586Sdim // For now, we're only handling the functions that return aliases of their 3177226586Sdim // arguments: CFRetain and CFMakeCollectable (and their families). 3178226586Sdim // Eventually we should add other functions we can model entirely, 3179226586Sdim // such as CFRelease, which don't invalidate their arguments or globals. 3180226586Sdim if (CE->getNumArgs() != 1) 3181226586Sdim return false; 3182226586Sdim 3183226586Sdim // Get the name of the function. 3184226586Sdim StringRef FName = II->getName(); 3185226586Sdim FName = FName.substr(FName.find_first_not_of('_')); 3186226586Sdim 3187226586Sdim // See if it's one of the specific functions we know how to eval. 3188226586Sdim bool canEval = false; 3189226586Sdim 3190234353Sdim QualType ResultTy = CE->getCallReturnType(); 3191226586Sdim if (ResultTy->isObjCIdType()) { 3192226586Sdim // Handle: id NSMakeCollectable(CFTypeRef) 3193226586Sdim canEval = II->isStr("NSMakeCollectable"); 3194226586Sdim } else if (ResultTy->isPointerType()) { 3195226586Sdim // Handle: (CF|CG)Retain 3196226586Sdim // CFMakeCollectable 3197226586Sdim // It's okay to be a little sloppy here (CGMakeCollectable doesn't exist). 3198226586Sdim if (cocoa::isRefType(ResultTy, "CF", FName) || 3199226586Sdim cocoa::isRefType(ResultTy, "CG", FName)) { 3200226586Sdim canEval = isRetain(FD, FName) || isMakeCollectable(FD, FName); 3201226586Sdim } 3202226586Sdim } 3203226586Sdim 3204226586Sdim if (!canEval) 3205226586Sdim return false; 3206226586Sdim 3207226586Sdim // Bind the return value. 3208234353Sdim const LocationContext *LCtx = C.getLocationContext(); 3209234353Sdim SVal RetVal = state->getSVal(CE->getArg(0), LCtx); 3210226586Sdim if (RetVal.isUnknown()) { 3211226586Sdim // If the receiver is unknown, conjure a return value. 3212226586Sdim SValBuilder &SVB = C.getSValBuilder(); 3213243830Sdim RetVal = SVB.conjureSymbolVal(0, CE, LCtx, ResultTy, C.blockCount()); 3214226586Sdim } 3215234353Sdim state = state->BindExpr(CE, LCtx, RetVal, false); 3216226586Sdim 3217226586Sdim // FIXME: This should not be necessary, but otherwise the argument seems to be 3218226586Sdim // considered alive during the next statement. 3219226586Sdim if (const MemRegion *ArgRegion = RetVal.getAsRegion()) { 3220226586Sdim // Save the refcount status of the argument. 3221226586Sdim SymbolRef Sym = RetVal.getAsLocSymbol(); 3222239462Sdim const RefVal *Binding = 0; 3223226586Sdim if (Sym) 3224239462Sdim Binding = getRefBinding(state, Sym); 3225226586Sdim 3226226586Sdim // Invalidate the argument region. 3227249423Sdim state = state->invalidateRegions(ArgRegion, CE, C.blockCount(), LCtx, 3228249423Sdim /*CausesPointerEscape*/ false); 3229226586Sdim 3230226586Sdim // Restore the refcount status of the argument. 3231226586Sdim if (Binding) 3232239462Sdim state = setRefBinding(state, Sym, *Binding); 3233226586Sdim } 3234226586Sdim 3235226586Sdim C.addTransition(state); 3236226586Sdim return true; 3237226586Sdim} 3238226586Sdim 3239226586Sdim//===----------------------------------------------------------------------===// 3240226586Sdim// Handle return statements. 3241226586Sdim//===----------------------------------------------------------------------===// 3242226586Sdim 3243226586Sdimvoid RetainCountChecker::checkPreStmt(const ReturnStmt *S, 3244226586Sdim CheckerContext &C) const { 3245234353Sdim 3246234353Sdim // Only adjust the reference count if this is the top-level call frame, 3247234353Sdim // and not the result of inlining. In the future, we should do 3248234353Sdim // better checking even for inlined calls, and see if they match 3249234353Sdim // with their expected semantics (e.g., the method should return a retained 3250234353Sdim // object, etc.). 3251243830Sdim if (!C.inTopFrame()) 3252234353Sdim return; 3253234353Sdim 3254226586Sdim const Expr *RetE = S->getRetValue(); 3255226586Sdim if (!RetE) 3256226586Sdim return; 3257226586Sdim 3258234353Sdim ProgramStateRef state = C.getState(); 3259234353Sdim SymbolRef Sym = 3260234353Sdim state->getSValAsScalarOrLoc(RetE, C.getLocationContext()).getAsLocSymbol(); 3261226586Sdim if (!Sym) 3262226586Sdim return; 3263226586Sdim 3264226586Sdim // Get the reference count binding (if any). 3265239462Sdim const RefVal *T = getRefBinding(state, Sym); 3266226586Sdim if (!T) 3267226586Sdim return; 3268226586Sdim 3269226586Sdim // Change the reference count. 3270226586Sdim RefVal X = *T; 3271226586Sdim 3272226586Sdim switch (X.getKind()) { 3273226586Sdim case RefVal::Owned: { 3274226586Sdim unsigned cnt = X.getCount(); 3275226586Sdim assert(cnt > 0); 3276226586Sdim X.setCount(cnt - 1); 3277226586Sdim X = X ^ RefVal::ReturnedOwned; 3278226586Sdim break; 3279226586Sdim } 3280226586Sdim 3281226586Sdim case RefVal::NotOwned: { 3282226586Sdim unsigned cnt = X.getCount(); 3283226586Sdim if (cnt) { 3284226586Sdim X.setCount(cnt - 1); 3285226586Sdim X = X ^ RefVal::ReturnedOwned; 3286226586Sdim } 3287226586Sdim else { 3288226586Sdim X = X ^ RefVal::ReturnedNotOwned; 3289226586Sdim } 3290226586Sdim break; 3291226586Sdim } 3292226586Sdim 3293226586Sdim default: 3294226586Sdim return; 3295226586Sdim } 3296226586Sdim 3297226586Sdim // Update the binding. 3298239462Sdim state = setRefBinding(state, Sym, X); 3299234353Sdim ExplodedNode *Pred = C.addTransition(state); 3300226586Sdim 3301226586Sdim // At this point we have updated the state properly. 3302226586Sdim // Everything after this is merely checking to see if the return value has 3303226586Sdim // been over- or under-retained. 3304226586Sdim 3305226586Sdim // Did we cache out? 3306226586Sdim if (!Pred) 3307226586Sdim return; 3308226586Sdim 3309226586Sdim // Update the autorelease counts. 3310226586Sdim static SimpleProgramPointTag 3311226586Sdim AutoreleaseTag("RetainCountChecker : Autorelease"); 3312249423Sdim state = handleAutoreleaseCounts(state, Pred, &AutoreleaseTag, C, Sym, X); 3313226586Sdim 3314226586Sdim // Did we cache out? 3315249423Sdim if (!state) 3316226586Sdim return; 3317226586Sdim 3318226586Sdim // Get the updated binding. 3319239462Sdim T = getRefBinding(state, Sym); 3320226586Sdim assert(T); 3321226586Sdim X = *T; 3322226586Sdim 3323226586Sdim // Consult the summary of the enclosing method. 3324226586Sdim RetainSummaryManager &Summaries = getSummaryManager(C); 3325226586Sdim const Decl *CD = &Pred->getCodeDecl(); 3326239462Sdim RetEffect RE = RetEffect::MakeNoRet(); 3327226586Sdim 3328239462Sdim // FIXME: What is the convention for blocks? Is there one? 3329226586Sdim if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(CD)) { 3330226586Sdim const RetainSummary *Summ = Summaries.getMethodSummary(MD); 3331239462Sdim RE = Summ->getRetEffect(); 3332239462Sdim } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CD)) { 3333239462Sdim if (!isa<CXXMethodDecl>(FD)) { 3334239462Sdim const RetainSummary *Summ = Summaries.getFunctionSummary(FD); 3335239462Sdim RE = Summ->getRetEffect(); 3336239462Sdim } 3337226586Sdim } 3338226586Sdim 3339239462Sdim checkReturnWithRetEffect(S, C, Pred, RE, X, Sym, state); 3340226586Sdim} 3341226586Sdim 3342226586Sdimvoid RetainCountChecker::checkReturnWithRetEffect(const ReturnStmt *S, 3343226586Sdim CheckerContext &C, 3344226586Sdim ExplodedNode *Pred, 3345226586Sdim RetEffect RE, RefVal X, 3346226586Sdim SymbolRef Sym, 3347234353Sdim ProgramStateRef state) const { 3348226586Sdim // Any leaks or other errors? 3349226586Sdim if (X.isReturnedOwned() && X.getCount() == 0) { 3350226586Sdim if (RE.getKind() != RetEffect::NoRet) { 3351226586Sdim bool hasError = false; 3352226586Sdim if (C.isObjCGCEnabled() && RE.getObjKind() == RetEffect::ObjC) { 3353226586Sdim // Things are more complicated with garbage collection. If the 3354226586Sdim // returned object is suppose to be an Objective-C object, we have 3355226586Sdim // a leak (as the caller expects a GC'ed object) because no 3356226586Sdim // method should return ownership unless it returns a CF object. 3357226586Sdim hasError = true; 3358226586Sdim X = X ^ RefVal::ErrorGCLeakReturned; 3359226586Sdim } 3360226586Sdim else if (!RE.isOwned()) { 3361226586Sdim // Either we are using GC and the returned object is a CF type 3362226586Sdim // or we aren't using GC. In either case, we expect that the 3363226586Sdim // enclosing method is expected to return ownership. 3364226586Sdim hasError = true; 3365226586Sdim X = X ^ RefVal::ErrorLeakReturned; 3366226586Sdim } 3367226586Sdim 3368226586Sdim if (hasError) { 3369226586Sdim // Generate an error node. 3370239462Sdim state = setRefBinding(state, Sym, X); 3371226586Sdim 3372226586Sdim static SimpleProgramPointTag 3373226586Sdim ReturnOwnLeakTag("RetainCountChecker : ReturnsOwnLeak"); 3374234353Sdim ExplodedNode *N = C.addTransition(state, Pred, &ReturnOwnLeakTag); 3375226586Sdim if (N) { 3376234353Sdim const LangOptions &LOpts = C.getASTContext().getLangOpts(); 3377226586Sdim bool GCEnabled = C.isObjCGCEnabled(); 3378226586Sdim CFRefReport *report = 3379226586Sdim new CFRefLeakReport(*getLeakAtReturnBug(LOpts, GCEnabled), 3380226586Sdim LOpts, GCEnabled, SummaryLog, 3381251662Sdim N, Sym, C, IncludeAllocationLine); 3382251662Sdim 3383243830Sdim C.emitReport(report); 3384226586Sdim } 3385226586Sdim } 3386226586Sdim } 3387226586Sdim } else if (X.isReturnedNotOwned()) { 3388226586Sdim if (RE.isOwned()) { 3389226586Sdim // Trying to return a not owned object to a caller expecting an 3390226586Sdim // owned object. 3391239462Sdim state = setRefBinding(state, Sym, X ^ RefVal::ErrorReturnedNotOwned); 3392226586Sdim 3393226586Sdim static SimpleProgramPointTag 3394226586Sdim ReturnNotOwnedTag("RetainCountChecker : ReturnNotOwnedForOwned"); 3395234353Sdim ExplodedNode *N = C.addTransition(state, Pred, &ReturnNotOwnedTag); 3396226586Sdim if (N) { 3397226586Sdim if (!returnNotOwnedForOwned) 3398226586Sdim returnNotOwnedForOwned.reset(new ReturnedNotOwnedForOwned()); 3399226586Sdim 3400226586Sdim CFRefReport *report = 3401226586Sdim new CFRefReport(*returnNotOwnedForOwned, 3402234353Sdim C.getASTContext().getLangOpts(), 3403226586Sdim C.isObjCGCEnabled(), SummaryLog, N, Sym); 3404243830Sdim C.emitReport(report); 3405226586Sdim } 3406226586Sdim } 3407226586Sdim } 3408226586Sdim} 3409226586Sdim 3410226586Sdim//===----------------------------------------------------------------------===// 3411226586Sdim// Check various ways a symbol can be invalidated. 3412226586Sdim//===----------------------------------------------------------------------===// 3413226586Sdim 3414226586Sdimvoid RetainCountChecker::checkBind(SVal loc, SVal val, const Stmt *S, 3415226586Sdim CheckerContext &C) const { 3416226586Sdim // Are we storing to something that causes the value to "escape"? 3417226586Sdim bool escapes = true; 3418226586Sdim 3419226586Sdim // A value escapes in three possible cases (this may change): 3420226586Sdim // 3421226586Sdim // (1) we are binding to something that is not a memory region. 3422226586Sdim // (2) we are binding to a memregion that does not have stack storage 3423226586Sdim // (3) we are binding to a memregion with stack storage that the store 3424226586Sdim // does not understand. 3425234353Sdim ProgramStateRef state = C.getState(); 3426226586Sdim 3427249423Sdim if (Optional<loc::MemRegionVal> regionLoc = loc.getAs<loc::MemRegionVal>()) { 3428226586Sdim escapes = !regionLoc->getRegion()->hasStackStorage(); 3429226586Sdim 3430226586Sdim if (!escapes) { 3431226586Sdim // To test (3), generate a new state with the binding added. If it is 3432226586Sdim // the same state, then it escapes (since the store cannot represent 3433226586Sdim // the binding). 3434239462Sdim // Do this only if we know that the store is not supposed to generate the 3435239462Sdim // same state. 3436239462Sdim SVal StoredVal = state->getSVal(regionLoc->getRegion()); 3437239462Sdim if (StoredVal != val) 3438239462Sdim escapes = (state == (state->bindLoc(*regionLoc, val))); 3439226586Sdim } 3440234353Sdim if (!escapes) { 3441234353Sdim // Case 4: We do not currently model what happens when a symbol is 3442234353Sdim // assigned to a struct field, so be conservative here and let the symbol 3443234353Sdim // go. TODO: This could definitely be improved upon. 3444234353Sdim escapes = !isa<VarRegion>(regionLoc->getRegion()); 3445234353Sdim } 3446226586Sdim } 3447226586Sdim 3448226586Sdim // If our store can represent the binding and we aren't storing to something 3449226586Sdim // that doesn't have local storage then just return and have the simulation 3450226586Sdim // state continue as is. 3451226586Sdim if (!escapes) 3452226586Sdim return; 3453226586Sdim 3454226586Sdim // Otherwise, find all symbols referenced by 'val' that we are tracking 3455226586Sdim // and stop tracking them. 3456226586Sdim state = state->scanReachableSymbols<StopTrackingCallback>(val).getState(); 3457226586Sdim C.addTransition(state); 3458226586Sdim} 3459226586Sdim 3460234353SdimProgramStateRef RetainCountChecker::evalAssume(ProgramStateRef state, 3461226586Sdim SVal Cond, 3462226586Sdim bool Assumption) const { 3463226586Sdim 3464226586Sdim // FIXME: We may add to the interface of evalAssume the list of symbols 3465226586Sdim // whose assumptions have changed. For now we just iterate through the 3466226586Sdim // bindings and check if any of the tracked symbols are NULL. This isn't 3467226586Sdim // too bad since the number of symbols we will track in practice are 3468226586Sdim // probably small and evalAssume is only called at branches and a few 3469226586Sdim // other places. 3470243830Sdim RefBindingsTy B = state->get<RefBindings>(); 3471226586Sdim 3472226586Sdim if (B.isEmpty()) 3473226586Sdim return state; 3474226586Sdim 3475226586Sdim bool changed = false; 3476243830Sdim RefBindingsTy::Factory &RefBFactory = state->get_context<RefBindings>(); 3477226586Sdim 3478243830Sdim for (RefBindingsTy::iterator I = B.begin(), E = B.end(); I != E; ++I) { 3479243830Sdim // Check if the symbol is null stop tracking the symbol. 3480243830Sdim ConstraintManager &CMgr = state->getConstraintManager(); 3481243830Sdim ConditionTruthVal AllocFailed = CMgr.isNull(state, I.getKey()); 3482243830Sdim if (AllocFailed.isConstrainedTrue()) { 3483226586Sdim changed = true; 3484226586Sdim B = RefBFactory.remove(B, I.getKey()); 3485226586Sdim } 3486226586Sdim } 3487226586Sdim 3488226586Sdim if (changed) 3489226586Sdim state = state->set<RefBindings>(B); 3490226586Sdim 3491226586Sdim return state; 3492226586Sdim} 3493226586Sdim 3494234353SdimProgramStateRef 3495234353SdimRetainCountChecker::checkRegionChanges(ProgramStateRef state, 3496249423Sdim const InvalidatedSymbols *invalidated, 3497226586Sdim ArrayRef<const MemRegion *> ExplicitRegions, 3498234353Sdim ArrayRef<const MemRegion *> Regions, 3499239462Sdim const CallEvent *Call) const { 3500226586Sdim if (!invalidated) 3501226586Sdim return state; 3502226586Sdim 3503226586Sdim llvm::SmallPtrSet<SymbolRef, 8> WhitelistedSymbols; 3504226586Sdim for (ArrayRef<const MemRegion *>::iterator I = ExplicitRegions.begin(), 3505226586Sdim E = ExplicitRegions.end(); I != E; ++I) { 3506226586Sdim if (const SymbolicRegion *SR = (*I)->StripCasts()->getAs<SymbolicRegion>()) 3507226586Sdim WhitelistedSymbols.insert(SR->getSymbol()); 3508226586Sdim } 3509226586Sdim 3510249423Sdim for (InvalidatedSymbols::const_iterator I=invalidated->begin(), 3511226586Sdim E = invalidated->end(); I!=E; ++I) { 3512226586Sdim SymbolRef sym = *I; 3513226586Sdim if (WhitelistedSymbols.count(sym)) 3514226586Sdim continue; 3515226586Sdim // Remove any existing reference-count binding. 3516239462Sdim state = removeRefBinding(state, sym); 3517226586Sdim } 3518226586Sdim return state; 3519226586Sdim} 3520226586Sdim 3521226586Sdim//===----------------------------------------------------------------------===// 3522226586Sdim// Handle dead symbols and end-of-path. 3523226586Sdim//===----------------------------------------------------------------------===// 3524226586Sdim 3525249423SdimProgramStateRef 3526249423SdimRetainCountChecker::handleAutoreleaseCounts(ProgramStateRef state, 3527234353Sdim ExplodedNode *Pred, 3528243830Sdim const ProgramPointTag *Tag, 3529234353Sdim CheckerContext &Ctx, 3530226586Sdim SymbolRef Sym, RefVal V) const { 3531226586Sdim unsigned ACnt = V.getAutoreleaseCount(); 3532226586Sdim 3533226586Sdim // No autorelease counts? Nothing to be done. 3534226586Sdim if (!ACnt) 3535249423Sdim return state; 3536226586Sdim 3537234353Sdim assert(!Ctx.isObjCGCEnabled() && "Autorelease counts in GC mode?"); 3538226586Sdim unsigned Cnt = V.getCount(); 3539226586Sdim 3540226586Sdim // FIXME: Handle sending 'autorelease' to already released object. 3541226586Sdim 3542226586Sdim if (V.getKind() == RefVal::ReturnedOwned) 3543226586Sdim ++Cnt; 3544226586Sdim 3545226586Sdim if (ACnt <= Cnt) { 3546226586Sdim if (ACnt == Cnt) { 3547226586Sdim V.clearCounts(); 3548226586Sdim if (V.getKind() == RefVal::ReturnedOwned) 3549226586Sdim V = V ^ RefVal::ReturnedNotOwned; 3550226586Sdim else 3551226586Sdim V = V ^ RefVal::NotOwned; 3552226586Sdim } else { 3553249423Sdim V.setCount(V.getCount() - ACnt); 3554226586Sdim V.setAutoreleaseCount(0); 3555226586Sdim } 3556249423Sdim return setRefBinding(state, Sym, V); 3557226586Sdim } 3558226586Sdim 3559226586Sdim // Woah! More autorelease counts then retain counts left. 3560226586Sdim // Emit hard error. 3561226586Sdim V = V ^ RefVal::ErrorOverAutorelease; 3562239462Sdim state = setRefBinding(state, Sym, V); 3563226586Sdim 3564243830Sdim ExplodedNode *N = Ctx.generateSink(state, Pred, Tag); 3565243830Sdim if (N) { 3566234353Sdim SmallString<128> sbuf; 3567226586Sdim llvm::raw_svector_ostream os(sbuf); 3568251662Sdim os << "Object was autoreleased "; 3569226586Sdim if (V.getAutoreleaseCount() > 1) 3570251662Sdim os << V.getAutoreleaseCount() << " times but the object "; 3571251662Sdim else 3572251662Sdim os << "but "; 3573251662Sdim os << "has a +" << V.getCount() << " retain count"; 3574226586Sdim 3575226586Sdim if (!overAutorelease) 3576226586Sdim overAutorelease.reset(new OverAutorelease()); 3577226586Sdim 3578234353Sdim const LangOptions &LOpts = Ctx.getASTContext().getLangOpts(); 3579226586Sdim CFRefReport *report = 3580226586Sdim new CFRefReport(*overAutorelease, LOpts, /* GCEnabled = */ false, 3581226586Sdim SummaryLog, N, Sym, os.str()); 3582243830Sdim Ctx.emitReport(report); 3583226586Sdim } 3584226586Sdim 3585249423Sdim return 0; 3586226586Sdim} 3587226586Sdim 3588234353SdimProgramStateRef 3589234353SdimRetainCountChecker::handleSymbolDeath(ProgramStateRef state, 3590226586Sdim SymbolRef sid, RefVal V, 3591226586Sdim SmallVectorImpl<SymbolRef> &Leaked) const { 3592226586Sdim bool hasLeak = false; 3593226586Sdim if (V.isOwned()) 3594226586Sdim hasLeak = true; 3595226586Sdim else if (V.isNotOwned() || V.isReturnedOwned()) 3596226586Sdim hasLeak = (V.getCount() > 0); 3597226586Sdim 3598226586Sdim if (!hasLeak) 3599239462Sdim return removeRefBinding(state, sid); 3600226586Sdim 3601226586Sdim Leaked.push_back(sid); 3602239462Sdim return setRefBinding(state, sid, V ^ RefVal::ErrorLeak); 3603226586Sdim} 3604226586Sdim 3605226586SdimExplodedNode * 3606234353SdimRetainCountChecker::processLeaks(ProgramStateRef state, 3607226586Sdim SmallVectorImpl<SymbolRef> &Leaked, 3608234353Sdim CheckerContext &Ctx, 3609234353Sdim ExplodedNode *Pred) const { 3610226586Sdim // Generate an intermediate node representing the leak point. 3611243830Sdim ExplodedNode *N = Ctx.addTransition(state, Pred); 3612226586Sdim 3613226586Sdim if (N) { 3614226586Sdim for (SmallVectorImpl<SymbolRef>::iterator 3615226586Sdim I = Leaked.begin(), E = Leaked.end(); I != E; ++I) { 3616226586Sdim 3617234353Sdim const LangOptions &LOpts = Ctx.getASTContext().getLangOpts(); 3618234353Sdim bool GCEnabled = Ctx.isObjCGCEnabled(); 3619226586Sdim CFRefBug *BT = Pred ? getLeakWithinFunctionBug(LOpts, GCEnabled) 3620226586Sdim : getLeakAtReturnBug(LOpts, GCEnabled); 3621226586Sdim assert(BT && "BugType not initialized."); 3622226586Sdim 3623226586Sdim CFRefLeakReport *report = new CFRefLeakReport(*BT, LOpts, GCEnabled, 3624251662Sdim SummaryLog, N, *I, Ctx, 3625251662Sdim IncludeAllocationLine); 3626243830Sdim Ctx.emitReport(report); 3627226586Sdim } 3628226586Sdim } 3629226586Sdim 3630226586Sdim return N; 3631226586Sdim} 3632226586Sdim 3633249423Sdimvoid RetainCountChecker::checkEndFunction(CheckerContext &Ctx) const { 3634234353Sdim ProgramStateRef state = Ctx.getState(); 3635243830Sdim RefBindingsTy B = state->get<RefBindings>(); 3636234353Sdim ExplodedNode *Pred = Ctx.getPredecessor(); 3637226586Sdim 3638243830Sdim for (RefBindingsTy::iterator I = B.begin(), E = B.end(); I != E; ++I) { 3639249423Sdim state = handleAutoreleaseCounts(state, Pred, /*Tag=*/0, Ctx, 3640249423Sdim I->first, I->second); 3641226586Sdim if (!state) 3642226586Sdim return; 3643226586Sdim } 3644226586Sdim 3645234353Sdim // If the current LocationContext has a parent, don't check for leaks. 3646234353Sdim // We will do that later. 3647239462Sdim // FIXME: we should instead check for imbalances of the retain/releases, 3648234353Sdim // and suggest annotations. 3649234353Sdim if (Ctx.getLocationContext()->getParent()) 3650234353Sdim return; 3651234353Sdim 3652226586Sdim B = state->get<RefBindings>(); 3653226586Sdim SmallVector<SymbolRef, 10> Leaked; 3654226586Sdim 3655243830Sdim for (RefBindingsTy::iterator I = B.begin(), E = B.end(); I != E; ++I) 3656226586Sdim state = handleSymbolDeath(state, I->first, I->second, Leaked); 3657226586Sdim 3658243830Sdim processLeaks(state, Leaked, Ctx, Pred); 3659226586Sdim} 3660226586Sdim 3661226586Sdimconst ProgramPointTag * 3662226586SdimRetainCountChecker::getDeadSymbolTag(SymbolRef sym) const { 3663226586Sdim const SimpleProgramPointTag *&tag = DeadSymbolTags[sym]; 3664226586Sdim if (!tag) { 3665234353Sdim SmallString<64> buf; 3666226586Sdim llvm::raw_svector_ostream out(buf); 3667234353Sdim out << "RetainCountChecker : Dead Symbol : "; 3668234353Sdim sym->dumpToStream(out); 3669226586Sdim tag = new SimpleProgramPointTag(out.str()); 3670226586Sdim } 3671226586Sdim return tag; 3672226586Sdim} 3673226586Sdim 3674226586Sdimvoid RetainCountChecker::checkDeadSymbols(SymbolReaper &SymReaper, 3675226586Sdim CheckerContext &C) const { 3676226586Sdim ExplodedNode *Pred = C.getPredecessor(); 3677226586Sdim 3678234353Sdim ProgramStateRef state = C.getState(); 3679243830Sdim RefBindingsTy B = state->get<RefBindings>(); 3680249423Sdim SmallVector<SymbolRef, 10> Leaked; 3681226586Sdim 3682226586Sdim // Update counts from autorelease pools 3683226586Sdim for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(), 3684226586Sdim E = SymReaper.dead_end(); I != E; ++I) { 3685226586Sdim SymbolRef Sym = *I; 3686226586Sdim if (const RefVal *T = B.lookup(Sym)){ 3687226586Sdim // Use the symbol as the tag. 3688226586Sdim // FIXME: This might not be as unique as we would like. 3689243830Sdim const ProgramPointTag *Tag = getDeadSymbolTag(Sym); 3690249423Sdim state = handleAutoreleaseCounts(state, Pred, Tag, C, Sym, *T); 3691226586Sdim if (!state) 3692226586Sdim return; 3693249423Sdim 3694249423Sdim // Fetch the new reference count from the state, and use it to handle 3695249423Sdim // this symbol. 3696249423Sdim state = handleSymbolDeath(state, *I, *getRefBinding(state, Sym), Leaked); 3697226586Sdim } 3698226586Sdim } 3699226586Sdim 3700249423Sdim if (Leaked.empty()) { 3701249423Sdim C.addTransition(state); 3702249423Sdim return; 3703226586Sdim } 3704226586Sdim 3705243830Sdim Pred = processLeaks(state, Leaked, C, Pred); 3706226586Sdim 3707226586Sdim // Did we cache out? 3708226586Sdim if (!Pred) 3709226586Sdim return; 3710226586Sdim 3711226586Sdim // Now generate a new node that nukes the old bindings. 3712249423Sdim // The only bindings left at this point are the leaked symbols. 3713243830Sdim RefBindingsTy::Factory &F = state->get_context<RefBindings>(); 3714249423Sdim B = state->get<RefBindings>(); 3715226586Sdim 3716249423Sdim for (SmallVectorImpl<SymbolRef>::iterator I = Leaked.begin(), 3717249423Sdim E = Leaked.end(); 3718249423Sdim I != E; ++I) 3719226586Sdim B = F.remove(B, *I); 3720226586Sdim 3721226586Sdim state = state->set<RefBindings>(B); 3722234353Sdim C.addTransition(state, Pred); 3723226586Sdim} 3724226586Sdim 3725234353Sdimvoid RetainCountChecker::printState(raw_ostream &Out, ProgramStateRef State, 3726226586Sdim const char *NL, const char *Sep) const { 3727226586Sdim 3728243830Sdim RefBindingsTy B = State->get<RefBindings>(); 3729226586Sdim 3730249423Sdim if (B.isEmpty()) 3731249423Sdim return; 3732226586Sdim 3733249423Sdim Out << Sep << NL; 3734249423Sdim 3735243830Sdim for (RefBindingsTy::iterator I = B.begin(), E = B.end(); I != E; ++I) { 3736226586Sdim Out << I->first << " : "; 3737226586Sdim I->second.print(Out); 3738226586Sdim Out << NL; 3739226586Sdim } 3740226586Sdim} 3741226586Sdim 3742226586Sdim//===----------------------------------------------------------------------===// 3743226586Sdim// Checker registration. 3744226586Sdim//===----------------------------------------------------------------------===// 3745226586Sdim 3746226586Sdimvoid ento::registerRetainCountChecker(CheckerManager &Mgr) { 3747251662Sdim Mgr.registerChecker<RetainCountChecker>(Mgr.getAnalyzerOptions()); 3748226586Sdim} 3749226586Sdim 3750