diff options
author | Mike Stump <mrs@apple.com> | 2009-09-09 15:08:12 +0000 |
---|---|---|
committer | Mike Stump <mrs@apple.com> | 2009-09-09 15:08:12 +0000 |
commit | 1eb4433ac451dc16f4133a88af2d002ac26c58ef (patch) | |
tree | 07065b80cb7787bb7b9ffcb985196007a57e86f7 /lib/Analysis/CFRefCount.cpp | |
parent | 79d39f92590cf2e91bf81486b02cd1156d13ca54 (diff) |
Remove tabs, and whitespace cleanups.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@81346 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Analysis/CFRefCount.cpp')
-rw-r--r-- | lib/Analysis/CFRefCount.cpp | 1275 |
1 files changed, 637 insertions, 638 deletions
diff --git a/lib/Analysis/CFRefCount.cpp b/lib/Analysis/CFRefCount.cpp index 9cd59c2c14..e511f76195 100644 --- a/lib/Analysis/CFRefCount.cpp +++ b/lib/Analysis/CFRefCount.cpp @@ -22,7 +22,7 @@ #include "clang/Analysis/PathSensitive/BugReporter.h" #include "clang/Analysis/PathSensitive/SymbolManager.h" #include "clang/Analysis/PathSensitive/GRTransferFuncs.h" -#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclObjC.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/ImmutableMap.h" @@ -44,7 +44,7 @@ using namespace clang; // MemoryMgmt/Tasks/MemoryManagementRules.html // // "You take ownership of an object if you create it using a method whose name -// begins with "alloc" or "new" or contains "copy" (for example, alloc, +// begins with "alloc" or "new" or contains "copy" (for example, alloc, // newObject, or mutableCopy), or if you send it a retain message. You are // responsible for relinquishing ownership of objects you own using release // or autorelease. Any other time you receive an object, you must @@ -62,8 +62,8 @@ static inline bool isWordEnd(char ch, char prev, char next) { || (isupper(prev) && isupper(ch) && islower(next)) // XXCreate || !isalpha(ch); } - -static inline const char* parseWord(const char* s) { + +static inline const char* parseWord(const char* s) { char ch = *s, prev = '\0'; assert(ch != '\0'); char next = *(s+1); @@ -77,18 +77,18 @@ static inline const char* parseWord(const char* s) { static NamingConvention deriveNamingConvention(Selector S) { IdentifierInfo *II = S.getIdentifierInfoForSlot(0); - + if (!II) return NoConvention; - + const char *s = II->getName(); - + // A method/function name may contain a prefix. We don't know it is there, // however, until we encounter the first '_'. bool InPossiblePrefix = true; bool AtBeginning = true; NamingConvention C = NoConvention; - + while (*s != '\0') { // Skip '_'. if (*s == '_') { @@ -103,24 +103,24 @@ static NamingConvention deriveNamingConvention(Selector S) { ++s; continue; } - + // Skip numbers, ':', etc. if (!isalpha(*s)) { ++s; continue; } - + const char *wordEnd = parseWord(s); assert(wordEnd > s); unsigned len = wordEnd - s; - + switch (len) { default: break; case 3: // Methods starting with 'new' follow the create rule. if (AtBeginning && StringsEqualNoCase("new", s, len)) - C = CreateRule; + C = CreateRule; break; case 4: // Methods starting with 'alloc' or contain 'copy' follow the @@ -136,7 +136,7 @@ static NamingConvention deriveNamingConvention(Selector S) { C = CreateRule; break; } - + // If we aren't in the prefix and have a derived convention then just // return it now. if (!InPossiblePrefix && C != NoConvention) @@ -156,10 +156,10 @@ static bool followsFundamentalRule(Selector S) { } static const ObjCMethodDecl* -ResolveToInterfaceMethodDecl(const ObjCMethodDecl *MD) { +ResolveToInterfaceMethodDecl(const ObjCMethodDecl *MD) { ObjCInterfaceDecl *ID = const_cast<ObjCInterfaceDecl*>(MD->getClassInterface()); - + return MD->isInstanceMethod() ? ID->lookupInstanceMethod(MD->getSelector()) : ID->lookupClassMethod(MD->getSelector()); @@ -178,12 +178,12 @@ public: GenericNodeBuilder(GREndPathNodeBuilder &enb) : SNB(0), S(0), tag(0), ENB(&enb) {} - + ExplodedNode *MakeNode(const GRState *state, ExplodedNode *Pred) { if (SNB) - return SNB->generateNode(PostStmt(S, Pred->getLocationContext(), tag), + return SNB->generateNode(PostStmt(S, Pred->getLocationContext(), tag), state, Pred); - + assert(ENB); return ENB->generateNode(state, Pred); } @@ -211,16 +211,16 @@ static inline Selector GetUnarySelector(const char* name, ASTContext& Ctx) { static bool hasPrefix(const char* s, const char* prefix) { if (!prefix) return true; - + char c = *s; char cP = *prefix; - + while (c != '\0' && cP != '\0') { if (c != cP) break; c = *(++s); cP = *(++prefix); } - + return cP == '\0'; } @@ -231,14 +231,14 @@ static bool hasSuffix(const char* s, const char* suffix) { static bool isRefType(QualType RetTy, const char* prefix, ASTContext* Ctx = 0, const char* name = 0) { - + // Recursively walk the typedef stack, allowing typedefs of reference types. while (1) { if (TypedefType* TD = dyn_cast<TypedefType>(RetTy.getTypePtr())) { const char* TDName = TD->getDecl()->getIdentifier()->getName(); if (hasPrefix(TDName, prefix) && hasSuffix(TDName, "Ref")) return true; - + RetTy = TD->getDecl()->getUnderlyingType(); continue; } @@ -282,14 +282,14 @@ typedef llvm::ImmutableMap<unsigned,ArgEffect> ArgEffects; namespace { /// RetEffect is used to summarize a function/method call's behavior with -/// respect to its return value. +/// respect to its return value. class VISIBILITY_HIDDEN RetEffect { public: enum Kind { NoRet, Alias, OwnedSymbol, OwnedAllocatedSymbol, NotOwnedSymbol, GCNotOwnedSymbol, ReceiverAlias, OwnedWhenTrackedReceiver }; - - enum ObjKind { CF, ObjC, AnyObj }; + + enum ObjKind { CF, ObjC, AnyObj }; private: Kind K; @@ -298,124 +298,124 @@ private: RetEffect(Kind k, unsigned idx = 0) : K(k), O(AnyObj), index(idx) {} RetEffect(Kind k, ObjKind o) : K(k), O(o), index(0) {} - + public: Kind getKind() const { return K; } ObjKind getObjKind() const { return O; } - - unsigned getIndex() const { + + unsigned getIndex() const { assert(getKind() == Alias); return index; } - + bool isOwned() const { return K == OwnedSymbol || K == OwnedAllocatedSymbol || K == OwnedWhenTrackedReceiver; } - + static RetEffect MakeOwnedWhenTrackedReceiver() { return RetEffect(OwnedWhenTrackedReceiver, ObjC); } - + static RetEffect MakeAlias(unsigned Idx) { return RetEffect(Alias, Idx); } static RetEffect MakeReceiverAlias() { return RetEffect(ReceiverAlias); - } + } static RetEffect MakeOwned(ObjKind o, bool isAllocated = false) { return RetEffect(isAllocated ? OwnedAllocatedSymbol : OwnedSymbol, o); - } + } static RetEffect MakeNotOwned(ObjKind o) { return RetEffect(NotOwnedSymbol, o); } static RetEffect MakeGCNotOwned() { return RetEffect(GCNotOwnedSymbol, ObjC); } - + static RetEffect MakeNoRet() { return RetEffect(NoRet); } - + void Profile(llvm::FoldingSetNodeID& ID) const { ID.AddInteger((unsigned)K); ID.AddInteger((unsigned)O); ID.AddInteger(index); } }; - - + + class VISIBILITY_HIDDEN RetainSummary { /// Args - an ordered vector of (index, ArgEffect) pairs, where index /// specifies the argument (starting from 0). This can be sparsely /// populated; arguments with no entry in Args use 'DefaultArgEffect'. ArgEffects Args; - + /// DefaultArgEffect - The default ArgEffect to apply to arguments that /// do not have an entry in Args. ArgEffect DefaultArgEffect; - + /// Receiver - If this summary applies to an Objective-C message expression, /// this is the effect applied to the state of the receiver. ArgEffect Receiver; - + /// Ret - The effect on the return value. Used to indicate if the /// function/method call returns a new tracked symbol, returns an /// alias of one of the arguments in the call, and so on. RetEffect Ret; - + /// EndPath - Indicates that execution of this method/function should /// terminate the simulation of a path. bool EndPath; - + public: RetainSummary(ArgEffects A, RetEffect R, ArgEffect defaultEff, ArgEffect ReceiverEff, bool endpath = false) : Args(A), DefaultArgEffect(defaultEff), Receiver(ReceiverEff), Ret(R), - EndPath(endpath) {} - + EndPath(endpath) {} + /// getArg - Return the argument effect on the argument specified by /// idx (starting from 0). ArgEffect getArg(unsigned idx) const { if (const ArgEffect *AE = Args.lookup(idx)) return *AE; - + return DefaultArgEffect; } - + /// setDefaultArgEffect - Set the default argument effect. void setDefaultArgEffect(ArgEffect E) { DefaultArgEffect = E; } - + /// setArg - Set the argument effect on the argument specified by idx. void setArgEffect(ArgEffects::Factory& AF, unsigned idx, ArgEffect E) { Args = AF.Add(Args, idx, E); } - + /// getRetEffect - Returns the effect on the return value of the call. RetEffect getRetEffect() const { return Ret; } - + /// setRetEffect - Set the effect of the return value of the call. void setRetEffect(RetEffect E) { Ret = E; } - + /// isEndPath - Returns true if executing the given method/function should /// terminate the path. bool isEndPath() const { return EndPath; } - + /// getReceiverEffect - Returns the effect on the receiver of the call. /// This is only meaningful if the summary applies to an ObjCMessageExpr*. ArgEffect getReceiverEffect() const { return Receiver; } - + /// setReceiverEffect - Set the effect on the receiver of the call. void setReceiverEffect(ArgEffect E) { Receiver = E; } - + typedef ArgEffects::iterator ExprIterator; - + ExprIterator begin_args() const { return Args.begin(); } ExprIterator end_args() const { return Args.end(); } - + static void Profile(llvm::FoldingSetNodeID& ID, ArgEffects A, RetEffect RetEff, ArgEffect DefaultEff, ArgEffect ReceiverEff, bool EndPath) { @@ -425,7 +425,7 @@ public: ID.AddInteger((unsigned) ReceiverEff); ID.AddInteger((unsigned) EndPath); } - + void Profile(llvm::FoldingSetNodeID& ID) const { Profile(ID, Args, Ret, DefaultArgEffect, Receiver, EndPath); } @@ -440,7 +440,7 @@ namespace { class VISIBILITY_HIDDEN ObjCSummaryKey { IdentifierInfo* II; Selector S; -public: +public: ObjCSummaryKey(IdentifierInfo* ii, Selector s) : II(ii), S(s) {} @@ -449,10 +449,10 @@ public: ObjCSummaryKey(const ObjCInterfaceDecl* d, IdentifierInfo *ii, Selector s) : II(d ? d->getIdentifier() : ii), S(s) {} - + ObjCSummaryKey(Selector s) : II(0), S(s) {} - + IdentifierInfo* getIdentifier() const { return II; } Selector getSelector() const { return S; } }; @@ -464,56 +464,56 @@ template <> struct DenseMapInfo<ObjCSummaryKey> { return ObjCSummaryKey(DenseMapInfo<IdentifierInfo*>::getEmptyKey(), DenseMapInfo<Selector>::getEmptyKey()); } - + static inline ObjCSummaryKey getTombstoneKey() { return ObjCSummaryKey(DenseMapInfo<IdentifierInfo*>::getTombstoneKey(), - DenseMapInfo<Selector>::getTombstoneKey()); + DenseMapInfo<Selector>::getTombstoneKey()); } - + static unsigned getHashValue(const ObjCSummaryKey &V) { return (DenseMapInfo<IdentifierInfo*>::getHashValue(V.getIdentifier()) - & 0x88888888) + & 0x88888888) | (DenseMapInfo<Selector>::getHashValue(V.getSelector()) & 0x55555555); } - + static bool isEqual(const ObjCSummaryKey& LHS, const ObjCSummaryKey& RHS) { return DenseMapInfo<IdentifierInfo*>::isEqual(LHS.getIdentifier(), RHS.getIdentifier()) && DenseMapInfo<Selector>::isEqual(LHS.getSelector(), RHS.getSelector()); } - + static bool isPod() { return DenseMapInfo<ObjCInterfaceDecl*>::isPod() && DenseMapInfo<Selector>::isPod(); } }; } // end llvm namespace - + namespace { class VISIBILITY_HIDDEN ObjCSummaryCache { typedef llvm::DenseMap<ObjCSummaryKey, RetainSummary*> MapTy; MapTy M; public: ObjCSummaryCache() {} - + RetainSummary* find(const ObjCInterfaceDecl* D, IdentifierInfo *ClsName, Selector S) { // Lookup the method using the decl for the class @interface. If we // have no decl, lookup using the class name. return D ? find(D, S) : find(ClsName, S); } - - RetainSummary* find(const ObjCInterfaceDecl* D, Selector S) { + + RetainSummary* find(const ObjCInterfaceDecl* D, Selector S) { // Do a lookup with the (D,S) pair. If we find a match return // the iterator. ObjCSummaryKey K(D, S); MapTy::iterator I = M.find(K); - + if (I != M.end() || !D) return I->second; - + // Walk the super chain. If we find a hit with a parent, we'll end // up returning that summary. We actually allow that key (null,S), as // we cache summaries for the null ObjCInterfaceDecl* to allow us to @@ -523,62 +523,62 @@ public: for (ObjCInterfaceDecl* C=D->getSuperClass() ;; C=C->getSuperClass()) { if ((I = M.find(ObjCSummaryKey(C, S))) != M.end()) break; - + if (!C) return NULL; } - - // Cache the summary with original key to make the next lookup faster + + // Cache the summary with original key to make the next lookup faster // and return the iterator. RetainSummary *Summ = I->second; M[K] = Summ; return Summ; } - + RetainSummary* find(Expr* Receiver, Selector S) { return find(getReceiverDecl(Receiver), S); } - + RetainSummary* find(IdentifierInfo* II, Selector S) { // FIXME: Class method lookup. Right now we dont' have a good way // of going between IdentifierInfo* and the class hierarchy. MapTy::iterator I = M.find(ObjCSummaryKey(II, S)); - + if (I == M.end()) I = M.find(ObjCSummaryKey(S)); - + return I == M.end() ? NULL : I->second; } - - const ObjCInterfaceDecl* getReceiverDecl(Expr* E) { + + const ObjCInterfaceDecl* getReceiverDecl(Expr* E) { if (const ObjCObjectPointerType* PT = E->getType()->getAsObjCObjectPointerType()) return PT->getInterfaceDecl(); return NULL; } - + RetainSummary*& operator[](ObjCMessageExpr* ME) { - + Selector S = ME->getSelector(); - + if (Expr* Receiver = ME->getReceiver()) { const ObjCInterfaceDecl* OD = getReceiverDecl(Receiver); return OD ? M[ObjCSummaryKey(OD->getIdentifier(), S)] : M[S]; } - + return M[ObjCSummaryKey(ME->getClassName(), S)]; } - + RetainSummary*& operator[](ObjCSummaryKey K) { return M[K]; } - + RetainSummary*& operator[](Selector S) { return M[ ObjCSummaryKey(S) ]; } -}; +}; } // end anonymous namespace //===----------------------------------------------------------------------===// @@ -591,29 +591,29 @@ class VISIBILITY_HIDDEN RetainSummaryManager { //==-----------------------------------------------------------------==// // Typedefs. //==-----------------------------------------------------------------==// - + typedef llvm::DenseMap<FunctionDecl*, RetainSummary*> FuncSummariesTy; - + typedef ObjCSummaryCache ObjCMethodSummariesTy; - + //==-----------------------------------------------------------------==// // Data. //==-----------------------------------------------------------------==// - + /// Ctx - The ASTContext object for the analyzed ASTs. ASTContext& Ctx; /// CFDictionaryCreateII - An IdentifierInfo* representing the indentifier /// "CFDictionaryCreate". IdentifierInfo* CFDictionaryCreateII; - + /// GCEnabled - Records whether or not the analyzed code runs in GC mode. const bool GCEnabled; - + /// FuncSummaries - A map from FunctionDecls to summaries. - FuncSummariesTy FuncSummaries; - + FuncSummariesTy FuncSummaries; + /// ObjCClassMethodSummaries - A map from selectors (for instance methods) /// to summaries. ObjCMethodSummariesTy ObjCClassMethodSummaries; @@ -624,34 +624,34 @@ class VISIBILITY_HIDDEN RetainSummaryManager { /// BPAlloc - A BumpPtrAllocator used for allocating summaries, ArgEffects, /// and all other data used by the checker. llvm::BumpPtrAllocator BPAlloc; - + /// AF - A factory for ArgEffects objects. - ArgEffects::Factory AF; - + ArgEffects::Factory AF; + /// ScratchArgs - A holding buffer for construct ArgEffects. ArgEffects ScratchArgs; - + /// ObjCAllocRetE - Default return effect for methods returning Objective-C /// objects. RetEffect ObjCAllocRetE; - /// ObjCInitRetE - Default return effect for init methods returning + /// ObjCInitRetE - Default return effect for init methods returning /// Objective-C objects. RetEffect ObjCInitRetE; - + RetainSummary DefaultSummary; RetainSummary* StopSummary; - + //==-----------------------------------------------------------------==// // Methods. //==-----------------------------------------------------------------==// - + /// getArgEffects - Returns a persistent ArgEffects object based on the /// data in ScratchArgs. ArgEffects getArgEffects(); - enum UnaryFuncKind { cfretain, cfrelease, cfmakecollectable }; - + enum UnaryFuncKind { cfretain, cfrelease, cfmakecollectable }; + public: RetEffect getObjAllocRetEffect() const { return ObjCAllocRetE; } @@ -659,13 +659,13 @@ public: RetainSummary *Summ = (RetainSummary*) BPAlloc.Allocate<RetainSummary>(); return new (Summ) RetainSummary(DefaultSummary); } - + RetainSummary* getUnarySummary(const FunctionType* FT, UnaryFuncKind func); - + RetainSummary* getCFSummaryCreateRule(FunctionDecl* FD); - RetainSummary* getCFSummaryGetRule(FunctionDecl* FD); + RetainSummary* getCFSummaryGetRule(FunctionDecl* FD); RetainSummary* getCFCreateGetRuleSummary(FunctionDecl* FD, const char* FName); - + RetainSummary* getPersistentSummary(ArgEffects AE, RetEffect RetEff, ArgEffect ReceiverEff = DoNothing, ArgEffect DefaultEff = MayEscape, @@ -676,36 +676,36 @@ public: ArgEffect DefaultEff = MayEscape) { return getPersistentSummary(getArgEffects(), RE, ReceiverEff, DefaultEff); } - + RetainSummary *getPersistentStopSummary() { if (StopSummary) return StopSummary; - + StopSummary = getPersistentSummary(RetEffect::MakeNoRet(), StopTracking, StopTracking); return StopSummary; - } + } RetainSummary *getInitMethodSummary(QualType RetTy); void InitializeClassMethodSummaries(); void InitializeMethodSummaries(); - + bool isTrackedObjCObjectType(QualType T); bool isTrackedCFObjectType(QualType T); - + private: - + void addClsMethSummary(IdentifierInfo* ClsII, Selector S, RetainSummary* Summ) { ObjCClassMethodSummaries[ObjCSummaryKey(ClsII, S)] = Summ; } - + void addNSObjectClsMethSummary(Selector S, RetainSummary *Summ) { ObjCClassMethodSummaries[S] = Summ; } - + void addNSObjectMethSummary(Selector S, RetainSummary *Summ) { ObjCMethodSummaries[S] = Summ; } @@ -716,43 +716,43 @@ private: Selector S = GetNullarySelector(nullaryName, Ctx); ObjCClassMethodSummaries[ObjCSummaryKey(ClsII, S)] = Summ; } - + void addInstMethSummary(const char* Cls, const char* nullaryName, RetainSummary *Summ) { IdentifierInfo* ClsII = &Ctx.Idents.get(Cls); Selector S = GetNullarySelector(nullaryName, Ctx); ObjCMethodSummaries[ObjCSummaryKey(ClsII, S)] = Summ; } - + Selector generateSelector(va_list argp) { llvm::SmallVector<IdentifierInfo*, 10> II; while (const char* s = va_arg(argp, const char*)) II.push_back(&Ctx.Idents.get(s)); - return Ctx.Selectors.getSelector(II.size(), &II[0]); + return Ctx.Selectors.getSelector(II.size(), &II[0]); } - + void addMethodSummary(IdentifierInfo *ClsII, ObjCMethodSummariesTy& Summaries, RetainSummary* Summ, va_list argp) { Selector S = generateSelector(argp); Summaries[ObjCSummaryKey(ClsII, S)] = Summ; } - + void addInstMethSummary(const char* Cls, RetainSummary* Summ, ...) { va_list argp; va_start(argp, Summ); addMethodSummary(&Ctx.Idents.get(Cls), ObjCMethodSummaries, Summ, argp); - va_end(argp); + va_end(argp); } - + void addClsMethSummary(const char* Cls, RetainSummary* Summ, ...) { va_list argp; va_start(argp, Summ); addMethodSummary(&Ctx.Idents.get(Cls),ObjCClassMethodSummaries, Summ, argp); va_end(argp); } - + void addClsMethSummary(IdentifierInfo *II, RetainSummary* Summ, ...) { va_list argp; va_start(argp, Summ); @@ -769,9 +769,9 @@ private: addMethodSummary(&Ctx.Idents.get(Cls), ObjCMethodSummaries, Summ, argp); va_end(argp); } - + public: - + RetainSummaryManager(ASTContext& ctx, bool gcenabled) : Ctx(ctx), CFDictionaryCreateII(&ctx.Idents.get("CFDictionaryCreate")), @@ -789,17 +789,17 @@ public: InitializeClassMethodSummaries(); InitializeMethodSummaries(); } - + ~RetainSummaryManager(); - - RetainSummary* getSummary(FunctionDecl* FD); - + + RetainSummary* getSummary(FunctionDecl* FD); + RetainSummary* getInstanceMethodSummary(ObjCMessageExpr* ME, const ObjCInterfaceDecl* ID) { return getInstanceMethodSummary(ME->getSelector(), ME->getClassName(), - ID, ME->getMethodDecl(), ME->getType()); + ID, ME->getMethodDecl(), ME->getType()); } - + RetainSummary* getInstanceMethodSummary(Selector S, IdentifierInfo *ClsName, const ObjCInterfaceDecl* ID, const ObjCMethodDecl *MD, @@ -809,7 +809,7 @@ public: const ObjCInterfaceDecl *ID, const ObjCMethodDecl *MD, QualType RetTy); - + RetainSummary *getClassMethodSummary(ObjCMessageExpr *ME) { return getClassMethodSummary(ME->getSelector(), ME->getClassName(), ME->getClassInfo().first, @@ -824,17 +824,17 @@ public: Selector S = MD->getSelector(); IdentifierInfo *ClsName = ID->getIdentifier(); QualType ResultTy = MD->getResultType(); - - // Resolve the method decl last. + + // Resolve the method decl last. if (const ObjCMethodDecl *InterfaceMD = ResolveToInterfaceMethodDecl(MD)) MD = InterfaceMD; - + if (MD->isInstanceMethod()) return getInstanceMethodSummary(S, ClsName, ID, MD, ResultTy); else return getClassMethodSummary(S, ClsName, ID, MD, ResultTy); } - + RetainSummary* getCommonMethodSummary(const ObjCMethodDecl* MD, Selector S, QualType RetTy); @@ -845,14 +845,14 @@ public: const FunctionDecl *FD); bool isGCEnabled() const { return GCEnabled; } - + RetainSummary *copySummary(RetainSummary *OldSumm) { RetainSummary *Summ = (RetainSummary*) BPAlloc.Allocate<RetainSummary>(); new (Summ) RetainSummary(*OldSumm); return Summ; - } + } }; - + } // end anonymous namespace //===----------------------------------------------------------------------===// @@ -871,7 +871,7 @@ RetainSummary* RetainSummaryManager::getPersistentSummary(ArgEffects AE, RetEffect RetEff, ArgEffect ReceiverEff, ArgEffect DefaultEff, - bool isEndPath) { + bool isEndPath) { // Create the summary and return it. RetainSummary *Summ = (RetainSummary*) BPAlloc.Allocate<RetainSummary>(); new (Summ) RetainSummary(AE, RetEff, DefaultEff, ReceiverEff, isEndPath); @@ -887,31 +887,31 @@ bool RetainSummaryManager::isTrackedObjCObjectType(QualType Ty) { return false; const ObjCObjectPointerType *PT = Ty->getAsObjCObjectPointerType(); - + // Can be true for objects with the 'NSObject' attribute. if (!PT) return true; - + // We assume that id<..>, id, and "Class" all represent tracked objects. if (PT->isObjCIdType() || PT->isObjCQualifiedIdType() || PT->isObjCClassType()) return true; - // Does the interface subclass NSObject? - // FIXME: We can memoize here if this gets too expensive. - const ObjCInterfaceDecl *ID = PT->getInterfaceDecl(); + // Does the interface subclass NSObject? + // FIXME: We can memoize here if this gets too expensive. + const ObjCInterfaceDecl *ID = PT->getInterfaceDecl(); // Assume that anything declared with a forward declaration and no // @interface subclasses NSObject. if (ID->isForwardDecl()) return true; - + IdentifierInfo* NSObjectII = &Ctx.Idents.get("NSObject"); for ( ; ID ; ID = ID->getSuperClass()) if (ID->getIdentifier() == NSObjectII) return true; - + return false; } @@ -945,33 +945,33 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) { // No summary? Generate one. RetainSummary *S = 0; - + do { // We generate "stop" summaries for implicitly defined functions. if (FD->isImplicit()) { S = getPersistentStopSummary(); break; } - + // [PR 3337] Use 'getAsFunctionType' to strip away any typedefs on the // function's type. const FunctionType* FT = FD->getType()->getAsFunctionType(); const char* FName = FD->getIdentifier()->getName(); - + // Strip away preceding '_'. Doing this here will effect all the checks // down below. while (*FName == '_') ++FName; - + // Inspect the result type. QualType RetTy = FT->getResultType(); - + // FIXME: This should all be refactored into a chain of "summary lookup" // filters. assert (ScratchArgs.isEmpty()); - + switch (strlen(FName)) { default: break; - + case 17: // Handle: id NSMakeCollectable(CFTypeRef) @@ -1003,10 +1003,10 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) { // Part of <rdar://problem/6961230>. (IOKit) // This should be addressed using a API table. ScratchArgs = AF.Add(ScratchArgs, 2, DecRef); - S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing); + S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing); } break; - + case 25: if (!memcmp(FName, "IORegistryEntryIDMatching", 25)) { // Part of <rdar://problem/6961230>. (IOKit) @@ -1015,13 +1015,13 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) { DoNothing, DoNothing); } break; - + case 26: if (!memcmp(FName, "IOOpenFirmwarePathMatching", 26)) { // Part of <rdar://problem/6961230>. (IOKit) // This should be addressed using a API table. S = getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF, true), - DoNothing, DoNothing); + DoNothing, DoNothing); } break; @@ -1030,7 +1030,7 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) { // Part of <rdar://problem/6961230>. // This should be addressed using a API table. ScratchArgs = AF.Add(ScratchArgs, 1, DecRef); - S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing); + S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing); } break; @@ -1043,17 +1043,17 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) { S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing); } break; - + case 32: if (!memcmp(FName, "IOServiceAddMatchingNotification", 32)) { // Part of <rdar://problem/6961230>. // This should be addressed using a API table. ScratchArgs = AF.Add(ScratchArgs, 2, DecRef); - S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing); + S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing); } break; } - + // Did we get a summary? if (S) break; @@ -1063,7 +1063,7 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) { #if 0 // Handle: NSDeallocateObject(id anObject); // This method does allow 'nil' (although we don't check it now). - if (strcmp(FName, "NSDeallocateObject") == 0) { + if (strcmp(FName, "NSDeallocateObject") == 0) { return RetTy == Ctx.VoidTy ? getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, Dealloc) : getPersistentStopSummary(); @@ -1077,7 +1077,7 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) { S = getUnarySummary(FT, cfretain); else if (strstr(FName, "MakeCollectable")) S = getUnarySummary(FT, cfmakecollectable); - else + else S = getCFCreateGetRuleSummary(FD, FName); break; @@ -1100,7 +1100,7 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) { S = getCFCreateGetRuleSummary(FD, FName); break; } - + break; } @@ -1112,7 +1112,7 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) { FName += 4; else FName += 2; - + if (isRelease(FD, FName)) S = getUnarySummary(FT, cfrelease); else { @@ -1122,9 +1122,9 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) { // and that ownership cannot be transferred. While this is technically // correct, many methods allow a tracked object to escape. For example: // - // CFMutableDictionaryRef x = CFDictionaryCreateMutable(...); + // CFMutableDictionaryRef x = CFDictionaryCreateMutable(...); // CFDictionaryAddValue(y, key, x); - // CFRelease(x); + // CFRelease(x); // ... it is okay to use 'x' since 'y' has a reference to it // // We handle this and similar cases with the follow heuristic. If the @@ -1138,34 +1138,34 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) { CStrInCStrNoCase(FName, "AppendValue") || CStrInCStrNoCase(FName, "SetAttribute")) ? MayEscape : DoNothing; - + S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, E); } } } while (0); - + if (!S) S = getDefaultSummary(); // Annotations override defaults. assert(S); updateSummaryFromAnnotations(*S, FD); - + FuncSummaries[FD] = S; - return S; + return S; } RetainSummary* RetainSummaryManager::getCFCreateGetRuleSummary(FunctionDecl* FD, const char* FName) { - + if (strstr(FName, "Create") || strstr(FName, "Copy")) return getCFSummaryCreateRule(FD); - + if (strstr(FName, "Get")) return getCFSummaryGetRule(FD); - + return getDefaultSummary(); } @@ -1178,27 +1178,27 @@ RetainSummaryManager::getUnarySummary(const FunctionType* FT, const FunctionProtoType* FTP = dyn_cast<FunctionProtoType>(FT); if (!FTP || FTP->getNumArgs() != 1) return getPersistentStopSummary(); - + assert (ScratchArgs.isEmpty()); - + switch (func) { case cfretain: { ScratchArgs = AF.Add(ScratchArgs, 0, IncRef); return getPersistentSummary(RetEffect::MakeAlias(0), DoNothing, DoNothing); } - + case cfrelease: { ScratchArgs = AF.Add(ScratchArgs, 0, DecRef); return getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing); } - + case cfmakecollectable: { ScratchArgs = AF.Add(ScratchArgs, 0, MakeCollectable); - return getPersistentSummary(RetEffect::MakeAlias(0),DoNothing, DoNothing); + return getPersistentSummary(RetEffect::MakeAlias(0),DoNothing, DoNothing); } - + default: assert (false && "Not a supported unary function."); return getDefaultSummary(); @@ -1207,17 +1207,17 @@ RetainSummaryManager::getUnarySummary(const FunctionType* FT, RetainSummary* RetainSummaryManager::getCFSummaryCreateRule(FunctionDecl* FD) { assert (ScratchArgs.isEmpty()); - + if (FD->getIdentifier() == CFDictionaryCreateII) { ScratchArgs = AF.Add(ScratchArgs, 1, DoNothingByRef); ScratchArgs = AF.Add(ScratchArgs, 2, DoNothingByRef); } - + return getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF, true)); } RetainSummary* RetainSummaryManager::getCFSummaryGetRule(FunctionDecl* FD) { - assert (ScratchArgs.isEmpty()); + assert (ScratchArgs.isEmpty()); return getPersistentSummary(RetEffect::MakeNotOwned(RetEffect::CF), DoNothing, DoNothing); } @@ -1228,12 +1228,12 @@ RetainSummary* RetainSummaryManager::getCFSummaryGetRule(FunctionDecl* FD) { RetainSummary* RetainSummaryManager::getInitMethodSummary(QualType RetTy) { - assert(ScratchArgs.isEmpty()); + assert(ScratchArgs.isEmpty()); // 'init' methods conceptually return a newly allocated object and claim - // the receiver. + // the receiver. if (isTrackedObjCObjectType(RetTy) || isTrackedCFObjectType(RetTy)) return getPersistentSummary(ObjCInitRetE, DecRefMsg); - + return getDefaultSummary(); } @@ -1244,7 +1244,7 @@ RetainSummaryManager::updateSummaryFromAnnotations(RetainSummary &Summ, return; QualType RetTy = FD->getResultType(); - + // Determine if there is a special return effect for this method. if (isTrackedObjCObjectType(RetTy)) { if (FD->getAttr<NSReturnsRetainedAttr>()) { @@ -1268,20 +1268,20 @@ RetainSummaryManager::updateSummaryFromAnnotations(RetainSummary &Summ, return; bool isTrackedLoc = false; - + // Determine if there is a special return effect for this method. if (isTrackedObjCObjectType(MD->getResultType())) { if (MD->getAttr<NSReturnsRetainedAttr>()) { Summ.setRetEffect(ObjCAllocRetE); return; } - + isTrackedLoc = true; } - + if (!isTrackedLoc) isTrackedLoc = MD->getResultType()->getAs<PointerType>() != NULL; - + if (isTrackedLoc && MD->getAttr<CFReturnsRetainedAttr>()) Summ.setRetEffect(RetEffect::MakeOwned(RetEffect::CF, true)); } @@ -1304,10 +1304,10 @@ RetainSummaryManager::getCommonMethodSummary(const ObjCMethodDecl* MD, ScratchArgs = AF.Add(ScratchArgs, i, StopTracking); } } - + // Any special effect for the receiver? ArgEffect ReceiverEff = DoNothing; - + // If one of the arguments in the selector has the keyword 'delegate' we // should stop tracking the reference count for the receiver. This is // because the reference count is quite possibly handled by a delegate @@ -1317,29 +1317,29 @@ RetainSummaryManager::getCommonMethodSummary(const ObjCMethodDecl* MD, assert(!str.empty()); if (CStrInCStrNoCase(&str[0], "delegate:")) ReceiverEff = StopTracking; } - + // Look for methods that return an owned object. - if (isTrackedObjCObjectType(RetTy)) { + if (isTrackedObjCObjectType(RetTy)) { // EXPERIMENTAL: Assume the Cocoa conventions for all objects returned // by instance methods. RetEffect E = followsFundamentalRule(S) ? ObjCAllocRetE : RetEffect::MakeNotOwned(RetEffect::ObjC); - - return getPersistentSummary(E, ReceiverEff, MayEscape); + + return getPersistentSummary(E, ReceiverEff, MayEscape); } - + // Look for methods that return an owned core foundation object. if (isTrackedCFObjectType(RetTy)) { RetEffect E = followsFundamentalRule(S) ? RetEffect::MakeOwned(RetEffect::CF, true) : RetEffect::MakeNotOwned(RetEffect::CF); - + return getPersistentSummary(E, ReceiverEff, MayEscape); } - + if (ScratchArgs.isEmpty() && ReceiverEff == DoNothing) return getDefaultSummary(); - + return getPersistentSummary(RetEffect::MakeNoRet(), ReceiverEff, MayEscape); } @@ -1352,23 +1352,23 @@ RetainSummaryManager::getInstanceMethodSummary(Selector S, // Look up a summary in our summary cache. RetainSummary *Summ = ObjCMethodSummaries.find(ID, ClsName, S); - + if (!Summ) { assert(ScratchArgs.isEmpty()); - + // "initXXX": pass-through for receiver. if (deriveNamingConvention(S) == InitRule) Summ = getInitMethodSummary(RetTy); else Summ = getCommonMethodSummary(MD, S, RetTy); - + // Annotations override defaults. updateSummaryFromAnnotations(*Summ, MD); - + // Memoize the summary. ObjCMethodSummaries[ObjCSummaryKey(ID, ClsName, S)] = Summ; } - + return Summ; } @@ -1379,8 +1379,8 @@ RetainSummaryManager::getClassMethodSummary(Selector S, IdentifierInfo *ClsName, QualType RetTy) { assert(ClsName && "Class name must be specified."); - RetainSummary *Summ = ObjCClassMethodSummaries.find(ID, ClsName, S); - + RetainSummary *Summ = ObjCClassMethodSummaries.find(ID, ClsName, S); + if (!Summ) { Summ = getCommonMethodSummary(MD, S, RetTy); // Annotations override defaults. @@ -1388,32 +1388,32 @@ RetainSummaryManager::getClassMethodSummary(Selector S, IdentifierInfo *ClsName, // Memoize the summary. ObjCClassMethodSummaries[ObjCSummaryKey(ID, ClsName, S)] = Summ; } - + return Summ; } -void RetainSummaryManager::InitializeClassMethodSummaries() { +void RetainSummaryManager::InitializeClassMethodSummaries() { assert(ScratchArgs.isEmpty()); RetainSummary* Summ = getPersistentSummary(ObjCAllocRetE); - + // Create the summaries for "alloc", "new", and "allocWithZone:" for // NSObject and its derivatives. addNSObjectClsMethSummary(GetNullarySelector("alloc", Ctx), Summ); addNSObjectClsMethSummary(GetNullarySelector("new", Ctx), Summ); addNSObjectClsMethSummary(GetUnarySelector("allocWithZone", Ctx), Summ); - - // Create the [NSAssertionHandler currentHander] summary. + + // Create the [NSAssertionHandler currentHander] summary. addClsMethSummary(&Ctx.Idents.get("NSAssertionHandler"), GetNullarySelector("currentHandler", Ctx), getPersistentSummary(RetEffect::MakeNotOwned(RetEffect::ObjC))); - + // Create the [NSAutoreleasePool addObject:] summary. ScratchArgs = AF.Add(ScratchArgs, 0, Autorelease); addClsMethSummary(&Ctx.Idents.get("NSAutoreleasePool"), GetUnarySelector("addObject", Ctx), getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, Autorelease)); - + // Create the summaries for [NSObject performSelector...]. We treat // these as 'stop tracking' for the arguments because they are often // used for delegates that can release the object. When we have better @@ -1435,7 +1435,7 @@ void RetainSummaryManager::InitializeClassMethodSummaries() { "withObject", "waitUntilDone", "modes", NULL); addClsMethSummary(NSObjectII, Summ, "performSelectorInBackground", "withObject", NULL); - + // Specially handle NSData. RetainSummary *dataWithBytesNoCopySumm = getPersistentSummary(RetEffect::MakeNotOwned(RetEffect::ObjC), DoNothing, @@ -1447,43 +1447,43 @@ void RetainSummaryManager::InitializeClassMethodSummaries() { } void RetainSummaryManager::InitializeMethodSummaries() { - - assert (ScratchArgs.isEmpty()); - + + assert (ScratchArgs.isEmpty()); + // Create the "init" selector. It just acts as a pass-through for the // receiver. - RetainSummary *InitSumm = getPersistentSummary(ObjCInitRetE, DecRefMsg); + RetainSummary *InitSumm = getPersistentSummary(ObjCInitRetE, DecRefMsg); addNSObjectMethSummary(GetNullarySelector("init", Ctx), InitSumm); // awakeAfterUsingCoder: behaves basically like an 'init' method. It // claims the receiver and returns a retained object. addNSObjectMethSummary(GetUnarySelector("awakeAfterUsingCoder", Ctx), InitSumm); - + // The next methods are allocators. RetainSummary *AllocSumm = getPersistentSummary(ObjCAllocRetE); - RetainSummary *CFAllocSumm = + RetainSummary *CFAllocSumm = getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF, true)); - - // Create the "copy" selector. - addNSObjectMethSummary(GetNullarySelector("copy", Ctx), AllocSumm); + + // Create the "copy" selector. + addNSObjectMethSummary(GetNullarySelector("copy", Ctx), AllocSumm); // Create the "mutableCopy" selector. addNSObjectMethSummary(GetNullarySelector("mutableCopy", Ctx), AllocSumm); - + // Create the "retain" selector. RetEffect E = RetEffect::MakeReceiverAlias(); RetainSummary *Summ = getPersistentSummary(E, IncRefMsg); addNSObjectMethSummary(GetNullarySelector("retain", Ctx), Summ); - + // Create the "release" selector. Summ = getPersistentSummary(E, DecRefMsg); addNSObjectMethSummary(GetNullarySelector("release", Ctx), Summ); - + // Create the "drain" selector. Summ = getPersistentSummary(E, isGCEnabled() ? DoNothing : DecRef); addNSObjectMethSummary(GetNullarySelector("drain", Ctx), Summ); - + // Create the -dealloc summary. Summ = getPersistentSummary(RetEffect::MakeNoRet(), Dealloc); addNSObjectMethSummary(GetNullarySelector("dealloc", Ctx), Summ); @@ -1491,13 +1491,13 @@ void RetainSummaryManager::InitializeMethodSummaries() { // Create the "autorelease" selector. Summ = getPersistentSummary(E, Autorelease); addNSObjectMethSummary(GetNullarySelector("autorelease", Ctx), Summ); - + // Specially handle NSAutoreleasePool. addInstMethSummary("NSAutoreleasePool", "init", getPersistentSummary(RetEffect::MakeReceiverAlias(), NewAutoreleasePool)); - - // For NSWindow, allocated objects are (initially) self-owned. + + // For NSWindow, allocated objects are (initially) self-owned. // FIXME: For now we opt for false negatives with NSWindow, as these objects // self-own themselves. However, they only do this once they are displayed. // Thus, we need to track an NSWindow's display status. @@ -1506,42 +1506,42 @@ void RetainSummaryManager::InitializeMethodSummaries() { RetainSummary *NoTrackYet = getPersistentSummary(RetEffect::MakeNoRet(), StopTracking, StopTracking); - + addClassMethSummary("NSWindow", "alloc", NoTrackYet); #if 0 addInstMethSummary("NSWindow", NoTrackYet, "initWithContentRect", "styleMask", "backing", "defer", NULL); - + addInstMethSummary("NSWindow", NoTrackYet, "initWithContentRect", "styleMask", "backing", "defer", "screen", NULL); #endif - + // For NSPanel (which subclasses NSWindow), allocated objects are not // self-owned. // FIXME: For now we don't track NSPanels. object for the same reason // as for NSWindow objects. addClassMethSummary("NSPanel", "alloc", NoTrackYet); - + #if 0 addInstMethSummary("NSPanel", NoTrackYet, "initWithContentRect", "styleMask", "backing", "defer", NULL); - + addInstMethSummary("NSPanel", NoTrackYet, "initWithContentRect", "styleMask", "backing", "defer", "screen", NULL); #endif - + // Don't track allocated autorelease pools yet, as it is okay to prematurely // exit a method. addClassMethSummary("NSAutoreleasePool", "alloc", NoTrackYet); // Create NSAssertionHandler summaries. addPanicSummary("NSAssertionHandler", "handleFailureInFunction", "file", - "lineNumber", "description", NULL); - + "lineNumber", "description", NULL); + addPanicSummary("NSAssertionHandler", "handleFailureInMethod", "object", "file", "lineNumber", "description", NULL); - + // Create summaries QCRenderer/QCView -createSnapShotImageOfType: addInstMethSummary("QCRenderer", AllocSumm, "createSnapshotImageOfType", NULL); @@ -1554,7 +1554,7 @@ void RetainSummaryManager::InitializeMethodSummaries() { addInstMethSummary("CIContext", CFAllocSumm, "createCGImage", "fromRect", NULL); addInstMethSummary("CIContext", CFAllocSumm, - "createCGImage", "fromRect", "format", "colorSpace", NULL); + "createCGImage", "fromRect", "format", "colorSpace", NULL); addInstMethSummary("CIContext", CFAllocSumm, "createCGLayerWithSize", "info", NULL); } @@ -1564,19 +1564,19 @@ void RetainSummaryManager::InitializeMethodSummaries() { //===----------------------------------------------------------------------===// namespace { - + class VISIBILITY_HIDDEN RefVal { -public: +public: enum Kind { - Owned = 0, // Owning reference. - NotOwned, // Reference is not owned by still valid (not freed). + Owned = 0, // Owning reference. + NotOwned, // Reference is not owned by still valid (not freed). Released, // Object has been released. ReturnedOwned, // Returned object passes ownership to caller. ReturnedNotOwned, // Return object does not pass ownership to caller. ERROR_START, ErrorDeallocNotOwned, // -dealloc called on non-owned object. ErrorDeallocGC, // Calling -dealloc with GC enabled. - ErrorUseAfterRelease, // Object used after released. + ErrorUseAfterRelease, // Object used after released. ErrorReleaseNotOwned, // Release of an object that was not owned. ERROR_LEAK_START, ErrorLeak, // A memory leak due to excessive reference counts. @@ -1587,7 +1587,7 @@ public: ErrorReturnedNotOwned }; -private: +private: Kind kind; RetEffect::ObjKind okind; unsigned Cnt; @@ -1600,9 +1600,9 @@ private: RefVal(Kind k, unsigned cnt = 0) : kind(k), okind(RetEffect::AnyObj), Cnt(cnt), ACnt(0) {} -public: +public: Kind getKind() const { return kind; } - + RetEffect::ObjKind getObjKind() const { return okind; } unsigned getCount() const { return Cnt; } @@ -1611,72 +1611,72 @@ public: void clearCounts() { Cnt = 0; ACnt = 0; } void setCount(unsigned i) { Cnt = i; } void setAutoreleaseCount(unsigned i) { ACnt = i; } - + QualType getType() const { return T; } - + // Useful predicates. - + static bool isError(Kind k) { return k >= ERROR_START; } - + static bool isLeak(Kind k) { return k >= ERROR_LEAK_START; } - + bool isOwned() const { return getKind() == Owned; } - + bool isNotOwned() const { return getKind() == NotOwned; } - + bool isReturnedOwned() const { return getKind() == ReturnedOwned; } - + bool isReturnedNotOwned() const { return getKind() == ReturnedNotOwned; } - + bool isNonLeakError() const { Kind k = getKind(); return isError(k) && !isLeak(k); } - + static RefVal makeOwned(RetEffect::ObjKind o, QualType t, unsigned Count = 1) { return RefVal(Owned, o, Count, 0, t); } - + static RefVal makeNotOwned(RetEffect::ObjKind o, QualType t, unsigned Count = 0) { return RefVal(NotOwned, o, Count, 0, t); } - + // Comparison, profiling, and pretty-printing. - + bool operator==(const RefVal& X) const { return kind == X.kind && Cnt == X.Cnt && T == X.T && ACnt == X.ACnt; } - + RefVal operator-(size_t i) const { return RefVal(getKind(), getObjKind(), getCount() - i, getAutoreleaseCount(), getType()); } - + RefVal operator+(size_t i) const { return RefVal(getKind(), getObjKind(), getCount() + i, getAutoreleaseCount(), getType()); } - + RefVal operator^(Kind k) const { return RefVal(k, getObjKind(), getCount(), getAutoreleaseCount(), getType()); } - + RefVal autorelease() const { return RefVal(getKind(), getObjKind(), getCount(), getAutoreleaseCount()+1, getType()); } - + void Profile(llvm::FoldingSetNodeID& ID) const { ID.AddInteger((unsigned) kind); ID.AddInteger(Cnt); @@ -1686,41 +1686,41 @@ public: void print(llvm::raw_ostream& Out) const; }; - + void RefVal::print(llvm::raw_ostream& Out) const { if (!T.isNull()) Out << "Tracked Type:" << T.getAsString() << '\n'; - + switch (getKind()) { default: assert(false); - case Owned: { + case Owned: { Out << "Owned"; unsigned cnt = getCount(); if (cnt) Out << " (+ " << cnt << ")"; break; } - + case NotOwned: { Out << "NotOwned"; unsigned cnt = getCount(); if (cnt) Out << " (+ " << cnt << ")"; break; } - - case ReturnedOwned: { + + case ReturnedOwned: { Out << "ReturnedOwned"; unsigned cnt = getCount(); if (cnt) Out << " (+ " << cnt << ")"; break; } - + case ReturnedNotOwned: { Out << "ReturnedNotOwned"; unsigned cnt = getCount(); if (cnt) Out << " (+ " << cnt << ")"; break; } - + case Released: Out << "Released"; break; @@ -1728,19 +1728,19 @@ void RefVal::print(llvm::raw_ostream& Out) const { case ErrorDeallocGC: Out << "-dealloc (GC)"; break; - + case ErrorDeallocNotOwned: Out << "-dealloc (not-owned)"; break; - + case ErrorLeak: Out << "Leaked"; - break; - + break; + case ErrorLeakReturned: Out << "Leaked (Bad naming)"; break; - + case ErrorGCLeakReturned: Out << "Leaked (GC-ed at return)"; break; @@ -1748,38 +1748,38 @@ void RefVal::print(llvm::raw_ostream& Out) const { case ErrorUseAfterRelease: Out << "Use-After-Release [ERROR]"; break; - + case ErrorReleaseNotOwned: Out << "Release of Not-Owned [ERROR]"; break; - + case RefVal::ErrorOverAutorelease: Out << "Over autoreleased"; break; - + case RefVal::ErrorReturnedNotOwned: Out << "Non-owned object returned instead of owned"; break; } - + if (ACnt) { Out << " [ARC +" << ACnt << ']'; } } - + } // end anonymous namespace //===----------------------------------------------------------------------===// // RefBindings - State used to track object reference counts. //===----------------------------------------------------------------------===// - + typedef llvm::ImmutableMap<SymbolRef, RefVal> RefBindings; static int RefBIndex = 0; namespace clang { template<> struct GRStateTrait<RefBindings> : public GRStatePartialTrait<RefBindings> { - static inline void* GDMIndex() { return &RefBIndex; } + static inline void* GDMIndex() { return &RefBIndex; } }; } @@ -1800,12 +1800,12 @@ namespace { class VISIBILITY_HIDDEN AutoreleaseStack {}; } namespace clang { template<> struct GRStateTrait<AutoreleaseStack> : public GRStatePartialTrait<ARStack> { - static inline void* GDMIndex() { return &AutoRBIndex; } + static inline void* GDMIndex() { return &AutoRBIndex; } }; template<> struct GRStateTrait<AutoreleasePoolContents> : public GRStatePartialTrait<ARPoolContents> { - static inline void* GDMIndex() { return &AutoRCIndex; } + static inline void* GDMIndex() { return &AutoRCIndex; } }; } // end clang namespace @@ -1820,14 +1820,14 @@ static const GRState * SendAutorelease(const GRState *state, SymbolRef pool = GetCurrentAutoreleasePool(state); const ARCounts *cnts = state->get<AutoreleasePoolContents>(pool); ARCounts newCnts(0); - + if (cnts) { const unsigned *cnt = (*cnts).lookup(sym); newCnts = F.Add(*cnts, sym, cnt ? *cnt + 1 : 1); } else newCnts = F.Add(F.GetEmptyMap(), sym, 1); - + return state->set<AutoreleasePoolContents>(pool, newCnts); } @@ -1836,7 +1836,7 @@ static const GRState * SendAutorelease(const GRState *state, //===----------------------------------------------------------------------===// namespace { - + class VISIBILITY_HIDDEN CFRefCount : public GRTransferFuncs { public: class BindingsPrinter : public GRState::Printer { @@ -1847,9 +1847,9 @@ public: private: typedef llvm::DenseMap<const ExplodedNode*, const RetainSummary*> - SummaryLogTy; + SummaryLogTy; - RetainSummaryManager Summaries; + RetainSummaryManager Summaries; SummaryLogTy SummaryLog; const LangOptions& LOpts; ARCounts::Factory ARCountFactory; @@ -1860,7 +1860,7 @@ private: BugType *overAutorelease; BugType *returnNotOwnedForOwned; BugReporter *BR; - + const GRState * Update(const GRState * state, SymbolRef sym, RefVal V, ArgEffect E, RefVal::Kind& hasErr); @@ -1870,40 +1870,40 @@ private: ExplodedNode* Pred, const GRState* St, RefVal::Kind hasErr, SymbolRef Sym); - + const GRState * HandleSymbolDeath(const GRState * state, SymbolRef sid, RefVal V, llvm::SmallVectorImpl<SymbolRef> &Leaked); - + ExplodedNode* ProcessLeaks(const GRState * state, llvm::SmallVectorImpl<SymbolRef> &Leaked, GenericNodeBuilder &Builder, GRExprEngine &Eng, ExplodedNode *Pred = 0); - -public: + +public: CFRefCount(ASTContext& Ctx, bool gcenabled, const LangOptions& lopts) : Summaries(Ctx, gcenabled), LOpts(lopts), useAfterRelease(0), releaseNotOwned(0), deallocGC(0), deallocNotOwned(0), leakWithinFunction(0), leakAtReturn(0), overAutorelease(0), returnNotOwnedForOwned(0), BR(0) {} - + virtual ~CFRefCount() {} - + void RegisterChecks(BugReporter &BR); - + virtual void RegisterPrinters(std::vector<GRState::Printer*>& Printers) { Printers.push_back(new BindingsPrinter()); } - + bool isGCEnabled() const { return Summaries.isGCEnabled(); } const LangOptions& getLangOptions() const { return LOpts; } - + const RetainSummary *getSummaryOfNode(const ExplodedNode *N) const { SummaryLogTy::const_iterator I = SummaryLog.find(N); return I == SummaryLog.end() ? 0 : I->second; } - + // Calls. void EvalSummary(ExplodedNodeSet& Dst, @@ -1914,47 +1914,47 @@ public: const RetainSummary& Summ, ExprIterator arg_beg, ExprIterator arg_end, ExplodedNode* Pred); - + virtual void EvalCall(ExplodedNodeSet& Dst, GRExprEngine& Eng, GRStmtNodeBuilder& Builder, CallExpr* CE, SVal L, - ExplodedNode* Pred); - - + ExplodedNode* Pred); + + virtual void EvalObjCMessageExpr(ExplodedNodeSet& Dst, GRExprEngine& Engine, GRStmtNodeBuilder& Builder, ObjCMessageExpr* ME, ExplodedNode* Pred); - + bool EvalObjCMessageExprAux(ExplodedNodeSet& Dst, GRExprEngine& Engine, GRStmtNodeBuilder& Builder, ObjCMessageExpr* ME, ExplodedNode* Pred); - // Stores. + // Stores. virtual void EvalBind(GRStmtNodeBuilderRef& B, SVal location, SVal val); // End-of-path. - + virtual void EvalEndPath(GRExprEngine& Engine, GREndPathNodeBuilder& Builder); - + virtual void EvalDeadSymbols(ExplodedNodeSet& Dst, GRExprEngine& Engine, GRStmtNodeBuilder& Builder, ExplodedNode* Pred, Stmt* S, const GRState* state, SymbolReaper& SymReaper); - + std::pair<ExplodedNode*, const GRState *> HandleAutoreleaseCounts(const GRState * state, GenericNodeBuilder Bd, ExplodedNode* Pred, GRExprEngine &Eng, SymbolRef Sym, RefVal V, bool &stop); // Return statements. - + virtual void EvalReturn(ExplodedNodeSet& Dst, GRExprEngine& Engine, GRStmtNodeBuilder& Builder, @@ -1977,34 +1977,34 @@ static void PrintPool(llvm::raw_ostream &Out, SymbolRef Sym, else Out << "<pool>"; Out << ":{"; - + // Get the contents of the pool. if (const ARCounts *cnts = state->get<AutoreleasePoolContents>(Sym)) for (ARCounts::iterator J=cnts->begin(), EJ=cnts->end(); J != EJ; ++J) Out << '(' << J.getKey() << ',' << J.getData() << ')'; - Out << '}'; + Out << '}'; } void CFRefCount::BindingsPrinter::Print(llvm::raw_ostream& Out, const GRState* state, const char* nl, const char* sep) { - + RefBindings B = state->get<RefBindings>(); - + if (!B.isEmpty()) Out << sep << nl; - + for (RefBindings::iterator I=B.begin(), E=B.end(); I!=E; ++I) { Out << (*I).first << " : "; (*I).second.print(Out); Out << nl; } - + // Print the autorelease stack. Out << sep << nl << "AR pool stack:"; ARStack stack = state->get<AutoreleaseStack>(); - + PrintPool(Out, SymbolRef(), state); // Print the caller's pool. for (ARStack::iterator I=stack.begin(), E=stack.end(); I!=E; ++I) PrintPool(Out, *I, state); @@ -2017,117 +2017,117 @@ void CFRefCount::BindingsPrinter::Print(llvm::raw_ostream& Out, //===----------------------------------------------------------------------===// namespace { - + //===-------------===// // Bug Descriptions. // - //===-------------===// - + //===-------------===// + class VISIBILITY_HIDDEN CFRefBug : public BugType { protected: CFRefCount& TF; - - CFRefBug(CFRefCount* tf, const char* name) - : BugType(name, "Memory (Core Foundation/Objective-C)"), TF(*tf) {} + + CFRefBug(CFRefCount* tf, const char* name) + : BugType(name, "Memory (Core Foundation/Objective-C)"), TF(*tf) {} public: - + CFRefCount& getTF() { return TF; } const CFRefCount& getTF() const { return TF; } - + // FIXME: Eventually remove. virtual const char* getDescription() const = 0; - + virtual bool isLeak() const { return false; } }; - + class VISIBILITY_HIDDEN UseAfterRelease : public CFRefBug { public: UseAfterRelease(CFRefCount* tf) : CFRefBug(tf, "Use-after-release") {} - + const char* getDescription() const { return "Reference-counted object is used after it is released"; - } + } }; - + class VISIBILITY_HIDDEN BadRelease : public CFRefBug { public: BadRelease(CFRefCount* tf) : CFRefBug(tf, "Bad release") {} - + const char* getDescription() const { return "Incorrect decrement of the reference count of an " "object is not owned at this point by the caller"; } }; - + class VISIBILITY_HIDDEN DeallocGC : public CFRefBug { public: DeallocGC(CFRefCount *tf) : CFRefBug(tf, "-dealloc called while using garbage collection") {} - + const char *getDescription() const { return "-dealloc called while using garbage collection"; } }; - + class VISIBILITY_HIDDEN DeallocNotOwned : public CFRefBug { public: DeallocNotOwned(CFRefCount *tf) : CFRefBug(tf, "-dealloc sent to non-exclusively owned object") {} - + const char *getDescription() const { return "-dealloc sent to object that may be referenced elsewhere"; } - }; - + }; + class VISIBILITY_HIDDEN OverAutorelease : public CFRefBug { public: - OverAutorelease(CFRefCount *tf) : + OverAutorelease(CFRefCount *tf) : CFRefBug(tf, "Object sent -autorelease too many times") {} - + const char *getDescription() const { return "Object sent -autorelease too many times"; } }; - + class VISIBILITY_HIDDEN ReturnedNotOwnedForOwned : public CFRefBug { public: ReturnedNotOwnedForOwned(CFRefCount *tf) : CFRefBug(tf, "Method should return an owned object") {} - + const char *getDescription() const { return "Object with +0 retain counts returned to caller where a +1 " "(owning) retain count is expected"; } }; - + class VISIBILITY_HIDDEN Leak : public CFRefBug { const bool isReturn; protected: Leak(CFRefCount* tf, const char* name, bool isRet) : CFRefBug(tf, name), isReturn(isRet) {} public: - + const char* getDescription() const { return ""; } - + bool isLeak() const { return true; } }; - + class VISIBILITY_HIDDEN LeakAtReturn : public Leak { public: LeakAtReturn(CFRefCount* tf, const char* name) : Leak(tf, name, true) {} }; - + class VISIBILITY_HIDDEN LeakWithinFunction : public Leak { public: LeakWithinFunction(CFRefCount* tf, const char* name) : Leak(tf, name, false) {} - }; - + }; + //===---------===// // Bug Reports. // //===---------===// - + class VISIBILITY_HIDDEN CFRefReport : public RangedBugReport { protected: SymbolRef Sym; @@ -2140,30 +2140,30 @@ namespace { CFRefReport(CFRefBug& D, const CFRefCount &tf, ExplodedNode *n, SymbolRef sym, const char* endText) : RangedBugReport(D, D.getDescription(), endText, n), Sym(sym), TF(tf) {} - + virtual ~CFRefReport() {} - + CFRefBug& getBugType() { return (CFRefBug&) RangedBugReport::getBugType(); } const CFRefBug& getBugType() const { return (const CFRefBug&) RangedBugReport::getBugType(); } - + virtual void getRanges(const SourceRange*& beg, const SourceRange*& end) { if (!getBugType().isLeak()) RangedBugReport::getRanges(beg, end); else beg = end = 0; } - + SymbolRef getSymbol() const { return Sym; } - + PathDiagnosticPiece* getEndPath(BugReporterContext& BRC, const ExplodedNode* N); - + std::pair<const char**,const char**> getExtraDescriptiveText(); - + PathDiagnosticPiece* VisitNode(const ExplodedNode* N, const ExplodedNode* PrevN, BugReporterContext& BRC); @@ -2176,36 +2176,36 @@ namespace { CFRefLeakReport(CFRefBug& D, const CFRefCount &tf, ExplodedNode *n, SymbolRef sym, GRExprEngine& Eng); - + PathDiagnosticPiece* getEndPath(BugReporterContext& BRC, const ExplodedNode* N); - + SourceLocation getLocation() const { return AllocSite; } - }; + }; } // end anonymous namespace void CFRefCount::RegisterChecks(BugReporter& BR) { useAfterRelease = new UseAfterRelease(this); BR.Register(useAfterRelease); - + releaseNotOwned = new BadRelease(this); BR.Register(releaseNotOwned); - + deallocGC = new DeallocGC(this); BR.Register(deallocGC); - + deallocNotOwned = new DeallocNotOwned(this); BR.Register(deallocNotOwned); - + overAutorelease = new OverAutorelease(this); BR.Register(overAutorelease); - + returnNotOwnedForOwned = new ReturnedNotOwnedForOwned(this); BR.Register(returnNotOwnedForOwned); - + // First register "return" leaks. const char* name = 0; - + if (isGCEnabled()) name = "Leak of returned object when using garbage collection"; else if (getLangOptions().getGCMode() == LangOptions::HybridGC) @@ -2215,13 +2215,13 @@ void CFRefCount::RegisterChecks(BugReporter& BR) { assert(getLangOptions().getGCMode() == LangOptions::NonGC); name = "Leak of returned object"; } - + leakAtReturn = new LeakAtReturn(this, name); BR.Register(leakAtReturn); - + // Second, register leaks within a function/method. if (isGCEnabled()) - name = "Leak of object when using garbage collection"; + name = "Leak of object when using garbage collection"; else if (getLangOptions().getGCMode() == LangOptions::HybridGC) name = "Leak of object when not using garbage collection (GC) in " "dual GC/non-GC code"; @@ -2229,22 +2229,22 @@ void CFRefCount::RegisterChecks(BugReporter& BR) { assert(getLangOptions().getGCMode() == LangOptions::NonGC); name = "Leak"; } - + leakWithinFunction = new LeakWithinFunction(this, name); BR.Register(leakWithinFunction); - + // Save the reference to the BugReporter. this->BR = &BR; } static const char* Msgs[] = { // GC only - "Code is compiled to only use garbage collection", + "Code is compiled to only use garbage collection", // No GC. "Code is compiled to use reference counts", // Hybrid, with GC. "Code is compiled to use either garbage collection (GC) or reference counts" - " (non-GC). The bug occurs with GC enabled", + " (non-GC). The bug occurs with GC enabled", // Hybrid, without GC "Code is compiled to use either garbage collection (GC) or reference counts" " (non-GC). The bug occurs in non-GC mode" @@ -2252,19 +2252,19 @@ static const char* Msgs[] = { std::pair<const char**,const char**> CFRefReport::getExtraDescriptiveText() { CFRefCount& TF = static_cast<CFRefBug&>(getBugType()).getTF(); - + switch (TF.getLangOptions().getGCMode()) { default: assert(false); - + case LangOptions::GCOnly: assert (TF.isGCEnabled()); - return std::make_pair(&Msgs[0], &Msgs[0]+1); - + return std::make_pair(&Msgs[0], &Msgs[0]+1); + case LangOptions::NonGC: assert (!TF.isGCEnabled()); return std::make_pair(&Msgs[1], &Msgs[1]+1); - + case LangOptions::HybridGC: if (TF.isGCEnabled()) return std::make_pair(&Msgs[2], &Msgs[2]+1); @@ -2278,50 +2278,50 @@ static inline bool contains(const llvm::SmallVectorImpl<ArgEffect>& V, for (llvm::SmallVectorImpl<ArgEffect>::const_iterator I=V.begin(), E=V.end(); I!=E; ++I) if (*I == X) return true; - + return false; } PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N, const ExplodedNode* PrevN, BugReporterContext& BRC) { - + if (!isa<PostStmt>(N->getLocation())) return NULL; - + // Check if the type state has changed. const GRState *PrevSt = PrevN->getState(); const GRState *CurrSt = N->getState(); - - const RefVal* CurrT = CurrSt->get<RefBindings>(Sym); + + const RefVal* CurrT = CurrSt->get<RefBindings>(Sym); if (!CurrT) return NULL; - + const RefVal &CurrV = *CurrT; const RefVal *PrevT = PrevSt->get<RefBindings>(Sym); - + // Create a string buffer to constain all the useful things we want // to tell the user. std::string sbuf; llvm::raw_string_ostream os(sbuf); - + // This is the allocation site since the previous node had no bindings // for this symbol. if (!PrevT) { const Stmt* S = cast<PostStmt>(N->getLocation()).getStmt(); - + if (const CallExpr *CE = dyn_cast<CallExpr>(S)) { // Get the name of the callee (if it is available). SVal X = CurrSt->getSValAsScalarOrLoc(CE->getCallee()); if (const FunctionDecl* FD = X.getAsFunctionDecl()) os << "Call to function '" << FD->getNameAsString() <<'\''; else - os << "function call"; - } + os << "function call"; + } else { assert (isa<ObjCMessageExpr>(S)); os << "Method"; } - + if (CurrV.getObjKind() == RetEffect::CF) { os << " returns a Core Foundation object with a "; } @@ -2329,10 +2329,10 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N, assert (CurrV.getObjKind() == RetEffect::ObjC); os << " returns an Objective-C object with a "; } - + if (CurrV.isOwned()) { os << "+1 retain count (owning reference)."; - + if (static_cast<CFRefBug&>(getBugType()).getTF().isGCEnabled()) { assert(CurrV.getObjKind() == RetEffect::CF); os << " " @@ -2343,39 +2343,39 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N, assert (CurrV.isNotOwned()); os << "+0 retain count (non-owning reference)."; } - + PathDiagnosticLocation Pos(S, BRC.getSourceManager()); return new PathDiagnosticEventPiece(Pos, os.str()); } - + // Gather up the effects that were performed on the object at this // program point llvm::SmallVector<ArgEffect, 2> AEffects; - + if (const RetainSummary *Summ = TF.getSummaryOfNode(BRC.getNodeResolver().getOriginalNode(N))) { // We only have summaries attached to nodes after evaluating CallExpr and // ObjCMessageExprs. const Stmt* S = cast<PostStmt>(N->getLocation()).getStmt(); - + if (const CallExpr *CE = dyn_cast<CallExpr>(S)) { // Iterate through the parameter expressions and see if the symbol // was ever passed as an argument. unsigned i = 0; - + for (CallExpr::const_arg_iterator AI=CE->arg_begin(), AE=CE->arg_end(); AI!=AE; ++AI, ++i) { - + // Retrieve the value of the argument. Is it the symbol // we are interested in? if (CurrSt->getSValAsScalarOrLoc(*AI).getAsLocSymbol() != Sym) continue; - + // We have an argument. Get the effect! AEffects.push_back(Summ->getArg(i)); } } - else if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S)) { + else if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S)) { if (const Expr *receiver = ME->getReceiver()) if (CurrSt->getSValAsScalarOrLoc(receiver).getAsLocSymbol() == Sym) { // The symbol we are tracking is the receiver. @@ -2383,11 +2383,11 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N, } } } - + do { // Get the previous type state. RefVal PrevV = *PrevT; - + // Specially handle -dealloc. if (!TF.isGCEnabled() && contains(AEffects, Dealloc)) { // Determine if the object's reference count was pushed to zero. @@ -2400,7 +2400,7 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N, break; } } - + // Specially handle CFMakeCollectable and friends. if (contains(AEffects, MakeCollectable)) { // Get the name of the function. @@ -2408,15 +2408,15 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N, SVal X = CurrSt->getSValAsScalarOrLoc(cast<CallExpr>(S)->getCallee()); const FunctionDecl* FD = X.getAsFunctionDecl(); const std::string& FName = FD->getNameAsString(); - + if (TF.isGCEnabled()) { // Determine if the object's reference count was pushed to zero. assert(!(PrevV == CurrV) && "The typestate *must* have changed."); - + os << "In GC mode a call to '" << FName << "' decrements an object's retain count and registers the " "object with the garbage collector. "; - + if (CurrV.getKind() == RefVal::Released) { assert(CurrV.getCount() == 0); os << "Since it now has a 0 retain count the object can be " @@ -2427,67 +2427,67 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N, "After this call its retain count is +" << CurrV.getCount() << '.'; } - else + else os << "When GC is not enabled a call to '" << FName << "' has no effect on its argument."; - + // Nothing more to say. break; } - - // Determine if the typestate has changed. + + // Determine if the typestate has changed. if (!(PrevV == CurrV)) switch (CurrV.getKind()) { case RefVal::Owned: case RefVal::NotOwned: - + if (PrevV.getCount() == CurrV.getCount()) { // Did an autorelease message get sent? if (PrevV.getAutoreleaseCount() == CurrV.getAutoreleaseCount()) return 0; - + assert(PrevV.getAutoreleaseCount() < CurrV.getAutoreleaseCount()); os << "Object sent -autorelease message"; break; } - + if (PrevV.getCount() > CurrV.getCount()) os << "Reference count decremented."; else os << "Reference count incremented."; - + if (unsigned Count = CurrV.getCount()) os << " The object now has a +" << Count << " retain count."; - + if (PrevV.getKind() == RefVal::Released) { assert(TF.isGCEnabled() && CurrV.getCount() > 0); os << " The object is not eligible for garbage collection until the " "retain count reaches 0 again."; } - + break; - + case RefVal::Released: os << "Object released."; break; - + case RefVal::ReturnedOwned: os << "Object returned to caller as an owning reference (single retain " "count transferred to caller)."; break; - + case RefVal::ReturnedNotOwned: os << "Object returned to caller with a +0 (non-owning) retain count."; break; - + default: return NULL; } - + // Emit any remaining diagnostics for the argument effects (if any). for (llvm::SmallVectorImpl<ArgEffect>::iterator I=AEffects.begin(), E=AEffects.end(); I != E; ++I) { - + // A bunch of things have alternate behavior under GC. if (TF.isGCEnabled()) switch (*I) { @@ -2503,25 +2503,25 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N, continue; } } - } while(0); - + } while (0); + if (os.str().empty()) return 0; // We have nothing to say! const Stmt* S = cast<PostStmt>(N->getLocation()).getStmt(); PathDiagnosticLocation Pos(S, BRC.getSourceManager()); PathDiagnosticPiece* P = new PathDiagnosticEventPiece(Pos, os.str()); - + // Add the range by scanning the children of the statement for any bindings // to Sym. - for (Stmt::const_child_iterator I = S->child_begin(), E = S->child_end(); + for (Stmt::const_child_iterator I = S->child_begin(), E = S->child_end(); I!=E; ++I) if (const Expr* Exp = dyn_cast_or_null<Expr>(*I)) if (CurrSt->getSValAsScalarOrLoc(Exp).getAsLocSymbol() == Sym) { P->addRange(Exp->getSourceRange()); break; } - + return P; } @@ -2531,56 +2531,56 @@ namespace { SymbolRef Sym; const MemRegion* Binding; bool First; - + public: FindUniqueBinding(SymbolRef sym) : Sym(sym), Binding(0), First(true) {} - + bool HandleBinding(StoreManager& SMgr, Store store, const MemRegion* R, SVal val) { - - SymbolRef SymV = val.getAsSymbol(); + + SymbolRef SymV = val.getAsSymbol(); if (!SymV || SymV != Sym) return true; - + if (Binding) { First = false; return false; } else Binding = R; - - return true; + + return true; } - + operator bool() { return First && Binding; } const MemRegion* getRegion() { return Binding; } - }; + }; } static std::pair<const ExplodedNode*,const MemRegion*> GetAllocationSite(GRStateManager& StateMgr, const ExplodedNode* N, SymbolRef Sym) { - + // Find both first node that referred to the tracked symbol and the // memory location that value was store to. const ExplodedNode* Last = N; - const MemRegion* FirstBinding = 0; - + const MemRegion* FirstBinding = 0; + while (N) { const GRState* St = N->getState(); RefBindings B = St->get<RefBindings>(); - + if (!B.lookup(Sym)) break; - + FindUniqueBinding FB(Sym); - StateMgr.iterBindings(St, FB); - if (FB) FirstBinding = FB.getRegion(); - + StateMgr.iterBindings(St, FB); + if (FB) FirstBinding = FB.getRegion(); + Last = N; - N = N->pred_empty() ? NULL : *(N->pred_begin()); + N = N->pred_empty() ? NULL : *(N->pred_begin()); } - + return std::make_pair(Last, FirstBinding); } @@ -2596,36 +2596,36 @@ CFRefReport::getEndPath(BugReporterContext& BRC, PathDiagnosticPiece* CFRefLeakReport::getEndPath(BugReporterContext& BRC, const ExplodedNode* EndN){ - + // Tell the BugReporterContext to report cases when the tracked symbol is // assigned to different variables, etc. BRC.addNotableSymbol(Sym); - + // We are reporting a leak. Walk up the graph to get to the first node where // the symbol appeared, and also get the first VarDecl that tracked object // is stored to. const ExplodedNode* AllocNode = 0; const MemRegion* FirstBinding = 0; - + llvm::tie(AllocNode, FirstBinding) = GetAllocationSite(BRC.getStateManager(), EndN, Sym); - - // Get the allocate site. + + // Get the allocate site. assert(AllocNode); const Stmt* FirstStmt = cast<PostStmt>(AllocNode->getLocation()).getStmt(); - + SourceManager& SMgr = BRC.getSourceManager(); unsigned AllocLine =SMgr.getInstantiationLineNumber(FirstStmt->getLocStart()); - + // Compute an actual location for the leak. Sometimes a leak doesn't // occur at an actual statement (e.g., transition between blocks; end // of function) so we need to walk the graph and compute a real location. const ExplodedNode* LeakN = EndN; PathDiagnosticLocation L; - + while (LeakN) { ProgramPoint P = LeakN->getLocation(); - + if (const PostStmt *PS = dyn_cast<PostStmt>(&P)) { L = PathDiagnosticLocation(PS->getStmt()->getLocStart(), SMgr); break; @@ -2636,26 +2636,26 @@ CFRefLeakReport::getEndPath(BugReporterContext& BRC, break; } } - + LeakN = LeakN->succ_empty() ? 0 : *(LeakN->succ_begin()); } - + if (!L.isValid()) { const Decl &D = BRC.getCodeDecl(); L = PathDiagnosticLocation(D.getBodyRBrace(), SMgr); } - + std::string sbuf; llvm::raw_string_ostream os(sbuf); - + os << "Object allocated on line " << AllocLine; - + if (FirstBinding) - os << " and stored into '" << FirstBinding->getString() << '\''; - + os << " and stored into '" << FirstBinding->getString() << '\''; + // Get the retain count. const RefVal* RV = EndN->getState()->get<RefBindings>(Sym); - + if (RV->getKind() == RefVal::ErrorLeakReturned) { // FIXME: Per comments in rdar://6320065, "create" only applies to CF // ojbects. Only "copy", "alloc", "retain" and "new" transfer ownership @@ -2678,16 +2678,15 @@ CFRefLeakReport::getEndPath(BugReporterContext& BRC, else os << " is no longer referenced after this point and has a retain count of" " +" << RV->getCount() << " (object leaked)"; - + return new PathDiagnosticEventPiece(L, os.str()); } CFRefLeakReport::CFRefLeakReport(CFRefBug& D, const CFRefCount &tf, ExplodedNode *n, SymbolRef sym, GRExprEngine& Eng) -: CFRefReport(D, tf, n, sym) -{ - +: CFRefReport(D, tf, n, sym) { + // Most bug reports are cached at the location where they occured. // With leaks, we want to unique them by the location where they were // allocated, and only report a single path. To do this, we need to find @@ -2697,14 +2696,14 @@ CFRefLeakReport::CFRefLeakReport(CFRefBug& D, const CFRefCount &tf, // that all ancestor nodes that represent the allocation site have the // same SourceLocation. const ExplodedNode* AllocNode = 0; - + llvm::tie(AllocNode, AllocBinding) = // Set AllocBinding. GetAllocationSite(Eng.getStateManager(), getEndNode(), getSymbol()); - + // Get the SourceLocation for the allocation site. ProgramPoint P = AllocNode->getLocation(); AllocSite = cast<PostStmt>(P).getStmt()->getLocStart(); - + // Fill in the description of the bug. Description.clear(); llvm::raw_string_ostream os(Description); @@ -2713,9 +2712,9 @@ CFRefLeakReport::CFRefLeakReport(CFRefBug& D, const CFRefCount &tf, os << "Potential leak "; if (tf.isGCEnabled()) { os << "(when using garbage collection) "; - } + } os << "of an object allocated on line " << AllocLine; - + // FIXME: AllocBinding doesn't get populated for RegionStore yet. if (AllocBinding) os << " and stored into '" << AllocBinding->getString() << '\''; @@ -2737,16 +2736,16 @@ static QualType GetReturnType(const Expr* RetE, ASTContext& Ctx) { /// more specific than id. if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(RetE)) if (const ObjCObjectPointerType *PT = RetTy->getAsObjCObjectPointerType()) - if (PT->isObjCQualifiedIdType() || PT->isObjCIdType() || + if (PT->isObjCQualifiedIdType() || PT->isObjCIdType() || PT->isObjCClassType()) { // At this point we know the return type of the message expression is // id, id<...>, or Class. If we have an ObjCInterfaceDecl, we know this // is a call to a class method whose type we can resolve. In such // cases, promote the return type to XXX* (where XXX is the class). - const ObjCInterfaceDecl *D = ME->getClassInfo().first; + const ObjCInterfaceDecl *D = ME->getClassInfo().first; return !D ? RetTy : Ctx.getPointerType(Ctx.getObjCInterfaceType(D)); } - + return RetTy; } @@ -2758,7 +2757,7 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst, const RetainSummary& Summ, ExprIterator arg_beg, ExprIterator arg_end, ExplodedNode* Pred) { - + // Get the state. const GRState *state = Builder.GetState(Pred); @@ -2766,10 +2765,10 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst, RefVal::Kind hasErr = (RefVal::Kind) 0; unsigned idx = 0; Expr* ErrorExpr = NULL; - SymbolRef ErrorSym = 0; - - for (ExprIterator I = arg_beg; I != arg_end; ++I, ++idx) { - SVal V = state->getSValAsScalarOrLoc(*I); + SymbolRef ErrorSym = 0; + + for (ExprIterator I = arg_beg; I != arg_end; ++I, ++idx) { + SVal V = state->getSValAsScalarOrLoc(*I); SymbolRef Sym = V.getAsLocSymbol(); if (Sym) @@ -2779,7 +2778,7 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst, ErrorExpr = *I; ErrorSym = Sym; break; - } + } continue; } @@ -2787,14 +2786,14 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst, if (loc::MemRegionVal* MR = dyn_cast<loc::MemRegionVal>(&V)) { if (Summ.getArg(idx) == DoNothingByRef) continue; - - // Invalidate the value of the variable passed by reference. - + + // Invalidate the value of the variable passed by reference. + // FIXME: We can have collisions on the conjured symbol if the // expression *I also creates conjured symbols. We probably want // to identify conjured symbols by an expression pair: the enclosing // expression (the context) and the expression itself. This should - // disambiguate conjured symbols. + // disambiguate conjured symbols. unsigned Count = Builder.getCurrentBlockCount(); StoreManager& StoreMgr = Eng.getStateManager().getStoreManager(); @@ -2825,9 +2824,9 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst, // Is the invalidated variable something that we were tracking? SymbolRef Sym = state->getSValAsScalarOrLoc(R).getAsLocSymbol(); - + // Remove any existing reference-count binding. - if (Sym) + if (Sym) state = state->remove<RefBindings>(Sym); state = StoreMgr.InvalidateRegion(state, R, *I, Count); @@ -2845,9 +2844,9 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst, // We should bind it to UnknownVal explicitly. Otherwise default value // may be loaded. state = state->unbindLoc(cast<nonloc::LocAsInteger>(V).getLoc()); - } - - // Evaluate the effect on the message receiver. + } + + // Evaluate the effect on the message receiver. if (!ErrorExpr && Receiver) { SymbolRef Sym = state->getSValAsScalarOrLoc(Receiver).getAsLocSymbol(); if (Sym) { @@ -2860,17 +2859,17 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst, } } } - - // Process any errors. + + // Process any errors. if (hasErr) { ProcessNonLeakError(Dst, Builder, Ex, ErrorExpr, Pred, state, hasErr, ErrorSym); return; } - - // Consult the summary for the return value. + + // Consult the summary for the return value. RetEffect RE = Summ.getRetEffect(); - + if (RE.getKind() == RetEffect::OwnedWhenTrackedReceiver) { assert(Receiver); SVal V = state->getSValAsScalarOrLoc(Receiver); @@ -2883,32 +2882,32 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst, if (!found) RE = RetEffect::MakeNoRet(); - } - + } + switch (RE.getKind()) { default: assert (false && "Unhandled RetEffect."); break; - - case RetEffect::NoRet: { + + case RetEffect::NoRet: { // Make up a symbol for the return value (not reference counted). // FIXME: Most of this logic is not specific to the retain/release // checker. - + // FIXME: We eventually should handle structs and other compound types // that are returned by value. - + QualType T = Ex->getType(); - + if (Loc::IsLocType(T) || (T->isIntegerType() && T->isScalarType())) { unsigned Count = Builder.getCurrentBlockCount(); ValueManager &ValMgr = Eng.getValueManager(); SVal X = ValMgr.getConjuredSymbolVal(Ex, T, Count); state = state->BindExpr(Ex, X, false); - } - + } + break; } - + case RetEffect::Alias: { unsigned idx = RE.getIndex(); assert (arg_end >= arg_beg); @@ -2917,20 +2916,20 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst, state = state->BindExpr(Ex, V, false); break; } - + case RetEffect::ReceiverAlias: { assert (Receiver); SVal V = state->getSValAsScalarOrLoc(Receiver); state = state->BindExpr(Ex, V, false); break; } - + case RetEffect::OwnedAllocatedSymbol: case RetEffect::OwnedSymbol: { unsigned Count = Builder.getCurrentBlockCount(); - ValueManager &ValMgr = Eng.getValueManager(); + ValueManager &ValMgr = Eng.getValueManager(); SymbolRef Sym = ValMgr.getConjuredSymbol(Ex, Count); - QualType RetT = GetReturnType(Ex, ValMgr.getContext()); + QualType RetT = GetReturnType(Ex, ValMgr.getContext()); state = state->set<RefBindings>(Sym, RefVal::makeOwned(RE.getObjKind(), RetT)); state = state->BindExpr(Ex, ValMgr.makeLoc(Sym), false); @@ -2941,31 +2940,31 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst, if (RE.getKind() == RetEffect::OwnedAllocatedSymbol) { bool isFeasible; state = state.Assume(loc::SymbolVal(Sym), true, isFeasible); - assert(isFeasible && "Cannot assume fresh symbol is non-null."); + assert(isFeasible && "Cannot assume fresh symbol is non-null."); } #endif - + break; } - + case RetEffect::GCNotOwnedSymbol: case RetEffect::NotOwnedSymbol: { unsigned Count = Builder.getCurrentBlockCount(); ValueManager &ValMgr = Eng.getValueManager(); SymbolRef Sym = ValMgr.getConjuredSymbol(Ex, Count); - QualType RetT = GetReturnType(Ex, ValMgr.getContext()); + QualType RetT = GetReturnType(Ex, ValMgr.getContext()); state = state->set<RefBindings>(Sym, RefVal::makeNotOwned(RE.getObjKind(), RetT)); state = state->BindExpr(Ex, ValMgr.makeLoc(Sym), false); break; } } - + // Generate a sink node if we are at the end of a path. ExplodedNode *NewNode = Summ.isEndPath() ? Builder.MakeSinkNode(Dst, Ex, Pred, state) : Builder.MakeNode(Dst, Ex, Pred, state); - + // Annotate the edge with summary we used. if (NewNode) SummaryLog[NewNode] = &Summ; } @@ -2977,9 +2976,9 @@ void CFRefCount::EvalCall(ExplodedNodeSet& Dst, CallExpr* CE, SVal L, ExplodedNode* Pred) { const FunctionDecl* FD = L.getAsFunctionDecl(); - RetainSummary* Summ = !FD ? Summaries.getDefaultSummary() + RetainSummary* Summ = !FD ? Summaries.getDefaultSummary() : Summaries.getSummary(const_cast<FunctionDecl*>(FD)); - + assert(Summ); EvalSummary(Dst, Eng, Builder, CE, 0, *Summ, CE->arg_begin(), CE->arg_end(), Pred); @@ -2989,9 +2988,9 @@ void CFRefCount::EvalObjCMessageExpr(ExplodedNodeSet& Dst, GRExprEngine& Eng, GRStmtNodeBuilder& Builder, ObjCMessageExpr* ME, - ExplodedNode* Pred) { + ExplodedNode* Pred) { RetainSummary* Summ = 0; - + if (Expr* Receiver = ME->getReceiver()) { // We need the type-information of the tracked receiver object // Retrieve it from the state. @@ -3005,7 +3004,7 @@ void CFRefCount::EvalObjCMessageExpr(ExplodedNodeSet& Dst, SVal V = St->getSValAsScalarOrLoc(Receiver); SymbolRef Sym = V.getAsLocSymbol(); - + if (Sym) { if (const RefVal* T = St->get<RefBindings>(Sym)) { if (const ObjCObjectPointerType* PT = @@ -3028,21 +3027,21 @@ void CFRefCount::EvalObjCMessageExpr(ExplodedNodeSet& Dst, // Special-case: are we sending a mesage to "self"? // This is a hack. When we have full-IP this should be removed. - if (isa<ObjCMethodDecl>(Pred->getLocationContext()->getDecl())) { + if (isa<ObjCMethodDecl>(Pred->getLocationContext()->getDecl())) { if (Expr* Receiver = ME->getReceiver()) { SVal X = St->getSValAsScalarOrLoc(Receiver); - if (loc::MemRegionVal* L = dyn_cast<loc::MemRegionVal>(&X)) { + if (loc::MemRegionVal* L = dyn_cast<loc::MemRegionVal>(&X)) { // Get the region associated with 'self'. - const LocationContext *LC = Pred->getLocationContext(); + const LocationContext *LC = Pred->getLocationContext(); if (const ImplicitParamDecl *SelfDecl = LC->getSelfDecl()) { - SVal SelfVal = St->getSVal(St->getRegion(SelfDecl, LC)); + SVal SelfVal = St->getSVal(St->getRegion(SelfDecl, LC)); if (L->getBaseRegion() == SelfVal.getAsRegion()) { // Update the summary to make the default argument effect // 'StopTracking'. Summ = Summaries.copySummary(Summ); Summ->setDefaultArgEffect(StopTracking); } - } + } } } } @@ -3070,18 +3069,18 @@ public: } }; } // end anonymous namespace - -void CFRefCount::EvalBind(GRStmtNodeBuilderRef& B, SVal location, SVal val) { - // Are we storing to something that causes the value to "escape"? + +void CFRefCount::EvalBind(GRStmtNodeBuilderRef& B, SVal location, SVal val) { + // Are we storing to something that causes the value to "escape"? bool escapes = false; - + // A value escapes in three possible cases (this may change): // // (1) we are binding to something that is not a memory region. // (2) we are binding to a memregion that does not have stack storage // (3) we are binding to a memregion with stack storage that the store - // does not understand. + // does not understand. const GRState *state = B.getState(); if (!isa<loc::MemRegionVal>(location)) @@ -3089,7 +3088,7 @@ void CFRefCount::EvalBind(GRStmtNodeBuilderRef& B, SVal location, SVal val) { else { const MemRegion* R = cast<loc::MemRegionVal>(location).getRegion(); escapes = !R->hasStackStorage(); - + if (!escapes) { // To test (3), generate a new state with the binding removed. If it is // the same state, then it escapes (since the store cannot represent @@ -3116,35 +3115,35 @@ void CFRefCount::EvalReturn(ExplodedNodeSet& Dst, GRStmtNodeBuilder& Builder, ReturnStmt* S, ExplodedNode* Pred) { - + Expr* RetE = S->getRetValue(); if (!RetE) return; - + const GRState *state = Builder.GetState(Pred); SymbolRef Sym = state->getSValAsScalarOrLoc(RetE).getAsLocSymbol(); - + if (!Sym) return; - + // Get the reference count binding (if any). const RefVal* T = state->get<RefBindings>(Sym); - + if (!T) return; - - // Change the reference count. - RefVal X = *T; - - switch (X.getKind()) { - case RefVal::Owned: { + + // Change the reference count. + RefVal X = *T; + + switch (X.getKind()) { + case RefVal::Owned: { unsigned cnt = X.getCount(); assert (cnt > 0); X.setCount(cnt - 1); X = X ^ RefVal::ReturnedOwned; break; } - + case RefVal::NotOwned: { unsigned cnt = X.getCount(); if (cnt) { @@ -3156,39 +3155,39 @@ void CFRefCount::EvalReturn(ExplodedNodeSet& Dst, } break; } - - default: + + default: return; } - + // Update the binding. state = state->set<RefBindings>(Sym, X); Pred = Builder.MakeNode(Dst, S, Pred, state); - + // Did we cache out? if (!Pred) return; - + // Update the autorelease counts. static unsigned autoreleasetag = 0; GenericNodeBuilder Bd(Builder, S, &autoreleasetag); bool stop = false; llvm::tie(Pred, state) = HandleAutoreleaseCounts(state , Bd, Pred, Eng, Sym, X, stop); - + // Did we cache out? if (!Pred || stop) return; - + // Get the updated binding. T = state->get<RefBindings>(Sym); assert(T); X = *T; - + // Any leaks or other errors? if (X.isReturnedOwned() && X.getCount() == 0) { - const Decl *CD = Eng.getAnalysisManager().getCodeDecl(); - if (const ObjCMethodDecl* MD = dyn_cast<ObjCMethodDecl>(CD)) { + const Decl *CD = Eng.getAnalysisManager().getCodeDecl(); + if (const ObjCMethodDecl* MD = dyn_cast<ObjCMethodDecl>(CD)) { const RetainSummary &Summ = *Summaries.getMethodSummary(MD); RetEffect RE = Summ.getRetEffect(); bool hasError = false; @@ -3200,20 +3199,20 @@ void CFRefCount::EvalReturn(ExplodedNodeSet& Dst, // a leak (as the caller expects a GC'ed object) because no // method should return ownership unless it returns a CF object. X = X ^ RefVal::ErrorGCLeakReturned; - + // Keep this false until this is properly tested. hasError = true; } else if (!RE.isOwned()) { // Either we are using GC and the returned object is a CF type // or we aren't using GC. In either case, we expect that the - // enclosing method is expected to return ownership. + // enclosing method is expected to return ownership. hasError = true; X = X ^ RefVal::ErrorLeakReturned; } } - - if (hasError) { + + if (hasError) { // Generate an error node. static int ReturnOwnLeakTag = 0; state = state->set<RefBindings>(Sym, X); @@ -3227,16 +3226,16 @@ void CFRefCount::EvalReturn(ExplodedNodeSet& Dst, BR->EmitReport(report); } } - } + } } else if (X.isReturnedNotOwned()) { - const Decl *CD = Eng.getAnalysisManager().getCodeDecl(); + const Decl *CD = Eng.getAnalysisManager().getCodeDecl(); if (const ObjCMethodDecl* MD = dyn_cast<ObjCMethodDecl>(CD)) { const RetainSummary &Summ = *Summaries.getMethodSummary(MD); if (Summ.getRetEffect().isOwned()) { // Trying to return a not owned object to a caller expecting an // owned object. - + static int ReturnNotOwnedForOwnedTag = 0; state = state->set<RefBindings>(Sym, X ^ RefVal::ErrorReturnedNotOwned); if (ExplodedNode *N = @@ -3261,18 +3260,18 @@ const GRState* CFRefCount::EvalAssume(const GRState *state, // FIXME: We may add to the interface of EvalAssume the list of symbols // whose assumptions have changed. For now we just iterate through the // bindings and check if any of the tracked symbols are NULL. This isn't - // too bad since the number of symbols we will track in practice are + // too bad since the number of symbols we will track in practice are // probably small and EvalAssume is only called at branches and a few // other places. RefBindings B = state->get<RefBindings>(); - + if (B.isEmpty()) return state; - - bool changed = false; + + bool changed = false; RefBindings::Factory& RefBFactory = state->get_context<RefBindings>(); - for (RefBindings::iterator I=B.begin(), E=B.end(); I!=E; ++I) { + for (RefBindings::iterator I=B.begin(), E=B.end(); I!=E; ++I) { // Check if the symbol is null (or equal to any constant). // If this is the case, stop tracking the symbol. if (state->getSymVal(I.getKey())) { @@ -3280,10 +3279,10 @@ const GRState* CFRefCount::EvalAssume(const GRState *state, B = RefBFactory.Remove(B, I.getKey()); } } - + if (changed) state = state->set<RefBindings>(B); - + return state; } @@ -3297,21 +3296,21 @@ const GRState * CFRefCount::Update(const GRState * state, SymbolRef sym, case IncRefMsg: E = isGCEnabled() ? DoNothing : IncRef; break; case DecRefMsg: E = isGCEnabled() ? DoNothing : DecRef; break; case MakeCollectable: E = isGCEnabled() ? DecRef : DoNothing; break; - case NewAutoreleasePool: E = isGCEnabled() ? DoNothing : + case NewAutoreleasePool: E = isGCEnabled() ? DoNothing : NewAutoreleasePool; break; } - + // Handle all use-after-releases. if (!isGCEnabled() && V.getKind() == RefVal::Released) { V = V ^ RefVal::ErrorUseAfterRelease; hasErr = V.getKind(); return state->set<RefBindings>(sym, V); - } - + } + switch (E) { default: assert (false && "Unhandled CFRef transition."); - + case Dealloc: // Any use of -dealloc in GC is *bad*. if (isGCEnabled()) { @@ -3319,7 +3318,7 @@ const GRState * CFRefCount::Update(const GRState * state, SymbolRef sym, hasErr = V.getKind(); break; } - + switch (V.getKind()) { default: assert(false && "Invalid case."); @@ -3332,13 +3331,13 @@ const GRState * CFRefCount::Update(const GRState * state, SymbolRef sym, V = V ^ RefVal::ErrorDeallocNotOwned; hasErr = V.getKind(); break; - } + } break; case NewAutoreleasePool: assert(!isGCEnabled()); return state->add<AutoreleaseStack>(sym); - + case MayEscape: if (V.getKind() == RefVal::Owned) { V = V ^ RefVal::NotOwned; @@ -3346,7 +3345,7 @@ const GRState * CFRefCount::Update(const GRState * state, SymbolRef sym, } // Fall-through. - + case DoNothingByRef: case DoNothing: return state; @@ -3354,7 +3353,7 @@ const GRState * CFRefCount::Update(const GRState * state, SymbolRef sym, case Autorelease: if (isGCEnabled()) return state; - + // Update the autorelease counts. state = SendAutorelease(state, ARCountFactory, sym); V = V.autorelease(); @@ -3363,7 +3362,7 @@ const GRState * CFRefCount::Update(const GRState * state, SymbolRef sym, case StopTracking: return state->remove<RefBindings>(sym); - case IncRef: + case IncRef: switch (V.getKind()) { default: assert(false); @@ -3371,15 +3370,15 @@ const GRState * CFRefCount::Update(const GRState * state, SymbolRef sym, case RefVal::Owned: case RefVal::NotOwned: V = V + 1; - break; + break; case RefVal::Released: // Non-GC cases are handled above. assert(isGCEnabled()); V = (V ^ RefVal::Owned) + 1; break; - } + } break; - + case SelfOwn: V = V ^ RefVal::NotOwned; // Fall-through. @@ -3394,23 +3393,23 @@ const GRState * CFRefCount::Update(const GRState * state, SymbolRef sym, if (V.getCount() == 1) V = V ^ RefVal::Released; V = V - 1; break; - + case RefVal::NotOwned: if (V.getCount() > 0) V = V - 1; else { V = V ^ RefVal::ErrorReleaseNotOwned; hasErr = V.getKind(); - } + } break; - + case RefVal::Released: // Non-GC cases are handled above. assert(isGCEnabled()); V = V ^ RefVal::ErrorUseAfterRelease; hasErr = V.getKind(); - break; - } + break; + } break; } return state->set<RefBindings>(sym, V); @@ -3425,22 +3424,22 @@ CFRefCount::HandleAutoreleaseCounts(const GRState * state, GenericNodeBuilder Bd ExplodedNode* Pred, GRExprEngine &Eng, SymbolRef Sym, RefVal V, bool &stop) { - + unsigned ACnt = V.getAutoreleaseCount(); stop = false; // No autorelease counts? Nothing to be done. if (!ACnt) return std::make_pair(Pred, state); - - assert(!isGCEnabled() && "Autorelease counts in GC mode?"); + + assert(!isGCEnabled() && "Autorelease counts in GC mode?"); unsigned Cnt = V.getCount(); - + // FIXME: Handle sending 'autorelease' to already released object. if (V.getKind() == RefVal::ReturnedOwned) ++Cnt; - + if (ACnt <= Cnt) { if (ACnt == Cnt) { V.clearCounts(); @@ -3457,7 +3456,7 @@ CFRefCount::HandleAutoreleaseCounts(const GRState * state, GenericNodeBuilder Bd ExplodedNode *N = Bd.MakeNode(state, Pred); stop = (N == 0); return std::make_pair(N, state); - } + } // Woah! More autorelease counts then retain counts left. // Emit hard error. @@ -3467,7 +3466,7 @@ CFRefCount::HandleAutoreleaseCounts(const GRState * state, GenericNodeBuilder Bd if (ExplodedNode *N = Bd.MakeNode(state, Pred)) { N->markAsSink(); - + std::string sbuf; llvm::raw_string_ostream os(sbuf); os << "Object over-autoreleased: object was sent -autorelease"; @@ -3479,26 +3478,26 @@ CFRefCount::HandleAutoreleaseCounts(const GRState * state, GenericNodeBuilder Bd else os << "+" << V.getCount(); os << " retain counts"; - + CFRefReport *report = new CFRefReport(*static_cast<CFRefBug*>(overAutorelease), *this, N, Sym, os.str().c_str()); BR->EmitReport(report); } - + return std::make_pair((ExplodedNode*)0, state); } const GRState * CFRefCount::HandleSymbolDeath(const GRState * state, SymbolRef sid, RefVal V, llvm::SmallVectorImpl<SymbolRef> &Leaked) { - - bool hasLeak = V.isOwned() || + + bool hasLeak = V.isOwned() || ((V.isNotOwned() || V.isReturnedOwned()) && V.getCount() > 0); - + if (!hasLeak) return state->remove<RefBindings>(sid); - + Leaked.push_back(sid); return state->set<RefBindings>(sid, V ^ RefVal::ErrorLeak); } @@ -3509,49 +3508,49 @@ CFRefCount::ProcessLeaks(const GRState * state, GenericNodeBuilder &Builder, GRExprEngine& Eng, ExplodedNode *Pred) { - + if (Leaked.empty()) return Pred; - + // Generate an intermediate node representing the leak point. ExplodedNode *N = Builder.MakeNode(state, Pred); - + if (N) { for (llvm::SmallVectorImpl<SymbolRef>::iterator I = Leaked.begin(), E = Leaked.end(); I != E; ++I) { - - CFRefBug *BT = static_cast<CFRefBug*>(Pred ? leakWithinFunction + + CFRefBug *BT = static_cast<CFRefBug*>(Pred ? leakWithinFunction : leakAtReturn); assert(BT && "BugType not initialized."); CFRefLeakReport* report = new CFRefLeakReport(*BT, *this, N, *I, Eng); BR->EmitReport(report); } } - + return N; } void CFRefCount::EvalEndPath(GRExprEngine& Eng, GREndPathNodeBuilder& Builder) { - + const GRState *state = Builder.getState(); GenericNodeBuilder Bd(Builder); - RefBindings B = state->get<RefBindings>(); + RefBindings B = state->get<RefBindings>(); ExplodedNode *Pred = 0; for (RefBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) { bool stop = false; llvm::tie(Pred, state) = HandleAutoreleaseCounts(state, Bd, Pred, Eng, (*I).first, - (*I).second, stop); + (*I).second, stop); if (stop) return; } - - B = state->get<RefBindings>(); - llvm::SmallVector<SymbolRef, 10> Leaked; - + + B = state->get<RefBindings>(); + llvm::SmallVector<SymbolRef, 10> Leaked; + for (RefBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) state = HandleSymbolDeath(state, (*I).first, (*I).second, Leaked); @@ -3567,7 +3566,7 @@ void CFRefCount::EvalDeadSymbols(ExplodedNodeSet& Dst, SymbolReaper& SymReaper) { RefBindings B = state->get<RefBindings>(); - + // Update counts from autorelease pools for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(), E = SymReaper.dead_end(); I != E; ++I) { @@ -3583,32 +3582,32 @@ void CFRefCount::EvalDeadSymbols(ExplodedNodeSet& Dst, return; } } - + B = state->get<RefBindings>(); llvm::SmallVector<SymbolRef, 10> Leaked; - + for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(), - E = SymReaper.dead_end(); I != E; ++I) { + E = SymReaper.dead_end(); I != E; ++I) { if (const RefVal* T = B.lookup(*I)) state = HandleSymbolDeath(state, *I, *T, Leaked); - } - + } + static unsigned LeakPPTag = 0; { GenericNodeBuilder Bd(Builder, S, &LeakPPTag); Pred = ProcessLeaks(state, Leaked, Bd, Eng, Pred); } - + // Did we cache out? if (!Pred) return; - + // Now generate a new node that nukes the old bindings. RefBindings::Factory& F = state->get_context<RefBindings>(); - + for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(), E = SymReaper.dead_end(); I!=E; ++I) B = F.Remove(B, *I); - + state = state->set<RefBindings>(B); Builder.MakeNode(Dst, S, Pred, state); } @@ -3621,19 +3620,19 @@ void CFRefCount::ProcessNonLeakError(ExplodedNodeSet& Dst, RefVal::Kind hasErr, SymbolRef Sym) { Builder.BuildSinks = true; ExplodedNode *N = Builder.MakeNode(Dst, NodeExpr, Pred, St); - + if (!N) return; - + CFRefBug *BT = 0; - + switch (hasErr) { default: assert(false && "Unhandled error."); return; case RefVal::ErrorUseAfterRelease: BT = static_cast<CFRefBug*>(useAfterRelease); - break; + break; case RefVal::ErrorReleaseNotOwned: BT = static_cast<CFRefBug*>(releaseNotOwned); break; @@ -3644,7 +3643,7 @@ void CFRefCount::ProcessNonLeakError(ExplodedNodeSet& Dst, BT = static_cast<CFRefBug*>(deallocNotOwned); break; } - + CFRefReport *report = new CFRefReport(*BT, *this, N, Sym); report->addRange(ErrorExpr->getSourceRange()); BR->EmitReport(report); @@ -3657,4 +3656,4 @@ void CFRefCount::ProcessNonLeakError(ExplodedNodeSet& Dst, GRTransferFuncs* clang::MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled, const LangOptions& lopts) { return new CFRefCount(Ctx, GCEnabled, lopts); -} +} |