16fdd2bd5SGeorge Karpenkov //== RetainSummaryManager.cpp - Summaries for reference counting --*- C++ -*--// 26fdd2bd5SGeorge Karpenkov // 36fdd2bd5SGeorge Karpenkov // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 46fdd2bd5SGeorge Karpenkov // See https://llvm.org/LICENSE.txt for license information. 56fdd2bd5SGeorge Karpenkov // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 66fdd2bd5SGeorge Karpenkov // 76fdd2bd5SGeorge Karpenkov //===----------------------------------------------------------------------===// 86fdd2bd5SGeorge Karpenkov // 96fdd2bd5SGeorge Karpenkov // This file defines summaries implementation for retain counting, which 106fdd2bd5SGeorge Karpenkov // implements a reference count checker for Core Foundation, Cocoa 116fdd2bd5SGeorge Karpenkov // and OSObject (on Mac OS X). 126fdd2bd5SGeorge Karpenkov // 136fdd2bd5SGeorge Karpenkov //===----------------------------------------------------------------------===// 146fdd2bd5SGeorge Karpenkov 156fdd2bd5SGeorge Karpenkov #include "clang/Analysis/DomainSpecific/CocoaConventions.h" 166fdd2bd5SGeorge Karpenkov #include "clang/Analysis/RetainSummaryManager.h" 176fdd2bd5SGeorge Karpenkov #include "clang/AST/Attr.h" 186fdd2bd5SGeorge Karpenkov #include "clang/AST/DeclCXX.h" 196fdd2bd5SGeorge Karpenkov #include "clang/AST/DeclObjC.h" 206fdd2bd5SGeorge Karpenkov #include "clang/AST/ParentMap.h" 216fdd2bd5SGeorge Karpenkov #include "clang/ASTMatchers/ASTMatchFinder.h" 226fdd2bd5SGeorge Karpenkov 236fdd2bd5SGeorge Karpenkov using namespace clang; 246fdd2bd5SGeorge Karpenkov using namespace ento; 256fdd2bd5SGeorge Karpenkov 266fdd2bd5SGeorge Karpenkov template <class T> 276fdd2bd5SGeorge Karpenkov constexpr static bool isOneOf() { 286fdd2bd5SGeorge Karpenkov return false; 296fdd2bd5SGeorge Karpenkov } 306fdd2bd5SGeorge Karpenkov 316fdd2bd5SGeorge Karpenkov /// Helper function to check whether the class is one of the 326fdd2bd5SGeorge Karpenkov /// rest of varargs. 336fdd2bd5SGeorge Karpenkov template <class T, class P, class... ToCompare> 346fdd2bd5SGeorge Karpenkov constexpr static bool isOneOf() { 356fdd2bd5SGeorge Karpenkov return std::is_same<T, P>::value || isOneOf<T, ToCompare...>(); 366fdd2bd5SGeorge Karpenkov } 376fdd2bd5SGeorge Karpenkov 386fdd2bd5SGeorge Karpenkov namespace { 396fdd2bd5SGeorge Karpenkov 406fdd2bd5SGeorge Karpenkov /// Fake attribute class for RC* attributes. 416fdd2bd5SGeorge Karpenkov struct GeneralizedReturnsRetainedAttr { 426fdd2bd5SGeorge Karpenkov static bool classof(const Attr *A) { 436fdd2bd5SGeorge Karpenkov if (auto AA = dyn_cast<AnnotateAttr>(A)) 446fdd2bd5SGeorge Karpenkov return AA->getAnnotation() == "rc_ownership_returns_retained"; 456fdd2bd5SGeorge Karpenkov return false; 466fdd2bd5SGeorge Karpenkov } 476fdd2bd5SGeorge Karpenkov }; 486fdd2bd5SGeorge Karpenkov 496fdd2bd5SGeorge Karpenkov struct GeneralizedReturnsNotRetainedAttr { 506fdd2bd5SGeorge Karpenkov static bool classof(const Attr *A) { 516fdd2bd5SGeorge Karpenkov if (auto AA = dyn_cast<AnnotateAttr>(A)) 526fdd2bd5SGeorge Karpenkov return AA->getAnnotation() == "rc_ownership_returns_not_retained"; 536fdd2bd5SGeorge Karpenkov return false; 546fdd2bd5SGeorge Karpenkov } 556fdd2bd5SGeorge Karpenkov }; 566fdd2bd5SGeorge Karpenkov 576fdd2bd5SGeorge Karpenkov struct GeneralizedConsumedAttr { 586fdd2bd5SGeorge Karpenkov static bool classof(const Attr *A) { 596fdd2bd5SGeorge Karpenkov if (auto AA = dyn_cast<AnnotateAttr>(A)) 606fdd2bd5SGeorge Karpenkov return AA->getAnnotation() == "rc_ownership_consumed"; 616fdd2bd5SGeorge Karpenkov return false; 626fdd2bd5SGeorge Karpenkov } 636fdd2bd5SGeorge Karpenkov }; 646fdd2bd5SGeorge Karpenkov 656fdd2bd5SGeorge Karpenkov } 666fdd2bd5SGeorge Karpenkov 676fdd2bd5SGeorge Karpenkov template <class T> 686fdd2bd5SGeorge Karpenkov Optional<ObjKind> RetainSummaryManager::hasAnyEnabledAttrOf(const Decl *D, 696fdd2bd5SGeorge Karpenkov QualType QT) { 706fdd2bd5SGeorge Karpenkov ObjKind K; 716fdd2bd5SGeorge Karpenkov if (isOneOf<T, CFConsumedAttr, CFReturnsRetainedAttr, 726fdd2bd5SGeorge Karpenkov CFReturnsNotRetainedAttr>()) { 736fdd2bd5SGeorge Karpenkov if (!TrackObjCAndCFObjects) 746fdd2bd5SGeorge Karpenkov return None; 756fdd2bd5SGeorge Karpenkov 766fdd2bd5SGeorge Karpenkov K = ObjKind::CF; 776fdd2bd5SGeorge Karpenkov } else if (isOneOf<T, NSConsumedAttr, NSConsumesSelfAttr, 786fdd2bd5SGeorge Karpenkov NSReturnsAutoreleasedAttr, NSReturnsRetainedAttr, 796fdd2bd5SGeorge Karpenkov NSReturnsNotRetainedAttr, NSConsumesSelfAttr>()) { 806fdd2bd5SGeorge Karpenkov 816fdd2bd5SGeorge Karpenkov if (!TrackObjCAndCFObjects) 826fdd2bd5SGeorge Karpenkov return None; 836fdd2bd5SGeorge Karpenkov 846fdd2bd5SGeorge Karpenkov if (isOneOf<T, NSReturnsRetainedAttr, NSReturnsAutoreleasedAttr, 856fdd2bd5SGeorge Karpenkov NSReturnsNotRetainedAttr>() && 866fdd2bd5SGeorge Karpenkov !cocoa::isCocoaObjectRef(QT)) 876fdd2bd5SGeorge Karpenkov return None; 886fdd2bd5SGeorge Karpenkov K = ObjKind::ObjC; 896fdd2bd5SGeorge Karpenkov } else if (isOneOf<T, OSConsumedAttr, OSConsumesThisAttr, 906fdd2bd5SGeorge Karpenkov OSReturnsNotRetainedAttr, OSReturnsRetainedAttr, 916fdd2bd5SGeorge Karpenkov OSReturnsRetainedOnZeroAttr, 926fdd2bd5SGeorge Karpenkov OSReturnsRetainedOnNonZeroAttr>()) { 936fdd2bd5SGeorge Karpenkov if (!TrackOSObjects) 946fdd2bd5SGeorge Karpenkov return None; 956fdd2bd5SGeorge Karpenkov K = ObjKind::OS; 966fdd2bd5SGeorge Karpenkov } else if (isOneOf<T, GeneralizedReturnsNotRetainedAttr, 976fdd2bd5SGeorge Karpenkov GeneralizedReturnsRetainedAttr, 986fdd2bd5SGeorge Karpenkov GeneralizedConsumedAttr>()) { 996fdd2bd5SGeorge Karpenkov K = ObjKind::Generalized; 1006fdd2bd5SGeorge Karpenkov } else { 1016fdd2bd5SGeorge Karpenkov llvm_unreachable("Unexpected attribute"); 1026fdd2bd5SGeorge Karpenkov } 1036fdd2bd5SGeorge Karpenkov if (D->hasAttr<T>()) 1046fdd2bd5SGeorge Karpenkov return K; 1056fdd2bd5SGeorge Karpenkov return None; 1066fdd2bd5SGeorge Karpenkov } 1076fdd2bd5SGeorge Karpenkov 1086fdd2bd5SGeorge Karpenkov template <class T1, class T2, class... Others> 1096fdd2bd5SGeorge Karpenkov Optional<ObjKind> RetainSummaryManager::hasAnyEnabledAttrOf(const Decl *D, 1106fdd2bd5SGeorge Karpenkov QualType QT) { 1116fdd2bd5SGeorge Karpenkov if (auto Out = hasAnyEnabledAttrOf<T1>(D, QT)) 1126fdd2bd5SGeorge Karpenkov return Out; 1136fdd2bd5SGeorge Karpenkov return hasAnyEnabledAttrOf<T2, Others...>(D, QT); 1146fdd2bd5SGeorge Karpenkov } 1156fdd2bd5SGeorge Karpenkov 1166fdd2bd5SGeorge Karpenkov const RetainSummary * 1176fdd2bd5SGeorge Karpenkov RetainSummaryManager::getPersistentSummary(const RetainSummary &OldSumm) { 1186fdd2bd5SGeorge Karpenkov // Unique "simple" summaries -- those without ArgEffects. 1196fdd2bd5SGeorge Karpenkov if (OldSumm.isSimple()) { 1206fdd2bd5SGeorge Karpenkov ::llvm::FoldingSetNodeID ID; 1216fdd2bd5SGeorge Karpenkov OldSumm.Profile(ID); 1226fdd2bd5SGeorge Karpenkov 1236fdd2bd5SGeorge Karpenkov void *Pos; 1246fdd2bd5SGeorge Karpenkov CachedSummaryNode *N = SimpleSummaries.FindNodeOrInsertPos(ID, Pos); 1256fdd2bd5SGeorge Karpenkov 1266fdd2bd5SGeorge Karpenkov if (!N) { 1276fdd2bd5SGeorge Karpenkov N = (CachedSummaryNode *) BPAlloc.Allocate<CachedSummaryNode>(); 1286fdd2bd5SGeorge Karpenkov new (N) CachedSummaryNode(OldSumm); 1296fdd2bd5SGeorge Karpenkov SimpleSummaries.InsertNode(N, Pos); 1306fdd2bd5SGeorge Karpenkov } 1316fdd2bd5SGeorge Karpenkov 1326fdd2bd5SGeorge Karpenkov return &N->getValue(); 1336fdd2bd5SGeorge Karpenkov } 1346fdd2bd5SGeorge Karpenkov 1356fdd2bd5SGeorge Karpenkov RetainSummary *Summ = (RetainSummary *) BPAlloc.Allocate<RetainSummary>(); 1366fdd2bd5SGeorge Karpenkov new (Summ) RetainSummary(OldSumm); 1376fdd2bd5SGeorge Karpenkov return Summ; 1386fdd2bd5SGeorge Karpenkov } 1396fdd2bd5SGeorge Karpenkov 1406fdd2bd5SGeorge Karpenkov static bool isSubclass(const Decl *D, 1416fdd2bd5SGeorge Karpenkov StringRef ClassName) { 1426fdd2bd5SGeorge Karpenkov using namespace ast_matchers; 143adcd0268SBenjamin Kramer DeclarationMatcher SubclassM = 144adcd0268SBenjamin Kramer cxxRecordDecl(isSameOrDerivedFrom(std::string(ClassName))); 1456fdd2bd5SGeorge Karpenkov return !(match(SubclassM, *D, D->getASTContext()).empty()); 1466fdd2bd5SGeorge Karpenkov } 1476fdd2bd5SGeorge Karpenkov 1486fdd2bd5SGeorge Karpenkov static bool isOSObjectSubclass(const Decl *D) { 149ddb01010SArtem Dergachev return D && isSubclass(D, "OSMetaClassBase"); 1506fdd2bd5SGeorge Karpenkov } 1516fdd2bd5SGeorge Karpenkov 1526fdd2bd5SGeorge Karpenkov static bool isOSObjectDynamicCast(StringRef S) { 1536fdd2bd5SGeorge Karpenkov return S == "safeMetaCast"; 1546fdd2bd5SGeorge Karpenkov } 1556fdd2bd5SGeorge Karpenkov 156b03854f8SArtem Dergachev static bool isOSObjectRequiredCast(StringRef S) { 157b03854f8SArtem Dergachev return S == "requiredMetaCast"; 158b03854f8SArtem Dergachev } 159b03854f8SArtem Dergachev 1606fdd2bd5SGeorge Karpenkov static bool isOSObjectThisCast(StringRef S) { 1616fdd2bd5SGeorge Karpenkov return S == "metaCast"; 1626fdd2bd5SGeorge Karpenkov } 1636fdd2bd5SGeorge Karpenkov 164d37ff4e8SGeorge Karpenkov 165d37ff4e8SGeorge Karpenkov static bool isOSObjectPtr(QualType QT) { 166d37ff4e8SGeorge Karpenkov return isOSObjectSubclass(QT->getPointeeCXXRecordDecl()); 167d37ff4e8SGeorge Karpenkov } 168d37ff4e8SGeorge Karpenkov 169d37ff4e8SGeorge Karpenkov static bool isISLObjectRef(QualType Ty) { 170d37ff4e8SGeorge Karpenkov return StringRef(Ty.getAsString()).startswith("isl_"); 171d37ff4e8SGeorge Karpenkov } 172d37ff4e8SGeorge Karpenkov 1736fdd2bd5SGeorge Karpenkov static bool isOSIteratorSubclass(const Decl *D) { 1746fdd2bd5SGeorge Karpenkov return isSubclass(D, "OSIterator"); 1756fdd2bd5SGeorge Karpenkov } 1766fdd2bd5SGeorge Karpenkov 1776fdd2bd5SGeorge Karpenkov static bool hasRCAnnotation(const Decl *D, StringRef rcAnnotation) { 1786fdd2bd5SGeorge Karpenkov for (const auto *Ann : D->specific_attrs<AnnotateAttr>()) { 1796fdd2bd5SGeorge Karpenkov if (Ann->getAnnotation() == rcAnnotation) 1806fdd2bd5SGeorge Karpenkov return true; 1816fdd2bd5SGeorge Karpenkov } 1826fdd2bd5SGeorge Karpenkov return false; 1836fdd2bd5SGeorge Karpenkov } 1846fdd2bd5SGeorge Karpenkov 1856fdd2bd5SGeorge Karpenkov static bool isRetain(const FunctionDecl *FD, StringRef FName) { 1866fdd2bd5SGeorge Karpenkov return FName.startswith_lower("retain") || FName.endswith_lower("retain"); 1876fdd2bd5SGeorge Karpenkov } 1886fdd2bd5SGeorge Karpenkov 1896fdd2bd5SGeorge Karpenkov static bool isRelease(const FunctionDecl *FD, StringRef FName) { 1906fdd2bd5SGeorge Karpenkov return FName.startswith_lower("release") || FName.endswith_lower("release"); 1916fdd2bd5SGeorge Karpenkov } 1926fdd2bd5SGeorge Karpenkov 1936fdd2bd5SGeorge Karpenkov static bool isAutorelease(const FunctionDecl *FD, StringRef FName) { 1946fdd2bd5SGeorge Karpenkov return FName.startswith_lower("autorelease") || 1956fdd2bd5SGeorge Karpenkov FName.endswith_lower("autorelease"); 1966fdd2bd5SGeorge Karpenkov } 1976fdd2bd5SGeorge Karpenkov 1986fdd2bd5SGeorge Karpenkov static bool isMakeCollectable(StringRef FName) { 1996fdd2bd5SGeorge Karpenkov return FName.contains_lower("MakeCollectable"); 2006fdd2bd5SGeorge Karpenkov } 2016fdd2bd5SGeorge Karpenkov 2026fdd2bd5SGeorge Karpenkov /// A function is OSObject related if it is declared on a subclass 2036fdd2bd5SGeorge Karpenkov /// of OSObject, or any of the parameters is a subclass of an OSObject. 2046fdd2bd5SGeorge Karpenkov static bool isOSObjectRelated(const CXXMethodDecl *MD) { 2056fdd2bd5SGeorge Karpenkov if (isOSObjectSubclass(MD->getParent())) 2066fdd2bd5SGeorge Karpenkov return true; 2076fdd2bd5SGeorge Karpenkov 2086fdd2bd5SGeorge Karpenkov for (ParmVarDecl *Param : MD->parameters()) { 2096fdd2bd5SGeorge Karpenkov QualType PT = Param->getType()->getPointeeType(); 2106fdd2bd5SGeorge Karpenkov if (!PT.isNull()) 2116fdd2bd5SGeorge Karpenkov if (CXXRecordDecl *RD = PT->getAsCXXRecordDecl()) 2126fdd2bd5SGeorge Karpenkov if (isOSObjectSubclass(RD)) 2136fdd2bd5SGeorge Karpenkov return true; 2146fdd2bd5SGeorge Karpenkov } 2156fdd2bd5SGeorge Karpenkov 2166fdd2bd5SGeorge Karpenkov return false; 2176fdd2bd5SGeorge Karpenkov } 2186fdd2bd5SGeorge Karpenkov 2196fdd2bd5SGeorge Karpenkov bool 2206fdd2bd5SGeorge Karpenkov RetainSummaryManager::isKnownSmartPointer(QualType QT) { 2216fdd2bd5SGeorge Karpenkov QT = QT.getCanonicalType(); 2226fdd2bd5SGeorge Karpenkov const auto *RD = QT->getAsCXXRecordDecl(); 2236fdd2bd5SGeorge Karpenkov if (!RD) 2246fdd2bd5SGeorge Karpenkov return false; 2256fdd2bd5SGeorge Karpenkov const IdentifierInfo *II = RD->getIdentifier(); 2266fdd2bd5SGeorge Karpenkov if (II && II->getName() == "smart_ptr") 2276fdd2bd5SGeorge Karpenkov if (const auto *ND = dyn_cast<NamespaceDecl>(RD->getDeclContext())) 2286fdd2bd5SGeorge Karpenkov if (ND->getNameAsString() == "os") 2296fdd2bd5SGeorge Karpenkov return true; 2306fdd2bd5SGeorge Karpenkov return false; 2316fdd2bd5SGeorge Karpenkov } 2326fdd2bd5SGeorge Karpenkov 2336fdd2bd5SGeorge Karpenkov const RetainSummary * 2346fdd2bd5SGeorge Karpenkov RetainSummaryManager::getSummaryForOSObject(const FunctionDecl *FD, 2356fdd2bd5SGeorge Karpenkov StringRef FName, QualType RetTy) { 23648e7a2faSArtem Dergachev assert(TrackOSObjects && 23748e7a2faSArtem Dergachev "Requesting a summary for an OSObject but OSObjects are not tracked"); 23848e7a2faSArtem Dergachev 2396fdd2bd5SGeorge Karpenkov if (RetTy->isPointerType()) { 2406fdd2bd5SGeorge Karpenkov const CXXRecordDecl *PD = RetTy->getPointeeType()->getAsCXXRecordDecl(); 2416fdd2bd5SGeorge Karpenkov if (PD && isOSObjectSubclass(PD)) { 242b03854f8SArtem Dergachev if (isOSObjectDynamicCast(FName) || isOSObjectRequiredCast(FName) || 243b03854f8SArtem Dergachev isOSObjectThisCast(FName)) 2446fdd2bd5SGeorge Karpenkov return getDefaultSummary(); 2456fdd2bd5SGeorge Karpenkov 24648e7a2faSArtem Dergachev // TODO: Add support for the slightly common *Matching(table) idiom. 24748e7a2faSArtem Dergachev // Cf. IOService::nameMatching() etc. - these function have an unusual 24848e7a2faSArtem Dergachev // contract of returning at +0 or +1 depending on their last argument. 24948e7a2faSArtem Dergachev if (FName.endswith("Matching")) { 25048e7a2faSArtem Dergachev return getPersistentStopSummary(); 25148e7a2faSArtem Dergachev } 25248e7a2faSArtem Dergachev 25348e7a2faSArtem Dergachev // All objects returned with functions *not* starting with 'get', 25448e7a2faSArtem Dergachev // or iterators, are returned at +1. 25548e7a2faSArtem Dergachev if ((!FName.startswith("get") && !FName.startswith("Get")) || 2566fdd2bd5SGeorge Karpenkov isOSIteratorSubclass(PD)) { 2576fdd2bd5SGeorge Karpenkov return getOSSummaryCreateRule(FD); 2586fdd2bd5SGeorge Karpenkov } else { 2596fdd2bd5SGeorge Karpenkov return getOSSummaryGetRule(FD); 2606fdd2bd5SGeorge Karpenkov } 2616fdd2bd5SGeorge Karpenkov } 2626fdd2bd5SGeorge Karpenkov } 2636fdd2bd5SGeorge Karpenkov 2646fdd2bd5SGeorge Karpenkov if (const auto *MD = dyn_cast<CXXMethodDecl>(FD)) { 2656fdd2bd5SGeorge Karpenkov const CXXRecordDecl *Parent = MD->getParent(); 26648e7a2faSArtem Dergachev if (Parent && isOSObjectSubclass(Parent)) { 2670f3bbbaeSGeorge Karpenkov if (FName == "release" || FName == "taggedRelease") 2686fdd2bd5SGeorge Karpenkov return getOSSummaryReleaseRule(FD); 2696fdd2bd5SGeorge Karpenkov 2700f3bbbaeSGeorge Karpenkov if (FName == "retain" || FName == "taggedRetain") 2716fdd2bd5SGeorge Karpenkov return getOSSummaryRetainRule(FD); 2726fdd2bd5SGeorge Karpenkov 2736fdd2bd5SGeorge Karpenkov if (FName == "free") 2746fdd2bd5SGeorge Karpenkov return getOSSummaryFreeRule(FD); 2756fdd2bd5SGeorge Karpenkov 2766fdd2bd5SGeorge Karpenkov if (MD->getOverloadedOperator() == OO_New) 2776fdd2bd5SGeorge Karpenkov return getOSSummaryCreateRule(MD); 2786fdd2bd5SGeorge Karpenkov } 2796fdd2bd5SGeorge Karpenkov } 2806fdd2bd5SGeorge Karpenkov 2816fdd2bd5SGeorge Karpenkov return nullptr; 2826fdd2bd5SGeorge Karpenkov } 2836fdd2bd5SGeorge Karpenkov 2846fdd2bd5SGeorge Karpenkov const RetainSummary *RetainSummaryManager::getSummaryForObjCOrCFObject( 2856fdd2bd5SGeorge Karpenkov const FunctionDecl *FD, 2866fdd2bd5SGeorge Karpenkov StringRef FName, 2876fdd2bd5SGeorge Karpenkov QualType RetTy, 2886fdd2bd5SGeorge Karpenkov const FunctionType *FT, 2896fdd2bd5SGeorge Karpenkov bool &AllowAnnotations) { 2906fdd2bd5SGeorge Karpenkov 2916fdd2bd5SGeorge Karpenkov ArgEffects ScratchArgs(AF.getEmptyMap()); 2926fdd2bd5SGeorge Karpenkov 2936fdd2bd5SGeorge Karpenkov std::string RetTyName = RetTy.getAsString(); 2946fdd2bd5SGeorge Karpenkov if (FName == "pthread_create" || FName == "pthread_setspecific") { 2956fdd2bd5SGeorge Karpenkov // Part of: <rdar://problem/7299394> and <rdar://problem/11282706>. 2966fdd2bd5SGeorge Karpenkov // This will be addressed better with IPA. 2976fdd2bd5SGeorge Karpenkov return getPersistentStopSummary(); 2986fdd2bd5SGeorge Karpenkov } else if(FName == "NSMakeCollectable") { 2996fdd2bd5SGeorge Karpenkov // Handle: id NSMakeCollectable(CFTypeRef) 3006fdd2bd5SGeorge Karpenkov AllowAnnotations = false; 3016fdd2bd5SGeorge Karpenkov return RetTy->isObjCIdType() ? getUnarySummary(FT, DoNothing) 3026fdd2bd5SGeorge Karpenkov : getPersistentStopSummary(); 3036fdd2bd5SGeorge Karpenkov } else if (FName == "CMBufferQueueDequeueAndRetain" || 3046fdd2bd5SGeorge Karpenkov FName == "CMBufferQueueDequeueIfDataReadyAndRetain") { 3056fdd2bd5SGeorge Karpenkov // Part of: <rdar://problem/39390714>. 3066fdd2bd5SGeorge Karpenkov return getPersistentSummary(RetEffect::MakeOwned(ObjKind::CF), 3076fdd2bd5SGeorge Karpenkov ScratchArgs, 3086fdd2bd5SGeorge Karpenkov ArgEffect(DoNothing), 3096fdd2bd5SGeorge Karpenkov ArgEffect(DoNothing)); 3106fdd2bd5SGeorge Karpenkov } else if (FName == "CFPlugInInstanceCreate") { 3116fdd2bd5SGeorge Karpenkov return getPersistentSummary(RetEffect::MakeNoRet(), ScratchArgs); 3126fdd2bd5SGeorge Karpenkov } else if (FName == "IORegistryEntrySearchCFProperty" || 3136fdd2bd5SGeorge Karpenkov (RetTyName == "CFMutableDictionaryRef" && 3146fdd2bd5SGeorge Karpenkov (FName == "IOBSDNameMatching" || FName == "IOServiceMatching" || 3156fdd2bd5SGeorge Karpenkov FName == "IOServiceNameMatching" || 3166fdd2bd5SGeorge Karpenkov FName == "IORegistryEntryIDMatching" || 3176fdd2bd5SGeorge Karpenkov FName == "IOOpenFirmwarePathMatching"))) { 3186fdd2bd5SGeorge Karpenkov // Part of <rdar://problem/6961230>. (IOKit) 3196fdd2bd5SGeorge Karpenkov // This should be addressed using a API table. 3206fdd2bd5SGeorge Karpenkov return getPersistentSummary(RetEffect::MakeOwned(ObjKind::CF), ScratchArgs, 3216fdd2bd5SGeorge Karpenkov ArgEffect(DoNothing), ArgEffect(DoNothing)); 3226fdd2bd5SGeorge Karpenkov } else if (FName == "IOServiceGetMatchingService" || 3236fdd2bd5SGeorge Karpenkov FName == "IOServiceGetMatchingServices") { 3246fdd2bd5SGeorge Karpenkov // FIXES: <rdar://problem/6326900> 3256fdd2bd5SGeorge Karpenkov // This should be addressed using a API table. This strcmp is also 3266fdd2bd5SGeorge Karpenkov // a little gross, but there is no need to super optimize here. 3276fdd2bd5SGeorge Karpenkov ScratchArgs = AF.add(ScratchArgs, 1, ArgEffect(DecRef, ObjKind::CF)); 3286fdd2bd5SGeorge Karpenkov return getPersistentSummary(RetEffect::MakeNoRet(), 3296fdd2bd5SGeorge Karpenkov ScratchArgs, 3306fdd2bd5SGeorge Karpenkov ArgEffect(DoNothing), ArgEffect(DoNothing)); 3316fdd2bd5SGeorge Karpenkov } else if (FName == "IOServiceAddNotification" || 3326fdd2bd5SGeorge Karpenkov FName == "IOServiceAddMatchingNotification") { 3336fdd2bd5SGeorge Karpenkov // Part of <rdar://problem/6961230>. (IOKit) 3346fdd2bd5SGeorge Karpenkov // This should be addressed using a API table. 3356fdd2bd5SGeorge Karpenkov ScratchArgs = AF.add(ScratchArgs, 2, ArgEffect(DecRef, ObjKind::CF)); 3366fdd2bd5SGeorge Karpenkov return getPersistentSummary(RetEffect::MakeNoRet(), 3376fdd2bd5SGeorge Karpenkov ScratchArgs, 3386fdd2bd5SGeorge Karpenkov ArgEffect(DoNothing), ArgEffect(DoNothing)); 3396fdd2bd5SGeorge Karpenkov } else if (FName == "CVPixelBufferCreateWithBytes") { 3406fdd2bd5SGeorge Karpenkov // FIXES: <rdar://problem/7283567> 3416fdd2bd5SGeorge Karpenkov // Eventually this can be improved by recognizing that the pixel 3426fdd2bd5SGeorge Karpenkov // buffer passed to CVPixelBufferCreateWithBytes is released via 3436fdd2bd5SGeorge Karpenkov // a callback and doing full IPA to make sure this is done correctly. 3446fdd2bd5SGeorge Karpenkov // FIXME: This function has an out parameter that returns an 3456fdd2bd5SGeorge Karpenkov // allocated object. 3466fdd2bd5SGeorge Karpenkov ScratchArgs = AF.add(ScratchArgs, 7, ArgEffect(StopTracking)); 3476fdd2bd5SGeorge Karpenkov return getPersistentSummary(RetEffect::MakeNoRet(), 3486fdd2bd5SGeorge Karpenkov ScratchArgs, 3496fdd2bd5SGeorge Karpenkov ArgEffect(DoNothing), ArgEffect(DoNothing)); 3506fdd2bd5SGeorge Karpenkov } else if (FName == "CGBitmapContextCreateWithData") { 3516fdd2bd5SGeorge Karpenkov // FIXES: <rdar://problem/7358899> 3526fdd2bd5SGeorge Karpenkov // Eventually this can be improved by recognizing that 'releaseInfo' 3536fdd2bd5SGeorge Karpenkov // passed to CGBitmapContextCreateWithData is released via 3546fdd2bd5SGeorge Karpenkov // a callback and doing full IPA to make sure this is done correctly. 3556fdd2bd5SGeorge Karpenkov ScratchArgs = AF.add(ScratchArgs, 8, ArgEffect(ArgEffect(StopTracking))); 3566fdd2bd5SGeorge Karpenkov return getPersistentSummary(RetEffect::MakeOwned(ObjKind::CF), ScratchArgs, 3576fdd2bd5SGeorge Karpenkov ArgEffect(DoNothing), ArgEffect(DoNothing)); 3586fdd2bd5SGeorge Karpenkov } else if (FName == "CVPixelBufferCreateWithPlanarBytes") { 3596fdd2bd5SGeorge Karpenkov // FIXES: <rdar://problem/7283567> 3606fdd2bd5SGeorge Karpenkov // Eventually this can be improved by recognizing that the pixel 3616fdd2bd5SGeorge Karpenkov // buffer passed to CVPixelBufferCreateWithPlanarBytes is released 3626fdd2bd5SGeorge Karpenkov // via a callback and doing full IPA to make sure this is done 3636fdd2bd5SGeorge Karpenkov // correctly. 3646fdd2bd5SGeorge Karpenkov ScratchArgs = AF.add(ScratchArgs, 12, ArgEffect(StopTracking)); 3656fdd2bd5SGeorge Karpenkov return getPersistentSummary(RetEffect::MakeNoRet(), 3666fdd2bd5SGeorge Karpenkov ScratchArgs, 3676fdd2bd5SGeorge Karpenkov ArgEffect(DoNothing), ArgEffect(DoNothing)); 3686fdd2bd5SGeorge Karpenkov } else if (FName == "VTCompressionSessionEncodeFrame") { 3696fdd2bd5SGeorge Karpenkov // The context argument passed to VTCompressionSessionEncodeFrame() 3706fdd2bd5SGeorge Karpenkov // is passed to the callback specified when creating the session 3716fdd2bd5SGeorge Karpenkov // (e.g. with VTCompressionSessionCreate()) which can release it. 3726fdd2bd5SGeorge Karpenkov // To account for this possibility, conservatively stop tracking 3736fdd2bd5SGeorge Karpenkov // the context. 3746fdd2bd5SGeorge Karpenkov ScratchArgs = AF.add(ScratchArgs, 5, ArgEffect(StopTracking)); 3756fdd2bd5SGeorge Karpenkov return getPersistentSummary(RetEffect::MakeNoRet(), 3766fdd2bd5SGeorge Karpenkov ScratchArgs, 3776fdd2bd5SGeorge Karpenkov ArgEffect(DoNothing), ArgEffect(DoNothing)); 3786fdd2bd5SGeorge Karpenkov } else if (FName == "dispatch_set_context" || 3796fdd2bd5SGeorge Karpenkov FName == "xpc_connection_set_context") { 3806fdd2bd5SGeorge Karpenkov // <rdar://problem/11059275> - The analyzer currently doesn't have 3816fdd2bd5SGeorge Karpenkov // a good way to reason about the finalizer function for libdispatch. 3826fdd2bd5SGeorge Karpenkov // If we pass a context object that is memory managed, stop tracking it. 3836fdd2bd5SGeorge Karpenkov // <rdar://problem/13783514> - Same problem, but for XPC. 3846fdd2bd5SGeorge Karpenkov // FIXME: this hack should possibly go away once we can handle 3856fdd2bd5SGeorge Karpenkov // libdispatch and XPC finalizers. 3866fdd2bd5SGeorge Karpenkov ScratchArgs = AF.add(ScratchArgs, 1, ArgEffect(StopTracking)); 3876fdd2bd5SGeorge Karpenkov return getPersistentSummary(RetEffect::MakeNoRet(), 3886fdd2bd5SGeorge Karpenkov ScratchArgs, 3896fdd2bd5SGeorge Karpenkov ArgEffect(DoNothing), ArgEffect(DoNothing)); 3906fdd2bd5SGeorge Karpenkov } else if (FName.startswith("NSLog")) { 3916fdd2bd5SGeorge Karpenkov return getDoNothingSummary(); 3926fdd2bd5SGeorge Karpenkov } else if (FName.startswith("NS") && 3936fdd2bd5SGeorge Karpenkov (FName.find("Insert") != StringRef::npos)) { 3946fdd2bd5SGeorge Karpenkov // Whitelist NSXXInsertXX, for example NSMapInsertIfAbsent, since they can 3956fdd2bd5SGeorge Karpenkov // be deallocated by NSMapRemove. (radar://11152419) 3966fdd2bd5SGeorge Karpenkov ScratchArgs = AF.add(ScratchArgs, 1, ArgEffect(StopTracking)); 3976fdd2bd5SGeorge Karpenkov ScratchArgs = AF.add(ScratchArgs, 2, ArgEffect(StopTracking)); 3986fdd2bd5SGeorge Karpenkov return getPersistentSummary(RetEffect::MakeNoRet(), 3996fdd2bd5SGeorge Karpenkov ScratchArgs, ArgEffect(DoNothing), 4006fdd2bd5SGeorge Karpenkov ArgEffect(DoNothing)); 4016fdd2bd5SGeorge Karpenkov } 4026fdd2bd5SGeorge Karpenkov 4036fdd2bd5SGeorge Karpenkov if (RetTy->isPointerType()) { 4046fdd2bd5SGeorge Karpenkov 4056fdd2bd5SGeorge Karpenkov // For CoreFoundation ('CF') types. 4066fdd2bd5SGeorge Karpenkov if (cocoa::isRefType(RetTy, "CF", FName)) { 4076fdd2bd5SGeorge Karpenkov if (isRetain(FD, FName)) { 4086fdd2bd5SGeorge Karpenkov // CFRetain isn't supposed to be annotated. However, this may as 4096fdd2bd5SGeorge Karpenkov // well be a user-made "safe" CFRetain function that is incorrectly 4106fdd2bd5SGeorge Karpenkov // annotated as cf_returns_retained due to lack of better options. 4116fdd2bd5SGeorge Karpenkov // We want to ignore such annotation. 4126fdd2bd5SGeorge Karpenkov AllowAnnotations = false; 4136fdd2bd5SGeorge Karpenkov 4146fdd2bd5SGeorge Karpenkov return getUnarySummary(FT, IncRef); 4156fdd2bd5SGeorge Karpenkov } else if (isAutorelease(FD, FName)) { 4166fdd2bd5SGeorge Karpenkov // The headers use cf_consumed, but we can fully model CFAutorelease 4176fdd2bd5SGeorge Karpenkov // ourselves. 4186fdd2bd5SGeorge Karpenkov AllowAnnotations = false; 4196fdd2bd5SGeorge Karpenkov 4206fdd2bd5SGeorge Karpenkov return getUnarySummary(FT, Autorelease); 4216fdd2bd5SGeorge Karpenkov } else if (isMakeCollectable(FName)) { 4226fdd2bd5SGeorge Karpenkov AllowAnnotations = false; 4236fdd2bd5SGeorge Karpenkov return getUnarySummary(FT, DoNothing); 4246fdd2bd5SGeorge Karpenkov } else { 4256fdd2bd5SGeorge Karpenkov return getCFCreateGetRuleSummary(FD); 4266fdd2bd5SGeorge Karpenkov } 4276fdd2bd5SGeorge Karpenkov } 4286fdd2bd5SGeorge Karpenkov 4296fdd2bd5SGeorge Karpenkov // For CoreGraphics ('CG') and CoreVideo ('CV') types. 4306fdd2bd5SGeorge Karpenkov if (cocoa::isRefType(RetTy, "CG", FName) || 4316fdd2bd5SGeorge Karpenkov cocoa::isRefType(RetTy, "CV", FName)) { 4326fdd2bd5SGeorge Karpenkov if (isRetain(FD, FName)) 4336fdd2bd5SGeorge Karpenkov return getUnarySummary(FT, IncRef); 4346fdd2bd5SGeorge Karpenkov else 4356fdd2bd5SGeorge Karpenkov return getCFCreateGetRuleSummary(FD); 4366fdd2bd5SGeorge Karpenkov } 4376fdd2bd5SGeorge Karpenkov 4386fdd2bd5SGeorge Karpenkov // For all other CF-style types, use the Create/Get 4396fdd2bd5SGeorge Karpenkov // rule for summaries but don't support Retain functions 4406fdd2bd5SGeorge Karpenkov // with framework-specific prefixes. 4416fdd2bd5SGeorge Karpenkov if (coreFoundation::isCFObjectRef(RetTy)) { 4426fdd2bd5SGeorge Karpenkov return getCFCreateGetRuleSummary(FD); 4436fdd2bd5SGeorge Karpenkov } 4446fdd2bd5SGeorge Karpenkov 4456fdd2bd5SGeorge Karpenkov if (FD->hasAttr<CFAuditedTransferAttr>()) { 4466fdd2bd5SGeorge Karpenkov return getCFCreateGetRuleSummary(FD); 4476fdd2bd5SGeorge Karpenkov } 4486fdd2bd5SGeorge Karpenkov } 4496fdd2bd5SGeorge Karpenkov 4506fdd2bd5SGeorge Karpenkov // Check for release functions, the only kind of functions that we care 4516fdd2bd5SGeorge Karpenkov // about that don't return a pointer type. 4526fdd2bd5SGeorge Karpenkov if (FName.startswith("CG") || FName.startswith("CF")) { 4536fdd2bd5SGeorge Karpenkov // Test for 'CGCF'. 4546fdd2bd5SGeorge Karpenkov FName = FName.substr(FName.startswith("CGCF") ? 4 : 2); 4556fdd2bd5SGeorge Karpenkov 4566fdd2bd5SGeorge Karpenkov if (isRelease(FD, FName)) 4576fdd2bd5SGeorge Karpenkov return getUnarySummary(FT, DecRef); 4586fdd2bd5SGeorge Karpenkov else { 4596fdd2bd5SGeorge Karpenkov assert(ScratchArgs.isEmpty()); 4606fdd2bd5SGeorge Karpenkov // Remaining CoreFoundation and CoreGraphics functions. 4616fdd2bd5SGeorge Karpenkov // We use to assume that they all strictly followed the ownership idiom 4626fdd2bd5SGeorge Karpenkov // and that ownership cannot be transferred. While this is technically 4636fdd2bd5SGeorge Karpenkov // correct, many methods allow a tracked object to escape. For example: 4646fdd2bd5SGeorge Karpenkov // 4656fdd2bd5SGeorge Karpenkov // CFMutableDictionaryRef x = CFDictionaryCreateMutable(...); 4666fdd2bd5SGeorge Karpenkov // CFDictionaryAddValue(y, key, x); 4676fdd2bd5SGeorge Karpenkov // CFRelease(x); 4686fdd2bd5SGeorge Karpenkov // ... it is okay to use 'x' since 'y' has a reference to it 4696fdd2bd5SGeorge Karpenkov // 4706fdd2bd5SGeorge Karpenkov // We handle this and similar cases with the follow heuristic. If the 4716fdd2bd5SGeorge Karpenkov // function name contains "InsertValue", "SetValue", "AddValue", 4726fdd2bd5SGeorge Karpenkov // "AppendValue", or "SetAttribute", then we assume that arguments may 4736fdd2bd5SGeorge Karpenkov // "escape." This means that something else holds on to the object, 4746fdd2bd5SGeorge Karpenkov // allowing it be used even after its local retain count drops to 0. 4756fdd2bd5SGeorge Karpenkov ArgEffectKind E = 4766fdd2bd5SGeorge Karpenkov (StrInStrNoCase(FName, "InsertValue") != StringRef::npos || 4776fdd2bd5SGeorge Karpenkov StrInStrNoCase(FName, "AddValue") != StringRef::npos || 4786fdd2bd5SGeorge Karpenkov StrInStrNoCase(FName, "SetValue") != StringRef::npos || 4796fdd2bd5SGeorge Karpenkov StrInStrNoCase(FName, "AppendValue") != StringRef::npos || 4806fdd2bd5SGeorge Karpenkov StrInStrNoCase(FName, "SetAttribute") != StringRef::npos) 4816fdd2bd5SGeorge Karpenkov ? MayEscape 4826fdd2bd5SGeorge Karpenkov : DoNothing; 4836fdd2bd5SGeorge Karpenkov 4846fdd2bd5SGeorge Karpenkov return getPersistentSummary(RetEffect::MakeNoRet(), ScratchArgs, 4856fdd2bd5SGeorge Karpenkov ArgEffect(DoNothing), ArgEffect(E, ObjKind::CF)); 4866fdd2bd5SGeorge Karpenkov } 4876fdd2bd5SGeorge Karpenkov } 4886fdd2bd5SGeorge Karpenkov 4896fdd2bd5SGeorge Karpenkov return nullptr; 4906fdd2bd5SGeorge Karpenkov } 4916fdd2bd5SGeorge Karpenkov 4926fdd2bd5SGeorge Karpenkov const RetainSummary * 4936fdd2bd5SGeorge Karpenkov RetainSummaryManager::generateSummary(const FunctionDecl *FD, 4946fdd2bd5SGeorge Karpenkov bool &AllowAnnotations) { 4956fdd2bd5SGeorge Karpenkov // We generate "stop" summaries for implicitly defined functions. 4966fdd2bd5SGeorge Karpenkov if (FD->isImplicit()) 4976fdd2bd5SGeorge Karpenkov return getPersistentStopSummary(); 4986fdd2bd5SGeorge Karpenkov 4996fdd2bd5SGeorge Karpenkov const IdentifierInfo *II = FD->getIdentifier(); 5006fdd2bd5SGeorge Karpenkov 5016fdd2bd5SGeorge Karpenkov StringRef FName = II ? II->getName() : ""; 5026fdd2bd5SGeorge Karpenkov 5036fdd2bd5SGeorge Karpenkov // Strip away preceding '_'. Doing this here will effect all the checks 5046fdd2bd5SGeorge Karpenkov // down below. 5056fdd2bd5SGeorge Karpenkov FName = FName.substr(FName.find_first_not_of('_')); 5066fdd2bd5SGeorge Karpenkov 5076fdd2bd5SGeorge Karpenkov // Inspect the result type. Strip away any typedefs. 5083517d105SArtem Dergachev const auto *FT = FD->getType()->castAs<FunctionType>(); 5096fdd2bd5SGeorge Karpenkov QualType RetTy = FT->getReturnType(); 5106fdd2bd5SGeorge Karpenkov 5116fdd2bd5SGeorge Karpenkov if (TrackOSObjects) 5126fdd2bd5SGeorge Karpenkov if (const RetainSummary *S = getSummaryForOSObject(FD, FName, RetTy)) 5136fdd2bd5SGeorge Karpenkov return S; 5146fdd2bd5SGeorge Karpenkov 5156fdd2bd5SGeorge Karpenkov if (const auto *MD = dyn_cast<CXXMethodDecl>(FD)) 5166794aa70SGeorge Karpenkov if (!isOSObjectRelated(MD)) 5176fdd2bd5SGeorge Karpenkov return getPersistentSummary(RetEffect::MakeNoRet(), 5186fdd2bd5SGeorge Karpenkov ArgEffects(AF.getEmptyMap()), 5196fdd2bd5SGeorge Karpenkov ArgEffect(DoNothing), 5206fdd2bd5SGeorge Karpenkov ArgEffect(StopTracking), 5216fdd2bd5SGeorge Karpenkov ArgEffect(DoNothing)); 5226fdd2bd5SGeorge Karpenkov 5236794aa70SGeorge Karpenkov if (TrackObjCAndCFObjects) 5246794aa70SGeorge Karpenkov if (const RetainSummary *S = 5256794aa70SGeorge Karpenkov getSummaryForObjCOrCFObject(FD, FName, RetTy, FT, AllowAnnotations)) 5266794aa70SGeorge Karpenkov return S; 5276794aa70SGeorge Karpenkov 5286fdd2bd5SGeorge Karpenkov return getDefaultSummary(); 5296fdd2bd5SGeorge Karpenkov } 5306fdd2bd5SGeorge Karpenkov 5316fdd2bd5SGeorge Karpenkov const RetainSummary * 5326fdd2bd5SGeorge Karpenkov RetainSummaryManager::getFunctionSummary(const FunctionDecl *FD) { 5336fdd2bd5SGeorge Karpenkov // If we don't know what function we're calling, use our default summary. 5346fdd2bd5SGeorge Karpenkov if (!FD) 5356fdd2bd5SGeorge Karpenkov return getDefaultSummary(); 5366fdd2bd5SGeorge Karpenkov 5376fdd2bd5SGeorge Karpenkov // Look up a summary in our cache of FunctionDecls -> Summaries. 5386fdd2bd5SGeorge Karpenkov FuncSummariesTy::iterator I = FuncSummaries.find(FD); 5396fdd2bd5SGeorge Karpenkov if (I != FuncSummaries.end()) 5406fdd2bd5SGeorge Karpenkov return I->second; 5416fdd2bd5SGeorge Karpenkov 5426fdd2bd5SGeorge Karpenkov // No summary? Generate one. 5436fdd2bd5SGeorge Karpenkov bool AllowAnnotations = true; 5446fdd2bd5SGeorge Karpenkov const RetainSummary *S = generateSummary(FD, AllowAnnotations); 5456fdd2bd5SGeorge Karpenkov 5466fdd2bd5SGeorge Karpenkov // Annotations override defaults. 5476fdd2bd5SGeorge Karpenkov if (AllowAnnotations) 5486fdd2bd5SGeorge Karpenkov updateSummaryFromAnnotations(S, FD); 5496fdd2bd5SGeorge Karpenkov 5506fdd2bd5SGeorge Karpenkov FuncSummaries[FD] = S; 5516fdd2bd5SGeorge Karpenkov return S; 5526fdd2bd5SGeorge Karpenkov } 5536fdd2bd5SGeorge Karpenkov 5546fdd2bd5SGeorge Karpenkov //===----------------------------------------------------------------------===// 5556fdd2bd5SGeorge Karpenkov // Summary creation for functions (largely uses of Core Foundation). 5566fdd2bd5SGeorge Karpenkov //===----------------------------------------------------------------------===// 5576fdd2bd5SGeorge Karpenkov 5586fdd2bd5SGeorge Karpenkov static ArgEffect getStopTrackingHardEquivalent(ArgEffect E) { 5596fdd2bd5SGeorge Karpenkov switch (E.getKind()) { 5606fdd2bd5SGeorge Karpenkov case DoNothing: 5616fdd2bd5SGeorge Karpenkov case Autorelease: 5626fdd2bd5SGeorge Karpenkov case DecRefBridgedTransferred: 5636fdd2bd5SGeorge Karpenkov case IncRef: 5646fdd2bd5SGeorge Karpenkov case UnretainedOutParameter: 5656fdd2bd5SGeorge Karpenkov case RetainedOutParameter: 5666fdd2bd5SGeorge Karpenkov case RetainedOutParameterOnZero: 5676fdd2bd5SGeorge Karpenkov case RetainedOutParameterOnNonZero: 5686fdd2bd5SGeorge Karpenkov case MayEscape: 5696fdd2bd5SGeorge Karpenkov case StopTracking: 5706fdd2bd5SGeorge Karpenkov case StopTrackingHard: 5716fdd2bd5SGeorge Karpenkov return E.withKind(StopTrackingHard); 5726fdd2bd5SGeorge Karpenkov case DecRef: 5736fdd2bd5SGeorge Karpenkov case DecRefAndStopTrackingHard: 5746fdd2bd5SGeorge Karpenkov return E.withKind(DecRefAndStopTrackingHard); 5756fdd2bd5SGeorge Karpenkov case Dealloc: 5766fdd2bd5SGeorge Karpenkov return E.withKind(Dealloc); 5776fdd2bd5SGeorge Karpenkov } 5786fdd2bd5SGeorge Karpenkov 5796fdd2bd5SGeorge Karpenkov llvm_unreachable("Unknown ArgEffect kind"); 5806fdd2bd5SGeorge Karpenkov } 5816fdd2bd5SGeorge Karpenkov 582b0fc58b5SGeorge Karpenkov const RetainSummary * 583b0fc58b5SGeorge Karpenkov RetainSummaryManager::updateSummaryForNonZeroCallbackArg(const RetainSummary *S, 584b0fc58b5SGeorge Karpenkov AnyCall &C) { 585b0fc58b5SGeorge Karpenkov ArgEffect RecEffect = getStopTrackingHardEquivalent(S->getReceiverEffect()); 586b0fc58b5SGeorge Karpenkov ArgEffect DefEffect = getStopTrackingHardEquivalent(S->getDefaultArgEffect()); 5876fdd2bd5SGeorge Karpenkov 5886fdd2bd5SGeorge Karpenkov ArgEffects ScratchArgs(AF.getEmptyMap()); 5896fdd2bd5SGeorge Karpenkov ArgEffects CustomArgEffects = S->getArgEffects(); 5906fdd2bd5SGeorge Karpenkov for (ArgEffects::iterator I = CustomArgEffects.begin(), 5916fdd2bd5SGeorge Karpenkov E = CustomArgEffects.end(); 5926fdd2bd5SGeorge Karpenkov I != E; ++I) { 5936fdd2bd5SGeorge Karpenkov ArgEffect Translated = getStopTrackingHardEquivalent(I->second); 5946fdd2bd5SGeorge Karpenkov if (Translated.getKind() != DefEffect.getKind()) 5956fdd2bd5SGeorge Karpenkov ScratchArgs = AF.add(ScratchArgs, I->first, Translated); 5966fdd2bd5SGeorge Karpenkov } 5976fdd2bd5SGeorge Karpenkov 5986fdd2bd5SGeorge Karpenkov RetEffect RE = RetEffect::MakeNoRetHard(); 5996fdd2bd5SGeorge Karpenkov 6006fdd2bd5SGeorge Karpenkov // Special cases where the callback argument CANNOT free the return value. 6016fdd2bd5SGeorge Karpenkov // This can generally only happen if we know that the callback will only be 6026fdd2bd5SGeorge Karpenkov // called when the return value is already being deallocated. 6036fdd2bd5SGeorge Karpenkov if (const IdentifierInfo *Name = C.getIdentifier()) { 6046fdd2bd5SGeorge Karpenkov // When the CGBitmapContext is deallocated, the callback here will free 6056fdd2bd5SGeorge Karpenkov // the associated data buffer. 6066fdd2bd5SGeorge Karpenkov // The callback in dispatch_data_create frees the buffer, but not 6076fdd2bd5SGeorge Karpenkov // the data object. 6086fdd2bd5SGeorge Karpenkov if (Name->isStr("CGBitmapContextCreateWithData") || 6096fdd2bd5SGeorge Karpenkov Name->isStr("dispatch_data_create")) 6106fdd2bd5SGeorge Karpenkov RE = S->getRetEffect(); 6116fdd2bd5SGeorge Karpenkov } 612b0fc58b5SGeorge Karpenkov 613b0fc58b5SGeorge Karpenkov return getPersistentSummary(RE, ScratchArgs, RecEffect, DefEffect); 6146fdd2bd5SGeorge Karpenkov } 6156fdd2bd5SGeorge Karpenkov 616b0fc58b5SGeorge Karpenkov void RetainSummaryManager::updateSummaryForReceiverUnconsumedSelf( 617b0fc58b5SGeorge Karpenkov const RetainSummary *&S) { 6186fdd2bd5SGeorge Karpenkov 619b0fc58b5SGeorge Karpenkov RetainSummaryTemplate Template(S, *this); 620b0fc58b5SGeorge Karpenkov 621b0fc58b5SGeorge Karpenkov Template->setReceiverEffect(ArgEffect(DoNothing)); 622b0fc58b5SGeorge Karpenkov Template->setRetEffect(RetEffect::MakeNoRet()); 6236fdd2bd5SGeorge Karpenkov } 6246fdd2bd5SGeorge Karpenkov 625d37ff4e8SGeorge Karpenkov 626d37ff4e8SGeorge Karpenkov void RetainSummaryManager::updateSummaryForArgumentTypes( 627d37ff4e8SGeorge Karpenkov const AnyCall &C, const RetainSummary *&RS) { 628d37ff4e8SGeorge Karpenkov RetainSummaryTemplate Template(RS, *this); 629d37ff4e8SGeorge Karpenkov 630d37ff4e8SGeorge Karpenkov unsigned parm_idx = 0; 631d37ff4e8SGeorge Karpenkov for (auto pi = C.param_begin(), pe = C.param_end(); pi != pe; 632d37ff4e8SGeorge Karpenkov ++pi, ++parm_idx) { 633d37ff4e8SGeorge Karpenkov QualType QT = (*pi)->getType(); 634d37ff4e8SGeorge Karpenkov 635d37ff4e8SGeorge Karpenkov // Skip already created values. 636d37ff4e8SGeorge Karpenkov if (RS->getArgEffects().contains(parm_idx)) 637d37ff4e8SGeorge Karpenkov continue; 638d37ff4e8SGeorge Karpenkov 639d37ff4e8SGeorge Karpenkov ObjKind K = ObjKind::AnyObj; 640d37ff4e8SGeorge Karpenkov 641d37ff4e8SGeorge Karpenkov if (isISLObjectRef(QT)) { 642d37ff4e8SGeorge Karpenkov K = ObjKind::Generalized; 643d37ff4e8SGeorge Karpenkov } else if (isOSObjectPtr(QT)) { 644d37ff4e8SGeorge Karpenkov K = ObjKind::OS; 645d37ff4e8SGeorge Karpenkov } else if (cocoa::isCocoaObjectRef(QT)) { 646d37ff4e8SGeorge Karpenkov K = ObjKind::ObjC; 647d37ff4e8SGeorge Karpenkov } else if (coreFoundation::isCFObjectRef(QT)) { 648d37ff4e8SGeorge Karpenkov K = ObjKind::CF; 649d37ff4e8SGeorge Karpenkov } 650d37ff4e8SGeorge Karpenkov 651d37ff4e8SGeorge Karpenkov if (K != ObjKind::AnyObj) 652d37ff4e8SGeorge Karpenkov Template->addArg(AF, parm_idx, 653d37ff4e8SGeorge Karpenkov ArgEffect(RS->getDefaultArgEffect().getKind(), K)); 654d37ff4e8SGeorge Karpenkov } 655d37ff4e8SGeorge Karpenkov } 656d37ff4e8SGeorge Karpenkov 6576fdd2bd5SGeorge Karpenkov const RetainSummary * 6586fdd2bd5SGeorge Karpenkov RetainSummaryManager::getSummary(AnyCall C, 6596fdd2bd5SGeorge Karpenkov bool HasNonZeroCallbackArg, 6606fdd2bd5SGeorge Karpenkov bool IsReceiverUnconsumedSelf, 6616fdd2bd5SGeorge Karpenkov QualType ReceiverType) { 6626fdd2bd5SGeorge Karpenkov const RetainSummary *Summ; 6636fdd2bd5SGeorge Karpenkov switch (C.getKind()) { 6646fdd2bd5SGeorge Karpenkov case AnyCall::Function: 6656fdd2bd5SGeorge Karpenkov case AnyCall::Constructor: 666a82ffe9dSArtem Dergachev case AnyCall::InheritedConstructor: 6676fdd2bd5SGeorge Karpenkov case AnyCall::Allocator: 6686fdd2bd5SGeorge Karpenkov case AnyCall::Deallocator: 6696fdd2bd5SGeorge Karpenkov Summ = getFunctionSummary(cast_or_null<FunctionDecl>(C.getDecl())); 6706fdd2bd5SGeorge Karpenkov break; 6716fdd2bd5SGeorge Karpenkov case AnyCall::Block: 6726fdd2bd5SGeorge Karpenkov case AnyCall::Destructor: 6736fdd2bd5SGeorge Karpenkov // FIXME: These calls are currently unsupported. 6746fdd2bd5SGeorge Karpenkov return getPersistentStopSummary(); 6756fdd2bd5SGeorge Karpenkov case AnyCall::ObjCMethod: { 6762e466678SGeorge Karpenkov const auto *ME = cast_or_null<ObjCMessageExpr>(C.getExpr()); 6772e466678SGeorge Karpenkov if (!ME) { 67877eae6d4SGeorge Karpenkov Summ = getMethodSummary(cast<ObjCMethodDecl>(C.getDecl())); 6792e466678SGeorge Karpenkov } else if (ME->isInstanceMessage()) { 6806fdd2bd5SGeorge Karpenkov Summ = getInstanceMethodSummary(ME, ReceiverType); 6812e466678SGeorge Karpenkov } else { 6826fdd2bd5SGeorge Karpenkov Summ = getClassMethodSummary(ME); 6832e466678SGeorge Karpenkov } 6846fdd2bd5SGeorge Karpenkov break; 6856fdd2bd5SGeorge Karpenkov } 6866fdd2bd5SGeorge Karpenkov } 6876fdd2bd5SGeorge Karpenkov 688b0fc58b5SGeorge Karpenkov if (HasNonZeroCallbackArg) 689b0fc58b5SGeorge Karpenkov Summ = updateSummaryForNonZeroCallbackArg(Summ, C); 690b0fc58b5SGeorge Karpenkov 691b0fc58b5SGeorge Karpenkov if (IsReceiverUnconsumedSelf) 692b0fc58b5SGeorge Karpenkov updateSummaryForReceiverUnconsumedSelf(Summ); 6936fdd2bd5SGeorge Karpenkov 694d37ff4e8SGeorge Karpenkov updateSummaryForArgumentTypes(C, Summ); 695d37ff4e8SGeorge Karpenkov 6966fdd2bd5SGeorge Karpenkov assert(Summ && "Unknown call type?"); 6976fdd2bd5SGeorge Karpenkov return Summ; 6986fdd2bd5SGeorge Karpenkov } 6996fdd2bd5SGeorge Karpenkov 7006fdd2bd5SGeorge Karpenkov 7016fdd2bd5SGeorge Karpenkov const RetainSummary * 7026fdd2bd5SGeorge Karpenkov RetainSummaryManager::getCFCreateGetRuleSummary(const FunctionDecl *FD) { 7036fdd2bd5SGeorge Karpenkov if (coreFoundation::followsCreateRule(FD)) 7046fdd2bd5SGeorge Karpenkov return getCFSummaryCreateRule(FD); 7056fdd2bd5SGeorge Karpenkov 7066fdd2bd5SGeorge Karpenkov return getCFSummaryGetRule(FD); 7076fdd2bd5SGeorge Karpenkov } 7086fdd2bd5SGeorge Karpenkov 7096fdd2bd5SGeorge Karpenkov bool RetainSummaryManager::isTrustedReferenceCountImplementation( 71077eae6d4SGeorge Karpenkov const Decl *FD) { 7116fdd2bd5SGeorge Karpenkov return hasRCAnnotation(FD, "rc_ownership_trusted_implementation"); 7126fdd2bd5SGeorge Karpenkov } 7136fdd2bd5SGeorge Karpenkov 7146fdd2bd5SGeorge Karpenkov Optional<RetainSummaryManager::BehaviorSummary> 7156fdd2bd5SGeorge Karpenkov RetainSummaryManager::canEval(const CallExpr *CE, const FunctionDecl *FD, 7166fdd2bd5SGeorge Karpenkov bool &hasTrustedImplementationAnnotation) { 7176fdd2bd5SGeorge Karpenkov 7186fdd2bd5SGeorge Karpenkov IdentifierInfo *II = FD->getIdentifier(); 7196fdd2bd5SGeorge Karpenkov if (!II) 7206fdd2bd5SGeorge Karpenkov return None; 7216fdd2bd5SGeorge Karpenkov 7226fdd2bd5SGeorge Karpenkov StringRef FName = II->getName(); 7236fdd2bd5SGeorge Karpenkov FName = FName.substr(FName.find_first_not_of('_')); 7246fdd2bd5SGeorge Karpenkov 7256fdd2bd5SGeorge Karpenkov QualType ResultTy = CE->getCallReturnType(Ctx); 7266fdd2bd5SGeorge Karpenkov if (ResultTy->isObjCIdType()) { 7276fdd2bd5SGeorge Karpenkov if (II->isStr("NSMakeCollectable")) 7286fdd2bd5SGeorge Karpenkov return BehaviorSummary::Identity; 7296fdd2bd5SGeorge Karpenkov } else if (ResultTy->isPointerType()) { 7306fdd2bd5SGeorge Karpenkov // Handle: (CF|CG|CV)Retain 7316fdd2bd5SGeorge Karpenkov // CFAutorelease 7326fdd2bd5SGeorge Karpenkov // It's okay to be a little sloppy here. 7336fdd2bd5SGeorge Karpenkov if (FName == "CMBufferQueueDequeueAndRetain" || 7346fdd2bd5SGeorge Karpenkov FName == "CMBufferQueueDequeueIfDataReadyAndRetain") { 7356fdd2bd5SGeorge Karpenkov // Part of: <rdar://problem/39390714>. 7366fdd2bd5SGeorge Karpenkov // These are not retain. They just return something and retain it. 7376fdd2bd5SGeorge Karpenkov return None; 7386fdd2bd5SGeorge Karpenkov } 739f2192b20SArtem Dergachev if (CE->getNumArgs() == 1 && 740f2192b20SArtem Dergachev (cocoa::isRefType(ResultTy, "CF", FName) || 7416fdd2bd5SGeorge Karpenkov cocoa::isRefType(ResultTy, "CG", FName) || 742f2192b20SArtem Dergachev cocoa::isRefType(ResultTy, "CV", FName)) && 743f2192b20SArtem Dergachev (isRetain(FD, FName) || isAutorelease(FD, FName) || 744f2192b20SArtem Dergachev isMakeCollectable(FName))) 7456fdd2bd5SGeorge Karpenkov return BehaviorSummary::Identity; 7466fdd2bd5SGeorge Karpenkov 7476fdd2bd5SGeorge Karpenkov // safeMetaCast is called by OSDynamicCast. 7486fdd2bd5SGeorge Karpenkov // We assume that OSDynamicCast is either an identity (cast is OK, 7496fdd2bd5SGeorge Karpenkov // the input was non-zero), 7506fdd2bd5SGeorge Karpenkov // or that it returns zero (when the cast failed, or the input 7516fdd2bd5SGeorge Karpenkov // was zero). 7526fdd2bd5SGeorge Karpenkov if (TrackOSObjects) { 7536fdd2bd5SGeorge Karpenkov if (isOSObjectDynamicCast(FName) && FD->param_size() >= 1) { 7546fdd2bd5SGeorge Karpenkov return BehaviorSummary::IdentityOrZero; 755b03854f8SArtem Dergachev } else if (isOSObjectRequiredCast(FName) && FD->param_size() >= 1) { 756b03854f8SArtem Dergachev return BehaviorSummary::Identity; 7576fdd2bd5SGeorge Karpenkov } else if (isOSObjectThisCast(FName) && isa<CXXMethodDecl>(FD) && 7586fdd2bd5SGeorge Karpenkov !cast<CXXMethodDecl>(FD)->isStatic()) { 7596fdd2bd5SGeorge Karpenkov return BehaviorSummary::IdentityThis; 7606fdd2bd5SGeorge Karpenkov } 7616fdd2bd5SGeorge Karpenkov } 7626fdd2bd5SGeorge Karpenkov 7636fdd2bd5SGeorge Karpenkov const FunctionDecl* FDD = FD->getDefinition(); 7646fdd2bd5SGeorge Karpenkov if (FDD && isTrustedReferenceCountImplementation(FDD)) { 7656fdd2bd5SGeorge Karpenkov hasTrustedImplementationAnnotation = true; 7666fdd2bd5SGeorge Karpenkov return BehaviorSummary::Identity; 7676fdd2bd5SGeorge Karpenkov } 7686fdd2bd5SGeorge Karpenkov } 7696fdd2bd5SGeorge Karpenkov 7706fdd2bd5SGeorge Karpenkov if (const auto *MD = dyn_cast<CXXMethodDecl>(FD)) { 7716fdd2bd5SGeorge Karpenkov const CXXRecordDecl *Parent = MD->getParent(); 7726fdd2bd5SGeorge Karpenkov if (TrackOSObjects && Parent && isOSObjectSubclass(Parent)) 7736fdd2bd5SGeorge Karpenkov if (FName == "release" || FName == "retain") 7746fdd2bd5SGeorge Karpenkov return BehaviorSummary::NoOp; 7756fdd2bd5SGeorge Karpenkov } 7766fdd2bd5SGeorge Karpenkov 7776fdd2bd5SGeorge Karpenkov return None; 7786fdd2bd5SGeorge Karpenkov } 7796fdd2bd5SGeorge Karpenkov 7806fdd2bd5SGeorge Karpenkov const RetainSummary * 7816fdd2bd5SGeorge Karpenkov RetainSummaryManager::getUnarySummary(const FunctionType* FT, 7826fdd2bd5SGeorge Karpenkov ArgEffectKind AE) { 7836fdd2bd5SGeorge Karpenkov 7846fdd2bd5SGeorge Karpenkov // Unary functions have no arg effects by definition. 7856fdd2bd5SGeorge Karpenkov ArgEffects ScratchArgs(AF.getEmptyMap()); 7866fdd2bd5SGeorge Karpenkov 7876fdd2bd5SGeorge Karpenkov // Sanity check that this is *really* a unary function. This can 7886fdd2bd5SGeorge Karpenkov // happen if people do weird things. 7896fdd2bd5SGeorge Karpenkov const FunctionProtoType* FTP = dyn_cast<FunctionProtoType>(FT); 7906fdd2bd5SGeorge Karpenkov if (!FTP || FTP->getNumParams() != 1) 7916fdd2bd5SGeorge Karpenkov return getPersistentStopSummary(); 7926fdd2bd5SGeorge Karpenkov 7936fdd2bd5SGeorge Karpenkov ArgEffect Effect(AE, ObjKind::CF); 7946fdd2bd5SGeorge Karpenkov 7956fdd2bd5SGeorge Karpenkov ScratchArgs = AF.add(ScratchArgs, 0, Effect); 7966fdd2bd5SGeorge Karpenkov return getPersistentSummary(RetEffect::MakeNoRet(), 7976fdd2bd5SGeorge Karpenkov ScratchArgs, 7986fdd2bd5SGeorge Karpenkov ArgEffect(DoNothing), ArgEffect(DoNothing)); 7996fdd2bd5SGeorge Karpenkov } 8006fdd2bd5SGeorge Karpenkov 8016fdd2bd5SGeorge Karpenkov const RetainSummary * 8026fdd2bd5SGeorge Karpenkov RetainSummaryManager::getOSSummaryRetainRule(const FunctionDecl *FD) { 8036fdd2bd5SGeorge Karpenkov return getPersistentSummary(RetEffect::MakeNoRet(), 8046fdd2bd5SGeorge Karpenkov AF.getEmptyMap(), 8056fdd2bd5SGeorge Karpenkov /*ReceiverEff=*/ArgEffect(DoNothing), 8066fdd2bd5SGeorge Karpenkov /*DefaultEff=*/ArgEffect(DoNothing), 8076fdd2bd5SGeorge Karpenkov /*ThisEff=*/ArgEffect(IncRef, ObjKind::OS)); 8086fdd2bd5SGeorge Karpenkov } 8096fdd2bd5SGeorge Karpenkov 8106fdd2bd5SGeorge Karpenkov const RetainSummary * 8116fdd2bd5SGeorge Karpenkov RetainSummaryManager::getOSSummaryReleaseRule(const FunctionDecl *FD) { 8126fdd2bd5SGeorge Karpenkov return getPersistentSummary(RetEffect::MakeNoRet(), 8136fdd2bd5SGeorge Karpenkov AF.getEmptyMap(), 8146fdd2bd5SGeorge Karpenkov /*ReceiverEff=*/ArgEffect(DoNothing), 8156fdd2bd5SGeorge Karpenkov /*DefaultEff=*/ArgEffect(DoNothing), 8166fdd2bd5SGeorge Karpenkov /*ThisEff=*/ArgEffect(DecRef, ObjKind::OS)); 8176fdd2bd5SGeorge Karpenkov } 8186fdd2bd5SGeorge Karpenkov 8196fdd2bd5SGeorge Karpenkov const RetainSummary * 8206fdd2bd5SGeorge Karpenkov RetainSummaryManager::getOSSummaryFreeRule(const FunctionDecl *FD) { 8216fdd2bd5SGeorge Karpenkov return getPersistentSummary(RetEffect::MakeNoRet(), 8226fdd2bd5SGeorge Karpenkov AF.getEmptyMap(), 8236fdd2bd5SGeorge Karpenkov /*ReceiverEff=*/ArgEffect(DoNothing), 8246fdd2bd5SGeorge Karpenkov /*DefaultEff=*/ArgEffect(DoNothing), 8256fdd2bd5SGeorge Karpenkov /*ThisEff=*/ArgEffect(Dealloc, ObjKind::OS)); 8266fdd2bd5SGeorge Karpenkov } 8276fdd2bd5SGeorge Karpenkov 8286fdd2bd5SGeorge Karpenkov const RetainSummary * 8296fdd2bd5SGeorge Karpenkov RetainSummaryManager::getOSSummaryCreateRule(const FunctionDecl *FD) { 8306fdd2bd5SGeorge Karpenkov return getPersistentSummary(RetEffect::MakeOwned(ObjKind::OS), 8316fdd2bd5SGeorge Karpenkov AF.getEmptyMap()); 8326fdd2bd5SGeorge Karpenkov } 8336fdd2bd5SGeorge Karpenkov 8346fdd2bd5SGeorge Karpenkov const RetainSummary * 8356fdd2bd5SGeorge Karpenkov RetainSummaryManager::getOSSummaryGetRule(const FunctionDecl *FD) { 8366fdd2bd5SGeorge Karpenkov return getPersistentSummary(RetEffect::MakeNotOwned(ObjKind::OS), 8376fdd2bd5SGeorge Karpenkov AF.getEmptyMap()); 8386fdd2bd5SGeorge Karpenkov } 8396fdd2bd5SGeorge Karpenkov 8406fdd2bd5SGeorge Karpenkov const RetainSummary * 8416fdd2bd5SGeorge Karpenkov RetainSummaryManager::getCFSummaryCreateRule(const FunctionDecl *FD) { 8426fdd2bd5SGeorge Karpenkov return getPersistentSummary(RetEffect::MakeOwned(ObjKind::CF), 8436fdd2bd5SGeorge Karpenkov ArgEffects(AF.getEmptyMap())); 8446fdd2bd5SGeorge Karpenkov } 8456fdd2bd5SGeorge Karpenkov 8466fdd2bd5SGeorge Karpenkov const RetainSummary * 8476fdd2bd5SGeorge Karpenkov RetainSummaryManager::getCFSummaryGetRule(const FunctionDecl *FD) { 8486fdd2bd5SGeorge Karpenkov return getPersistentSummary(RetEffect::MakeNotOwned(ObjKind::CF), 8496fdd2bd5SGeorge Karpenkov ArgEffects(AF.getEmptyMap()), 8506fdd2bd5SGeorge Karpenkov ArgEffect(DoNothing), ArgEffect(DoNothing)); 8516fdd2bd5SGeorge Karpenkov } 8526fdd2bd5SGeorge Karpenkov 8536fdd2bd5SGeorge Karpenkov 8546fdd2bd5SGeorge Karpenkov 8556fdd2bd5SGeorge Karpenkov 8566fdd2bd5SGeorge Karpenkov //===----------------------------------------------------------------------===// 8576fdd2bd5SGeorge Karpenkov // Summary creation for Selectors. 8586fdd2bd5SGeorge Karpenkov //===----------------------------------------------------------------------===// 8596fdd2bd5SGeorge Karpenkov 8606fdd2bd5SGeorge Karpenkov Optional<RetEffect> 8616fdd2bd5SGeorge Karpenkov RetainSummaryManager::getRetEffectFromAnnotations(QualType RetTy, 8626fdd2bd5SGeorge Karpenkov const Decl *D) { 8636fdd2bd5SGeorge Karpenkov if (hasAnyEnabledAttrOf<NSReturnsRetainedAttr>(D, RetTy)) 8646fdd2bd5SGeorge Karpenkov return ObjCAllocRetE; 8656fdd2bd5SGeorge Karpenkov 8666fdd2bd5SGeorge Karpenkov if (auto K = hasAnyEnabledAttrOf<CFReturnsRetainedAttr, OSReturnsRetainedAttr, 8676fdd2bd5SGeorge Karpenkov GeneralizedReturnsRetainedAttr>(D, RetTy)) 8686fdd2bd5SGeorge Karpenkov return RetEffect::MakeOwned(*K); 8696fdd2bd5SGeorge Karpenkov 8706fdd2bd5SGeorge Karpenkov if (auto K = hasAnyEnabledAttrOf< 8716fdd2bd5SGeorge Karpenkov CFReturnsNotRetainedAttr, OSReturnsNotRetainedAttr, 8726fdd2bd5SGeorge Karpenkov GeneralizedReturnsNotRetainedAttr, NSReturnsNotRetainedAttr, 8736fdd2bd5SGeorge Karpenkov NSReturnsAutoreleasedAttr>(D, RetTy)) 8746fdd2bd5SGeorge Karpenkov return RetEffect::MakeNotOwned(*K); 8756fdd2bd5SGeorge Karpenkov 8766fdd2bd5SGeorge Karpenkov if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) 8776fdd2bd5SGeorge Karpenkov for (const auto *PD : MD->overridden_methods()) 8786fdd2bd5SGeorge Karpenkov if (auto RE = getRetEffectFromAnnotations(RetTy, PD)) 8796fdd2bd5SGeorge Karpenkov return RE; 8806fdd2bd5SGeorge Karpenkov 8816fdd2bd5SGeorge Karpenkov return None; 8826fdd2bd5SGeorge Karpenkov } 8836fdd2bd5SGeorge Karpenkov 884*1cb15b10SAaron Puchert /// \return Whether the chain of typedefs starting from @c QT 885*1cb15b10SAaron Puchert /// has a typedef with a given name @c Name. 8866fdd2bd5SGeorge Karpenkov static bool hasTypedefNamed(QualType QT, 8876fdd2bd5SGeorge Karpenkov StringRef Name) { 8886fdd2bd5SGeorge Karpenkov while (auto *T = dyn_cast<TypedefType>(QT)) { 8896fdd2bd5SGeorge Karpenkov const auto &Context = T->getDecl()->getASTContext(); 8906fdd2bd5SGeorge Karpenkov if (T->getDecl()->getIdentifier() == &Context.Idents.get(Name)) 8916fdd2bd5SGeorge Karpenkov return true; 8926fdd2bd5SGeorge Karpenkov QT = T->getDecl()->getUnderlyingType(); 8936fdd2bd5SGeorge Karpenkov } 8946fdd2bd5SGeorge Karpenkov return false; 8956fdd2bd5SGeorge Karpenkov } 8966fdd2bd5SGeorge Karpenkov 8976fdd2bd5SGeorge Karpenkov static QualType getCallableReturnType(const NamedDecl *ND) { 8986fdd2bd5SGeorge Karpenkov if (const auto *FD = dyn_cast<FunctionDecl>(ND)) { 8996fdd2bd5SGeorge Karpenkov return FD->getReturnType(); 9006fdd2bd5SGeorge Karpenkov } else if (const auto *MD = dyn_cast<ObjCMethodDecl>(ND)) { 9016fdd2bd5SGeorge Karpenkov return MD->getReturnType(); 9026fdd2bd5SGeorge Karpenkov } else { 9036fdd2bd5SGeorge Karpenkov llvm_unreachable("Unexpected decl"); 9046fdd2bd5SGeorge Karpenkov } 9056fdd2bd5SGeorge Karpenkov } 9066fdd2bd5SGeorge Karpenkov 9076fdd2bd5SGeorge Karpenkov bool RetainSummaryManager::applyParamAnnotationEffect( 9086fdd2bd5SGeorge Karpenkov const ParmVarDecl *pd, unsigned parm_idx, const NamedDecl *FD, 9096fdd2bd5SGeorge Karpenkov RetainSummaryTemplate &Template) { 9106fdd2bd5SGeorge Karpenkov QualType QT = pd->getType(); 9116fdd2bd5SGeorge Karpenkov if (auto K = 9126fdd2bd5SGeorge Karpenkov hasAnyEnabledAttrOf<NSConsumedAttr, CFConsumedAttr, OSConsumedAttr, 9136fdd2bd5SGeorge Karpenkov GeneralizedConsumedAttr>(pd, QT)) { 9146fdd2bd5SGeorge Karpenkov Template->addArg(AF, parm_idx, ArgEffect(DecRef, *K)); 9156fdd2bd5SGeorge Karpenkov return true; 9166fdd2bd5SGeorge Karpenkov } else if (auto K = hasAnyEnabledAttrOf< 9176fdd2bd5SGeorge Karpenkov CFReturnsRetainedAttr, OSReturnsRetainedAttr, 9186fdd2bd5SGeorge Karpenkov OSReturnsRetainedOnNonZeroAttr, OSReturnsRetainedOnZeroAttr, 9196fdd2bd5SGeorge Karpenkov GeneralizedReturnsRetainedAttr>(pd, QT)) { 9206fdd2bd5SGeorge Karpenkov 9216fdd2bd5SGeorge Karpenkov // For OSObjects, we try to guess whether the object is created based 9226fdd2bd5SGeorge Karpenkov // on the return value. 9236fdd2bd5SGeorge Karpenkov if (K == ObjKind::OS) { 9246fdd2bd5SGeorge Karpenkov QualType QT = getCallableReturnType(FD); 9256fdd2bd5SGeorge Karpenkov 9266fdd2bd5SGeorge Karpenkov bool HasRetainedOnZero = pd->hasAttr<OSReturnsRetainedOnZeroAttr>(); 9276fdd2bd5SGeorge Karpenkov bool HasRetainedOnNonZero = pd->hasAttr<OSReturnsRetainedOnNonZeroAttr>(); 9286fdd2bd5SGeorge Karpenkov 9296fdd2bd5SGeorge Karpenkov // The usual convention is to create an object on non-zero return, but 9306fdd2bd5SGeorge Karpenkov // it's reverted if the typedef chain has a typedef kern_return_t, 9316fdd2bd5SGeorge Karpenkov // because kReturnSuccess constant is defined as zero. 9326fdd2bd5SGeorge Karpenkov // The convention can be overwritten by custom attributes. 9336fdd2bd5SGeorge Karpenkov bool SuccessOnZero = 9346fdd2bd5SGeorge Karpenkov HasRetainedOnZero || 9356fdd2bd5SGeorge Karpenkov (hasTypedefNamed(QT, "kern_return_t") && !HasRetainedOnNonZero); 9366fdd2bd5SGeorge Karpenkov bool ShouldSplit = !QT.isNull() && !QT->isVoidType(); 9376fdd2bd5SGeorge Karpenkov ArgEffectKind AK = RetainedOutParameter; 9386fdd2bd5SGeorge Karpenkov if (ShouldSplit && SuccessOnZero) { 9396fdd2bd5SGeorge Karpenkov AK = RetainedOutParameterOnZero; 9406fdd2bd5SGeorge Karpenkov } else if (ShouldSplit && (!SuccessOnZero || HasRetainedOnNonZero)) { 9416fdd2bd5SGeorge Karpenkov AK = RetainedOutParameterOnNonZero; 9426fdd2bd5SGeorge Karpenkov } 9436fdd2bd5SGeorge Karpenkov Template->addArg(AF, parm_idx, ArgEffect(AK, ObjKind::OS)); 9446fdd2bd5SGeorge Karpenkov } 9456fdd2bd5SGeorge Karpenkov 9466fdd2bd5SGeorge Karpenkov // For others: 9476fdd2bd5SGeorge Karpenkov // Do nothing. Retained out parameters will either point to a +1 reference 9486fdd2bd5SGeorge Karpenkov // or NULL, but the way you check for failure differs depending on the 9496fdd2bd5SGeorge Karpenkov // API. Consequently, we don't have a good way to track them yet. 9506fdd2bd5SGeorge Karpenkov return true; 9516fdd2bd5SGeorge Karpenkov } else if (auto K = hasAnyEnabledAttrOf<CFReturnsNotRetainedAttr, 9526fdd2bd5SGeorge Karpenkov OSReturnsNotRetainedAttr, 9536fdd2bd5SGeorge Karpenkov GeneralizedReturnsNotRetainedAttr>( 9546fdd2bd5SGeorge Karpenkov pd, QT)) { 9556fdd2bd5SGeorge Karpenkov Template->addArg(AF, parm_idx, ArgEffect(UnretainedOutParameter, *K)); 9566fdd2bd5SGeorge Karpenkov return true; 9576fdd2bd5SGeorge Karpenkov } 9586fdd2bd5SGeorge Karpenkov 9596fdd2bd5SGeorge Karpenkov if (const auto *MD = dyn_cast<CXXMethodDecl>(FD)) { 9606fdd2bd5SGeorge Karpenkov for (const auto *OD : MD->overridden_methods()) { 9616fdd2bd5SGeorge Karpenkov const ParmVarDecl *OP = OD->parameters()[parm_idx]; 9626fdd2bd5SGeorge Karpenkov if (applyParamAnnotationEffect(OP, parm_idx, OD, Template)) 9636fdd2bd5SGeorge Karpenkov return true; 9646fdd2bd5SGeorge Karpenkov } 9656fdd2bd5SGeorge Karpenkov } 9666fdd2bd5SGeorge Karpenkov 9676fdd2bd5SGeorge Karpenkov return false; 9686fdd2bd5SGeorge Karpenkov } 9696fdd2bd5SGeorge Karpenkov 9706fdd2bd5SGeorge Karpenkov void 9716fdd2bd5SGeorge Karpenkov RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ, 9726fdd2bd5SGeorge Karpenkov const FunctionDecl *FD) { 9736fdd2bd5SGeorge Karpenkov if (!FD) 9746fdd2bd5SGeorge Karpenkov return; 9756fdd2bd5SGeorge Karpenkov 9766fdd2bd5SGeorge Karpenkov assert(Summ && "Must have a summary to add annotations to."); 9776fdd2bd5SGeorge Karpenkov RetainSummaryTemplate Template(Summ, *this); 9786fdd2bd5SGeorge Karpenkov 9796fdd2bd5SGeorge Karpenkov // Effects on the parameters. 9806fdd2bd5SGeorge Karpenkov unsigned parm_idx = 0; 9816fdd2bd5SGeorge Karpenkov for (auto pi = FD->param_begin(), 9826fdd2bd5SGeorge Karpenkov pe = FD->param_end(); pi != pe; ++pi, ++parm_idx) 9836fdd2bd5SGeorge Karpenkov applyParamAnnotationEffect(*pi, parm_idx, FD, Template); 9846fdd2bd5SGeorge Karpenkov 9856fdd2bd5SGeorge Karpenkov QualType RetTy = FD->getReturnType(); 9866fdd2bd5SGeorge Karpenkov if (Optional<RetEffect> RetE = getRetEffectFromAnnotations(RetTy, FD)) 9876fdd2bd5SGeorge Karpenkov Template->setRetEffect(*RetE); 9886fdd2bd5SGeorge Karpenkov 9896fdd2bd5SGeorge Karpenkov if (hasAnyEnabledAttrOf<OSConsumesThisAttr>(FD, RetTy)) 9906fdd2bd5SGeorge Karpenkov Template->setThisEffect(ArgEffect(DecRef, ObjKind::OS)); 9916fdd2bd5SGeorge Karpenkov } 9926fdd2bd5SGeorge Karpenkov 9936fdd2bd5SGeorge Karpenkov void 9946fdd2bd5SGeorge Karpenkov RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ, 9956fdd2bd5SGeorge Karpenkov const ObjCMethodDecl *MD) { 9966fdd2bd5SGeorge Karpenkov if (!MD) 9976fdd2bd5SGeorge Karpenkov return; 9986fdd2bd5SGeorge Karpenkov 9996fdd2bd5SGeorge Karpenkov assert(Summ && "Must have a valid summary to add annotations to"); 10006fdd2bd5SGeorge Karpenkov RetainSummaryTemplate Template(Summ, *this); 10016fdd2bd5SGeorge Karpenkov 10026fdd2bd5SGeorge Karpenkov // Effects on the receiver. 10036fdd2bd5SGeorge Karpenkov if (hasAnyEnabledAttrOf<NSConsumesSelfAttr>(MD, MD->getReturnType())) 10046fdd2bd5SGeorge Karpenkov Template->setReceiverEffect(ArgEffect(DecRef, ObjKind::ObjC)); 10056fdd2bd5SGeorge Karpenkov 10066fdd2bd5SGeorge Karpenkov // Effects on the parameters. 10076fdd2bd5SGeorge Karpenkov unsigned parm_idx = 0; 10086fdd2bd5SGeorge Karpenkov for (auto pi = MD->param_begin(), pe = MD->param_end(); pi != pe; 10096fdd2bd5SGeorge Karpenkov ++pi, ++parm_idx) 10106fdd2bd5SGeorge Karpenkov applyParamAnnotationEffect(*pi, parm_idx, MD, Template); 10116fdd2bd5SGeorge Karpenkov 10126fdd2bd5SGeorge Karpenkov QualType RetTy = MD->getReturnType(); 10136fdd2bd5SGeorge Karpenkov if (Optional<RetEffect> RetE = getRetEffectFromAnnotations(RetTy, MD)) 10146fdd2bd5SGeorge Karpenkov Template->setRetEffect(*RetE); 10156fdd2bd5SGeorge Karpenkov } 10166fdd2bd5SGeorge Karpenkov 10176fdd2bd5SGeorge Karpenkov const RetainSummary * 10186fdd2bd5SGeorge Karpenkov RetainSummaryManager::getStandardMethodSummary(const ObjCMethodDecl *MD, 10196fdd2bd5SGeorge Karpenkov Selector S, QualType RetTy) { 10206fdd2bd5SGeorge Karpenkov // Any special effects? 10216fdd2bd5SGeorge Karpenkov ArgEffect ReceiverEff = ArgEffect(DoNothing, ObjKind::ObjC); 10226fdd2bd5SGeorge Karpenkov RetEffect ResultEff = RetEffect::MakeNoRet(); 10236fdd2bd5SGeorge Karpenkov 10246fdd2bd5SGeorge Karpenkov // Check the method family, and apply any default annotations. 10256fdd2bd5SGeorge Karpenkov switch (MD ? MD->getMethodFamily() : S.getMethodFamily()) { 10266fdd2bd5SGeorge Karpenkov case OMF_None: 10276fdd2bd5SGeorge Karpenkov case OMF_initialize: 10286fdd2bd5SGeorge Karpenkov case OMF_performSelector: 10296fdd2bd5SGeorge Karpenkov // Assume all Objective-C methods follow Cocoa Memory Management rules. 10306fdd2bd5SGeorge Karpenkov // FIXME: Does the non-threaded performSelector family really belong here? 10316fdd2bd5SGeorge Karpenkov // The selector could be, say, @selector(copy). 10326fdd2bd5SGeorge Karpenkov if (cocoa::isCocoaObjectRef(RetTy)) 10336fdd2bd5SGeorge Karpenkov ResultEff = RetEffect::MakeNotOwned(ObjKind::ObjC); 10346fdd2bd5SGeorge Karpenkov else if (coreFoundation::isCFObjectRef(RetTy)) { 10356fdd2bd5SGeorge Karpenkov // ObjCMethodDecl currently doesn't consider CF objects as valid return 10366fdd2bd5SGeorge Karpenkov // values for alloc, new, copy, or mutableCopy, so we have to 10376fdd2bd5SGeorge Karpenkov // double-check with the selector. This is ugly, but there aren't that 10386fdd2bd5SGeorge Karpenkov // many Objective-C methods that return CF objects, right? 10396fdd2bd5SGeorge Karpenkov if (MD) { 10406fdd2bd5SGeorge Karpenkov switch (S.getMethodFamily()) { 10416fdd2bd5SGeorge Karpenkov case OMF_alloc: 10426fdd2bd5SGeorge Karpenkov case OMF_new: 10436fdd2bd5SGeorge Karpenkov case OMF_copy: 10446fdd2bd5SGeorge Karpenkov case OMF_mutableCopy: 10456fdd2bd5SGeorge Karpenkov ResultEff = RetEffect::MakeOwned(ObjKind::CF); 10466fdd2bd5SGeorge Karpenkov break; 10476fdd2bd5SGeorge Karpenkov default: 10486fdd2bd5SGeorge Karpenkov ResultEff = RetEffect::MakeNotOwned(ObjKind::CF); 10496fdd2bd5SGeorge Karpenkov break; 10506fdd2bd5SGeorge Karpenkov } 10516fdd2bd5SGeorge Karpenkov } else { 10526fdd2bd5SGeorge Karpenkov ResultEff = RetEffect::MakeNotOwned(ObjKind::CF); 10536fdd2bd5SGeorge Karpenkov } 10546fdd2bd5SGeorge Karpenkov } 10556fdd2bd5SGeorge Karpenkov break; 10566fdd2bd5SGeorge Karpenkov case OMF_init: 10576fdd2bd5SGeorge Karpenkov ResultEff = ObjCInitRetE; 10586fdd2bd5SGeorge Karpenkov ReceiverEff = ArgEffect(DecRef, ObjKind::ObjC); 10596fdd2bd5SGeorge Karpenkov break; 10606fdd2bd5SGeorge Karpenkov case OMF_alloc: 10616fdd2bd5SGeorge Karpenkov case OMF_new: 10626fdd2bd5SGeorge Karpenkov case OMF_copy: 10636fdd2bd5SGeorge Karpenkov case OMF_mutableCopy: 10646fdd2bd5SGeorge Karpenkov if (cocoa::isCocoaObjectRef(RetTy)) 10656fdd2bd5SGeorge Karpenkov ResultEff = ObjCAllocRetE; 10666fdd2bd5SGeorge Karpenkov else if (coreFoundation::isCFObjectRef(RetTy)) 10676fdd2bd5SGeorge Karpenkov ResultEff = RetEffect::MakeOwned(ObjKind::CF); 10686fdd2bd5SGeorge Karpenkov break; 10696fdd2bd5SGeorge Karpenkov case OMF_autorelease: 10706fdd2bd5SGeorge Karpenkov ReceiverEff = ArgEffect(Autorelease, ObjKind::ObjC); 10716fdd2bd5SGeorge Karpenkov break; 10726fdd2bd5SGeorge Karpenkov case OMF_retain: 10736fdd2bd5SGeorge Karpenkov ReceiverEff = ArgEffect(IncRef, ObjKind::ObjC); 10746fdd2bd5SGeorge Karpenkov break; 10756fdd2bd5SGeorge Karpenkov case OMF_release: 10766fdd2bd5SGeorge Karpenkov ReceiverEff = ArgEffect(DecRef, ObjKind::ObjC); 10776fdd2bd5SGeorge Karpenkov break; 10786fdd2bd5SGeorge Karpenkov case OMF_dealloc: 10796fdd2bd5SGeorge Karpenkov ReceiverEff = ArgEffect(Dealloc, ObjKind::ObjC); 10806fdd2bd5SGeorge Karpenkov break; 10816fdd2bd5SGeorge Karpenkov case OMF_self: 10826fdd2bd5SGeorge Karpenkov // -self is handled specially by the ExprEngine to propagate the receiver. 10836fdd2bd5SGeorge Karpenkov break; 10846fdd2bd5SGeorge Karpenkov case OMF_retainCount: 10856fdd2bd5SGeorge Karpenkov case OMF_finalize: 10866fdd2bd5SGeorge Karpenkov // These methods don't return objects. 10876fdd2bd5SGeorge Karpenkov break; 10886fdd2bd5SGeorge Karpenkov } 10896fdd2bd5SGeorge Karpenkov 10906fdd2bd5SGeorge Karpenkov // If one of the arguments in the selector has the keyword 'delegate' we 10916fdd2bd5SGeorge Karpenkov // should stop tracking the reference count for the receiver. This is 10926fdd2bd5SGeorge Karpenkov // because the reference count is quite possibly handled by a delegate 10936fdd2bd5SGeorge Karpenkov // method. 10946fdd2bd5SGeorge Karpenkov if (S.isKeywordSelector()) { 10956fdd2bd5SGeorge Karpenkov for (unsigned i = 0, e = S.getNumArgs(); i != e; ++i) { 10966fdd2bd5SGeorge Karpenkov StringRef Slot = S.getNameForSlot(i); 10976fdd2bd5SGeorge Karpenkov if (Slot.substr(Slot.size() - 8).equals_lower("delegate")) { 10986fdd2bd5SGeorge Karpenkov if (ResultEff == ObjCInitRetE) 10996fdd2bd5SGeorge Karpenkov ResultEff = RetEffect::MakeNoRetHard(); 11006fdd2bd5SGeorge Karpenkov else 11016fdd2bd5SGeorge Karpenkov ReceiverEff = ArgEffect(StopTrackingHard, ObjKind::ObjC); 11026fdd2bd5SGeorge Karpenkov } 11036fdd2bd5SGeorge Karpenkov } 11046fdd2bd5SGeorge Karpenkov } 11056fdd2bd5SGeorge Karpenkov 11066fdd2bd5SGeorge Karpenkov if (ReceiverEff.getKind() == DoNothing && 11076fdd2bd5SGeorge Karpenkov ResultEff.getKind() == RetEffect::NoRet) 11086fdd2bd5SGeorge Karpenkov return getDefaultSummary(); 11096fdd2bd5SGeorge Karpenkov 11106fdd2bd5SGeorge Karpenkov return getPersistentSummary(ResultEff, ArgEffects(AF.getEmptyMap()), 11116fdd2bd5SGeorge Karpenkov ArgEffect(ReceiverEff), ArgEffect(MayEscape)); 11126fdd2bd5SGeorge Karpenkov } 11136fdd2bd5SGeorge Karpenkov 11146fdd2bd5SGeorge Karpenkov const RetainSummary * 11156fdd2bd5SGeorge Karpenkov RetainSummaryManager::getClassMethodSummary(const ObjCMessageExpr *ME) { 11166fdd2bd5SGeorge Karpenkov assert(!ME->isInstanceMessage()); 11176fdd2bd5SGeorge Karpenkov const ObjCInterfaceDecl *Class = ME->getReceiverInterface(); 11186fdd2bd5SGeorge Karpenkov 11196fdd2bd5SGeorge Karpenkov return getMethodSummary(ME->getSelector(), Class, ME->getMethodDecl(), 11206fdd2bd5SGeorge Karpenkov ME->getType(), ObjCClassMethodSummaries); 11216fdd2bd5SGeorge Karpenkov } 11226fdd2bd5SGeorge Karpenkov 11236fdd2bd5SGeorge Karpenkov const RetainSummary *RetainSummaryManager::getInstanceMethodSummary( 11246fdd2bd5SGeorge Karpenkov const ObjCMessageExpr *ME, 11256fdd2bd5SGeorge Karpenkov QualType ReceiverType) { 11266fdd2bd5SGeorge Karpenkov const ObjCInterfaceDecl *ReceiverClass = nullptr; 11276fdd2bd5SGeorge Karpenkov 11286fdd2bd5SGeorge Karpenkov // We do better tracking of the type of the object than the core ExprEngine. 11296fdd2bd5SGeorge Karpenkov // See if we have its type in our private state. 11306fdd2bd5SGeorge Karpenkov if (!ReceiverType.isNull()) 11316fdd2bd5SGeorge Karpenkov if (const auto *PT = ReceiverType->getAs<ObjCObjectPointerType>()) 11326fdd2bd5SGeorge Karpenkov ReceiverClass = PT->getInterfaceDecl(); 11336fdd2bd5SGeorge Karpenkov 11346fdd2bd5SGeorge Karpenkov // If we don't know what kind of object this is, fall back to its static type. 11356fdd2bd5SGeorge Karpenkov if (!ReceiverClass) 11366fdd2bd5SGeorge Karpenkov ReceiverClass = ME->getReceiverInterface(); 11376fdd2bd5SGeorge Karpenkov 11386fdd2bd5SGeorge Karpenkov // FIXME: The receiver could be a reference to a class, meaning that 11396fdd2bd5SGeorge Karpenkov // we should use the class method. 11406fdd2bd5SGeorge Karpenkov // id x = [NSObject class]; 11416fdd2bd5SGeorge Karpenkov // [x performSelector:... withObject:... afterDelay:...]; 11426fdd2bd5SGeorge Karpenkov Selector S = ME->getSelector(); 11436fdd2bd5SGeorge Karpenkov const ObjCMethodDecl *Method = ME->getMethodDecl(); 11446fdd2bd5SGeorge Karpenkov if (!Method && ReceiverClass) 11456fdd2bd5SGeorge Karpenkov Method = ReceiverClass->getInstanceMethod(S); 11466fdd2bd5SGeorge Karpenkov 11476fdd2bd5SGeorge Karpenkov return getMethodSummary(S, ReceiverClass, Method, ME->getType(), 11486fdd2bd5SGeorge Karpenkov ObjCMethodSummaries); 11496fdd2bd5SGeorge Karpenkov } 11506fdd2bd5SGeorge Karpenkov 11516fdd2bd5SGeorge Karpenkov const RetainSummary * 11526fdd2bd5SGeorge Karpenkov RetainSummaryManager::getMethodSummary(Selector S, 11536fdd2bd5SGeorge Karpenkov const ObjCInterfaceDecl *ID, 11546fdd2bd5SGeorge Karpenkov const ObjCMethodDecl *MD, QualType RetTy, 11556fdd2bd5SGeorge Karpenkov ObjCMethodSummariesTy &CachedSummaries) { 11566fdd2bd5SGeorge Karpenkov 11576fdd2bd5SGeorge Karpenkov // Objective-C method summaries are only applicable to ObjC and CF objects. 11586fdd2bd5SGeorge Karpenkov if (!TrackObjCAndCFObjects) 11596fdd2bd5SGeorge Karpenkov return getDefaultSummary(); 11606fdd2bd5SGeorge Karpenkov 11616fdd2bd5SGeorge Karpenkov // Look up a summary in our summary cache. 11626fdd2bd5SGeorge Karpenkov const RetainSummary *Summ = CachedSummaries.find(ID, S); 11636fdd2bd5SGeorge Karpenkov 11646fdd2bd5SGeorge Karpenkov if (!Summ) { 11656fdd2bd5SGeorge Karpenkov Summ = getStandardMethodSummary(MD, S, RetTy); 11666fdd2bd5SGeorge Karpenkov 11676fdd2bd5SGeorge Karpenkov // Annotations override defaults. 11686fdd2bd5SGeorge Karpenkov updateSummaryFromAnnotations(Summ, MD); 11696fdd2bd5SGeorge Karpenkov 11706fdd2bd5SGeorge Karpenkov // Memoize the summary. 11716fdd2bd5SGeorge Karpenkov CachedSummaries[ObjCSummaryKey(ID, S)] = Summ; 11726fdd2bd5SGeorge Karpenkov } 11736fdd2bd5SGeorge Karpenkov 11746fdd2bd5SGeorge Karpenkov return Summ; 11756fdd2bd5SGeorge Karpenkov } 11766fdd2bd5SGeorge Karpenkov 11776fdd2bd5SGeorge Karpenkov void RetainSummaryManager::InitializeClassMethodSummaries() { 11786fdd2bd5SGeorge Karpenkov ArgEffects ScratchArgs = AF.getEmptyMap(); 11796fdd2bd5SGeorge Karpenkov 11806fdd2bd5SGeorge Karpenkov // Create the [NSAssertionHandler currentHander] summary. 11816fdd2bd5SGeorge Karpenkov addClassMethSummary("NSAssertionHandler", "currentHandler", 11826fdd2bd5SGeorge Karpenkov getPersistentSummary(RetEffect::MakeNotOwned(ObjKind::ObjC), 11836fdd2bd5SGeorge Karpenkov ScratchArgs)); 11846fdd2bd5SGeorge Karpenkov 11856fdd2bd5SGeorge Karpenkov // Create the [NSAutoreleasePool addObject:] summary. 11866fdd2bd5SGeorge Karpenkov ScratchArgs = AF.add(ScratchArgs, 0, ArgEffect(Autorelease)); 11876fdd2bd5SGeorge Karpenkov addClassMethSummary("NSAutoreleasePool", "addObject", 11886fdd2bd5SGeorge Karpenkov getPersistentSummary(RetEffect::MakeNoRet(), ScratchArgs, 11896fdd2bd5SGeorge Karpenkov ArgEffect(DoNothing), 11906fdd2bd5SGeorge Karpenkov ArgEffect(Autorelease))); 11916fdd2bd5SGeorge Karpenkov } 11926fdd2bd5SGeorge Karpenkov 11936fdd2bd5SGeorge Karpenkov void RetainSummaryManager::InitializeMethodSummaries() { 11946fdd2bd5SGeorge Karpenkov 11956fdd2bd5SGeorge Karpenkov ArgEffects ScratchArgs = AF.getEmptyMap(); 11966fdd2bd5SGeorge Karpenkov // Create the "init" selector. It just acts as a pass-through for the 11976fdd2bd5SGeorge Karpenkov // receiver. 11986fdd2bd5SGeorge Karpenkov const RetainSummary *InitSumm = getPersistentSummary( 11996fdd2bd5SGeorge Karpenkov ObjCInitRetE, ScratchArgs, ArgEffect(DecRef, ObjKind::ObjC)); 12006fdd2bd5SGeorge Karpenkov addNSObjectMethSummary(GetNullarySelector("init", Ctx), InitSumm); 12016fdd2bd5SGeorge Karpenkov 12026fdd2bd5SGeorge Karpenkov // awakeAfterUsingCoder: behaves basically like an 'init' method. It 12036fdd2bd5SGeorge Karpenkov // claims the receiver and returns a retained object. 12046fdd2bd5SGeorge Karpenkov addNSObjectMethSummary(GetUnarySelector("awakeAfterUsingCoder", Ctx), 12056fdd2bd5SGeorge Karpenkov InitSumm); 12066fdd2bd5SGeorge Karpenkov 12076fdd2bd5SGeorge Karpenkov // The next methods are allocators. 12086fdd2bd5SGeorge Karpenkov const RetainSummary *AllocSumm = getPersistentSummary(ObjCAllocRetE, 12096fdd2bd5SGeorge Karpenkov ScratchArgs); 12106fdd2bd5SGeorge Karpenkov const RetainSummary *CFAllocSumm = 12116fdd2bd5SGeorge Karpenkov getPersistentSummary(RetEffect::MakeOwned(ObjKind::CF), ScratchArgs); 12126fdd2bd5SGeorge Karpenkov 12136fdd2bd5SGeorge Karpenkov // Create the "retain" selector. 12146fdd2bd5SGeorge Karpenkov RetEffect NoRet = RetEffect::MakeNoRet(); 12156fdd2bd5SGeorge Karpenkov const RetainSummary *Summ = getPersistentSummary( 12166fdd2bd5SGeorge Karpenkov NoRet, ScratchArgs, ArgEffect(IncRef, ObjKind::ObjC)); 12176fdd2bd5SGeorge Karpenkov addNSObjectMethSummary(GetNullarySelector("retain", Ctx), Summ); 12186fdd2bd5SGeorge Karpenkov 12196fdd2bd5SGeorge Karpenkov // Create the "release" selector. 12206fdd2bd5SGeorge Karpenkov Summ = getPersistentSummary(NoRet, ScratchArgs, 12216fdd2bd5SGeorge Karpenkov ArgEffect(DecRef, ObjKind::ObjC)); 12226fdd2bd5SGeorge Karpenkov addNSObjectMethSummary(GetNullarySelector("release", Ctx), Summ); 12236fdd2bd5SGeorge Karpenkov 12246fdd2bd5SGeorge Karpenkov // Create the -dealloc summary. 12256fdd2bd5SGeorge Karpenkov Summ = getPersistentSummary(NoRet, ScratchArgs, ArgEffect(Dealloc, 12266fdd2bd5SGeorge Karpenkov ObjKind::ObjC)); 12276fdd2bd5SGeorge Karpenkov addNSObjectMethSummary(GetNullarySelector("dealloc", Ctx), Summ); 12286fdd2bd5SGeorge Karpenkov 12296fdd2bd5SGeorge Karpenkov // Create the "autorelease" selector. 12306fdd2bd5SGeorge Karpenkov Summ = getPersistentSummary(NoRet, ScratchArgs, ArgEffect(Autorelease, 12316fdd2bd5SGeorge Karpenkov ObjKind::ObjC)); 12326fdd2bd5SGeorge Karpenkov addNSObjectMethSummary(GetNullarySelector("autorelease", Ctx), Summ); 12336fdd2bd5SGeorge Karpenkov 12346fdd2bd5SGeorge Karpenkov // For NSWindow, allocated objects are (initially) self-owned. 12356fdd2bd5SGeorge Karpenkov // FIXME: For now we opt for false negatives with NSWindow, as these objects 12366fdd2bd5SGeorge Karpenkov // self-own themselves. However, they only do this once they are displayed. 12376fdd2bd5SGeorge Karpenkov // Thus, we need to track an NSWindow's display status. 12386fdd2bd5SGeorge Karpenkov // This is tracked in <rdar://problem/6062711>. 12396fdd2bd5SGeorge Karpenkov // See also http://llvm.org/bugs/show_bug.cgi?id=3714. 12406fdd2bd5SGeorge Karpenkov const RetainSummary *NoTrackYet = 12416fdd2bd5SGeorge Karpenkov getPersistentSummary(RetEffect::MakeNoRet(), ScratchArgs, 12426fdd2bd5SGeorge Karpenkov ArgEffect(StopTracking), ArgEffect(StopTracking)); 12436fdd2bd5SGeorge Karpenkov 12446fdd2bd5SGeorge Karpenkov addClassMethSummary("NSWindow", "alloc", NoTrackYet); 12456fdd2bd5SGeorge Karpenkov 12466fdd2bd5SGeorge Karpenkov // For NSPanel (which subclasses NSWindow), allocated objects are not 12476fdd2bd5SGeorge Karpenkov // self-owned. 12486fdd2bd5SGeorge Karpenkov // FIXME: For now we don't track NSPanels. object for the same reason 12496fdd2bd5SGeorge Karpenkov // as for NSWindow objects. 12506fdd2bd5SGeorge Karpenkov addClassMethSummary("NSPanel", "alloc", NoTrackYet); 12516fdd2bd5SGeorge Karpenkov 12526fdd2bd5SGeorge Karpenkov // For NSNull, objects returned by +null are singletons that ignore 12536fdd2bd5SGeorge Karpenkov // retain/release semantics. Just don't track them. 12546fdd2bd5SGeorge Karpenkov // <rdar://problem/12858915> 12556fdd2bd5SGeorge Karpenkov addClassMethSummary("NSNull", "null", NoTrackYet); 12566fdd2bd5SGeorge Karpenkov 12576fdd2bd5SGeorge Karpenkov // Don't track allocated autorelease pools, as it is okay to prematurely 12586fdd2bd5SGeorge Karpenkov // exit a method. 12596fdd2bd5SGeorge Karpenkov addClassMethSummary("NSAutoreleasePool", "alloc", NoTrackYet); 12606fdd2bd5SGeorge Karpenkov addClassMethSummary("NSAutoreleasePool", "allocWithZone", NoTrackYet, false); 12616fdd2bd5SGeorge Karpenkov addClassMethSummary("NSAutoreleasePool", "new", NoTrackYet); 12626fdd2bd5SGeorge Karpenkov 12636fdd2bd5SGeorge Karpenkov // Create summaries QCRenderer/QCView -createSnapShotImageOfType: 12646fdd2bd5SGeorge Karpenkov addInstMethSummary("QCRenderer", AllocSumm, "createSnapshotImageOfType"); 12656fdd2bd5SGeorge Karpenkov addInstMethSummary("QCView", AllocSumm, "createSnapshotImageOfType"); 12666fdd2bd5SGeorge Karpenkov 12676fdd2bd5SGeorge Karpenkov // Create summaries for CIContext, 'createCGImage' and 12686fdd2bd5SGeorge Karpenkov // 'createCGLayerWithSize'. These objects are CF objects, and are not 12696fdd2bd5SGeorge Karpenkov // automatically garbage collected. 12706fdd2bd5SGeorge Karpenkov addInstMethSummary("CIContext", CFAllocSumm, "createCGImage", "fromRect"); 12716fdd2bd5SGeorge Karpenkov addInstMethSummary("CIContext", CFAllocSumm, "createCGImage", "fromRect", 12726fdd2bd5SGeorge Karpenkov "format", "colorSpace"); 12736fdd2bd5SGeorge Karpenkov addInstMethSummary("CIContext", CFAllocSumm, "createCGLayerWithSize", "info"); 12746fdd2bd5SGeorge Karpenkov } 12756fdd2bd5SGeorge Karpenkov 12766fdd2bd5SGeorge Karpenkov const RetainSummary * 12776fdd2bd5SGeorge Karpenkov RetainSummaryManager::getMethodSummary(const ObjCMethodDecl *MD) { 12786fdd2bd5SGeorge Karpenkov const ObjCInterfaceDecl *ID = MD->getClassInterface(); 12796fdd2bd5SGeorge Karpenkov Selector S = MD->getSelector(); 12806fdd2bd5SGeorge Karpenkov QualType ResultTy = MD->getReturnType(); 12816fdd2bd5SGeorge Karpenkov 12826fdd2bd5SGeorge Karpenkov ObjCMethodSummariesTy *CachedSummaries; 12836fdd2bd5SGeorge Karpenkov if (MD->isInstanceMethod()) 12846fdd2bd5SGeorge Karpenkov CachedSummaries = &ObjCMethodSummaries; 12856fdd2bd5SGeorge Karpenkov else 12866fdd2bd5SGeorge Karpenkov CachedSummaries = &ObjCClassMethodSummaries; 12876fdd2bd5SGeorge Karpenkov 12886fdd2bd5SGeorge Karpenkov return getMethodSummary(S, ID, MD, ResultTy, *CachedSummaries); 12896fdd2bd5SGeorge Karpenkov } 1290