RetainSummaryManager.cpp revision 360784
1719Swollman//== RetainSummaryManager.cpp - Summaries for reference counting --*- C++ -*--// 21402Sache// 3652Sjkh// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4652Sjkh// See https://llvm.org/LICENSE.txt for license information. 5652Sjkh// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6652Sjkh// 7652Sjkh//===----------------------------------------------------------------------===// 8652Sjkh// 9652Sjkh// This file defines summaries implementation for retain counting, which 10652Sjkh// implements a reference count checker for Core Foundation, Cocoa 11652Sjkh// and OSObject (on Mac OS X). 12652Sjkh// 13652Sjkh//===----------------------------------------------------------------------===// 14652Sjkh 15805Sache#include "clang/Analysis/DomainSpecific/CocoaConventions.h" 16652Sjkh#include "clang/Analysis/RetainSummaryManager.h" 17652Sjkh#include "clang/AST/Attr.h" 18805Sache#include "clang/AST/DeclCXX.h" 19652Sjkh#include "clang/AST/DeclObjC.h" 20652Sjkh#include "clang/AST/ParentMap.h" 21652Sjkh#include "clang/ASTMatchers/ASTMatchFinder.h" 22652Sjkh 23652Sjkhusing namespace clang; 24652Sjkhusing namespace ento; 25652Sjkh 26652Sjkhtemplate <class T> 27652Sjkhconstexpr static bool isOneOf() { 28652Sjkh return false; 29652Sjkh} 30652Sjkh 31652Sjkh/// Helper function to check whether the class is one of the 32652Sjkh/// rest of varargs. 331258Sswallacetemplate <class T, class P, class... ToCompare> 34652Sjkhconstexpr static bool isOneOf() { 35652Sjkh return std::is_same<T, P>::value || isOneOf<T, ToCompare...>(); 36652Sjkh} 371402Sache 38652Sjkhnamespace { 39652Sjkh 401402Sache/// Fake attribute class for RC* attributes. 411258Sswallacestruct GeneralizedReturnsRetainedAttr { 42652Sjkh static bool classof(const Attr *A) { 43652Sjkh if (auto AA = dyn_cast<AnnotateAttr>(A)) 44652Sjkh return AA->getAnnotation() == "rc_ownership_returns_retained"; 45652Sjkh return false; 46652Sjkh } 47652Sjkh}; 48652Sjkh 49652Sjkhstruct GeneralizedReturnsNotRetainedAttr { 50652Sjkh static bool classof(const Attr *A) { 51652Sjkh if (auto AA = dyn_cast<AnnotateAttr>(A)) 52652Sjkh return AA->getAnnotation() == "rc_ownership_returns_not_retained"; 53652Sjkh return false; 541258Sswallace } 551258Sswallace}; 56652Sjkh 57652Sjkhstruct GeneralizedConsumedAttr { 58652Sjkh static bool classof(const Attr *A) { 59652Sjkh if (auto AA = dyn_cast<AnnotateAttr>(A)) 60652Sjkh return AA->getAnnotation() == "rc_ownership_consumed"; 61652Sjkh return false; 62652Sjkh } 63652Sjkh}; 64652Sjkh 65652Sjkh} 66652Sjkh 67652Sjkhtemplate <class T> 68652SjkhOptional<ObjKind> RetainSummaryManager::hasAnyEnabledAttrOf(const Decl *D, 69652Sjkh QualType QT) { 70652Sjkh ObjKind K; 71652Sjkh if (isOneOf<T, CFConsumedAttr, CFReturnsRetainedAttr, 721258Sswallace CFReturnsNotRetainedAttr>()) { 731258Sswallace if (!TrackObjCAndCFObjects) 741258Sswallace return None; 75652Sjkh 76652Sjkh K = ObjKind::CF; 77652Sjkh } else if (isOneOf<T, NSConsumedAttr, NSConsumesSelfAttr, 78652Sjkh NSReturnsAutoreleasedAttr, NSReturnsRetainedAttr, 79652Sjkh NSReturnsNotRetainedAttr, NSConsumesSelfAttr>()) { 80652Sjkh 81652Sjkh if (!TrackObjCAndCFObjects) 82652Sjkh return None; 83652Sjkh 84652Sjkh if (isOneOf<T, NSReturnsRetainedAttr, NSReturnsAutoreleasedAttr, 85652Sjkh NSReturnsNotRetainedAttr>() && 86652Sjkh !cocoa::isCocoaObjectRef(QT)) 87652Sjkh return None; 88652Sjkh K = ObjKind::ObjC; 89652Sjkh } else if (isOneOf<T, OSConsumedAttr, OSConsumesThisAttr, 90652Sjkh OSReturnsNotRetainedAttr, OSReturnsRetainedAttr, 91652Sjkh OSReturnsRetainedOnZeroAttr, 92652Sjkh OSReturnsRetainedOnNonZeroAttr>()) { 93652Sjkh if (!TrackOSObjects) 94652Sjkh return None; 95652Sjkh K = ObjKind::OS; 96652Sjkh } else if (isOneOf<T, GeneralizedReturnsNotRetainedAttr, 97652Sjkh GeneralizedReturnsRetainedAttr, 98652Sjkh GeneralizedConsumedAttr>()) { 99652Sjkh K = ObjKind::Generalized; 100652Sjkh } else { 101652Sjkh llvm_unreachable("Unexpected attribute"); 102652Sjkh } 103652Sjkh if (D->hasAttr<T>()) 104652Sjkh return K; 105652Sjkh return None; 106652Sjkh} 107652Sjkh 108652Sjkhtemplate <class T1, class T2, class... Others> 109652SjkhOptional<ObjKind> RetainSummaryManager::hasAnyEnabledAttrOf(const Decl *D, 110652Sjkh QualType QT) { 111652Sjkh if (auto Out = hasAnyEnabledAttrOf<T1>(D, QT)) 112652Sjkh return Out; 113652Sjkh return hasAnyEnabledAttrOf<T2, Others...>(D, QT); 114652Sjkh} 115652Sjkh 116652Sjkhconst RetainSummary * 117652SjkhRetainSummaryManager::getPersistentSummary(const RetainSummary &OldSumm) { 118652Sjkh // Unique "simple" summaries -- those without ArgEffects. 119652Sjkh if (OldSumm.isSimple()) { 120652Sjkh ::llvm::FoldingSetNodeID ID; 121652Sjkh OldSumm.Profile(ID); 122652Sjkh 123652Sjkh void *Pos; 124652Sjkh CachedSummaryNode *N = SimpleSummaries.FindNodeOrInsertPos(ID, Pos); 125652Sjkh 126652Sjkh if (!N) { 127652Sjkh N = (CachedSummaryNode *) BPAlloc.Allocate<CachedSummaryNode>(); 128652Sjkh new (N) CachedSummaryNode(OldSumm); 129652Sjkh SimpleSummaries.InsertNode(N, Pos); 130652Sjkh } 131652Sjkh 132652Sjkh return &N->getValue(); 133652Sjkh } 134652Sjkh 135652Sjkh RetainSummary *Summ = (RetainSummary *) BPAlloc.Allocate<RetainSummary>(); 136652Sjkh new (Summ) RetainSummary(OldSumm); 137652Sjkh return Summ; 138652Sjkh} 139652Sjkh 140652Sjkhstatic bool isSubclass(const Decl *D, 141652Sjkh StringRef ClassName) { 142652Sjkh using namespace ast_matchers; 143652Sjkh DeclarationMatcher SubclassM = cxxRecordDecl(isSameOrDerivedFrom(ClassName)); 144652Sjkh return !(match(SubclassM, *D, D->getASTContext()).empty()); 145652Sjkh} 146652Sjkh 147652Sjkhstatic bool isOSObjectSubclass(const Decl *D) { 148652Sjkh return D && isSubclass(D, "OSMetaClassBase"); 149652Sjkh} 150652Sjkh 151652Sjkhstatic bool isOSObjectDynamicCast(StringRef S) { 152652Sjkh return S == "safeMetaCast"; 153652Sjkh} 154652Sjkh 155652Sjkhstatic bool isOSObjectRequiredCast(StringRef S) { 156652Sjkh return S == "requiredMetaCast"; 157652Sjkh} 158652Sjkh 159652Sjkhstatic bool isOSObjectThisCast(StringRef S) { 160652Sjkh return S == "metaCast"; 161652Sjkh} 162652Sjkh 163652Sjkh 164652Sjkhstatic bool isOSObjectPtr(QualType QT) { 165652Sjkh return isOSObjectSubclass(QT->getPointeeCXXRecordDecl()); 166652Sjkh} 167652Sjkh 168652Sjkhstatic bool isISLObjectRef(QualType Ty) { 169652Sjkh return StringRef(Ty.getAsString()).startswith("isl_"); 170652Sjkh} 171652Sjkh 172652Sjkhstatic bool isOSIteratorSubclass(const Decl *D) { 173652Sjkh return isSubclass(D, "OSIterator"); 174652Sjkh} 175652Sjkh 176652Sjkhstatic bool hasRCAnnotation(const Decl *D, StringRef rcAnnotation) { 177652Sjkh for (const auto *Ann : D->specific_attrs<AnnotateAttr>()) { 178652Sjkh if (Ann->getAnnotation() == rcAnnotation) 179652Sjkh return true; 180652Sjkh } 181652Sjkh return false; 182652Sjkh} 183652Sjkh 184652Sjkhstatic bool isRetain(const FunctionDecl *FD, StringRef FName) { 185652Sjkh return FName.startswith_lower("retain") || FName.endswith_lower("retain"); 1861258Sswallace} 187652Sjkh 188652Sjkhstatic bool isRelease(const FunctionDecl *FD, StringRef FName) { 189652Sjkh return FName.startswith_lower("release") || FName.endswith_lower("release"); 190652Sjkh} 191652Sjkh 192652Sjkhstatic bool isAutorelease(const FunctionDecl *FD, StringRef FName) { 193652Sjkh return FName.startswith_lower("autorelease") || 194652Sjkh FName.endswith_lower("autorelease"); 195652Sjkh} 196652Sjkh 197652Sjkhstatic bool isMakeCollectable(StringRef FName) { 198652Sjkh return FName.contains_lower("MakeCollectable"); 199652Sjkh} 200652Sjkh 201652Sjkh/// A function is OSObject related if it is declared on a subclass 202652Sjkh/// of OSObject, or any of the parameters is a subclass of an OSObject. 203652Sjkhstatic bool isOSObjectRelated(const CXXMethodDecl *MD) { 204652Sjkh if (isOSObjectSubclass(MD->getParent())) 205652Sjkh return true; 206652Sjkh 207652Sjkh for (ParmVarDecl *Param : MD->parameters()) { 208652Sjkh QualType PT = Param->getType()->getPointeeType(); 209652Sjkh if (!PT.isNull()) 210652Sjkh if (CXXRecordDecl *RD = PT->getAsCXXRecordDecl()) 211652Sjkh if (isOSObjectSubclass(RD)) 212652Sjkh return true; 213652Sjkh } 214652Sjkh 215652Sjkh return false; 216652Sjkh} 217652Sjkh 218652Sjkhbool 219652SjkhRetainSummaryManager::isKnownSmartPointer(QualType QT) { 220652Sjkh QT = QT.getCanonicalType(); 221652Sjkh const auto *RD = QT->getAsCXXRecordDecl(); 222652Sjkh if (!RD) 223652Sjkh return false; 224652Sjkh const IdentifierInfo *II = RD->getIdentifier(); 225652Sjkh if (II && II->getName() == "smart_ptr") 226652Sjkh if (const auto *ND = dyn_cast<NamespaceDecl>(RD->getDeclContext())) 227652Sjkh if (ND->getNameAsString() == "os") 228652Sjkh return true; 229652Sjkh return false; 230652Sjkh} 231652Sjkh 232652Sjkhconst RetainSummary * 233652SjkhRetainSummaryManager::getSummaryForOSObject(const FunctionDecl *FD, 234652Sjkh StringRef FName, QualType RetTy) { 235652Sjkh assert(TrackOSObjects && 236652Sjkh "Requesting a summary for an OSObject but OSObjects are not tracked"); 237652Sjkh 238652Sjkh if (RetTy->isPointerType()) { 239652Sjkh const CXXRecordDecl *PD = RetTy->getPointeeType()->getAsCXXRecordDecl(); 240652Sjkh if (PD && isOSObjectSubclass(PD)) { 241652Sjkh if (isOSObjectDynamicCast(FName) || isOSObjectRequiredCast(FName) || 242652Sjkh isOSObjectThisCast(FName)) 243652Sjkh return getDefaultSummary(); 244652Sjkh 245652Sjkh // TODO: Add support for the slightly common *Matching(table) idiom. 246652Sjkh // Cf. IOService::nameMatching() etc. - these function have an unusual 247652Sjkh // contract of returning at +0 or +1 depending on their last argument. 248652Sjkh if (FName.endswith("Matching")) { 249652Sjkh return getPersistentStopSummary(); 250652Sjkh } 251652Sjkh 252652Sjkh // All objects returned with functions *not* starting with 'get', 253652Sjkh // or iterators, are returned at +1. 254652Sjkh if ((!FName.startswith("get") && !FName.startswith("Get")) || 255652Sjkh isOSIteratorSubclass(PD)) { 256652Sjkh return getOSSummaryCreateRule(FD); 257652Sjkh } else { 258652Sjkh return getOSSummaryGetRule(FD); 259652Sjkh } 260652Sjkh } 261652Sjkh } 262652Sjkh 263652Sjkh if (const auto *MD = dyn_cast<CXXMethodDecl>(FD)) { 264652Sjkh const CXXRecordDecl *Parent = MD->getParent(); 265652Sjkh if (Parent && isOSObjectSubclass(Parent)) { 266652Sjkh if (FName == "release" || FName == "taggedRelease") 267652Sjkh return getOSSummaryReleaseRule(FD); 268652Sjkh 269652Sjkh if (FName == "retain" || FName == "taggedRetain") 270652Sjkh return getOSSummaryRetainRule(FD); 271652Sjkh 272652Sjkh if (FName == "free") 273652Sjkh return getOSSummaryFreeRule(FD); 274652Sjkh 275652Sjkh if (MD->getOverloadedOperator() == OO_New) 276652Sjkh return getOSSummaryCreateRule(MD); 277652Sjkh } 278652Sjkh } 279652Sjkh 280652Sjkh return nullptr; 281652Sjkh} 282652Sjkh 283652Sjkhconst RetainSummary *RetainSummaryManager::getSummaryForObjCOrCFObject( 284652Sjkh const FunctionDecl *FD, 285652Sjkh StringRef FName, 286652Sjkh QualType RetTy, 287652Sjkh const FunctionType *FT, 288652Sjkh bool &AllowAnnotations) { 289652Sjkh 290652Sjkh ArgEffects ScratchArgs(AF.getEmptyMap()); 291652Sjkh 292652Sjkh std::string RetTyName = RetTy.getAsString(); 293652Sjkh if (FName == "pthread_create" || FName == "pthread_setspecific") { 294652Sjkh // Part of: <rdar://problem/7299394> and <rdar://problem/11282706>. 295652Sjkh // This will be addressed better with IPA. 296652Sjkh return getPersistentStopSummary(); 297652Sjkh } else if(FName == "NSMakeCollectable") { 298652Sjkh // Handle: id NSMakeCollectable(CFTypeRef) 299652Sjkh AllowAnnotations = false; 300652Sjkh return RetTy->isObjCIdType() ? getUnarySummary(FT, DoNothing) 301652Sjkh : getPersistentStopSummary(); 302652Sjkh } else if (FName == "CMBufferQueueDequeueAndRetain" || 303652Sjkh FName == "CMBufferQueueDequeueIfDataReadyAndRetain") { 304652Sjkh // Part of: <rdar://problem/39390714>. 305652Sjkh return getPersistentSummary(RetEffect::MakeOwned(ObjKind::CF), 306652Sjkh ScratchArgs, 307652Sjkh ArgEffect(DoNothing), 308652Sjkh ArgEffect(DoNothing)); 309652Sjkh } else if (FName == "CFPlugInInstanceCreate") { 310652Sjkh return getPersistentSummary(RetEffect::MakeNoRet(), ScratchArgs); 311652Sjkh } else if (FName == "IORegistryEntrySearchCFProperty" || 312652Sjkh (RetTyName == "CFMutableDictionaryRef" && 3131402Sache (FName == "IOBSDNameMatching" || FName == "IOServiceMatching" || 314652Sjkh FName == "IOServiceNameMatching" || 315652Sjkh FName == "IORegistryEntryIDMatching" || 3161402Sache FName == "IOOpenFirmwarePathMatching"))) { 3171402Sache // Part of <rdar://problem/6961230>. (IOKit) 3181402Sache // This should be addressed using a API table. 3191402Sache return getPersistentSummary(RetEffect::MakeOwned(ObjKind::CF), ScratchArgs, 3201402Sache ArgEffect(DoNothing), ArgEffect(DoNothing)); 3211402Sache } else if (FName == "IOServiceGetMatchingService" || 3221402Sache FName == "IOServiceGetMatchingServices") { 323652Sjkh // FIXES: <rdar://problem/6326900> 324652Sjkh // This should be addressed using a API table. This strcmp is also 325652Sjkh // a little gross, but there is no need to super optimize here. 326652Sjkh ScratchArgs = AF.add(ScratchArgs, 1, ArgEffect(DecRef, ObjKind::CF)); 327652Sjkh return getPersistentSummary(RetEffect::MakeNoRet(), 328652Sjkh ScratchArgs, 329652Sjkh ArgEffect(DoNothing), ArgEffect(DoNothing)); 330652Sjkh } else if (FName == "IOServiceAddNotification" || 331652Sjkh FName == "IOServiceAddMatchingNotification") { 332652Sjkh // Part of <rdar://problem/6961230>. (IOKit) 333652Sjkh // This should be addressed using a API table. 334652Sjkh ScratchArgs = AF.add(ScratchArgs, 2, ArgEffect(DecRef, ObjKind::CF)); 335652Sjkh return getPersistentSummary(RetEffect::MakeNoRet(), 336652Sjkh ScratchArgs, 337652Sjkh ArgEffect(DoNothing), ArgEffect(DoNothing)); 338652Sjkh } else if (FName == "CVPixelBufferCreateWithBytes") { 339652Sjkh // FIXES: <rdar://problem/7283567> 340652Sjkh // Eventually this can be improved by recognizing that the pixel 341652Sjkh // buffer passed to CVPixelBufferCreateWithBytes is released via 342652Sjkh // a callback and doing full IPA to make sure this is done correctly. 343652Sjkh // FIXME: This function has an out parameter that returns an 344652Sjkh // allocated object. 345652Sjkh ScratchArgs = AF.add(ScratchArgs, 7, ArgEffect(StopTracking)); 346652Sjkh return getPersistentSummary(RetEffect::MakeNoRet(), 347652Sjkh ScratchArgs, 348652Sjkh ArgEffect(DoNothing), ArgEffect(DoNothing)); 349652Sjkh } else if (FName == "CGBitmapContextCreateWithData") { 350652Sjkh // FIXES: <rdar://problem/7358899> 351652Sjkh // Eventually this can be improved by recognizing that 'releaseInfo' 352652Sjkh // passed to CGBitmapContextCreateWithData is released via 353652Sjkh // a callback and doing full IPA to make sure this is done correctly. 354652Sjkh ScratchArgs = AF.add(ScratchArgs, 8, ArgEffect(ArgEffect(StopTracking))); 355652Sjkh return getPersistentSummary(RetEffect::MakeOwned(ObjKind::CF), ScratchArgs, 356652Sjkh ArgEffect(DoNothing), ArgEffect(DoNothing)); 357652Sjkh } else if (FName == "CVPixelBufferCreateWithPlanarBytes") { 358652Sjkh // FIXES: <rdar://problem/7283567> 359652Sjkh // Eventually this can be improved by recognizing that the pixel 360652Sjkh // buffer passed to CVPixelBufferCreateWithPlanarBytes is released 361652Sjkh // via a callback and doing full IPA to make sure this is done 362652Sjkh // correctly. 363652Sjkh ScratchArgs = AF.add(ScratchArgs, 12, ArgEffect(StopTracking)); 364652Sjkh return getPersistentSummary(RetEffect::MakeNoRet(), 365652Sjkh ScratchArgs, 366652Sjkh ArgEffect(DoNothing), ArgEffect(DoNothing)); 367652Sjkh } else if (FName == "VTCompressionSessionEncodeFrame") { 368652Sjkh // The context argument passed to VTCompressionSessionEncodeFrame() 369652Sjkh // is passed to the callback specified when creating the session 370652Sjkh // (e.g. with VTCompressionSessionCreate()) which can release it. 371652Sjkh // To account for this possibility, conservatively stop tracking 372652Sjkh // the context. 373652Sjkh ScratchArgs = AF.add(ScratchArgs, 5, ArgEffect(StopTracking)); 374652Sjkh return getPersistentSummary(RetEffect::MakeNoRet(), 375652Sjkh ScratchArgs, 376652Sjkh ArgEffect(DoNothing), ArgEffect(DoNothing)); 377652Sjkh } else if (FName == "dispatch_set_context" || 378652Sjkh FName == "xpc_connection_set_context") { 379652Sjkh // <rdar://problem/11059275> - The analyzer currently doesn't have 380652Sjkh // a good way to reason about the finalizer function for libdispatch. 381652Sjkh // If we pass a context object that is memory managed, stop tracking it. 382652Sjkh // <rdar://problem/13783514> - Same problem, but for XPC. 383652Sjkh // FIXME: this hack should possibly go away once we can handle 384652Sjkh // libdispatch and XPC finalizers. 385652Sjkh ScratchArgs = AF.add(ScratchArgs, 1, ArgEffect(StopTracking)); 386652Sjkh return getPersistentSummary(RetEffect::MakeNoRet(), 387652Sjkh ScratchArgs, 388652Sjkh ArgEffect(DoNothing), ArgEffect(DoNothing)); 389652Sjkh } else if (FName.startswith("NSLog")) { 390652Sjkh return getDoNothingSummary(); 391652Sjkh } else if (FName.startswith("NS") && 392652Sjkh (FName.find("Insert") != StringRef::npos)) { 393652Sjkh // Whitelist NSXXInsertXX, for example NSMapInsertIfAbsent, since they can 394652Sjkh // be deallocated by NSMapRemove. (radar://11152419) 395652Sjkh ScratchArgs = AF.add(ScratchArgs, 1, ArgEffect(StopTracking)); 396652Sjkh ScratchArgs = AF.add(ScratchArgs, 2, ArgEffect(StopTracking)); 397652Sjkh return getPersistentSummary(RetEffect::MakeNoRet(), 398652Sjkh ScratchArgs, ArgEffect(DoNothing), 399652Sjkh ArgEffect(DoNothing)); 400652Sjkh } 401652Sjkh 402652Sjkh if (RetTy->isPointerType()) { 403652Sjkh 404652Sjkh // For CoreFoundation ('CF') types. 405652Sjkh if (cocoa::isRefType(RetTy, "CF", FName)) { 406652Sjkh if (isRetain(FD, FName)) { 407652Sjkh // CFRetain isn't supposed to be annotated. However, this may as 408652Sjkh // well be a user-made "safe" CFRetain function that is incorrectly 409652Sjkh // annotated as cf_returns_retained due to lack of better options. 410652Sjkh // We want to ignore such annotation. 411652Sjkh AllowAnnotations = false; 412652Sjkh 413652Sjkh return getUnarySummary(FT, IncRef); 414652Sjkh } else if (isAutorelease(FD, FName)) { 415652Sjkh // The headers use cf_consumed, but we can fully model CFAutorelease 4161258Sswallace // ourselves. 4171258Sswallace AllowAnnotations = false; 418652Sjkh 419652Sjkh return getUnarySummary(FT, Autorelease); 420652Sjkh } else if (isMakeCollectable(FName)) { 421652Sjkh AllowAnnotations = false; 422652Sjkh return getUnarySummary(FT, DoNothing); 423652Sjkh } else { 424652Sjkh return getCFCreateGetRuleSummary(FD); 425652Sjkh } 426652Sjkh } 427652Sjkh 428652Sjkh // For CoreGraphics ('CG') and CoreVideo ('CV') types. 429652Sjkh if (cocoa::isRefType(RetTy, "CG", FName) || 430652Sjkh cocoa::isRefType(RetTy, "CV", FName)) { 431652Sjkh if (isRetain(FD, FName)) 432652Sjkh return getUnarySummary(FT, IncRef); 4331258Sswallace else 434652Sjkh return getCFCreateGetRuleSummary(FD); 435652Sjkh } 436652Sjkh 437652Sjkh // For all other CF-style types, use the Create/Get 438652Sjkh // rule for summaries but don't support Retain functions 439652Sjkh // with framework-specific prefixes. 440652Sjkh if (coreFoundation::isCFObjectRef(RetTy)) { 441652Sjkh return getCFCreateGetRuleSummary(FD); 442652Sjkh } 443652Sjkh 444652Sjkh if (FD->hasAttr<CFAuditedTransferAttr>()) { 445652Sjkh return getCFCreateGetRuleSummary(FD); 4461258Sswallace } 447652Sjkh } 448652Sjkh 449652Sjkh // Check for release functions, the only kind of functions that we care 450652Sjkh // about that don't return a pointer type. 451652Sjkh if (FName.startswith("CG") || FName.startswith("CF")) { 452652Sjkh // Test for 'CGCF'. 453652Sjkh FName = FName.substr(FName.startswith("CGCF") ? 4 : 2); 454652Sjkh 455652Sjkh if (isRelease(FD, FName)) 456652Sjkh return getUnarySummary(FT, DecRef); 457652Sjkh else { 458652Sjkh assert(ScratchArgs.isEmpty()); 459652Sjkh // Remaining CoreFoundation and CoreGraphics functions. 460652Sjkh // We use to assume that they all strictly followed the ownership idiom 461652Sjkh // and that ownership cannot be transferred. While this is technically 462652Sjkh // correct, many methods allow a tracked object to escape. For example: 463652Sjkh // 464652Sjkh // CFMutableDictionaryRef x = CFDictionaryCreateMutable(...); 465652Sjkh // CFDictionaryAddValue(y, key, x); 466652Sjkh // CFRelease(x); 467652Sjkh // ... it is okay to use 'x' since 'y' has a reference to it 468652Sjkh // 469652Sjkh // We handle this and similar cases with the follow heuristic. If the 470652Sjkh // function name contains "InsertValue", "SetValue", "AddValue", 471652Sjkh // "AppendValue", or "SetAttribute", then we assume that arguments may 472652Sjkh // "escape." This means that something else holds on to the object, 473652Sjkh // allowing it be used even after its local retain count drops to 0. 474652Sjkh ArgEffectKind E = 475652Sjkh (StrInStrNoCase(FName, "InsertValue") != StringRef::npos || 476652Sjkh StrInStrNoCase(FName, "AddValue") != StringRef::npos || 477652Sjkh StrInStrNoCase(FName, "SetValue") != StringRef::npos || 478652Sjkh StrInStrNoCase(FName, "AppendValue") != StringRef::npos || 479652Sjkh StrInStrNoCase(FName, "SetAttribute") != StringRef::npos) 480652Sjkh ? MayEscape 481652Sjkh : DoNothing; 482652Sjkh 483652Sjkh return getPersistentSummary(RetEffect::MakeNoRet(), ScratchArgs, 484652Sjkh ArgEffect(DoNothing), ArgEffect(E, ObjKind::CF)); 485652Sjkh } 486652Sjkh } 487652Sjkh 488652Sjkh return nullptr; 489652Sjkh} 490652Sjkh 491652Sjkhconst RetainSummary * 492652SjkhRetainSummaryManager::generateSummary(const FunctionDecl *FD, 493652Sjkh bool &AllowAnnotations) { 494652Sjkh // We generate "stop" summaries for implicitly defined functions. 495652Sjkh if (FD->isImplicit()) 496652Sjkh return getPersistentStopSummary(); 497652Sjkh 498652Sjkh const IdentifierInfo *II = FD->getIdentifier(); 499652Sjkh 500652Sjkh StringRef FName = II ? II->getName() : ""; 501652Sjkh 502652Sjkh // Strip away preceding '_'. Doing this here will effect all the checks 503652Sjkh // down below. 504652Sjkh FName = FName.substr(FName.find_first_not_of('_')); 505652Sjkh 506652Sjkh // Inspect the result type. Strip away any typedefs. 507652Sjkh const auto *FT = FD->getType()->castAs<FunctionType>(); 508652Sjkh QualType RetTy = FT->getReturnType(); 509652Sjkh 510652Sjkh if (TrackOSObjects) 511652Sjkh if (const RetainSummary *S = getSummaryForOSObject(FD, FName, RetTy)) 512652Sjkh return S; 513652Sjkh 514652Sjkh if (const auto *MD = dyn_cast<CXXMethodDecl>(FD)) 515652Sjkh if (!isOSObjectRelated(MD)) 516652Sjkh return getPersistentSummary(RetEffect::MakeNoRet(), 517652Sjkh ArgEffects(AF.getEmptyMap()), 518652Sjkh ArgEffect(DoNothing), 519652Sjkh ArgEffect(StopTracking), 520652Sjkh ArgEffect(DoNothing)); 521652Sjkh 522652Sjkh if (TrackObjCAndCFObjects) 523652Sjkh if (const RetainSummary *S = 524652Sjkh getSummaryForObjCOrCFObject(FD, FName, RetTy, FT, AllowAnnotations)) 525652Sjkh return S; 526652Sjkh 527652Sjkh return getDefaultSummary(); 528652Sjkh} 529652Sjkh 530652Sjkhconst RetainSummary * 531652SjkhRetainSummaryManager::getFunctionSummary(const FunctionDecl *FD) { 532652Sjkh // If we don't know what function we're calling, use our default summary. 533652Sjkh if (!FD) 534652Sjkh return getDefaultSummary(); 535652Sjkh 536652Sjkh // Look up a summary in our cache of FunctionDecls -> Summaries. 537652Sjkh FuncSummariesTy::iterator I = FuncSummaries.find(FD); 538652Sjkh if (I != FuncSummaries.end()) 539652Sjkh return I->second; 540652Sjkh 541652Sjkh // No summary? Generate one. 542652Sjkh bool AllowAnnotations = true; 543652Sjkh const RetainSummary *S = generateSummary(FD, AllowAnnotations); 544652Sjkh 545652Sjkh // Annotations override defaults. 546652Sjkh if (AllowAnnotations) 547652Sjkh updateSummaryFromAnnotations(S, FD); 548652Sjkh 549652Sjkh FuncSummaries[FD] = S; 550652Sjkh return S; 551652Sjkh} 552652Sjkh 553652Sjkh//===----------------------------------------------------------------------===// 554652Sjkh// Summary creation for functions (largely uses of Core Foundation). 555652Sjkh//===----------------------------------------------------------------------===// 556652Sjkh 557652Sjkhstatic ArgEffect getStopTrackingHardEquivalent(ArgEffect E) { 558652Sjkh switch (E.getKind()) { 559652Sjkh case DoNothing: 560652Sjkh case Autorelease: 561652Sjkh case DecRefBridgedTransferred: 562652Sjkh case IncRef: 563652Sjkh case UnretainedOutParameter: 564652Sjkh case RetainedOutParameter: 565652Sjkh case RetainedOutParameterOnZero: 566652Sjkh case RetainedOutParameterOnNonZero: 567652Sjkh case MayEscape: 568652Sjkh case StopTracking: 569652Sjkh case StopTrackingHard: 570652Sjkh return E.withKind(StopTrackingHard); 571652Sjkh case DecRef: 572652Sjkh case DecRefAndStopTrackingHard: 573652Sjkh return E.withKind(DecRefAndStopTrackingHard); 574652Sjkh case Dealloc: 575652Sjkh return E.withKind(Dealloc); 576652Sjkh } 577652Sjkh 578652Sjkh llvm_unreachable("Unknown ArgEffect kind"); 579652Sjkh} 580652Sjkh 581652Sjkhconst RetainSummary * 582652SjkhRetainSummaryManager::updateSummaryForNonZeroCallbackArg(const RetainSummary *S, 583652Sjkh AnyCall &C) { 584652Sjkh ArgEffect RecEffect = getStopTrackingHardEquivalent(S->getReceiverEffect()); 585652Sjkh ArgEffect DefEffect = getStopTrackingHardEquivalent(S->getDefaultArgEffect()); 586652Sjkh 587652Sjkh ArgEffects ScratchArgs(AF.getEmptyMap()); 588652Sjkh ArgEffects CustomArgEffects = S->getArgEffects(); 589652Sjkh for (ArgEffects::iterator I = CustomArgEffects.begin(), 590652Sjkh E = CustomArgEffects.end(); 591652Sjkh I != E; ++I) { 592652Sjkh ArgEffect Translated = getStopTrackingHardEquivalent(I->second); 593652Sjkh if (Translated.getKind() != DefEffect.getKind()) 594652Sjkh ScratchArgs = AF.add(ScratchArgs, I->first, Translated); 595652Sjkh } 596652Sjkh 597652Sjkh RetEffect RE = RetEffect::MakeNoRetHard(); 598652Sjkh 599652Sjkh // Special cases where the callback argument CANNOT free the return value. 600652Sjkh // This can generally only happen if we know that the callback will only be 601652Sjkh // called when the return value is already being deallocated. 602652Sjkh if (const IdentifierInfo *Name = C.getIdentifier()) { 603652Sjkh // When the CGBitmapContext is deallocated, the callback here will free 604652Sjkh // the associated data buffer. 605652Sjkh // The callback in dispatch_data_create frees the buffer, but not 606652Sjkh // the data object. 607652Sjkh if (Name->isStr("CGBitmapContextCreateWithData") || 608652Sjkh Name->isStr("dispatch_data_create")) 609652Sjkh RE = S->getRetEffect(); 610652Sjkh } 611652Sjkh 612652Sjkh return getPersistentSummary(RE, ScratchArgs, RecEffect, DefEffect); 613652Sjkh} 614652Sjkh 615652Sjkhvoid RetainSummaryManager::updateSummaryForReceiverUnconsumedSelf( 616652Sjkh const RetainSummary *&S) { 617652Sjkh 618652Sjkh RetainSummaryTemplate Template(S, *this); 619652Sjkh 620805Sache Template->setReceiverEffect(ArgEffect(DoNothing)); 621652Sjkh Template->setRetEffect(RetEffect::MakeNoRet()); 622652Sjkh} 623652Sjkh 624652Sjkh 625652Sjkhvoid RetainSummaryManager::updateSummaryForArgumentTypes( 626652Sjkh const AnyCall &C, const RetainSummary *&RS) { 627652Sjkh RetainSummaryTemplate Template(RS, *this); 628652Sjkh 629652Sjkh unsigned parm_idx = 0; 630652Sjkh for (auto pi = C.param_begin(), pe = C.param_end(); pi != pe; 631652Sjkh ++pi, ++parm_idx) { 632652Sjkh QualType QT = (*pi)->getType(); 633652Sjkh 634652Sjkh // Skip already created values. 635652Sjkh if (RS->getArgEffects().contains(parm_idx)) 636652Sjkh continue; 637652Sjkh 638652Sjkh ObjKind K = ObjKind::AnyObj; 639652Sjkh 640652Sjkh if (isISLObjectRef(QT)) { 6411402Sache K = ObjKind::Generalized; 6421402Sache } else if (isOSObjectPtr(QT)) { 643652Sjkh K = ObjKind::OS; 644652Sjkh } else if (cocoa::isCocoaObjectRef(QT)) { 645652Sjkh K = ObjKind::ObjC; 646652Sjkh } else if (coreFoundation::isCFObjectRef(QT)) { 647652Sjkh K = ObjKind::CF; 648652Sjkh } 649652Sjkh 650652Sjkh if (K != ObjKind::AnyObj) 651652Sjkh Template->addArg(AF, parm_idx, 652652Sjkh ArgEffect(RS->getDefaultArgEffect().getKind(), K)); 653652Sjkh } 654652Sjkh} 655652Sjkh 6561402Sacheconst RetainSummary * 6571402SacheRetainSummaryManager::getSummary(AnyCall C, 6581402Sache bool HasNonZeroCallbackArg, 6591402Sache bool IsReceiverUnconsumedSelf, 6601402Sache QualType ReceiverType) { 6611402Sache const RetainSummary *Summ; 6621402Sache switch (C.getKind()) { 6631402Sache case AnyCall::Function: 6641402Sache case AnyCall::Constructor: 6651402Sache case AnyCall::Allocator: 6661402Sache case AnyCall::Deallocator: 667652Sjkh Summ = getFunctionSummary(cast_or_null<FunctionDecl>(C.getDecl())); 668652Sjkh break; 669652Sjkh case AnyCall::Block: 670652Sjkh case AnyCall::Destructor: 671652Sjkh // FIXME: These calls are currently unsupported. 672652Sjkh return getPersistentStopSummary(); 673652Sjkh case AnyCall::ObjCMethod: { 674652Sjkh const auto *ME = cast_or_null<ObjCMessageExpr>(C.getExpr()); 675652Sjkh if (!ME) { 676652Sjkh Summ = getMethodSummary(cast<ObjCMethodDecl>(C.getDecl())); 677652Sjkh } else if (ME->isInstanceMessage()) { 678652Sjkh Summ = getInstanceMethodSummary(ME, ReceiverType); 679652Sjkh } else { 680652Sjkh Summ = getClassMethodSummary(ME); 681652Sjkh } 682652Sjkh break; 683652Sjkh } 684652Sjkh } 685652Sjkh 686652Sjkh if (HasNonZeroCallbackArg) 687652Sjkh Summ = updateSummaryForNonZeroCallbackArg(Summ, C); 688652Sjkh 689652Sjkh if (IsReceiverUnconsumedSelf) 690652Sjkh updateSummaryForReceiverUnconsumedSelf(Summ); 691652Sjkh 692652Sjkh updateSummaryForArgumentTypes(C, Summ); 693652Sjkh 694652Sjkh assert(Summ && "Unknown call type?"); 695652Sjkh return Summ; 696652Sjkh} 697652Sjkh 698652Sjkh 699652Sjkhconst RetainSummary * 700652SjkhRetainSummaryManager::getCFCreateGetRuleSummary(const FunctionDecl *FD) { 701652Sjkh if (coreFoundation::followsCreateRule(FD)) 702652Sjkh return getCFSummaryCreateRule(FD); 703652Sjkh 704652Sjkh return getCFSummaryGetRule(FD); 705652Sjkh} 706652Sjkh 707652Sjkhbool RetainSummaryManager::isTrustedReferenceCountImplementation( 708652Sjkh const Decl *FD) { 709652Sjkh return hasRCAnnotation(FD, "rc_ownership_trusted_implementation"); 710652Sjkh} 711652Sjkh 712652SjkhOptional<RetainSummaryManager::BehaviorSummary> 713652SjkhRetainSummaryManager::canEval(const CallExpr *CE, const FunctionDecl *FD, 714652Sjkh bool &hasTrustedImplementationAnnotation) { 715652Sjkh 716652Sjkh IdentifierInfo *II = FD->getIdentifier(); 717652Sjkh if (!II) 718652Sjkh return None; 719652Sjkh 720652Sjkh StringRef FName = II->getName(); 721652Sjkh FName = FName.substr(FName.find_first_not_of('_')); 722652Sjkh 723652Sjkh QualType ResultTy = CE->getCallReturnType(Ctx); 724652Sjkh if (ResultTy->isObjCIdType()) { 725652Sjkh if (II->isStr("NSMakeCollectable")) 726652Sjkh return BehaviorSummary::Identity; 727652Sjkh } else if (ResultTy->isPointerType()) { 728652Sjkh // Handle: (CF|CG|CV)Retain 729652Sjkh // CFAutorelease 730652Sjkh // It's okay to be a little sloppy here. 731652Sjkh if (FName == "CMBufferQueueDequeueAndRetain" || 732652Sjkh FName == "CMBufferQueueDequeueIfDataReadyAndRetain") { 733652Sjkh // Part of: <rdar://problem/39390714>. 734652Sjkh // These are not retain. They just return something and retain it. 735652Sjkh return None; 736652Sjkh } 737652Sjkh if (CE->getNumArgs() == 1 && 738652Sjkh (cocoa::isRefType(ResultTy, "CF", FName) || 739652Sjkh cocoa::isRefType(ResultTy, "CG", FName) || 740652Sjkh cocoa::isRefType(ResultTy, "CV", FName)) && 741652Sjkh (isRetain(FD, FName) || isAutorelease(FD, FName) || 742652Sjkh isMakeCollectable(FName))) 743652Sjkh return BehaviorSummary::Identity; 744652Sjkh 745652Sjkh // safeMetaCast is called by OSDynamicCast. 746652Sjkh // We assume that OSDynamicCast is either an identity (cast is OK, 747652Sjkh // the input was non-zero), 748652Sjkh // or that it returns zero (when the cast failed, or the input 749652Sjkh // was zero). 750652Sjkh if (TrackOSObjects) { 751652Sjkh if (isOSObjectDynamicCast(FName) && FD->param_size() >= 1) { 752652Sjkh return BehaviorSummary::IdentityOrZero; 753652Sjkh } else if (isOSObjectRequiredCast(FName) && FD->param_size() >= 1) { 754652Sjkh return BehaviorSummary::Identity; 755652Sjkh } else if (isOSObjectThisCast(FName) && isa<CXXMethodDecl>(FD) && 756652Sjkh !cast<CXXMethodDecl>(FD)->isStatic()) { 7571402Sache return BehaviorSummary::IdentityThis; 7581402Sache } 759652Sjkh } 760652Sjkh 761652Sjkh const FunctionDecl* FDD = FD->getDefinition(); 762652Sjkh if (FDD && isTrustedReferenceCountImplementation(FDD)) { 763719Swollman hasTrustedImplementationAnnotation = true; 764 return BehaviorSummary::Identity; 765 } 766 } 767 768 if (const auto *MD = dyn_cast<CXXMethodDecl>(FD)) { 769 const CXXRecordDecl *Parent = MD->getParent(); 770 if (TrackOSObjects && Parent && isOSObjectSubclass(Parent)) 771 if (FName == "release" || FName == "retain") 772 return BehaviorSummary::NoOp; 773 } 774 775 return None; 776} 777 778const RetainSummary * 779RetainSummaryManager::getUnarySummary(const FunctionType* FT, 780 ArgEffectKind AE) { 781 782 // Unary functions have no arg effects by definition. 783 ArgEffects ScratchArgs(AF.getEmptyMap()); 784 785 // Sanity check that this is *really* a unary function. This can 786 // happen if people do weird things. 787 const FunctionProtoType* FTP = dyn_cast<FunctionProtoType>(FT); 788 if (!FTP || FTP->getNumParams() != 1) 789 return getPersistentStopSummary(); 790 791 ArgEffect Effect(AE, ObjKind::CF); 792 793 ScratchArgs = AF.add(ScratchArgs, 0, Effect); 794 return getPersistentSummary(RetEffect::MakeNoRet(), 795 ScratchArgs, 796 ArgEffect(DoNothing), ArgEffect(DoNothing)); 797} 798 799const RetainSummary * 800RetainSummaryManager::getOSSummaryRetainRule(const FunctionDecl *FD) { 801 return getPersistentSummary(RetEffect::MakeNoRet(), 802 AF.getEmptyMap(), 803 /*ReceiverEff=*/ArgEffect(DoNothing), 804 /*DefaultEff=*/ArgEffect(DoNothing), 805 /*ThisEff=*/ArgEffect(IncRef, ObjKind::OS)); 806} 807 808const RetainSummary * 809RetainSummaryManager::getOSSummaryReleaseRule(const FunctionDecl *FD) { 810 return getPersistentSummary(RetEffect::MakeNoRet(), 811 AF.getEmptyMap(), 812 /*ReceiverEff=*/ArgEffect(DoNothing), 813 /*DefaultEff=*/ArgEffect(DoNothing), 814 /*ThisEff=*/ArgEffect(DecRef, ObjKind::OS)); 815} 816 817const RetainSummary * 818RetainSummaryManager::getOSSummaryFreeRule(const FunctionDecl *FD) { 819 return getPersistentSummary(RetEffect::MakeNoRet(), 820 AF.getEmptyMap(), 821 /*ReceiverEff=*/ArgEffect(DoNothing), 822 /*DefaultEff=*/ArgEffect(DoNothing), 823 /*ThisEff=*/ArgEffect(Dealloc, ObjKind::OS)); 824} 825 826const RetainSummary * 827RetainSummaryManager::getOSSummaryCreateRule(const FunctionDecl *FD) { 828 return getPersistentSummary(RetEffect::MakeOwned(ObjKind::OS), 829 AF.getEmptyMap()); 830} 831 832const RetainSummary * 833RetainSummaryManager::getOSSummaryGetRule(const FunctionDecl *FD) { 834 return getPersistentSummary(RetEffect::MakeNotOwned(ObjKind::OS), 835 AF.getEmptyMap()); 836} 837 838const RetainSummary * 839RetainSummaryManager::getCFSummaryCreateRule(const FunctionDecl *FD) { 840 return getPersistentSummary(RetEffect::MakeOwned(ObjKind::CF), 841 ArgEffects(AF.getEmptyMap())); 842} 843 844const RetainSummary * 845RetainSummaryManager::getCFSummaryGetRule(const FunctionDecl *FD) { 846 return getPersistentSummary(RetEffect::MakeNotOwned(ObjKind::CF), 847 ArgEffects(AF.getEmptyMap()), 848 ArgEffect(DoNothing), ArgEffect(DoNothing)); 849} 850 851 852 853 854//===----------------------------------------------------------------------===// 855// Summary creation for Selectors. 856//===----------------------------------------------------------------------===// 857 858Optional<RetEffect> 859RetainSummaryManager::getRetEffectFromAnnotations(QualType RetTy, 860 const Decl *D) { 861 if (hasAnyEnabledAttrOf<NSReturnsRetainedAttr>(D, RetTy)) 862 return ObjCAllocRetE; 863 864 if (auto K = hasAnyEnabledAttrOf<CFReturnsRetainedAttr, OSReturnsRetainedAttr, 865 GeneralizedReturnsRetainedAttr>(D, RetTy)) 866 return RetEffect::MakeOwned(*K); 867 868 if (auto K = hasAnyEnabledAttrOf< 869 CFReturnsNotRetainedAttr, OSReturnsNotRetainedAttr, 870 GeneralizedReturnsNotRetainedAttr, NSReturnsNotRetainedAttr, 871 NSReturnsAutoreleasedAttr>(D, RetTy)) 872 return RetEffect::MakeNotOwned(*K); 873 874 if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) 875 for (const auto *PD : MD->overridden_methods()) 876 if (auto RE = getRetEffectFromAnnotations(RetTy, PD)) 877 return RE; 878 879 return None; 880} 881 882/// \return Whether the chain of typedefs starting from {@code QT} 883/// has a typedef with a given name {@code Name}. 884static bool hasTypedefNamed(QualType QT, 885 StringRef Name) { 886 while (auto *T = dyn_cast<TypedefType>(QT)) { 887 const auto &Context = T->getDecl()->getASTContext(); 888 if (T->getDecl()->getIdentifier() == &Context.Idents.get(Name)) 889 return true; 890 QT = T->getDecl()->getUnderlyingType(); 891 } 892 return false; 893} 894 895static QualType getCallableReturnType(const NamedDecl *ND) { 896 if (const auto *FD = dyn_cast<FunctionDecl>(ND)) { 897 return FD->getReturnType(); 898 } else if (const auto *MD = dyn_cast<ObjCMethodDecl>(ND)) { 899 return MD->getReturnType(); 900 } else { 901 llvm_unreachable("Unexpected decl"); 902 } 903} 904 905bool RetainSummaryManager::applyParamAnnotationEffect( 906 const ParmVarDecl *pd, unsigned parm_idx, const NamedDecl *FD, 907 RetainSummaryTemplate &Template) { 908 QualType QT = pd->getType(); 909 if (auto K = 910 hasAnyEnabledAttrOf<NSConsumedAttr, CFConsumedAttr, OSConsumedAttr, 911 GeneralizedConsumedAttr>(pd, QT)) { 912 Template->addArg(AF, parm_idx, ArgEffect(DecRef, *K)); 913 return true; 914 } else if (auto K = hasAnyEnabledAttrOf< 915 CFReturnsRetainedAttr, OSReturnsRetainedAttr, 916 OSReturnsRetainedOnNonZeroAttr, OSReturnsRetainedOnZeroAttr, 917 GeneralizedReturnsRetainedAttr>(pd, QT)) { 918 919 // For OSObjects, we try to guess whether the object is created based 920 // on the return value. 921 if (K == ObjKind::OS) { 922 QualType QT = getCallableReturnType(FD); 923 924 bool HasRetainedOnZero = pd->hasAttr<OSReturnsRetainedOnZeroAttr>(); 925 bool HasRetainedOnNonZero = pd->hasAttr<OSReturnsRetainedOnNonZeroAttr>(); 926 927 // The usual convention is to create an object on non-zero return, but 928 // it's reverted if the typedef chain has a typedef kern_return_t, 929 // because kReturnSuccess constant is defined as zero. 930 // The convention can be overwritten by custom attributes. 931 bool SuccessOnZero = 932 HasRetainedOnZero || 933 (hasTypedefNamed(QT, "kern_return_t") && !HasRetainedOnNonZero); 934 bool ShouldSplit = !QT.isNull() && !QT->isVoidType(); 935 ArgEffectKind AK = RetainedOutParameter; 936 if (ShouldSplit && SuccessOnZero) { 937 AK = RetainedOutParameterOnZero; 938 } else if (ShouldSplit && (!SuccessOnZero || HasRetainedOnNonZero)) { 939 AK = RetainedOutParameterOnNonZero; 940 } 941 Template->addArg(AF, parm_idx, ArgEffect(AK, ObjKind::OS)); 942 } 943 944 // For others: 945 // Do nothing. Retained out parameters will either point to a +1 reference 946 // or NULL, but the way you check for failure differs depending on the 947 // API. Consequently, we don't have a good way to track them yet. 948 return true; 949 } else if (auto K = hasAnyEnabledAttrOf<CFReturnsNotRetainedAttr, 950 OSReturnsNotRetainedAttr, 951 GeneralizedReturnsNotRetainedAttr>( 952 pd, QT)) { 953 Template->addArg(AF, parm_idx, ArgEffect(UnretainedOutParameter, *K)); 954 return true; 955 } 956 957 if (const auto *MD = dyn_cast<CXXMethodDecl>(FD)) { 958 for (const auto *OD : MD->overridden_methods()) { 959 const ParmVarDecl *OP = OD->parameters()[parm_idx]; 960 if (applyParamAnnotationEffect(OP, parm_idx, OD, Template)) 961 return true; 962 } 963 } 964 965 return false; 966} 967 968void 969RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ, 970 const FunctionDecl *FD) { 971 if (!FD) 972 return; 973 974 assert(Summ && "Must have a summary to add annotations to."); 975 RetainSummaryTemplate Template(Summ, *this); 976 977 // Effects on the parameters. 978 unsigned parm_idx = 0; 979 for (auto pi = FD->param_begin(), 980 pe = FD->param_end(); pi != pe; ++pi, ++parm_idx) 981 applyParamAnnotationEffect(*pi, parm_idx, FD, Template); 982 983 QualType RetTy = FD->getReturnType(); 984 if (Optional<RetEffect> RetE = getRetEffectFromAnnotations(RetTy, FD)) 985 Template->setRetEffect(*RetE); 986 987 if (hasAnyEnabledAttrOf<OSConsumesThisAttr>(FD, RetTy)) 988 Template->setThisEffect(ArgEffect(DecRef, ObjKind::OS)); 989} 990 991void 992RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ, 993 const ObjCMethodDecl *MD) { 994 if (!MD) 995 return; 996 997 assert(Summ && "Must have a valid summary to add annotations to"); 998 RetainSummaryTemplate Template(Summ, *this); 999 1000 // Effects on the receiver. 1001 if (hasAnyEnabledAttrOf<NSConsumesSelfAttr>(MD, MD->getReturnType())) 1002 Template->setReceiverEffect(ArgEffect(DecRef, ObjKind::ObjC)); 1003 1004 // Effects on the parameters. 1005 unsigned parm_idx = 0; 1006 for (auto pi = MD->param_begin(), pe = MD->param_end(); pi != pe; 1007 ++pi, ++parm_idx) 1008 applyParamAnnotationEffect(*pi, parm_idx, MD, Template); 1009 1010 QualType RetTy = MD->getReturnType(); 1011 if (Optional<RetEffect> RetE = getRetEffectFromAnnotations(RetTy, MD)) 1012 Template->setRetEffect(*RetE); 1013} 1014 1015const RetainSummary * 1016RetainSummaryManager::getStandardMethodSummary(const ObjCMethodDecl *MD, 1017 Selector S, QualType RetTy) { 1018 // Any special effects? 1019 ArgEffect ReceiverEff = ArgEffect(DoNothing, ObjKind::ObjC); 1020 RetEffect ResultEff = RetEffect::MakeNoRet(); 1021 1022 // Check the method family, and apply any default annotations. 1023 switch (MD ? MD->getMethodFamily() : S.getMethodFamily()) { 1024 case OMF_None: 1025 case OMF_initialize: 1026 case OMF_performSelector: 1027 // Assume all Objective-C methods follow Cocoa Memory Management rules. 1028 // FIXME: Does the non-threaded performSelector family really belong here? 1029 // The selector could be, say, @selector(copy). 1030 if (cocoa::isCocoaObjectRef(RetTy)) 1031 ResultEff = RetEffect::MakeNotOwned(ObjKind::ObjC); 1032 else if (coreFoundation::isCFObjectRef(RetTy)) { 1033 // ObjCMethodDecl currently doesn't consider CF objects as valid return 1034 // values for alloc, new, copy, or mutableCopy, so we have to 1035 // double-check with the selector. This is ugly, but there aren't that 1036 // many Objective-C methods that return CF objects, right? 1037 if (MD) { 1038 switch (S.getMethodFamily()) { 1039 case OMF_alloc: 1040 case OMF_new: 1041 case OMF_copy: 1042 case OMF_mutableCopy: 1043 ResultEff = RetEffect::MakeOwned(ObjKind::CF); 1044 break; 1045 default: 1046 ResultEff = RetEffect::MakeNotOwned(ObjKind::CF); 1047 break; 1048 } 1049 } else { 1050 ResultEff = RetEffect::MakeNotOwned(ObjKind::CF); 1051 } 1052 } 1053 break; 1054 case OMF_init: 1055 ResultEff = ObjCInitRetE; 1056 ReceiverEff = ArgEffect(DecRef, ObjKind::ObjC); 1057 break; 1058 case OMF_alloc: 1059 case OMF_new: 1060 case OMF_copy: 1061 case OMF_mutableCopy: 1062 if (cocoa::isCocoaObjectRef(RetTy)) 1063 ResultEff = ObjCAllocRetE; 1064 else if (coreFoundation::isCFObjectRef(RetTy)) 1065 ResultEff = RetEffect::MakeOwned(ObjKind::CF); 1066 break; 1067 case OMF_autorelease: 1068 ReceiverEff = ArgEffect(Autorelease, ObjKind::ObjC); 1069 break; 1070 case OMF_retain: 1071 ReceiverEff = ArgEffect(IncRef, ObjKind::ObjC); 1072 break; 1073 case OMF_release: 1074 ReceiverEff = ArgEffect(DecRef, ObjKind::ObjC); 1075 break; 1076 case OMF_dealloc: 1077 ReceiverEff = ArgEffect(Dealloc, ObjKind::ObjC); 1078 break; 1079 case OMF_self: 1080 // -self is handled specially by the ExprEngine to propagate the receiver. 1081 break; 1082 case OMF_retainCount: 1083 case OMF_finalize: 1084 // These methods don't return objects. 1085 break; 1086 } 1087 1088 // If one of the arguments in the selector has the keyword 'delegate' we 1089 // should stop tracking the reference count for the receiver. This is 1090 // because the reference count is quite possibly handled by a delegate 1091 // method. 1092 if (S.isKeywordSelector()) { 1093 for (unsigned i = 0, e = S.getNumArgs(); i != e; ++i) { 1094 StringRef Slot = S.getNameForSlot(i); 1095 if (Slot.substr(Slot.size() - 8).equals_lower("delegate")) { 1096 if (ResultEff == ObjCInitRetE) 1097 ResultEff = RetEffect::MakeNoRetHard(); 1098 else 1099 ReceiverEff = ArgEffect(StopTrackingHard, ObjKind::ObjC); 1100 } 1101 } 1102 } 1103 1104 if (ReceiverEff.getKind() == DoNothing && 1105 ResultEff.getKind() == RetEffect::NoRet) 1106 return getDefaultSummary(); 1107 1108 return getPersistentSummary(ResultEff, ArgEffects(AF.getEmptyMap()), 1109 ArgEffect(ReceiverEff), ArgEffect(MayEscape)); 1110} 1111 1112const RetainSummary * 1113RetainSummaryManager::getClassMethodSummary(const ObjCMessageExpr *ME) { 1114 assert(!ME->isInstanceMessage()); 1115 const ObjCInterfaceDecl *Class = ME->getReceiverInterface(); 1116 1117 return getMethodSummary(ME->getSelector(), Class, ME->getMethodDecl(), 1118 ME->getType(), ObjCClassMethodSummaries); 1119} 1120 1121const RetainSummary *RetainSummaryManager::getInstanceMethodSummary( 1122 const ObjCMessageExpr *ME, 1123 QualType ReceiverType) { 1124 const ObjCInterfaceDecl *ReceiverClass = nullptr; 1125 1126 // We do better tracking of the type of the object than the core ExprEngine. 1127 // See if we have its type in our private state. 1128 if (!ReceiverType.isNull()) 1129 if (const auto *PT = ReceiverType->getAs<ObjCObjectPointerType>()) 1130 ReceiverClass = PT->getInterfaceDecl(); 1131 1132 // If we don't know what kind of object this is, fall back to its static type. 1133 if (!ReceiverClass) 1134 ReceiverClass = ME->getReceiverInterface(); 1135 1136 // FIXME: The receiver could be a reference to a class, meaning that 1137 // we should use the class method. 1138 // id x = [NSObject class]; 1139 // [x performSelector:... withObject:... afterDelay:...]; 1140 Selector S = ME->getSelector(); 1141 const ObjCMethodDecl *Method = ME->getMethodDecl(); 1142 if (!Method && ReceiverClass) 1143 Method = ReceiverClass->getInstanceMethod(S); 1144 1145 return getMethodSummary(S, ReceiverClass, Method, ME->getType(), 1146 ObjCMethodSummaries); 1147} 1148 1149const RetainSummary * 1150RetainSummaryManager::getMethodSummary(Selector S, 1151 const ObjCInterfaceDecl *ID, 1152 const ObjCMethodDecl *MD, QualType RetTy, 1153 ObjCMethodSummariesTy &CachedSummaries) { 1154 1155 // Objective-C method summaries are only applicable to ObjC and CF objects. 1156 if (!TrackObjCAndCFObjects) 1157 return getDefaultSummary(); 1158 1159 // Look up a summary in our summary cache. 1160 const RetainSummary *Summ = CachedSummaries.find(ID, S); 1161 1162 if (!Summ) { 1163 Summ = getStandardMethodSummary(MD, S, RetTy); 1164 1165 // Annotations override defaults. 1166 updateSummaryFromAnnotations(Summ, MD); 1167 1168 // Memoize the summary. 1169 CachedSummaries[ObjCSummaryKey(ID, S)] = Summ; 1170 } 1171 1172 return Summ; 1173} 1174 1175void RetainSummaryManager::InitializeClassMethodSummaries() { 1176 ArgEffects ScratchArgs = AF.getEmptyMap(); 1177 1178 // Create the [NSAssertionHandler currentHander] summary. 1179 addClassMethSummary("NSAssertionHandler", "currentHandler", 1180 getPersistentSummary(RetEffect::MakeNotOwned(ObjKind::ObjC), 1181 ScratchArgs)); 1182 1183 // Create the [NSAutoreleasePool addObject:] summary. 1184 ScratchArgs = AF.add(ScratchArgs, 0, ArgEffect(Autorelease)); 1185 addClassMethSummary("NSAutoreleasePool", "addObject", 1186 getPersistentSummary(RetEffect::MakeNoRet(), ScratchArgs, 1187 ArgEffect(DoNothing), 1188 ArgEffect(Autorelease))); 1189} 1190 1191void RetainSummaryManager::InitializeMethodSummaries() { 1192 1193 ArgEffects ScratchArgs = AF.getEmptyMap(); 1194 // Create the "init" selector. It just acts as a pass-through for the 1195 // receiver. 1196 const RetainSummary *InitSumm = getPersistentSummary( 1197 ObjCInitRetE, ScratchArgs, ArgEffect(DecRef, ObjKind::ObjC)); 1198 addNSObjectMethSummary(GetNullarySelector("init", Ctx), InitSumm); 1199 1200 // awakeAfterUsingCoder: behaves basically like an 'init' method. It 1201 // claims the receiver and returns a retained object. 1202 addNSObjectMethSummary(GetUnarySelector("awakeAfterUsingCoder", Ctx), 1203 InitSumm); 1204 1205 // The next methods are allocators. 1206 const RetainSummary *AllocSumm = getPersistentSummary(ObjCAllocRetE, 1207 ScratchArgs); 1208 const RetainSummary *CFAllocSumm = 1209 getPersistentSummary(RetEffect::MakeOwned(ObjKind::CF), ScratchArgs); 1210 1211 // Create the "retain" selector. 1212 RetEffect NoRet = RetEffect::MakeNoRet(); 1213 const RetainSummary *Summ = getPersistentSummary( 1214 NoRet, ScratchArgs, ArgEffect(IncRef, ObjKind::ObjC)); 1215 addNSObjectMethSummary(GetNullarySelector("retain", Ctx), Summ); 1216 1217 // Create the "release" selector. 1218 Summ = getPersistentSummary(NoRet, ScratchArgs, 1219 ArgEffect(DecRef, ObjKind::ObjC)); 1220 addNSObjectMethSummary(GetNullarySelector("release", Ctx), Summ); 1221 1222 // Create the -dealloc summary. 1223 Summ = getPersistentSummary(NoRet, ScratchArgs, ArgEffect(Dealloc, 1224 ObjKind::ObjC)); 1225 addNSObjectMethSummary(GetNullarySelector("dealloc", Ctx), Summ); 1226 1227 // Create the "autorelease" selector. 1228 Summ = getPersistentSummary(NoRet, ScratchArgs, ArgEffect(Autorelease, 1229 ObjKind::ObjC)); 1230 addNSObjectMethSummary(GetNullarySelector("autorelease", Ctx), Summ); 1231 1232 // For NSWindow, allocated objects are (initially) self-owned. 1233 // FIXME: For now we opt for false negatives with NSWindow, as these objects 1234 // self-own themselves. However, they only do this once they are displayed. 1235 // Thus, we need to track an NSWindow's display status. 1236 // This is tracked in <rdar://problem/6062711>. 1237 // See also http://llvm.org/bugs/show_bug.cgi?id=3714. 1238 const RetainSummary *NoTrackYet = 1239 getPersistentSummary(RetEffect::MakeNoRet(), ScratchArgs, 1240 ArgEffect(StopTracking), ArgEffect(StopTracking)); 1241 1242 addClassMethSummary("NSWindow", "alloc", NoTrackYet); 1243 1244 // For NSPanel (which subclasses NSWindow), allocated objects are not 1245 // self-owned. 1246 // FIXME: For now we don't track NSPanels. object for the same reason 1247 // as for NSWindow objects. 1248 addClassMethSummary("NSPanel", "alloc", NoTrackYet); 1249 1250 // For NSNull, objects returned by +null are singletons that ignore 1251 // retain/release semantics. Just don't track them. 1252 // <rdar://problem/12858915> 1253 addClassMethSummary("NSNull", "null", NoTrackYet); 1254 1255 // Don't track allocated autorelease pools, as it is okay to prematurely 1256 // exit a method. 1257 addClassMethSummary("NSAutoreleasePool", "alloc", NoTrackYet); 1258 addClassMethSummary("NSAutoreleasePool", "allocWithZone", NoTrackYet, false); 1259 addClassMethSummary("NSAutoreleasePool", "new", NoTrackYet); 1260 1261 // Create summaries QCRenderer/QCView -createSnapShotImageOfType: 1262 addInstMethSummary("QCRenderer", AllocSumm, "createSnapshotImageOfType"); 1263 addInstMethSummary("QCView", AllocSumm, "createSnapshotImageOfType"); 1264 1265 // Create summaries for CIContext, 'createCGImage' and 1266 // 'createCGLayerWithSize'. These objects are CF objects, and are not 1267 // automatically garbage collected. 1268 addInstMethSummary("CIContext", CFAllocSumm, "createCGImage", "fromRect"); 1269 addInstMethSummary("CIContext", CFAllocSumm, "createCGImage", "fromRect", 1270 "format", "colorSpace"); 1271 addInstMethSummary("CIContext", CFAllocSumm, "createCGLayerWithSize", "info"); 1272} 1273 1274const RetainSummary * 1275RetainSummaryManager::getMethodSummary(const ObjCMethodDecl *MD) { 1276 const ObjCInterfaceDecl *ID = MD->getClassInterface(); 1277 Selector S = MD->getSelector(); 1278 QualType ResultTy = MD->getReturnType(); 1279 1280 ObjCMethodSummariesTy *CachedSummaries; 1281 if (MD->isInstanceMethod()) 1282 CachedSummaries = &ObjCMethodSummaries; 1283 else 1284 CachedSummaries = &ObjCClassMethodSummaries; 1285 1286 return getMethodSummary(S, ID, MD, ResultTy, *CachedSummaries); 1287} 1288