Hi George, This broke the modules build, reverted in r340117 for now. I can help you figure out any module map change if necessary next week.
Thanks, On Fri, Aug 17, 2018 at 6:46 PM George Karpenkov via cfe-commits <cfe-commits@lists.llvm.org> wrote: > > Author: george.karpenkov > Date: Fri Aug 17 18:45:50 2018 > New Revision: 340114 > > URL: http://llvm.org/viewvc/llvm-project?rev=340114&view=rev > Log: > [analyzer] [NFC] Split up RetainSummaryManager from RetainCountChecker > > ARCMigrator is using code from RetainCountChecker, which is a layering > violation (and it also does it badly, by using a different header, and > then relying on implementation being present in a header file). > > This change splits up RetainSummaryManager into a separate library in > lib/Analysis, which can be used independently of a checker. > > Differential Revision: https://reviews.llvm.org/D50934 > > Added: > cfe/trunk/include/clang/Analysis/RetainSummaryManager.h > cfe/trunk/include/clang/StaticAnalyzer/Checkers/SelectorExtras.h > cfe/trunk/lib/Analysis/RetainSummaryManager.cpp > Removed: > cfe/trunk/include/clang/Analysis/ObjCRetainCount.h > > cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountSummaries.cpp > > cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountSummaries.h > cfe/trunk/lib/StaticAnalyzer/Checkers/SelectorExtras.h > Modified: > cfe/trunk/lib/ARCMigrate/CMakeLists.txt > cfe/trunk/lib/ARCMigrate/ObjCMT.cpp > cfe/trunk/lib/Analysis/CMakeLists.txt > cfe/trunk/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp > cfe/trunk/lib/StaticAnalyzer/Checkers/CMakeLists.txt > cfe/trunk/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp > > cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp > > cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.h > > cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.h > cfe/trunk/lib/StaticAnalyzer/Checkers/TrustNonnullChecker.cpp > > Removed: cfe/trunk/include/clang/Analysis/ObjCRetainCount.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/ObjCRetainCount.h?rev=340113&view=auto > ============================================================================== > --- cfe/trunk/include/clang/Analysis/ObjCRetainCount.h (original) > +++ cfe/trunk/include/clang/Analysis/ObjCRetainCount.h (removed) > @@ -1,231 +0,0 @@ > -//==-- ObjCRetainCount.h - Retain count summaries for Cocoa -------*- C++ > -*--// > -// > -// The LLVM Compiler Infrastructure > -// > -// This file is distributed under the University of Illinois Open Source > -// License. See LICENSE.TXT for details. > -// > -//===----------------------------------------------------------------------===// > -// > -// This file defines the core data structures for retain count "summaries" > -// for Objective-C and Core Foundation APIs. These summaries are used > -// by the static analyzer to summarize the retain/release effects of > -// function and method calls. This drives a path-sensitive typestate > -// analysis in the static analyzer, but can also potentially be used by > -// other clients. > -// > -//===----------------------------------------------------------------------===// > - > -#ifndef LLVM_CLANG_STATICANALYZER_CHECKERS_OBJCRETAINCOUNT_H > -#define LLVM_CLANG_STATICANALYZER_CHECKERS_OBJCRETAINCOUNT_H > - > -#include "clang/Basic/LLVM.h" > -#include "llvm/ADT/ArrayRef.h" > -#include "llvm/ADT/SmallVector.h" > - > -namespace clang { > -class FunctionDecl; > -class ObjCMethodDecl; > - > -namespace ento { namespace objc_retain { > - > -/// An ArgEffect summarizes the retain count behavior on an argument or > receiver > -/// to a function or method. > -enum ArgEffect { > - /// There is no effect. > - DoNothing, > - > - /// The argument is treated as if an -autorelease message had been sent to > - /// the referenced object. > - Autorelease, > - > - /// The argument is treated as if an -dealloc message had been sent to > - /// the referenced object. > - Dealloc, > - > - /// The argument has its reference count decreased by 1. This is as > - /// if CFRelease has been called on the argument. > - DecRef, > - > - /// The argument has its reference count decreased by 1. This is as > - /// if a -release message has been sent to the argument. This differs > - /// in behavior from DecRef when GC is enabled. > - DecRefMsg, > - > - /// The argument has its reference count decreased by 1 to model > - /// a transferred bridge cast under ARC. > - DecRefBridgedTransferred, > - > - /// The argument has its reference count increased by 1. This is as > - /// if a -retain message has been sent to the argument. This differs > - /// in behavior from IncRef when GC is enabled. > - IncRefMsg, > - > - /// The argument has its reference count increased by 1. This is as > - /// if CFRetain has been called on the argument. > - IncRef, > - > - /// Used to mark an argument as collectible in GC mode, currently a noop. > - MakeCollectable, > - > - /// The argument is a pointer to a retain-counted object; on exit, the new > - /// value of the pointer is a +0 value or NULL. > - UnretainedOutParameter, > - > - /// The argument is a pointer to a retain-counted object; on exit, the new > - /// value of the pointer is a +1 value or NULL. > - RetainedOutParameter, > - > - /// The argument is treated as potentially escaping, meaning that > - /// even when its reference count hits 0 it should be treated as still > - /// possibly being alive as someone else *may* be holding onto the object. > - MayEscape, > - > - /// All typestate tracking of the object ceases. This is usually employed > - /// when the effect of the call is completely unknown. > - StopTracking, > - > - /// All typestate tracking of the object ceases. Unlike StopTracking, > - /// this is also enforced when the method body is inlined. > - /// > - /// In some cases, we obtain a better summary for this checker > - /// by looking at the call site than by inlining the function. > - /// Signifies that we should stop tracking the symbol even if > - /// the function is inlined. > - StopTrackingHard, > - > - /// Performs the combined functionality of DecRef and StopTrackingHard. > - /// > - /// The models the effect that the called function decrements the reference > - /// count of the argument and all typestate tracking on that argument > - /// should cease. > - DecRefAndStopTrackingHard, > - > - /// Performs the combined functionality of DecRefMsg and StopTrackingHard. > - /// > - /// The models the effect that the called function decrements the reference > - /// count of the argument and all typestate tracking on that argument > - /// should cease. > - DecRefMsgAndStopTrackingHard > -}; > - > -/// RetEffect summarizes a call's retain/release behavior with respect > -/// to its return value. > -class RetEffect { > -public: > - enum Kind { > - /// Indicates that no retain count information is tracked for > - /// the return value. > - NoRet, > - /// Indicates that the returned value is an owned (+1) symbol. > - OwnedSymbol, > - /// Indicates that the returned value is an object with retain count > - /// semantics but that it is not owned (+0). This is the default > - /// for getters, etc. > - NotOwnedSymbol, > - /// Indicates that the object is not owned and controlled by the > - /// Garbage collector. > - GCNotOwnedSymbol, > - /// Indicates that the return value is an owned object when the > - /// receiver is also a tracked object. > - OwnedWhenTrackedReceiver, > - // Treat this function as returning a non-tracked symbol even if > - // the function has been inlined. This is used where the call > - // site summary is more presise than the summary indirectly produced > - // by inlining the function > - NoRetHard > - }; > - > - /// Determines the object kind of a tracked object. > - enum ObjKind { > - /// Indicates that the tracked object is a CF object. This is > - /// important between GC and non-GC code. > - CF, > - /// Indicates that the tracked object is an Objective-C object. > - ObjC, > - /// Indicates that the tracked object could be a CF or Objective-C > object. > - AnyObj, > - /// Indicates that the tracked object is a generalized object. > - Generalized > - }; > - > -private: > - Kind K; > - ObjKind O; > - > - RetEffect(Kind k, ObjKind o = AnyObj) : K(k), O(o) {} > - > -public: > - Kind getKind() const { return K; } > - > - ObjKind getObjKind() const { return O; } > - > - bool isOwned() const { > - return K == OwnedSymbol || K == OwnedWhenTrackedReceiver; > - } > - > - bool notOwned() const { > - return K == NotOwnedSymbol; > - } > - > - bool operator==(const RetEffect &Other) const { > - return K == Other.K && O == Other.O; > - } > - > - static RetEffect MakeOwnedWhenTrackedReceiver() { > - return RetEffect(OwnedWhenTrackedReceiver, ObjC); > - } > - > - static RetEffect MakeOwned(ObjKind o) { > - return RetEffect(OwnedSymbol, o); > - } > - static RetEffect MakeNotOwned(ObjKind o) { > - return RetEffect(NotOwnedSymbol, o); > - } > - static RetEffect MakeGCNotOwned() { > - return RetEffect(GCNotOwnedSymbol, ObjC); > - } > - static RetEffect MakeNoRet() { > - return RetEffect(NoRet); > - } > - static RetEffect MakeNoRetHard() { > - return RetEffect(NoRetHard); > - } > -}; > - > -/// Encapsulates the retain count semantics on the arguments, return value, > -/// and receiver (if any) of a function/method call. > -/// > -/// Note that construction of these objects is not highly efficient. That > -/// is okay for clients where creating these objects isn't really a > bottleneck. > -/// The purpose of the API is to provide something simple. The actual > -/// static analyzer checker that implements retain/release typestate > -/// tracking uses something more efficient. > -class CallEffects { > - llvm::SmallVector<ArgEffect, 10> Args; > - RetEffect Ret; > - ArgEffect Receiver; > - > - CallEffects(const RetEffect &R) : Ret(R) {} > - > -public: > - /// Returns the argument effects for a call. > - ArrayRef<ArgEffect> getArgs() const { return Args; } > - > - /// Returns the effects on the receiver. > - ArgEffect getReceiver() const { return Receiver; } > - > - /// Returns the effect on the return value. > - RetEffect getReturnValue() const { return Ret; } > - > - /// Return the CallEfect for a given Objective-C method. > - static CallEffects getEffect(const ObjCMethodDecl *MD); > - > - /// Return the CallEfect for a given C/C++ function. > - static CallEffects getEffect(const FunctionDecl *FD); > -}; > - > -}}} > - > -#endif > - > > Added: cfe/trunk/include/clang/Analysis/RetainSummaryManager.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/RetainSummaryManager.h?rev=340114&view=auto > ============================================================================== > --- cfe/trunk/include/clang/Analysis/RetainSummaryManager.h (added) > +++ cfe/trunk/include/clang/Analysis/RetainSummaryManager.h Fri Aug 17 > 18:45:50 2018 > @@ -0,0 +1,706 @@ > +//=== RetainSummaryManager.h - Summaries for reference counting ---*- C++ > -*--// > +// > +// The LLVM Compiler Infrastructure > +// > +// This file is distributed under the University of Illinois Open Source > +// License. See LICENSE.TXT for details. > +// > +//===----------------------------------------------------------------------===// > +// > +// This file defines summaries implementation for retain counting, which > +// implements a reference count checker for Core Foundation and Cocoa > +// on (Mac OS X). > +// > +//===----------------------------------------------------------------------===// > + > +#ifndef LLVM_CLANG_LIB_ANALYSIS_RETAINSUMMARYMANAGER > +#define LLVM_CLANG_LIB_ANALYSIS_RETAINSUMMARYMANAGER > + > +#include "llvm/ADT/DenseMap.h" > +#include "llvm/ADT/FoldingSet.h" > +#include "clang/AST/Attr.h" > +#include "clang/AST/DeclCXX.h" > +#include "clang/AST/DeclObjC.h" > +#include "clang/AST/ParentMap.h" > +#include "clang/StaticAnalyzer/Checkers/SelectorExtras.h" > +#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" > +#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" > +#include "clang/StaticAnalyzer/Core/Checker.h" > +#include "clang/StaticAnalyzer/Core/CheckerManager.h" > +#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" > +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" > +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" > +#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h" > +#include "llvm/ADT/ImmutableList.h" > +#include "llvm/ADT/ImmutableMap.h" > +#include "llvm/ADT/STLExtras.h" > + > +//===----------------------------------------------------------------------===// > +// Adapters for FoldingSet. > +//===----------------------------------------------------------------------===// > + > +using namespace clang; > +using namespace ento; > + > +namespace clang { > +namespace ento { > + > +/// An ArgEffect summarizes the retain count behavior on an argument or > receiver > +/// to a function or method. > +enum ArgEffect { > + /// There is no effect. > + DoNothing, > + > + /// The argument is treated as if an -autorelease message had been sent to > + /// the referenced object. > + Autorelease, > + > + /// The argument is treated as if an -dealloc message had been sent to > + /// the referenced object. > + Dealloc, > + > + /// The argument has its reference count decreased by 1. This is as > + /// if CFRelease has been called on the argument. > + DecRef, > + > + /// The argument has its reference count decreased by 1. This is as > + /// if a -release message has been sent to the argument. This differs > + /// in behavior from DecRef when GC is enabled. > + DecRefMsg, > + > + /// The argument has its reference count decreased by 1 to model > + /// a transferred bridge cast under ARC. > + DecRefBridgedTransferred, > + > + /// The argument has its reference count increased by 1. This is as > + /// if a -retain message has been sent to the argument. This differs > + /// in behavior from IncRef when GC is enabled. > + IncRefMsg, > + > + /// The argument has its reference count increased by 1. This is as > + /// if CFRetain has been called on the argument. > + IncRef, > + > + /// The argument acts as if has been passed to CFMakeCollectable, which > + /// transfers the object to the Garbage Collector under GC. > + MakeCollectable, > + > + /// The argument is a pointer to a retain-counted object; on exit, the new > + /// value of the pointer is a +0 value or NULL. > + UnretainedOutParameter, > + > + /// The argument is a pointer to a retain-counted object; on exit, the new > + /// value of the pointer is a +1 value or NULL. > + RetainedOutParameter, > + > + /// The argument is treated as potentially escaping, meaning that > + /// even when its reference count hits 0 it should be treated as still > + /// possibly being alive as someone else *may* be holding onto the object. > + MayEscape, > + > + /// All typestate tracking of the object ceases. This is usually employed > + /// when the effect of the call is completely unknown. > + StopTracking, > + > + /// All typestate tracking of the object ceases. Unlike StopTracking, > + /// this is also enforced when the method body is inlined. > + /// > + /// In some cases, we obtain a better summary for this checker > + /// by looking at the call site than by inlining the function. > + /// Signifies that we should stop tracking the symbol even if > + /// the function is inlined. > + StopTrackingHard, > + > + /// Performs the combined functionality of DecRef and StopTrackingHard. > + /// > + /// The models the effect that the called function decrements the reference > + /// count of the argument and all typestate tracking on that argument > + /// should cease. > + DecRefAndStopTrackingHard, > + > + /// Performs the combined functionality of DecRefMsg and StopTrackingHard. > + /// > + /// The models the effect that the called function decrements the reference > + /// count of the argument and all typestate tracking on that argument > + /// should cease. > + DecRefMsgAndStopTrackingHard > +}; > + > +/// RetEffect summarizes a call's retain/release behavior with respect > +/// to its return value. > +class RetEffect { > +public: > + enum Kind { > + /// Indicates that no retain count information is tracked for > + /// the return value. > + NoRet, > + /// Indicates that the returned value is an owned (+1) symbol. > + OwnedSymbol, > + /// Indicates that the returned value is an object with retain count > + /// semantics but that it is not owned (+0). This is the default > + /// for getters, etc. > + NotOwnedSymbol, > + /// Indicates that the object is not owned and controlled by the > + /// Garbage collector. > + GCNotOwnedSymbol, > + /// Indicates that the return value is an owned object when the > + /// receiver is also a tracked object. > + OwnedWhenTrackedReceiver, > + // Treat this function as returning a non-tracked symbol even if > + // the function has been inlined. This is used where the call > + // site summary is more presise than the summary indirectly produced > + // by inlining the function > + NoRetHard > + }; > + > + /// Determines the object kind of a tracked object. > + enum ObjKind { > + /// Indicates that the tracked object is a CF object. This is > + /// important between GC and non-GC code. > + CF, > + /// Indicates that the tracked object is an Objective-C object. > + ObjC, > + /// Indicates that the tracked object could be a CF or Objective-C > object. > + AnyObj, > + /// Indicates that the tracked object is a generalized object. > + Generalized > + }; > + > +private: > + Kind K; > + ObjKind O; > + > + RetEffect(Kind k, ObjKind o = AnyObj) : K(k), O(o) {} > + > +public: > + Kind getKind() const { return K; } > + > + ObjKind getObjKind() const { return O; } > + > + bool isOwned() const { > + return K == OwnedSymbol || K == OwnedWhenTrackedReceiver; > + } > + > + bool notOwned() const { > + return K == NotOwnedSymbol; > + } > + > + bool operator==(const RetEffect &Other) const { > + return K == Other.K && O == Other.O; > + } > + > + static RetEffect MakeOwnedWhenTrackedReceiver() { > + return RetEffect(OwnedWhenTrackedReceiver, ObjC); > + } > + > + static RetEffect MakeOwned(ObjKind o) { > + return RetEffect(OwnedSymbol, o); > + } > + static RetEffect MakeNotOwned(ObjKind o) { > + return RetEffect(NotOwnedSymbol, o); > + } > + static RetEffect MakeGCNotOwned() { > + return RetEffect(GCNotOwnedSymbol, ObjC); > + } > + static RetEffect MakeNoRet() { > + return RetEffect(NoRet); > + } > + static RetEffect MakeNoRetHard() { > + return RetEffect(NoRetHard); > + } > +}; > + > +/// Encapsulates the retain count semantics on the arguments, return value, > +/// and receiver (if any) of a function/method call. > +/// > +/// Note that construction of these objects is not highly efficient. That > +/// is okay for clients where creating these objects isn't really a > bottleneck. > +/// The purpose of the API is to provide something simple. The actual > +/// static analyzer checker that implements retain/release typestate > +/// tracking uses something more efficient. > +class CallEffects { > + llvm::SmallVector<ArgEffect, 10> Args; > + RetEffect Ret; > + ArgEffect Receiver; > + > + CallEffects(const RetEffect &R) : Ret(R) {} > + > +public: > + /// Returns the argument effects for a call. > + ArrayRef<ArgEffect> getArgs() const { return Args; } > + > + /// Returns the effects on the receiver. > + ArgEffect getReceiver() const { return Receiver; } > + > + /// Returns the effect on the return value. > + RetEffect getReturnValue() const { return Ret; } > + > + /// Return the CallEfect for a given Objective-C method. > + static CallEffects getEffect(const ObjCMethodDecl *MD); > + > + /// Return the CallEfect for a given C/C++ function. > + static CallEffects getEffect(const FunctionDecl *FD); > +}; > + > +/// A key identifying a summary. > +class ObjCSummaryKey { > + IdentifierInfo* II; > + Selector S; > +public: > + ObjCSummaryKey(IdentifierInfo* ii, Selector s) > + : II(ii), S(s) {} > + > + ObjCSummaryKey(const ObjCInterfaceDecl *d, Selector s) > + : II(d ? d->getIdentifier() : nullptr), S(s) {} > + > + ObjCSummaryKey(Selector s) > + : II(nullptr), S(s) {} > + > + IdentifierInfo *getIdentifier() const { return II; } > + Selector getSelector() const { return S; } > +}; > + > +} // end namespace ento > +} // end namespace clang > + > +namespace llvm { > + > +template <> struct FoldingSetTrait<ArgEffect> { > +static inline void Profile(const ArgEffect X, FoldingSetNodeID &ID) { > + ID.AddInteger((unsigned) X); > +} > +}; > +template <> struct FoldingSetTrait<RetEffect> { > + static inline void Profile(const RetEffect &X, FoldingSetNodeID &ID) { > + ID.AddInteger((unsigned) X.getKind()); > + ID.AddInteger((unsigned) X.getObjKind()); > +} > +}; > + > +template <> struct DenseMapInfo<ObjCSummaryKey> { > + static inline ObjCSummaryKey getEmptyKey() { > + return ObjCSummaryKey(DenseMapInfo<IdentifierInfo*>::getEmptyKey(), > + DenseMapInfo<Selector>::getEmptyKey()); > + } > + > + static inline ObjCSummaryKey getTombstoneKey() { > + return ObjCSummaryKey(DenseMapInfo<IdentifierInfo*>::getTombstoneKey(), > + DenseMapInfo<Selector>::getTombstoneKey()); > + } > + > + static unsigned getHashValue(const ObjCSummaryKey &V) { > + typedef std::pair<IdentifierInfo*, Selector> PairTy; > + return DenseMapInfo<PairTy>::getHashValue(PairTy(V.getIdentifier(), > + V.getSelector())); > + } > + > + static bool isEqual(const ObjCSummaryKey& LHS, const ObjCSummaryKey& RHS) { > + return LHS.getIdentifier() == RHS.getIdentifier() && > + LHS.getSelector() == RHS.getSelector(); > + } > + > +}; > + > +} // end llvm namespace > + > + > +namespace clang { > +namespace ento { > + > +/// ArgEffects summarizes the effects of a function/method call on all of > +/// its arguments. > +typedef llvm::ImmutableMap<unsigned, ArgEffect> ArgEffects; > + > +/// Summary for a function with respect to ownership changes. > +class RetainSummary { > + /// Args - a map 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. > + RetEffect Ret; > + > +public: > + RetainSummary(ArgEffects A, RetEffect R, ArgEffect defaultEff, > + ArgEffect ReceiverEff) > + : Args(A), DefaultArgEffect(defaultEff), Receiver(ReceiverEff), Ret(R) {} > + > + /// 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; > + } > + > + void addArg(ArgEffects::Factory &af, unsigned idx, ArgEffect e) { > + Args = af.add(Args, idx, e); > + } > + > + /// setDefaultArgEffect - Set the default argument effect. > + void setDefaultArgEffect(ArgEffect E) { > + DefaultArgEffect = 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; } > + > + > + /// Sets the effect on the receiver of the message. > + void setReceiverEffect(ArgEffect e) { Receiver = e; } > + > + /// 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; } > + > + /// Test if two retain summaries are identical. Note that merely equivalent > + /// summaries are not necessarily identical (for example, if an explicit > + /// argument effect matches the default effect). > + bool operator==(const RetainSummary &Other) const { > + return Args == Other.Args && DefaultArgEffect == Other.DefaultArgEffect > && > + Receiver == Other.Receiver && Ret == Other.Ret; > + } > + > + /// Profile this summary for inclusion in a FoldingSet. > + void Profile(llvm::FoldingSetNodeID& ID) const { > + ID.Add(Args); > + ID.Add(DefaultArgEffect); > + ID.Add(Receiver); > + ID.Add(Ret); > + } > + > + /// A retain summary is simple if it has no ArgEffects other than the > default. > + bool isSimple() const { > + return Args.isEmpty(); > + } > + > + ArgEffects getArgEffects() const { return Args; } > + > +private: > + ArgEffect getDefaultArgEffect() const { return DefaultArgEffect; } > + > + friend class RetainSummaryManager; > +}; > + > +class ObjCSummaryCache { > + typedef llvm::DenseMap<ObjCSummaryKey, const RetainSummary *> MapTy; > + MapTy M; > +public: > + ObjCSummaryCache() {} > + > + const 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()) > + return I->second; > + if (!D) > + return nullptr; > + > + // Walk the super chain. If we find a hit with a parent, we'll end > + // up returning that summary. We actually allow that key (null,S), as > + // we cache summaries for the null ObjCInterfaceDecl* to allow us to > + // generate initial summaries without having to worry about NSObject > + // being declared. > + // FIXME: We may change this at some point. > + for (ObjCInterfaceDecl *C=D->getSuperClass() ;; C=C->getSuperClass()) { > + if ((I = M.find(ObjCSummaryKey(C, S))) != M.end()) > + break; > + > + if (!C) > + return nullptr; > + } > + > + // Cache the summary with original key to make the next lookup faster > + // and return the iterator. > + const RetainSummary *Summ = I->second; > + M[K] = Summ; > + return Summ; > + } > + > + const RetainSummary *find(IdentifierInfo* II, Selector S) { > + // FIXME: Class method lookup. Right now we don't 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() ? nullptr : I->second; > + } > + > + const RetainSummary *& operator[](ObjCSummaryKey K) { > + return M[K]; > + } > + > + const RetainSummary *& operator[](Selector S) { > + return M[ ObjCSummaryKey(S) ]; > + } > +}; > + > +class RetainSummaryManager { > + typedef llvm::DenseMap<const FunctionDecl*, const RetainSummary *> > + FuncSummariesTy; > + > + typedef ObjCSummaryCache ObjCMethodSummariesTy; > + > + typedef llvm::FoldingSetNodeWrapper<RetainSummary> CachedSummaryNode; > + > + /// Ctx - The ASTContext object for the analyzed ASTs. > + ASTContext &Ctx; > + > + /// Records whether or not the analyzed code runs in ARC mode. > + const bool ARCEnabled; > + > + /// FuncSummaries - A map from FunctionDecls to summaries. > + FuncSummariesTy FuncSummaries; > + > + /// ObjCClassMethodSummaries - A map from selectors (for instance methods) > + /// to summaries. > + ObjCMethodSummariesTy ObjCClassMethodSummaries; > + > + /// ObjCMethodSummaries - A map from selectors to summaries. > + ObjCMethodSummariesTy ObjCMethodSummaries; > + > + /// BPAlloc - A BumpPtrAllocator used for allocating summaries, ArgEffects, > + /// and all other data used by the checker. > + llvm::BumpPtrAllocator BPAlloc; > + > + /// AF - A factory for ArgEffects objects. > + ArgEffects::Factory AF; > + > + /// ScratchArgs - A holding buffer for construct ArgEffects. > + ArgEffects ScratchArgs; > + > + /// ObjCAllocRetE - Default return effect for methods returning Objective-C > + /// objects. > + RetEffect ObjCAllocRetE; > + > + /// ObjCInitRetE - Default return effect for init methods returning > + /// Objective-C objects. > + RetEffect ObjCInitRetE; > + > + /// SimpleSummaries - Used for uniquing summaries that don't have special > + /// effects. > + llvm::FoldingSet<CachedSummaryNode> SimpleSummaries; > + > + /// getArgEffects - Returns a persistent ArgEffects object based on the > + /// data in ScratchArgs. > + ArgEffects getArgEffects(); > + > + enum UnaryFuncKind { cfretain, cfrelease, cfautorelease, cfmakecollectable > }; > + > + const RetainSummary *getUnarySummary(const FunctionType* FT, > + UnaryFuncKind func); > + > + const RetainSummary *getCFSummaryCreateRule(const FunctionDecl *FD); > + const RetainSummary *getCFSummaryGetRule(const FunctionDecl *FD); > + const RetainSummary *getCFCreateGetRuleSummary(const FunctionDecl *FD); > + > + const RetainSummary *getPersistentSummary(const RetainSummary &OldSumm); > + > + const RetainSummary *getPersistentSummary(RetEffect RetEff, > + ArgEffect ReceiverEff = > DoNothing, > + ArgEffect DefaultEff = > MayEscape) { > + RetainSummary Summ(getArgEffects(), RetEff, DefaultEff, ReceiverEff); > + return getPersistentSummary(Summ); > + } > + > + const RetainSummary *getDoNothingSummary() { > + return getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, > DoNothing); > + } > + > + const RetainSummary *getDefaultSummary() { > + return getPersistentSummary(RetEffect::MakeNoRet(), > + DoNothing, MayEscape); > + } > + > + const RetainSummary *getPersistentStopSummary() { > + return getPersistentSummary(RetEffect::MakeNoRet(), > + StopTracking, StopTracking); > + } > + > + void InitializeClassMethodSummaries(); > + void InitializeMethodSummaries(); > + > + void addNSObjectClsMethSummary(Selector S, const RetainSummary *Summ) { > + ObjCClassMethodSummaries[S] = Summ; > + } > + > + void addNSObjectMethSummary(Selector S, const RetainSummary *Summ) { > + ObjCMethodSummaries[S] = Summ; > + } > + > + void addClassMethSummary(const char* Cls, const char* name, > + const RetainSummary *Summ, bool isNullary = true) > { > + IdentifierInfo* ClsII = &Ctx.Idents.get(Cls); > + Selector S = isNullary ? GetNullarySelector(name, Ctx) > + : GetUnarySelector(name, Ctx); > + ObjCClassMethodSummaries[ObjCSummaryKey(ClsII, S)] = Summ; > + } > + > + void addInstMethSummary(const char* Cls, const char* nullaryName, > + const RetainSummary *Summ) { > + IdentifierInfo* ClsII = &Ctx.Idents.get(Cls); > + Selector S = GetNullarySelector(nullaryName, Ctx); > + ObjCMethodSummaries[ObjCSummaryKey(ClsII, S)] = Summ; > + } > + > + template <typename... Keywords> > + void addMethodSummary(IdentifierInfo *ClsII, ObjCMethodSummariesTy > &Summaries, > + const RetainSummary *Summ, Keywords *... Kws) { > + Selector S = getKeywordSelector(Ctx, Kws...); > + Summaries[ObjCSummaryKey(ClsII, S)] = Summ; > + } > + > + template <typename... Keywords> > + void addInstMethSummary(const char *Cls, const RetainSummary *Summ, > + Keywords *... Kws) { > + addMethodSummary(&Ctx.Idents.get(Cls), ObjCMethodSummaries, Summ, > Kws...); > + } > + > + template <typename... Keywords> > + void addClsMethSummary(const char *Cls, const RetainSummary *Summ, > + Keywords *... Kws) { > + addMethodSummary(&Ctx.Idents.get(Cls), ObjCClassMethodSummaries, Summ, > + Kws...); > + } > + > + template <typename... Keywords> > + void addClsMethSummary(IdentifierInfo *II, const RetainSummary *Summ, > + Keywords *... Kws) { > + addMethodSummary(II, ObjCClassMethodSummaries, Summ, Kws...); > + } > + > + const RetainSummary * generateSummary(const FunctionDecl *FD, > + bool &AllowAnnotations); > + > +public: > + RetainSummaryManager(ASTContext &ctx, bool usesARC) > + : Ctx(ctx), > + ARCEnabled(usesARC), > + AF(BPAlloc), ScratchArgs(AF.getEmptyMap()), > + ObjCAllocRetE(usesARC ? RetEffect::MakeNotOwned(RetEffect::ObjC) > + : RetEffect::MakeOwned(RetEffect::ObjC)), > + ObjCInitRetE(usesARC ? RetEffect::MakeNotOwned(RetEffect::ObjC) > + : RetEffect::MakeOwnedWhenTrackedReceiver()) { > + InitializeClassMethodSummaries(); > + InitializeMethodSummaries(); > + } > + > + bool canEval(const CallExpr *CE, > + const FunctionDecl *FD, > + bool &hasTrustedImplementationAnnotation); > + > + bool isTrustedReferenceCountImplementation(const FunctionDecl *FD); > + > + const RetainSummary *getSummary(const CallEvent &Call, > + QualType ReceiverType=QualType()); > + > + const RetainSummary *getFunctionSummary(const FunctionDecl *FD); > + > + const RetainSummary *getMethodSummary(Selector S, const ObjCInterfaceDecl > *ID, > + const ObjCMethodDecl *MD, > + QualType RetTy, > + ObjCMethodSummariesTy > &CachedSummaries); > + > + const RetainSummary * > + getInstanceMethodSummary(const ObjCMethodCall &M, > + QualType ReceiverType); > + > + const RetainSummary *getClassMethodSummary(const ObjCMethodCall &M) { > + assert(!M.isInstanceMessage()); > + const ObjCInterfaceDecl *Class = M.getReceiverInterface(); > + > + return getMethodSummary(M.getSelector(), Class, M.getDecl(), > + M.getResultType(), ObjCClassMethodSummaries); > + } > + > + /// getMethodSummary - This version of getMethodSummary is used to query > + /// the summary for the current method being analyzed. > + const RetainSummary *getMethodSummary(const ObjCMethodDecl *MD) { > + const ObjCInterfaceDecl *ID = MD->getClassInterface(); > + Selector S = MD->getSelector(); > + QualType ResultTy = MD->getReturnType(); > + > + ObjCMethodSummariesTy *CachedSummaries; > + if (MD->isInstanceMethod()) > + CachedSummaries = &ObjCMethodSummaries; > + else > + CachedSummaries = &ObjCClassMethodSummaries; > + > + return getMethodSummary(S, ID, MD, ResultTy, *CachedSummaries); > + } > + > + const RetainSummary *getStandardMethodSummary(const ObjCMethodDecl *MD, > + Selector S, QualType RetTy); > + > + /// Determine if there is a special return effect for this function or > method. > + Optional<RetEffect> getRetEffectFromAnnotations(QualType RetTy, > + const Decl *D); > + > + void updateSummaryFromAnnotations(const RetainSummary *&Summ, > + const ObjCMethodDecl *MD); > + > + void updateSummaryFromAnnotations(const RetainSummary *&Summ, > + const FunctionDecl *FD); > + > + void updateSummaryForCall(const RetainSummary *&Summ, > + const CallEvent &Call); > + > + bool isARCEnabled() const { return ARCEnabled; } > + > + RetEffect getObjAllocRetEffect() const { return ObjCAllocRetE; } > + > + friend class RetainSummaryTemplate; > +}; > + > +// Used to avoid allocating long-term (BPAlloc'd) memory for default retain > +// summaries. If a function or method looks like it has a default summary, > but > +// it has annotations, the annotations are added to the stack-based template > +// and then copied into managed memory. > +class RetainSummaryTemplate { > + RetainSummaryManager &Manager; > + const RetainSummary *&RealSummary; > + RetainSummary ScratchSummary; > + bool Accessed; > +public: > + RetainSummaryTemplate(const RetainSummary *&real, RetainSummaryManager > &mgr) > + : Manager(mgr), RealSummary(real), ScratchSummary(*real), > Accessed(false) {} > + > + ~RetainSummaryTemplate() { > + if (Accessed) > + RealSummary = Manager.getPersistentSummary(ScratchSummary); > + } > + > + RetainSummary &operator*() { > + Accessed = true; > + return ScratchSummary; > + } > + > + RetainSummary *operator->() { > + Accessed = true; > + return &ScratchSummary; > + } > +}; > + > +} // end namespace ento > +} // end namespace clang > + > +#endif > > Added: cfe/trunk/include/clang/StaticAnalyzer/Checkers/SelectorExtras.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Checkers/SelectorExtras.h?rev=340114&view=auto > ============================================================================== > --- cfe/trunk/include/clang/StaticAnalyzer/Checkers/SelectorExtras.h (added) > +++ cfe/trunk/include/clang/StaticAnalyzer/Checkers/SelectorExtras.h Fri Aug > 17 18:45:50 2018 > @@ -0,0 +1,39 @@ > +//=== SelectorExtras.h - Helpers for checkers using selectors -----*- C++ > -*-=// > +// > +// The LLVM Compiler Infrastructure > +// > +// This file is distributed under the University of Illinois Open Source > +// License. See LICENSE.TXT for details. > +// > +//===----------------------------------------------------------------------===// > + > +#ifndef LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_SELECTOREXTRAS_H > +#define LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_SELECTOREXTRAS_H > + > +#include "clang/AST/ASTContext.h" > + > +namespace clang { > +namespace ento { > + > +template <typename... IdentifierInfos> > +static inline Selector getKeywordSelector(ASTContext &Ctx, > + IdentifierInfos *... IIs) { > + static_assert(sizeof...(IdentifierInfos), > + "keyword selectors must have at least one argument"); > + SmallVector<IdentifierInfo *, 10> II({&Ctx.Idents.get(IIs)...}); > + > + return Ctx.Selectors.getSelector(II.size(), &II[0]); > +} > + > +template <typename... IdentifierInfos> > +static inline void lazyInitKeywordSelector(Selector &Sel, ASTContext &Ctx, > + IdentifierInfos *... IIs) { > + if (!Sel.isNull()) > + return; > + Sel = getKeywordSelector(Ctx, IIs...); > +} > + > +} // end namespace ento > +} // end namespace clang > + > +#endif > > Modified: cfe/trunk/lib/ARCMigrate/CMakeLists.txt > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ARCMigrate/CMakeLists.txt?rev=340114&r1=340113&r2=340114&view=diff > ============================================================================== > --- cfe/trunk/lib/ARCMigrate/CMakeLists.txt (original) > +++ cfe/trunk/lib/ARCMigrate/CMakeLists.txt Fri Aug 17 18:45:50 2018 > @@ -34,5 +34,4 @@ add_clang_library(clangARCMigrate > clangRewrite > clangSema > clangSerialization > - clangStaticAnalyzerCheckers > ) > > Modified: cfe/trunk/lib/ARCMigrate/ObjCMT.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ARCMigrate/ObjCMT.cpp?rev=340114&r1=340113&r2=340114&view=diff > ============================================================================== > --- cfe/trunk/lib/ARCMigrate/ObjCMT.cpp (original) > +++ cfe/trunk/lib/ARCMigrate/ObjCMT.cpp Fri Aug 17 18:45:50 2018 > @@ -8,7 +8,7 @@ > > //===----------------------------------------------------------------------===// > > #include "Transforms.h" > -#include "clang/Analysis/ObjCRetainCount.h" > +#include "clang/Analysis/RetainSummaryManager.h" > #include "clang/ARCMigrate/ARCMT.h" > #include "clang/ARCMigrate/ARCMTActions.h" > #include "clang/AST/ASTConsumer.h" > @@ -35,8 +35,8 @@ > #include "llvm/Support/YAMLParser.h" > > using namespace clang; > +using namespace ento; > using namespace arcmt; > -using namespace ento::objc_retain; > > namespace { > > > Modified: cfe/trunk/lib/Analysis/CMakeLists.txt > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CMakeLists.txt?rev=340114&r1=340113&r2=340114&view=diff > ============================================================================== > --- cfe/trunk/lib/Analysis/CMakeLists.txt (original) > +++ cfe/trunk/lib/Analysis/CMakeLists.txt Fri Aug 17 18:45:50 2018 > @@ -24,6 +24,7 @@ add_clang_library(clangAnalysis > ProgramPoint.cpp > PseudoConstantAnalysis.cpp > ReachableCode.cpp > + RetainSummaryManager.cpp > ScanfFormatString.cpp > ThreadSafety.cpp > ThreadSafetyCommon.cpp > > Added: cfe/trunk/lib/Analysis/RetainSummaryManager.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/RetainSummaryManager.cpp?rev=340114&view=auto > ============================================================================== > --- cfe/trunk/lib/Analysis/RetainSummaryManager.cpp (added) > +++ cfe/trunk/lib/Analysis/RetainSummaryManager.cpp Fri Aug 17 18:45:50 2018 > @@ -0,0 +1,902 @@ > +//== RetainSummaryManager.cpp - Summaries for reference counting --*- C++ > -*--// > +// > +// The LLVM Compiler Infrastructure > +// > +// This file is distributed under the University of Illinois Open Source > +// License. See LICENSE.TXT for details. > +// > +//===----------------------------------------------------------------------===// > +// > +// This file defines summaries implementation for retain counting, which > +// implements a reference count checker for Core Foundation and Cocoa > +// on (Mac OS X). > +// > +//===----------------------------------------------------------------------===// > + > +#include "clang/Analysis/RetainSummaryManager.h" > +#include "clang/Analysis/DomainSpecific/CocoaConventions.h" > +#include "clang/AST/Attr.h" > +#include "clang/AST/DeclCXX.h" > +#include "clang/AST/DeclObjC.h" > +#include "clang/AST/ParentMap.h" > + > +using namespace clang; > +using namespace ento; > + > +ArgEffects RetainSummaryManager::getArgEffects() { > + ArgEffects AE = ScratchArgs; > + ScratchArgs = AF.getEmptyMap(); > + return AE; > +} > + > +const RetainSummary * > +RetainSummaryManager::getPersistentSummary(const RetainSummary &OldSumm) { > + // Unique "simple" summaries -- those without ArgEffects. > + if (OldSumm.isSimple()) { > + ::llvm::FoldingSetNodeID ID; > + OldSumm.Profile(ID); > + > + void *Pos; > + CachedSummaryNode *N = SimpleSummaries.FindNodeOrInsertPos(ID, Pos); > + > + if (!N) { > + N = (CachedSummaryNode *) BPAlloc.Allocate<CachedSummaryNode>(); > + new (N) CachedSummaryNode(OldSumm); > + SimpleSummaries.InsertNode(N, Pos); > + } > + > + return &N->getValue(); > + } > + > + RetainSummary *Summ = (RetainSummary *) BPAlloc.Allocate<RetainSummary>(); > + new (Summ) RetainSummary(OldSumm); > + return Summ; > +} > + > +static bool hasRCAnnotation(const Decl *D, StringRef rcAnnotation) { > + for (const auto *Ann : D->specific_attrs<AnnotateAttr>()) { > + if (Ann->getAnnotation() == rcAnnotation) > + return true; > + } > + return false; > +} > + > +static bool isRetain(const FunctionDecl *FD, StringRef FName) { > + return FName.startswith_lower("retain") || FName.endswith_lower("retain"); > +} > + > +static bool isRelease(const FunctionDecl *FD, StringRef FName) { > + return FName.startswith_lower("release") || > FName.endswith_lower("release"); > +} > + > +static bool isAutorelease(const FunctionDecl *FD, StringRef FName) { > + return FName.startswith_lower("autorelease") || > + FName.endswith_lower("autorelease"); > +} > + > +static bool isMakeCollectable(StringRef FName) { > + return FName.contains_lower("MakeCollectable"); > +} > + > +const RetainSummary * > +RetainSummaryManager::generateSummary(const FunctionDecl *FD, > + bool &AllowAnnotations) { > + // We generate "stop" summaries for implicitly defined functions. > + if (FD->isImplicit()) { > + return getPersistentStopSummary(); > + } > + > + // [PR 3337] Use 'getAs<FunctionType>' to strip away any typedefs on the > + // function's type. > + const FunctionType *FT = FD->getType()->getAs<FunctionType>(); > + const IdentifierInfo *II = FD->getIdentifier(); > + if (!II) > + return getDefaultSummary(); > + > + StringRef FName = II->getName(); > + > + // Strip away preceding '_'. Doing this here will effect all the checks > + // down below. > + FName = FName.substr(FName.find_first_not_of('_')); > + > + // Inspect the result type. > + QualType RetTy = FT->getReturnType(); > + std::string RetTyName = RetTy.getAsString(); > + > + // FIXME: This should all be refactored into a chain of "summary lookup" > + // filters. > + assert(ScratchArgs.isEmpty()); > + > + if (FName == "pthread_create" || FName == "pthread_setspecific") { > + // Part of: <rdar://problem/7299394> and <rdar://problem/11282706>. > + // This will be addressed better with IPA. > + return getPersistentStopSummary(); > + } else if(FName == "NSMakeCollectable") { > + // Handle: id NSMakeCollectable(CFTypeRef) > + AllowAnnotations = false; > + return RetTy->isObjCIdType() ? getUnarySummary(FT, cfmakecollectable) > + : getPersistentStopSummary(); > + } else if (FName == "CFPlugInInstanceCreate") { > + return getPersistentSummary(RetEffect::MakeNoRet()); > + } else if (FName == "IORegistryEntrySearchCFProperty" || > + (RetTyName == "CFMutableDictionaryRef" && > + (FName == "IOBSDNameMatching" || FName == "IOServiceMatching" > || > + FName == "IOServiceNameMatching" || > + FName == "IORegistryEntryIDMatching" || > + FName == "IOOpenFirmwarePathMatching"))) { > + // Part of <rdar://problem/6961230>. (IOKit) > + // This should be addressed using a API table. > + return getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF), > DoNothing, > + DoNothing); > + } else if (FName == "IOServiceGetMatchingService" || > + FName == "IOServiceGetMatchingServices") { > + // FIXES: <rdar://problem/6326900> > + // This should be addressed using a API table. This strcmp is also > + // a little gross, but there is no need to super optimize here. > + ScratchArgs = AF.add(ScratchArgs, 1, DecRef); > + return getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, > DoNothing); > + } else if (FName == "IOServiceAddNotification" || > + FName == "IOServiceAddMatchingNotification") { > + // Part of <rdar://problem/6961230>. (IOKit) > + // This should be addressed using a API table. > + ScratchArgs = AF.add(ScratchArgs, 2, DecRef); > + return getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, > DoNothing); > + } else if (FName == "CVPixelBufferCreateWithBytes") { > + // FIXES: <rdar://problem/7283567> > + // Eventually this can be improved by recognizing that the pixel > + // buffer passed to CVPixelBufferCreateWithBytes is released via > + // a callback and doing full IPA to make sure this is done correctly. > + // FIXME: This function has an out parameter that returns an > + // allocated object. > + ScratchArgs = AF.add(ScratchArgs, 7, StopTracking); > + return getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, > DoNothing); > + } else if (FName == "CGBitmapContextCreateWithData") { > + // FIXES: <rdar://problem/7358899> > + // Eventually this can be improved by recognizing that 'releaseInfo' > + // passed to CGBitmapContextCreateWithData is released via > + // a callback and doing full IPA to make sure this is done correctly. > + ScratchArgs = AF.add(ScratchArgs, 8, StopTracking); > + return getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF), > DoNothing, > + DoNothing); > + } else if (FName == "CVPixelBufferCreateWithPlanarBytes") { > + // FIXES: <rdar://problem/7283567> > + // Eventually this can be improved by recognizing that the pixel > + // buffer passed to CVPixelBufferCreateWithPlanarBytes is released > + // via a callback and doing full IPA to make sure this is done > + // correctly. > + ScratchArgs = AF.add(ScratchArgs, 12, StopTracking); > + return getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, > DoNothing); > + } else if (FName == "VTCompressionSessionEncodeFrame") { > + // The context argument passed to VTCompressionSessionEncodeFrame() > + // is passed to the callback specified when creating the session > + // (e.g. with VTCompressionSessionCreate()) which can release it. > + // To account for this possibility, conservatively stop tracking > + // the context. > + ScratchArgs = AF.add(ScratchArgs, 5, StopTracking); > + return getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, > DoNothing); > + } else if (FName == "dispatch_set_context" || > + FName == "xpc_connection_set_context") { > + // <rdar://problem/11059275> - The analyzer currently doesn't have > + // a good way to reason about the finalizer function for libdispatch. > + // If we pass a context object that is memory managed, stop tracking it. > + // <rdar://problem/13783514> - Same problem, but for XPC. > + // FIXME: this hack should possibly go away once we can handle > + // libdispatch and XPC finalizers. > + ScratchArgs = AF.add(ScratchArgs, 1, StopTracking); > + return getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, > DoNothing); > + } else if (FName.startswith("NSLog")) { > + return getDoNothingSummary(); > + } else if (FName.startswith("NS") && > + (FName.find("Insert") != StringRef::npos)) { > + // Whitelist NSXXInsertXX, for example NSMapInsertIfAbsent, since they > can > + // be deallocated by NSMapRemove. (radar://11152419) > + ScratchArgs = AF.add(ScratchArgs, 1, StopTracking); > + ScratchArgs = AF.add(ScratchArgs, 2, StopTracking); > + return getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, > DoNothing); > + } > + > + if (RetTy->isPointerType()) { > + // For CoreFoundation ('CF') types. > + if (cocoa::isRefType(RetTy, "CF", FName)) { > + if (isRetain(FD, FName)) { > + // CFRetain isn't supposed to be annotated. However, this may as well > + // be a user-made "safe" CFRetain function that is incorrectly > + // annotated as cf_returns_retained due to lack of better options. > + // We want to ignore such annotation. > + AllowAnnotations = false; > + > + return getUnarySummary(FT, cfretain); > + } else if (isAutorelease(FD, FName)) { > + // The headers use cf_consumed, but we can fully model CFAutorelease > + // ourselves. > + AllowAnnotations = false; > + > + return getUnarySummary(FT, cfautorelease); > + } else if (isMakeCollectable(FName)) { > + AllowAnnotations = false; > + return getUnarySummary(FT, cfmakecollectable); > + } else { > + return getCFCreateGetRuleSummary(FD); > + } > + } > + > + // For CoreGraphics ('CG') and CoreVideo ('CV') types. > + if (cocoa::isRefType(RetTy, "CG", FName) || > + cocoa::isRefType(RetTy, "CV", FName)) { > + if (isRetain(FD, FName)) > + return getUnarySummary(FT, cfretain); > + else > + return getCFCreateGetRuleSummary(FD); > + } > + > + // For all other CF-style types, use the Create/Get > + // rule for summaries but don't support Retain functions > + // with framework-specific prefixes. > + if (coreFoundation::isCFObjectRef(RetTy)) { > + return getCFCreateGetRuleSummary(FD); > + } > + > + if (FD->hasAttr<CFAuditedTransferAttr>()) { > + return getCFCreateGetRuleSummary(FD); > + } > + } > + > + // Check for release functions, the only kind of functions that we care > + // about that don't return a pointer type. > + if (FName.size() >= 2 && FName[0] == 'C' && > + (FName[1] == 'F' || FName[1] == 'G')) { > + // Test for 'CGCF'. > + FName = FName.substr(FName.startswith("CGCF") ? 4 : 2); > + > + if (isRelease(FD, FName)) > + return getUnarySummary(FT, cfrelease); > + else { > + assert(ScratchArgs.isEmpty()); > + // Remaining CoreFoundation and CoreGraphics functions. > + // We use to assume that they all strictly followed the ownership idiom > + // and that ownership cannot be transferred. While this is technically > + // correct, many methods allow a tracked object to escape. For > example: > + // > + // CFMutableDictionaryRef x = CFDictionaryCreateMutable(...); > + // CFDictionaryAddValue(y, key, x); > + // CFRelease(x); > + // ... it is okay to use 'x' since 'y' has a reference to it > + // > + // We handle this and similar cases with the follow heuristic. If the > + // function name contains "InsertValue", "SetValue", "AddValue", > + // "AppendValue", or "SetAttribute", then we assume that arguments may > + // "escape." This means that something else holds on to the object, > + // allowing it be used even after its local retain count drops to 0. > + ArgEffect E = (StrInStrNoCase(FName, "InsertValue") != StringRef::npos > || > + StrInStrNoCase(FName, "AddValue") != StringRef::npos || > + StrInStrNoCase(FName, "SetValue") != StringRef::npos || > + StrInStrNoCase(FName, "AppendValue") != StringRef::npos > || > + StrInStrNoCase(FName, "SetAttribute") != > StringRef::npos) > + ? MayEscape > + : DoNothing; > + > + return getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, E); > + } > + } > + > + return getDefaultSummary(); > +} > + > +const RetainSummary * > +RetainSummaryManager::getFunctionSummary(const FunctionDecl *FD) { > + // If we don't know what function we're calling, use our default summary. > + if (!FD) > + return getDefaultSummary(); > + > + // Look up a summary in our cache of FunctionDecls -> Summaries. > + FuncSummariesTy::iterator I = FuncSummaries.find(FD); > + if (I != FuncSummaries.end()) > + return I->second; > + > + // No summary? Generate one. > + bool AllowAnnotations = true; > + const RetainSummary *S = generateSummary(FD, AllowAnnotations); > + > + // Annotations override defaults. > + if (AllowAnnotations) > + updateSummaryFromAnnotations(S, FD); > + > + FuncSummaries[FD] = S; > + return S; > +} > + > +//===----------------------------------------------------------------------===// > +// Summary creation for functions (largely uses of Core Foundation). > +//===----------------------------------------------------------------------===// > + > +static ArgEffect getStopTrackingHardEquivalent(ArgEffect E) { > + switch (E) { > + case DoNothing: > + case Autorelease: > + case DecRefBridgedTransferred: > + case IncRef: > + case IncRefMsg: > + case MakeCollectable: > + case UnretainedOutParameter: > + case RetainedOutParameter: > + case MayEscape: > + case StopTracking: > + case StopTrackingHard: > + return StopTrackingHard; > + case DecRef: > + case DecRefAndStopTrackingHard: > + return DecRefAndStopTrackingHard; > + case DecRefMsg: > + case DecRefMsgAndStopTrackingHard: > + return DecRefMsgAndStopTrackingHard; > + case Dealloc: > + return Dealloc; > + } > + > + llvm_unreachable("Unknown ArgEffect kind"); > +} > + > +void RetainSummaryManager::updateSummaryForCall(const RetainSummary *&S, > + const CallEvent &Call) { > + if (Call.hasNonZeroCallbackArg()) { > + ArgEffect RecEffect = > + getStopTrackingHardEquivalent(S->getReceiverEffect()); > + ArgEffect DefEffect = > + getStopTrackingHardEquivalent(S->getDefaultArgEffect()); > + > + ArgEffects CustomArgEffects = S->getArgEffects(); > + for (ArgEffects::iterator I = CustomArgEffects.begin(), > + E = CustomArgEffects.end(); > + I != E; ++I) { > + ArgEffect Translated = getStopTrackingHardEquivalent(I->second); > + if (Translated != DefEffect) > + ScratchArgs = AF.add(ScratchArgs, I->first, Translated); > + } > + > + RetEffect RE = RetEffect::MakeNoRetHard(); > + > + // Special cases where the callback argument CANNOT free the return > value. > + // This can generally only happen if we know that the callback will only > be > + // called when the return value is already being deallocated. > + if (const SimpleFunctionCall *FC = dyn_cast<SimpleFunctionCall>(&Call)) { > + if (IdentifierInfo *Name = FC->getDecl()->getIdentifier()) { > + // When the CGBitmapContext is deallocated, the callback here will > free > + // the associated data buffer. > + // The callback in dispatch_data_create frees the buffer, but not > + // the data object. > + if (Name->isStr("CGBitmapContextCreateWithData") || > + Name->isStr("dispatch_data_create")) > + RE = S->getRetEffect(); > + } > + } > + > + S = getPersistentSummary(RE, RecEffect, DefEffect); > + } > + > + // Special case '[super init];' and '[self init];' > + // > + // Even though calling '[super init]' without assigning the result to self > + // and checking if the parent returns 'nil' is a bad pattern, it is common. > + // Additionally, our Self Init checker already warns about it. To avoid > + // overwhelming the user with messages from both checkers, we model the > case > + // of '[super init]' in cases when it is not consumed by another expression > + // as if the call preserves the value of 'self'; essentially, assuming it > can > + // never fail and return 'nil'. > + // Note, we don't want to just stop tracking the value since we want the > + // RetainCount checker to report leaks and use-after-free if SelfInit > checker > + // is turned off. > + if (const ObjCMethodCall *MC = dyn_cast<ObjCMethodCall>(&Call)) { > + if (MC->getMethodFamily() == OMF_init && MC->isReceiverSelfOrSuper()) { > + > + // Check if the message is not consumed, we know it will not be used in > + // an assignment, ex: "self = [super init]". > + const Expr *ME = MC->getOriginExpr(); > + const LocationContext *LCtx = MC->getLocationContext(); > + ParentMap &PM = LCtx->getAnalysisDeclContext()->getParentMap(); > + if (!PM.isConsumedExpr(ME)) { > + RetainSummaryTemplate ModifiableSummaryTemplate(S, *this); > + ModifiableSummaryTemplate->setReceiverEffect(DoNothing); > + ModifiableSummaryTemplate->setRetEffect(RetEffect::MakeNoRet()); > + } > + } > + } > +} > + > +const RetainSummary * > +RetainSummaryManager::getSummary(const CallEvent &Call, > + QualType ReceiverType) { > + const RetainSummary *Summ; > + switch (Call.getKind()) { > + case CE_Function: > + Summ = getFunctionSummary(cast<SimpleFunctionCall>(Call).getDecl()); > + break; > + case CE_CXXMember: > + case CE_CXXMemberOperator: > + case CE_Block: > + case CE_CXXConstructor: > + case CE_CXXDestructor: > + case CE_CXXAllocator: > + // FIXME: These calls are currently unsupported. > + return getPersistentStopSummary(); > + case CE_ObjCMessage: { > + const ObjCMethodCall &Msg = cast<ObjCMethodCall>(Call); > + if (Msg.isInstanceMessage()) > + Summ = getInstanceMethodSummary(Msg, ReceiverType); > + else > + Summ = getClassMethodSummary(Msg); > + break; > + } > + } > + > + updateSummaryForCall(Summ, Call); > + > + assert(Summ && "Unknown call type?"); > + return Summ; > +} > + > + > +const RetainSummary * > +RetainSummaryManager::getCFCreateGetRuleSummary(const FunctionDecl *FD) { > + if (coreFoundation::followsCreateRule(FD)) > + return getCFSummaryCreateRule(FD); > + > + return getCFSummaryGetRule(FD); > +} > + > +bool RetainSummaryManager::isTrustedReferenceCountImplementation( > + const FunctionDecl *FD) { > + return hasRCAnnotation(FD, "rc_ownership_trusted_implementation"); > +} > + > +bool RetainSummaryManager::canEval(const CallExpr *CE, > + const FunctionDecl *FD, > + bool &hasTrustedImplementationAnnotation) > { > + // For now, we're only handling the functions that return aliases of their > + // arguments: CFRetain (and its families). > + // Eventually we should add other functions we can model entirely, > + // such as CFRelease, which don't invalidate their arguments or globals. > + if (CE->getNumArgs() != 1) > + return false; > + > + IdentifierInfo *II = FD->getIdentifier(); > + if (!II) > + return false; > + > + StringRef FName = II->getName(); > + FName = FName.substr(FName.find_first_not_of('_')); > + > + QualType ResultTy = CE->getCallReturnType(Ctx); > + if (ResultTy->isObjCIdType()) { > + return II->isStr("NSMakeCollectable"); > + } else if (ResultTy->isPointerType()) { > + // Handle: (CF|CG|CV)Retain > + // CFAutorelease > + // It's okay to be a little sloppy here. > + if (cocoa::isRefType(ResultTy, "CF", FName) || > + cocoa::isRefType(ResultTy, "CG", FName) || > + cocoa::isRefType(ResultTy, "CV", FName)) > + return isRetain(FD, FName) || isAutorelease(FD, FName) || > + isMakeCollectable(FName); > + > + const FunctionDecl* FDD = FD->getDefinition(); > + if (FDD && isTrustedReferenceCountImplementation(FDD)) { > + hasTrustedImplementationAnnotation = true; > + return true; > + } > + } > + > + return false; > + > +} > + > +const RetainSummary * > +RetainSummaryManager::getUnarySummary(const FunctionType* FT, > + UnaryFuncKind func) { > + > + // Sanity check that this is *really* a unary function. This can > + // happen if people do weird things. > + const FunctionProtoType* FTP = dyn_cast<FunctionProtoType>(FT); > + if (!FTP || FTP->getNumParams() != 1) > + return getPersistentStopSummary(); > + > + assert (ScratchArgs.isEmpty()); > + > + ArgEffect Effect; > + switch (func) { > + case cfretain: Effect = IncRef; break; > + case cfrelease: Effect = DecRef; break; > + case cfautorelease: Effect = Autorelease; break; > + case cfmakecollectable: Effect = MakeCollectable; break; > + } > + > + ScratchArgs = AF.add(ScratchArgs, 0, Effect); > + return getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing); > +} > + > +const RetainSummary * > +RetainSummaryManager::getCFSummaryCreateRule(const FunctionDecl *FD) { > + assert (ScratchArgs.isEmpty()); > + > + return getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF)); > +} > + > +const RetainSummary * > +RetainSummaryManager::getCFSummaryGetRule(const FunctionDecl *FD) { > + assert (ScratchArgs.isEmpty()); > + return getPersistentSummary(RetEffect::MakeNotOwned(RetEffect::CF), > + DoNothing, DoNothing); > +} > + > + > + > + > +//===----------------------------------------------------------------------===// > +// Summary creation for Selectors. > +//===----------------------------------------------------------------------===// > + > +Optional<RetEffect> > +RetainSummaryManager::getRetEffectFromAnnotations(QualType RetTy, > + const Decl *D) { > + if (cocoa::isCocoaObjectRef(RetTy)) { > + if (D->hasAttr<NSReturnsRetainedAttr>()) > + return ObjCAllocRetE; > + > + if (D->hasAttr<NSReturnsNotRetainedAttr>() || > + D->hasAttr<NSReturnsAutoreleasedAttr>()) > + return RetEffect::MakeNotOwned(RetEffect::ObjC); > + > + } else if (!RetTy->isPointerType()) { > + return None; > + } > + > + if (D->hasAttr<CFReturnsRetainedAttr>()) > + return RetEffect::MakeOwned(RetEffect::CF); > + else if (hasRCAnnotation(D, "rc_ownership_returns_retained")) > + return RetEffect::MakeOwned(RetEffect::Generalized); > + > + if (D->hasAttr<CFReturnsNotRetainedAttr>()) > + return RetEffect::MakeNotOwned(RetEffect::CF); > + > + return None; > +} > + > +void > +RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary > *&Summ, > + const FunctionDecl *FD) { > + if (!FD) > + return; > + > + assert(Summ && "Must have a summary to add annotations to."); > + RetainSummaryTemplate Template(Summ, *this); > + > + // Effects on the parameters. > + unsigned parm_idx = 0; > + for (FunctionDecl::param_const_iterator pi = FD->param_begin(), > + pe = FD->param_end(); pi != pe; ++pi, ++parm_idx) { > + const ParmVarDecl *pd = *pi; > + if (pd->hasAttr<NSConsumedAttr>()) > + Template->addArg(AF, parm_idx, DecRefMsg); > + else if (pd->hasAttr<CFConsumedAttr>() || > + hasRCAnnotation(pd, "rc_ownership_consumed")) > + Template->addArg(AF, parm_idx, DecRef); > + else if (pd->hasAttr<CFReturnsRetainedAttr>() || > + hasRCAnnotation(pd, "rc_ownership_returns_retained")) { > + QualType PointeeTy = pd->getType()->getPointeeType(); > + if (!PointeeTy.isNull()) > + if (coreFoundation::isCFObjectRef(PointeeTy)) > + Template->addArg(AF, parm_idx, RetainedOutParameter); > + } else if (pd->hasAttr<CFReturnsNotRetainedAttr>()) { > + QualType PointeeTy = pd->getType()->getPointeeType(); > + if (!PointeeTy.isNull()) > + if (coreFoundation::isCFObjectRef(PointeeTy)) > + Template->addArg(AF, parm_idx, UnretainedOutParameter); > + } > + } > + > + QualType RetTy = FD->getReturnType(); > + if (Optional<RetEffect> RetE = getRetEffectFromAnnotations(RetTy, FD)) > + Template->setRetEffect(*RetE); > +} > + > +void > +RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary > *&Summ, > + const ObjCMethodDecl *MD) > { > + if (!MD) > + return; > + > + assert(Summ && "Must have a valid summary to add annotations to"); > + RetainSummaryTemplate Template(Summ, *this); > + > + // Effects on the receiver. > + if (MD->hasAttr<NSConsumesSelfAttr>()) > + Template->setReceiverEffect(DecRefMsg); > + > + // Effects on the parameters. > + unsigned parm_idx = 0; > + for (ObjCMethodDecl::param_const_iterator > + pi=MD->param_begin(), pe=MD->param_end(); > + pi != pe; ++pi, ++parm_idx) { > + const ParmVarDecl *pd = *pi; > + if (pd->hasAttr<NSConsumedAttr>()) > + Template->addArg(AF, parm_idx, DecRefMsg); > + else if (pd->hasAttr<CFConsumedAttr>()) { > + Template->addArg(AF, parm_idx, DecRef); > + } else if (pd->hasAttr<CFReturnsRetainedAttr>()) { > + QualType PointeeTy = pd->getType()->getPointeeType(); > + if (!PointeeTy.isNull()) > + if (coreFoundation::isCFObjectRef(PointeeTy)) > + Template->addArg(AF, parm_idx, RetainedOutParameter); > + } else if (pd->hasAttr<CFReturnsNotRetainedAttr>()) { > + QualType PointeeTy = pd->getType()->getPointeeType(); > + if (!PointeeTy.isNull()) > + if (coreFoundation::isCFObjectRef(PointeeTy)) > + Template->addArg(AF, parm_idx, UnretainedOutParameter); > + } > + } > + > + QualType RetTy = MD->getReturnType(); > + if (Optional<RetEffect> RetE = getRetEffectFromAnnotations(RetTy, MD)) > + Template->setRetEffect(*RetE); > +} > + > +const RetainSummary * > +RetainSummaryManager::getStandardMethodSummary(const ObjCMethodDecl *MD, > + Selector S, QualType RetTy) { > + // Any special effects? > + ArgEffect ReceiverEff = DoNothing; > + RetEffect ResultEff = RetEffect::MakeNoRet(); > + > + // Check the method family, and apply any default annotations. > + switch (MD ? MD->getMethodFamily() : S.getMethodFamily()) { > + case OMF_None: > + case OMF_initialize: > + case OMF_performSelector: > + // Assume all Objective-C methods follow Cocoa Memory Management rules. > + // FIXME: Does the non-threaded performSelector family really belong > here? > + // The selector could be, say, @selector(copy). > + if (cocoa::isCocoaObjectRef(RetTy)) > + ResultEff = RetEffect::MakeNotOwned(RetEffect::ObjC); > + else if (coreFoundation::isCFObjectRef(RetTy)) { > + // ObjCMethodDecl currently doesn't consider CF objects as valid > return > + // values for alloc, new, copy, or mutableCopy, so we have to > + // double-check with the selector. This is ugly, but there aren't > that > + // many Objective-C methods that return CF objects, right? > + if (MD) { > + switch (S.getMethodFamily()) { > + case OMF_alloc: > + case OMF_new: > + case OMF_copy: > + case OMF_mutableCopy: > + ResultEff = RetEffect::MakeOwned(RetEffect::CF); > + break; > + default: > + ResultEff = RetEffect::MakeNotOwned(RetEffect::CF); > + break; > + } > + } else { > + ResultEff = RetEffect::MakeNotOwned(RetEffect::CF); > + } > + } > + break; > + case OMF_init: > + ResultEff = ObjCInitRetE; > + ReceiverEff = DecRefMsg; > + break; > + case OMF_alloc: > + case OMF_new: > + case OMF_copy: > + case OMF_mutableCopy: > + if (cocoa::isCocoaObjectRef(RetTy)) > + ResultEff = ObjCAllocRetE; > + else if (coreFoundation::isCFObjectRef(RetTy)) > + ResultEff = RetEffect::MakeOwned(RetEffect::CF); > + break; > + case OMF_autorelease: > + ReceiverEff = Autorelease; > + break; > + case OMF_retain: > + ReceiverEff = IncRefMsg; > + break; > + case OMF_release: > + ReceiverEff = DecRefMsg; > + break; > + case OMF_dealloc: > + ReceiverEff = Dealloc; > + break; > + case OMF_self: > + // -self is handled specially by the ExprEngine to propagate the > receiver. > + break; > + case OMF_retainCount: > + case OMF_finalize: > + // These methods don't return objects. > + break; > + } > + > + // If one of the arguments in the selector has the keyword 'delegate' we > + // should stop tracking the reference count for the receiver. This is > + // because the reference count is quite possibly handled by a delegate > + // method. > + if (S.isKeywordSelector()) { > + for (unsigned i = 0, e = S.getNumArgs(); i != e; ++i) { > + StringRef Slot = S.getNameForSlot(i); > + if (Slot.substr(Slot.size() - 8).equals_lower("delegate")) { > + if (ResultEff == ObjCInitRetE) > + ResultEff = RetEffect::MakeNoRetHard(); > + else > + ReceiverEff = StopTrackingHard; > + } > + } > + } > + > + if (ScratchArgs.isEmpty() && ReceiverEff == DoNothing && > + ResultEff.getKind() == RetEffect::NoRet) > + return getDefaultSummary(); > + > + return getPersistentSummary(ResultEff, ReceiverEff, MayEscape); > +} > + > +const RetainSummary *RetainSummaryManager::getInstanceMethodSummary( > + const ObjCMethodCall &Msg, QualType ReceiverType) { > + const ObjCInterfaceDecl *ReceiverClass = nullptr; > + > + // We do better tracking of the type of the object than the core > ExprEngine. > + // See if we have its type in our private state. > + if (!ReceiverType.isNull()) > + if (const auto *PT = ReceiverType->getAs<ObjCObjectPointerType>()) > + ReceiverClass = PT->getInterfaceDecl(); > + > + // If we don't know what kind of object this is, fall back to its static > type. > + if (!ReceiverClass) > + ReceiverClass = Msg.getReceiverInterface(); > + > + // FIXME: The receiver could be a reference to a class, meaning that > + // we should use the class method. > + // id x = [NSObject class]; > + // [x performSelector:... withObject:... afterDelay:...]; > + Selector S = Msg.getSelector(); > + const ObjCMethodDecl *Method = Msg.getDecl(); > + if (!Method && ReceiverClass) > + Method = ReceiverClass->getInstanceMethod(S); > + > + return getMethodSummary(S, ReceiverClass, Method, Msg.getResultType(), > + ObjCMethodSummaries); > +} > + > +const RetainSummary * > +RetainSummaryManager::getMethodSummary(Se -- Bruno Cardoso Lopes http://www.brunocardoso.cc _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits