1 //== RetainSummaryManager.cpp - Summaries for reference counting --*- C++ -*--// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file defines summaries implementation for retain counting, which 10 // implements a reference count checker for Core Foundation, Cocoa 11 // and OSObject (on Mac OS X). 12 // 13 //===----------------------------------------------------------------------===// 14 15 #include "clang/Analysis/DomainSpecific/CocoaConventions.h" 16 #include "clang/Analysis/RetainSummaryManager.h" 17 #include "clang/AST/Attr.h" 18 #include "clang/AST/DeclCXX.h" 19 #include "clang/AST/DeclObjC.h" 20 #include "clang/AST/ParentMap.h" 21 #include "clang/ASTMatchers/ASTMatchFinder.h" 22 23 using namespace clang; 24 using namespace ento; 25 26 template <class T> 27 constexpr static bool isOneOf() { 28 return false; 29 } 30 31 /// Helper function to check whether the class is one of the 32 /// rest of varargs. 33 template <class T, class P, class... ToCompare> 34 constexpr static bool isOneOf() { 35 return std::is_same<T, P>::value || isOneOf<T, ToCompare...>(); 36 } 37 38 namespace { 39 40 /// Fake attribute class for RC* attributes. 41 struct GeneralizedReturnsRetainedAttr { 42 static bool classof(const Attr *A) { 43 if (auto AA = dyn_cast<AnnotateAttr>(A)) 44 return AA->getAnnotation() == "rc_ownership_returns_retained"; 45 return false; 46 } 47 }; 48 49 struct GeneralizedReturnsNotRetainedAttr { 50 static bool classof(const Attr *A) { 51 if (auto AA = dyn_cast<AnnotateAttr>(A)) 52 return AA->getAnnotation() == "rc_ownership_returns_not_retained"; 53 return false; 54 } 55 }; 56 57 struct GeneralizedConsumedAttr { 58 static bool classof(const Attr *A) { 59 if (auto AA = dyn_cast<AnnotateAttr>(A)) 60 return AA->getAnnotation() == "rc_ownership_consumed"; 61 return false; 62 } 63 }; 64 65 } 66 67 template <class T> 68 Optional<ObjKind> RetainSummaryManager::hasAnyEnabledAttrOf(const Decl *D, 69 QualType QT) { 70 ObjKind K; 71 if (isOneOf<T, CFConsumedAttr, CFReturnsRetainedAttr, 72 CFReturnsNotRetainedAttr>()) { 73 if (!TrackObjCAndCFObjects) 74 return None; 75 76 K = ObjKind::CF; 77 } else if (isOneOf<T, NSConsumedAttr, NSConsumesSelfAttr, 78 NSReturnsAutoreleasedAttr, NSReturnsRetainedAttr, 79 NSReturnsNotRetainedAttr, NSConsumesSelfAttr>()) { 80 81 if (!TrackObjCAndCFObjects) 82 return None; 83 84 if (isOneOf<T, NSReturnsRetainedAttr, NSReturnsAutoreleasedAttr, 85 NSReturnsNotRetainedAttr>() && 86 !cocoa::isCocoaObjectRef(QT)) 87 return None; 88 K = ObjKind::ObjC; 89 } else if (isOneOf<T, OSConsumedAttr, OSConsumesThisAttr, 90 OSReturnsNotRetainedAttr, OSReturnsRetainedAttr, 91 OSReturnsRetainedOnZeroAttr, 92 OSReturnsRetainedOnNonZeroAttr>()) { 93 if (!TrackOSObjects) 94 return None; 95 K = ObjKind::OS; 96 } else if (isOneOf<T, GeneralizedReturnsNotRetainedAttr, 97 GeneralizedReturnsRetainedAttr, 98 GeneralizedConsumedAttr>()) { 99 K = ObjKind::Generalized; 100 } else { 101 llvm_unreachable("Unexpected attribute"); 102 } 103 if (D->hasAttr<T>()) 104 return K; 105 return None; 106 } 107 108 template <class T1, class T2, class... Others> 109 Optional<ObjKind> RetainSummaryManager::hasAnyEnabledAttrOf(const Decl *D, 110 QualType QT) { 111 if (auto Out = hasAnyEnabledAttrOf<T1>(D, QT)) 112 return Out; 113 return hasAnyEnabledAttrOf<T2, Others...>(D, QT); 114 } 115 116 const RetainSummary * 117 RetainSummaryManager::getPersistentSummary(const RetainSummary &OldSumm) { 118 // Unique "simple" summaries -- those without ArgEffects. 119 if (OldSumm.isSimple()) { 120 ::llvm::FoldingSetNodeID ID; 121 OldSumm.Profile(ID); 122 123 void *Pos; 124 CachedSummaryNode *N = SimpleSummaries.FindNodeOrInsertPos(ID, Pos); 125 126 if (!N) { 127 N = (CachedSummaryNode *) BPAlloc.Allocate<CachedSummaryNode>(); 128 new (N) CachedSummaryNode(OldSumm); 129 SimpleSummaries.InsertNode(N, Pos); 130 } 131 132 return &N->getValue(); 133 } 134 135 RetainSummary *Summ = (RetainSummary *) BPAlloc.Allocate<RetainSummary>(); 136 new (Summ) RetainSummary(OldSumm); 137 return Summ; 138 } 139 140 static bool isSubclass(const Decl *D, 141 StringRef ClassName) { 142 using namespace ast_matchers; 143 DeclarationMatcher SubclassM = cxxRecordDecl(isSameOrDerivedFrom(ClassName)); 144 return !(match(SubclassM, *D, D->getASTContext()).empty()); 145 } 146 147 static bool isOSObjectSubclass(const Decl *D) { 148 return D && isSubclass(D, "OSMetaClassBase"); 149 } 150 151 static bool isOSObjectDynamicCast(StringRef S) { 152 return S == "safeMetaCast"; 153 } 154 155 static bool isOSObjectThisCast(StringRef S) { 156 return S == "metaCast"; 157 } 158 159 160 static bool isOSObjectPtr(QualType QT) { 161 return isOSObjectSubclass(QT->getPointeeCXXRecordDecl()); 162 } 163 164 static bool isISLObjectRef(QualType Ty) { 165 return StringRef(Ty.getAsString()).startswith("isl_"); 166 } 167 168 static bool isOSIteratorSubclass(const Decl *D) { 169 return isSubclass(D, "OSIterator"); 170 } 171 172 static bool hasRCAnnotation(const Decl *D, StringRef rcAnnotation) { 173 for (const auto *Ann : D->specific_attrs<AnnotateAttr>()) { 174 if (Ann->getAnnotation() == rcAnnotation) 175 return true; 176 } 177 return false; 178 } 179 180 static bool isRetain(const FunctionDecl *FD, StringRef FName) { 181 return FName.startswith_lower("retain") || FName.endswith_lower("retain"); 182 } 183 184 static bool isRelease(const FunctionDecl *FD, StringRef FName) { 185 return FName.startswith_lower("release") || FName.endswith_lower("release"); 186 } 187 188 static bool isAutorelease(const FunctionDecl *FD, StringRef FName) { 189 return FName.startswith_lower("autorelease") || 190 FName.endswith_lower("autorelease"); 191 } 192 193 static bool isMakeCollectable(StringRef FName) { 194 return FName.contains_lower("MakeCollectable"); 195 } 196 197 /// A function is OSObject related if it is declared on a subclass 198 /// of OSObject, or any of the parameters is a subclass of an OSObject. 199 static bool isOSObjectRelated(const CXXMethodDecl *MD) { 200 if (isOSObjectSubclass(MD->getParent())) 201 return true; 202 203 for (ParmVarDecl *Param : MD->parameters()) { 204 QualType PT = Param->getType()->getPointeeType(); 205 if (!PT.isNull()) 206 if (CXXRecordDecl *RD = PT->getAsCXXRecordDecl()) 207 if (isOSObjectSubclass(RD)) 208 return true; 209 } 210 211 return false; 212 } 213 214 bool 215 RetainSummaryManager::isKnownSmartPointer(QualType QT) { 216 QT = QT.getCanonicalType(); 217 const auto *RD = QT->getAsCXXRecordDecl(); 218 if (!RD) 219 return false; 220 const IdentifierInfo *II = RD->getIdentifier(); 221 if (II && II->getName() == "smart_ptr") 222 if (const auto *ND = dyn_cast<NamespaceDecl>(RD->getDeclContext())) 223 if (ND->getNameAsString() == "os") 224 return true; 225 return false; 226 } 227 228 const RetainSummary * 229 RetainSummaryManager::getSummaryForOSObject(const FunctionDecl *FD, 230 StringRef FName, QualType RetTy) { 231 assert(TrackOSObjects && 232 "Requesting a summary for an OSObject but OSObjects are not tracked"); 233 234 if (RetTy->isPointerType()) { 235 const CXXRecordDecl *PD = RetTy->getPointeeType()->getAsCXXRecordDecl(); 236 if (PD && isOSObjectSubclass(PD)) { 237 if (isOSObjectDynamicCast(FName) || isOSObjectThisCast(FName)) 238 return getDefaultSummary(); 239 240 // TODO: Add support for the slightly common *Matching(table) idiom. 241 // Cf. IOService::nameMatching() etc. - these function have an unusual 242 // contract of returning at +0 or +1 depending on their last argument. 243 if (FName.endswith("Matching")) { 244 return getPersistentStopSummary(); 245 } 246 247 // All objects returned with functions *not* starting with 'get', 248 // or iterators, are returned at +1. 249 if ((!FName.startswith("get") && !FName.startswith("Get")) || 250 isOSIteratorSubclass(PD)) { 251 return getOSSummaryCreateRule(FD); 252 } else { 253 return getOSSummaryGetRule(FD); 254 } 255 } 256 } 257 258 if (const auto *MD = dyn_cast<CXXMethodDecl>(FD)) { 259 const CXXRecordDecl *Parent = MD->getParent(); 260 if (Parent && isOSObjectSubclass(Parent)) { 261 if (FName == "release" || FName == "taggedRelease") 262 return getOSSummaryReleaseRule(FD); 263 264 if (FName == "retain" || FName == "taggedRetain") 265 return getOSSummaryRetainRule(FD); 266 267 if (FName == "free") 268 return getOSSummaryFreeRule(FD); 269 270 if (MD->getOverloadedOperator() == OO_New) 271 return getOSSummaryCreateRule(MD); 272 } 273 } 274 275 return nullptr; 276 } 277 278 const RetainSummary *RetainSummaryManager::getSummaryForObjCOrCFObject( 279 const FunctionDecl *FD, 280 StringRef FName, 281 QualType RetTy, 282 const FunctionType *FT, 283 bool &AllowAnnotations) { 284 285 ArgEffects ScratchArgs(AF.getEmptyMap()); 286 287 std::string RetTyName = RetTy.getAsString(); 288 if (FName == "pthread_create" || FName == "pthread_setspecific") { 289 // Part of: <rdar://problem/7299394> and <rdar://problem/11282706>. 290 // This will be addressed better with IPA. 291 return getPersistentStopSummary(); 292 } else if(FName == "NSMakeCollectable") { 293 // Handle: id NSMakeCollectable(CFTypeRef) 294 AllowAnnotations = false; 295 return RetTy->isObjCIdType() ? getUnarySummary(FT, DoNothing) 296 : getPersistentStopSummary(); 297 } else if (FName == "CMBufferQueueDequeueAndRetain" || 298 FName == "CMBufferQueueDequeueIfDataReadyAndRetain") { 299 // Part of: <rdar://problem/39390714>. 300 return getPersistentSummary(RetEffect::MakeOwned(ObjKind::CF), 301 ScratchArgs, 302 ArgEffect(DoNothing), 303 ArgEffect(DoNothing)); 304 } else if (FName == "CFPlugInInstanceCreate") { 305 return getPersistentSummary(RetEffect::MakeNoRet(), ScratchArgs); 306 } else if (FName == "IORegistryEntrySearchCFProperty" || 307 (RetTyName == "CFMutableDictionaryRef" && 308 (FName == "IOBSDNameMatching" || FName == "IOServiceMatching" || 309 FName == "IOServiceNameMatching" || 310 FName == "IORegistryEntryIDMatching" || 311 FName == "IOOpenFirmwarePathMatching"))) { 312 // Part of <rdar://problem/6961230>. (IOKit) 313 // This should be addressed using a API table. 314 return getPersistentSummary(RetEffect::MakeOwned(ObjKind::CF), ScratchArgs, 315 ArgEffect(DoNothing), ArgEffect(DoNothing)); 316 } else if (FName == "IOServiceGetMatchingService" || 317 FName == "IOServiceGetMatchingServices") { 318 // FIXES: <rdar://problem/6326900> 319 // This should be addressed using a API table. This strcmp is also 320 // a little gross, but there is no need to super optimize here. 321 ScratchArgs = AF.add(ScratchArgs, 1, ArgEffect(DecRef, ObjKind::CF)); 322 return getPersistentSummary(RetEffect::MakeNoRet(), 323 ScratchArgs, 324 ArgEffect(DoNothing), ArgEffect(DoNothing)); 325 } else if (FName == "IOServiceAddNotification" || 326 FName == "IOServiceAddMatchingNotification") { 327 // Part of <rdar://problem/6961230>. (IOKit) 328 // This should be addressed using a API table. 329 ScratchArgs = AF.add(ScratchArgs, 2, ArgEffect(DecRef, ObjKind::CF)); 330 return getPersistentSummary(RetEffect::MakeNoRet(), 331 ScratchArgs, 332 ArgEffect(DoNothing), ArgEffect(DoNothing)); 333 } else if (FName == "CVPixelBufferCreateWithBytes") { 334 // FIXES: <rdar://problem/7283567> 335 // Eventually this can be improved by recognizing that the pixel 336 // buffer passed to CVPixelBufferCreateWithBytes is released via 337 // a callback and doing full IPA to make sure this is done correctly. 338 // FIXME: This function has an out parameter that returns an 339 // allocated object. 340 ScratchArgs = AF.add(ScratchArgs, 7, ArgEffect(StopTracking)); 341 return getPersistentSummary(RetEffect::MakeNoRet(), 342 ScratchArgs, 343 ArgEffect(DoNothing), ArgEffect(DoNothing)); 344 } else if (FName == "CGBitmapContextCreateWithData") { 345 // FIXES: <rdar://problem/7358899> 346 // Eventually this can be improved by recognizing that 'releaseInfo' 347 // passed to CGBitmapContextCreateWithData is released via 348 // a callback and doing full IPA to make sure this is done correctly. 349 ScratchArgs = AF.add(ScratchArgs, 8, ArgEffect(ArgEffect(StopTracking))); 350 return getPersistentSummary(RetEffect::MakeOwned(ObjKind::CF), ScratchArgs, 351 ArgEffect(DoNothing), ArgEffect(DoNothing)); 352 } else if (FName == "CVPixelBufferCreateWithPlanarBytes") { 353 // FIXES: <rdar://problem/7283567> 354 // Eventually this can be improved by recognizing that the pixel 355 // buffer passed to CVPixelBufferCreateWithPlanarBytes is released 356 // via a callback and doing full IPA to make sure this is done 357 // correctly. 358 ScratchArgs = AF.add(ScratchArgs, 12, ArgEffect(StopTracking)); 359 return getPersistentSummary(RetEffect::MakeNoRet(), 360 ScratchArgs, 361 ArgEffect(DoNothing), ArgEffect(DoNothing)); 362 } else if (FName == "VTCompressionSessionEncodeFrame") { 363 // The context argument passed to VTCompressionSessionEncodeFrame() 364 // is passed to the callback specified when creating the session 365 // (e.g. with VTCompressionSessionCreate()) which can release it. 366 // To account for this possibility, conservatively stop tracking 367 // the context. 368 ScratchArgs = AF.add(ScratchArgs, 5, ArgEffect(StopTracking)); 369 return getPersistentSummary(RetEffect::MakeNoRet(), 370 ScratchArgs, 371 ArgEffect(DoNothing), ArgEffect(DoNothing)); 372 } else if (FName == "dispatch_set_context" || 373 FName == "xpc_connection_set_context") { 374 // <rdar://problem/11059275> - The analyzer currently doesn't have 375 // a good way to reason about the finalizer function for libdispatch. 376 // If we pass a context object that is memory managed, stop tracking it. 377 // <rdar://problem/13783514> - Same problem, but for XPC. 378 // FIXME: this hack should possibly go away once we can handle 379 // libdispatch and XPC finalizers. 380 ScratchArgs = AF.add(ScratchArgs, 1, ArgEffect(StopTracking)); 381 return getPersistentSummary(RetEffect::MakeNoRet(), 382 ScratchArgs, 383 ArgEffect(DoNothing), ArgEffect(DoNothing)); 384 } else if (FName.startswith("NSLog")) { 385 return getDoNothingSummary(); 386 } else if (FName.startswith("NS") && 387 (FName.find("Insert") != StringRef::npos)) { 388 // Whitelist NSXXInsertXX, for example NSMapInsertIfAbsent, since they can 389 // be deallocated by NSMapRemove. (radar://11152419) 390 ScratchArgs = AF.add(ScratchArgs, 1, ArgEffect(StopTracking)); 391 ScratchArgs = AF.add(ScratchArgs, 2, ArgEffect(StopTracking)); 392 return getPersistentSummary(RetEffect::MakeNoRet(), 393 ScratchArgs, ArgEffect(DoNothing), 394 ArgEffect(DoNothing)); 395 } 396 397 if (RetTy->isPointerType()) { 398 399 // For CoreFoundation ('CF') types. 400 if (cocoa::isRefType(RetTy, "CF", FName)) { 401 if (isRetain(FD, FName)) { 402 // CFRetain isn't supposed to be annotated. However, this may as 403 // well be a user-made "safe" CFRetain function that is incorrectly 404 // annotated as cf_returns_retained due to lack of better options. 405 // We want to ignore such annotation. 406 AllowAnnotations = false; 407 408 return getUnarySummary(FT, IncRef); 409 } else if (isAutorelease(FD, FName)) { 410 // The headers use cf_consumed, but we can fully model CFAutorelease 411 // ourselves. 412 AllowAnnotations = false; 413 414 return getUnarySummary(FT, Autorelease); 415 } else if (isMakeCollectable(FName)) { 416 AllowAnnotations = false; 417 return getUnarySummary(FT, DoNothing); 418 } else { 419 return getCFCreateGetRuleSummary(FD); 420 } 421 } 422 423 // For CoreGraphics ('CG') and CoreVideo ('CV') types. 424 if (cocoa::isRefType(RetTy, "CG", FName) || 425 cocoa::isRefType(RetTy, "CV", FName)) { 426 if (isRetain(FD, FName)) 427 return getUnarySummary(FT, IncRef); 428 else 429 return getCFCreateGetRuleSummary(FD); 430 } 431 432 // For all other CF-style types, use the Create/Get 433 // rule for summaries but don't support Retain functions 434 // with framework-specific prefixes. 435 if (coreFoundation::isCFObjectRef(RetTy)) { 436 return getCFCreateGetRuleSummary(FD); 437 } 438 439 if (FD->hasAttr<CFAuditedTransferAttr>()) { 440 return getCFCreateGetRuleSummary(FD); 441 } 442 } 443 444 // Check for release functions, the only kind of functions that we care 445 // about that don't return a pointer type. 446 if (FName.startswith("CG") || FName.startswith("CF")) { 447 // Test for 'CGCF'. 448 FName = FName.substr(FName.startswith("CGCF") ? 4 : 2); 449 450 if (isRelease(FD, FName)) 451 return getUnarySummary(FT, DecRef); 452 else { 453 assert(ScratchArgs.isEmpty()); 454 // Remaining CoreFoundation and CoreGraphics functions. 455 // We use to assume that they all strictly followed the ownership idiom 456 // and that ownership cannot be transferred. While this is technically 457 // correct, many methods allow a tracked object to escape. For example: 458 // 459 // CFMutableDictionaryRef x = CFDictionaryCreateMutable(...); 460 // CFDictionaryAddValue(y, key, x); 461 // CFRelease(x); 462 // ... it is okay to use 'x' since 'y' has a reference to it 463 // 464 // We handle this and similar cases with the follow heuristic. If the 465 // function name contains "InsertValue", "SetValue", "AddValue", 466 // "AppendValue", or "SetAttribute", then we assume that arguments may 467 // "escape." This means that something else holds on to the object, 468 // allowing it be used even after its local retain count drops to 0. 469 ArgEffectKind E = 470 (StrInStrNoCase(FName, "InsertValue") != StringRef::npos || 471 StrInStrNoCase(FName, "AddValue") != StringRef::npos || 472 StrInStrNoCase(FName, "SetValue") != StringRef::npos || 473 StrInStrNoCase(FName, "AppendValue") != StringRef::npos || 474 StrInStrNoCase(FName, "SetAttribute") != StringRef::npos) 475 ? MayEscape 476 : DoNothing; 477 478 return getPersistentSummary(RetEffect::MakeNoRet(), ScratchArgs, 479 ArgEffect(DoNothing), ArgEffect(E, ObjKind::CF)); 480 } 481 } 482 483 return nullptr; 484 } 485 486 const RetainSummary * 487 RetainSummaryManager::generateSummary(const FunctionDecl *FD, 488 bool &AllowAnnotations) { 489 // We generate "stop" summaries for implicitly defined functions. 490 if (FD->isImplicit()) 491 return getPersistentStopSummary(); 492 493 const IdentifierInfo *II = FD->getIdentifier(); 494 495 StringRef FName = II ? II->getName() : ""; 496 497 // Strip away preceding '_'. Doing this here will effect all the checks 498 // down below. 499 FName = FName.substr(FName.find_first_not_of('_')); 500 501 // Inspect the result type. Strip away any typedefs. 502 const auto *FT = FD->getType()->getAs<FunctionType>(); 503 QualType RetTy = FT->getReturnType(); 504 505 if (TrackOSObjects) 506 if (const RetainSummary *S = getSummaryForOSObject(FD, FName, RetTy)) 507 return S; 508 509 if (const auto *MD = dyn_cast<CXXMethodDecl>(FD)) 510 if (!isOSObjectRelated(MD)) 511 return getPersistentSummary(RetEffect::MakeNoRet(), 512 ArgEffects(AF.getEmptyMap()), 513 ArgEffect(DoNothing), 514 ArgEffect(StopTracking), 515 ArgEffect(DoNothing)); 516 517 if (TrackObjCAndCFObjects) 518 if (const RetainSummary *S = 519 getSummaryForObjCOrCFObject(FD, FName, RetTy, FT, AllowAnnotations)) 520 return S; 521 522 return getDefaultSummary(); 523 } 524 525 const RetainSummary * 526 RetainSummaryManager::getFunctionSummary(const FunctionDecl *FD) { 527 // If we don't know what function we're calling, use our default summary. 528 if (!FD) 529 return getDefaultSummary(); 530 531 // Look up a summary in our cache of FunctionDecls -> Summaries. 532 FuncSummariesTy::iterator I = FuncSummaries.find(FD); 533 if (I != FuncSummaries.end()) 534 return I->second; 535 536 // No summary? Generate one. 537 bool AllowAnnotations = true; 538 const RetainSummary *S = generateSummary(FD, AllowAnnotations); 539 540 // Annotations override defaults. 541 if (AllowAnnotations) 542 updateSummaryFromAnnotations(S, FD); 543 544 FuncSummaries[FD] = S; 545 return S; 546 } 547 548 //===----------------------------------------------------------------------===// 549 // Summary creation for functions (largely uses of Core Foundation). 550 //===----------------------------------------------------------------------===// 551 552 static ArgEffect getStopTrackingHardEquivalent(ArgEffect E) { 553 switch (E.getKind()) { 554 case DoNothing: 555 case Autorelease: 556 case DecRefBridgedTransferred: 557 case IncRef: 558 case UnretainedOutParameter: 559 case RetainedOutParameter: 560 case RetainedOutParameterOnZero: 561 case RetainedOutParameterOnNonZero: 562 case MayEscape: 563 case StopTracking: 564 case StopTrackingHard: 565 return E.withKind(StopTrackingHard); 566 case DecRef: 567 case DecRefAndStopTrackingHard: 568 return E.withKind(DecRefAndStopTrackingHard); 569 case Dealloc: 570 return E.withKind(Dealloc); 571 } 572 573 llvm_unreachable("Unknown ArgEffect kind"); 574 } 575 576 const RetainSummary * 577 RetainSummaryManager::updateSummaryForNonZeroCallbackArg(const RetainSummary *S, 578 AnyCall &C) { 579 ArgEffect RecEffect = getStopTrackingHardEquivalent(S->getReceiverEffect()); 580 ArgEffect DefEffect = getStopTrackingHardEquivalent(S->getDefaultArgEffect()); 581 582 ArgEffects ScratchArgs(AF.getEmptyMap()); 583 ArgEffects CustomArgEffects = S->getArgEffects(); 584 for (ArgEffects::iterator I = CustomArgEffects.begin(), 585 E = CustomArgEffects.end(); 586 I != E; ++I) { 587 ArgEffect Translated = getStopTrackingHardEquivalent(I->second); 588 if (Translated.getKind() != DefEffect.getKind()) 589 ScratchArgs = AF.add(ScratchArgs, I->first, Translated); 590 } 591 592 RetEffect RE = RetEffect::MakeNoRetHard(); 593 594 // Special cases where the callback argument CANNOT free the return value. 595 // This can generally only happen if we know that the callback will only be 596 // called when the return value is already being deallocated. 597 if (const IdentifierInfo *Name = C.getIdentifier()) { 598 // When the CGBitmapContext is deallocated, the callback here will free 599 // the associated data buffer. 600 // The callback in dispatch_data_create frees the buffer, but not 601 // the data object. 602 if (Name->isStr("CGBitmapContextCreateWithData") || 603 Name->isStr("dispatch_data_create")) 604 RE = S->getRetEffect(); 605 } 606 607 return getPersistentSummary(RE, ScratchArgs, RecEffect, DefEffect); 608 } 609 610 void RetainSummaryManager::updateSummaryForReceiverUnconsumedSelf( 611 const RetainSummary *&S) { 612 613 RetainSummaryTemplate Template(S, *this); 614 615 Template->setReceiverEffect(ArgEffect(DoNothing)); 616 Template->setRetEffect(RetEffect::MakeNoRet()); 617 } 618 619 620 void RetainSummaryManager::updateSummaryForArgumentTypes( 621 const AnyCall &C, const RetainSummary *&RS) { 622 RetainSummaryTemplate Template(RS, *this); 623 624 unsigned parm_idx = 0; 625 for (auto pi = C.param_begin(), pe = C.param_end(); pi != pe; 626 ++pi, ++parm_idx) { 627 QualType QT = (*pi)->getType(); 628 629 // Skip already created values. 630 if (RS->getArgEffects().contains(parm_idx)) 631 continue; 632 633 ObjKind K = ObjKind::AnyObj; 634 635 if (isISLObjectRef(QT)) { 636 K = ObjKind::Generalized; 637 } else if (isOSObjectPtr(QT)) { 638 K = ObjKind::OS; 639 } else if (cocoa::isCocoaObjectRef(QT)) { 640 K = ObjKind::ObjC; 641 } else if (coreFoundation::isCFObjectRef(QT)) { 642 K = ObjKind::CF; 643 } 644 645 if (K != ObjKind::AnyObj) 646 Template->addArg(AF, parm_idx, 647 ArgEffect(RS->getDefaultArgEffect().getKind(), K)); 648 } 649 } 650 651 const RetainSummary * 652 RetainSummaryManager::getSummary(AnyCall C, 653 bool HasNonZeroCallbackArg, 654 bool IsReceiverUnconsumedSelf, 655 QualType ReceiverType) { 656 const RetainSummary *Summ; 657 switch (C.getKind()) { 658 case AnyCall::Function: 659 case AnyCall::Constructor: 660 case AnyCall::Allocator: 661 case AnyCall::Deallocator: 662 Summ = getFunctionSummary(cast_or_null<FunctionDecl>(C.getDecl())); 663 break; 664 case AnyCall::Block: 665 case AnyCall::Destructor: 666 // FIXME: These calls are currently unsupported. 667 return getPersistentStopSummary(); 668 case AnyCall::ObjCMethod: { 669 const auto *ME = cast_or_null<ObjCMessageExpr>(C.getExpr()); 670 if (!ME) { 671 Summ = getMethodSummary(cast<ObjCMethodDecl>(C.getDecl())); 672 } else if (ME->isInstanceMessage()) { 673 Summ = getInstanceMethodSummary(ME, ReceiverType); 674 } else { 675 Summ = getClassMethodSummary(ME); 676 } 677 break; 678 } 679 } 680 681 if (HasNonZeroCallbackArg) 682 Summ = updateSummaryForNonZeroCallbackArg(Summ, C); 683 684 if (IsReceiverUnconsumedSelf) 685 updateSummaryForReceiverUnconsumedSelf(Summ); 686 687 updateSummaryForArgumentTypes(C, Summ); 688 689 assert(Summ && "Unknown call type?"); 690 return Summ; 691 } 692 693 694 const RetainSummary * 695 RetainSummaryManager::getCFCreateGetRuleSummary(const FunctionDecl *FD) { 696 if (coreFoundation::followsCreateRule(FD)) 697 return getCFSummaryCreateRule(FD); 698 699 return getCFSummaryGetRule(FD); 700 } 701 702 bool RetainSummaryManager::isTrustedReferenceCountImplementation( 703 const Decl *FD) { 704 return hasRCAnnotation(FD, "rc_ownership_trusted_implementation"); 705 } 706 707 Optional<RetainSummaryManager::BehaviorSummary> 708 RetainSummaryManager::canEval(const CallExpr *CE, const FunctionDecl *FD, 709 bool &hasTrustedImplementationAnnotation) { 710 711 IdentifierInfo *II = FD->getIdentifier(); 712 if (!II) 713 return None; 714 715 StringRef FName = II->getName(); 716 FName = FName.substr(FName.find_first_not_of('_')); 717 718 QualType ResultTy = CE->getCallReturnType(Ctx); 719 if (ResultTy->isObjCIdType()) { 720 if (II->isStr("NSMakeCollectable")) 721 return BehaviorSummary::Identity; 722 } else if (ResultTy->isPointerType()) { 723 // Handle: (CF|CG|CV)Retain 724 // CFAutorelease 725 // It's okay to be a little sloppy here. 726 if (FName == "CMBufferQueueDequeueAndRetain" || 727 FName == "CMBufferQueueDequeueIfDataReadyAndRetain") { 728 // Part of: <rdar://problem/39390714>. 729 // These are not retain. They just return something and retain it. 730 return None; 731 } 732 if (CE->getNumArgs() == 1 && 733 (cocoa::isRefType(ResultTy, "CF", FName) || 734 cocoa::isRefType(ResultTy, "CG", FName) || 735 cocoa::isRefType(ResultTy, "CV", FName)) && 736 (isRetain(FD, FName) || isAutorelease(FD, FName) || 737 isMakeCollectable(FName))) 738 return BehaviorSummary::Identity; 739 740 // safeMetaCast is called by OSDynamicCast. 741 // We assume that OSDynamicCast is either an identity (cast is OK, 742 // the input was non-zero), 743 // or that it returns zero (when the cast failed, or the input 744 // was zero). 745 if (TrackOSObjects) { 746 if (isOSObjectDynamicCast(FName) && FD->param_size() >= 1) { 747 return BehaviorSummary::IdentityOrZero; 748 } else if (isOSObjectThisCast(FName) && isa<CXXMethodDecl>(FD) && 749 !cast<CXXMethodDecl>(FD)->isStatic()) { 750 return BehaviorSummary::IdentityThis; 751 } 752 } 753 754 const FunctionDecl* FDD = FD->getDefinition(); 755 if (FDD && isTrustedReferenceCountImplementation(FDD)) { 756 hasTrustedImplementationAnnotation = true; 757 return BehaviorSummary::Identity; 758 } 759 } 760 761 if (const auto *MD = dyn_cast<CXXMethodDecl>(FD)) { 762 const CXXRecordDecl *Parent = MD->getParent(); 763 if (TrackOSObjects && Parent && isOSObjectSubclass(Parent)) 764 if (FName == "release" || FName == "retain") 765 return BehaviorSummary::NoOp; 766 } 767 768 return None; 769 } 770 771 const RetainSummary * 772 RetainSummaryManager::getUnarySummary(const FunctionType* FT, 773 ArgEffectKind AE) { 774 775 // Unary functions have no arg effects by definition. 776 ArgEffects ScratchArgs(AF.getEmptyMap()); 777 778 // Sanity check that this is *really* a unary function. This can 779 // happen if people do weird things. 780 const FunctionProtoType* FTP = dyn_cast<FunctionProtoType>(FT); 781 if (!FTP || FTP->getNumParams() != 1) 782 return getPersistentStopSummary(); 783 784 ArgEffect Effect(AE, ObjKind::CF); 785 786 ScratchArgs = AF.add(ScratchArgs, 0, Effect); 787 return getPersistentSummary(RetEffect::MakeNoRet(), 788 ScratchArgs, 789 ArgEffect(DoNothing), ArgEffect(DoNothing)); 790 } 791 792 const RetainSummary * 793 RetainSummaryManager::getOSSummaryRetainRule(const FunctionDecl *FD) { 794 return getPersistentSummary(RetEffect::MakeNoRet(), 795 AF.getEmptyMap(), 796 /*ReceiverEff=*/ArgEffect(DoNothing), 797 /*DefaultEff=*/ArgEffect(DoNothing), 798 /*ThisEff=*/ArgEffect(IncRef, ObjKind::OS)); 799 } 800 801 const RetainSummary * 802 RetainSummaryManager::getOSSummaryReleaseRule(const FunctionDecl *FD) { 803 return getPersistentSummary(RetEffect::MakeNoRet(), 804 AF.getEmptyMap(), 805 /*ReceiverEff=*/ArgEffect(DoNothing), 806 /*DefaultEff=*/ArgEffect(DoNothing), 807 /*ThisEff=*/ArgEffect(DecRef, ObjKind::OS)); 808 } 809 810 const RetainSummary * 811 RetainSummaryManager::getOSSummaryFreeRule(const FunctionDecl *FD) { 812 return getPersistentSummary(RetEffect::MakeNoRet(), 813 AF.getEmptyMap(), 814 /*ReceiverEff=*/ArgEffect(DoNothing), 815 /*DefaultEff=*/ArgEffect(DoNothing), 816 /*ThisEff=*/ArgEffect(Dealloc, ObjKind::OS)); 817 } 818 819 const RetainSummary * 820 RetainSummaryManager::getOSSummaryCreateRule(const FunctionDecl *FD) { 821 return getPersistentSummary(RetEffect::MakeOwned(ObjKind::OS), 822 AF.getEmptyMap()); 823 } 824 825 const RetainSummary * 826 RetainSummaryManager::getOSSummaryGetRule(const FunctionDecl *FD) { 827 return getPersistentSummary(RetEffect::MakeNotOwned(ObjKind::OS), 828 AF.getEmptyMap()); 829 } 830 831 const RetainSummary * 832 RetainSummaryManager::getCFSummaryCreateRule(const FunctionDecl *FD) { 833 return getPersistentSummary(RetEffect::MakeOwned(ObjKind::CF), 834 ArgEffects(AF.getEmptyMap())); 835 } 836 837 const RetainSummary * 838 RetainSummaryManager::getCFSummaryGetRule(const FunctionDecl *FD) { 839 return getPersistentSummary(RetEffect::MakeNotOwned(ObjKind::CF), 840 ArgEffects(AF.getEmptyMap()), 841 ArgEffect(DoNothing), ArgEffect(DoNothing)); 842 } 843 844 845 846 847 //===----------------------------------------------------------------------===// 848 // Summary creation for Selectors. 849 //===----------------------------------------------------------------------===// 850 851 Optional<RetEffect> 852 RetainSummaryManager::getRetEffectFromAnnotations(QualType RetTy, 853 const Decl *D) { 854 if (hasAnyEnabledAttrOf<NSReturnsRetainedAttr>(D, RetTy)) 855 return ObjCAllocRetE; 856 857 if (auto K = hasAnyEnabledAttrOf<CFReturnsRetainedAttr, OSReturnsRetainedAttr, 858 GeneralizedReturnsRetainedAttr>(D, RetTy)) 859 return RetEffect::MakeOwned(*K); 860 861 if (auto K = hasAnyEnabledAttrOf< 862 CFReturnsNotRetainedAttr, OSReturnsNotRetainedAttr, 863 GeneralizedReturnsNotRetainedAttr, NSReturnsNotRetainedAttr, 864 NSReturnsAutoreleasedAttr>(D, RetTy)) 865 return RetEffect::MakeNotOwned(*K); 866 867 if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) 868 for (const auto *PD : MD->overridden_methods()) 869 if (auto RE = getRetEffectFromAnnotations(RetTy, PD)) 870 return RE; 871 872 return None; 873 } 874 875 /// \return Whether the chain of typedefs starting from {@code QT} 876 /// has a typedef with a given name {@code Name}. 877 static bool hasTypedefNamed(QualType QT, 878 StringRef Name) { 879 while (auto *T = dyn_cast<TypedefType>(QT)) { 880 const auto &Context = T->getDecl()->getASTContext(); 881 if (T->getDecl()->getIdentifier() == &Context.Idents.get(Name)) 882 return true; 883 QT = T->getDecl()->getUnderlyingType(); 884 } 885 return false; 886 } 887 888 static QualType getCallableReturnType(const NamedDecl *ND) { 889 if (const auto *FD = dyn_cast<FunctionDecl>(ND)) { 890 return FD->getReturnType(); 891 } else if (const auto *MD = dyn_cast<ObjCMethodDecl>(ND)) { 892 return MD->getReturnType(); 893 } else { 894 llvm_unreachable("Unexpected decl"); 895 } 896 } 897 898 bool RetainSummaryManager::applyParamAnnotationEffect( 899 const ParmVarDecl *pd, unsigned parm_idx, const NamedDecl *FD, 900 RetainSummaryTemplate &Template) { 901 QualType QT = pd->getType(); 902 if (auto K = 903 hasAnyEnabledAttrOf<NSConsumedAttr, CFConsumedAttr, OSConsumedAttr, 904 GeneralizedConsumedAttr>(pd, QT)) { 905 Template->addArg(AF, parm_idx, ArgEffect(DecRef, *K)); 906 return true; 907 } else if (auto K = hasAnyEnabledAttrOf< 908 CFReturnsRetainedAttr, OSReturnsRetainedAttr, 909 OSReturnsRetainedOnNonZeroAttr, OSReturnsRetainedOnZeroAttr, 910 GeneralizedReturnsRetainedAttr>(pd, QT)) { 911 912 // For OSObjects, we try to guess whether the object is created based 913 // on the return value. 914 if (K == ObjKind::OS) { 915 QualType QT = getCallableReturnType(FD); 916 917 bool HasRetainedOnZero = pd->hasAttr<OSReturnsRetainedOnZeroAttr>(); 918 bool HasRetainedOnNonZero = pd->hasAttr<OSReturnsRetainedOnNonZeroAttr>(); 919 920 // The usual convention is to create an object on non-zero return, but 921 // it's reverted if the typedef chain has a typedef kern_return_t, 922 // because kReturnSuccess constant is defined as zero. 923 // The convention can be overwritten by custom attributes. 924 bool SuccessOnZero = 925 HasRetainedOnZero || 926 (hasTypedefNamed(QT, "kern_return_t") && !HasRetainedOnNonZero); 927 bool ShouldSplit = !QT.isNull() && !QT->isVoidType(); 928 ArgEffectKind AK = RetainedOutParameter; 929 if (ShouldSplit && SuccessOnZero) { 930 AK = RetainedOutParameterOnZero; 931 } else if (ShouldSplit && (!SuccessOnZero || HasRetainedOnNonZero)) { 932 AK = RetainedOutParameterOnNonZero; 933 } 934 Template->addArg(AF, parm_idx, ArgEffect(AK, ObjKind::OS)); 935 } 936 937 // For others: 938 // Do nothing. Retained out parameters will either point to a +1 reference 939 // or NULL, but the way you check for failure differs depending on the 940 // API. Consequently, we don't have a good way to track them yet. 941 return true; 942 } else if (auto K = hasAnyEnabledAttrOf<CFReturnsNotRetainedAttr, 943 OSReturnsNotRetainedAttr, 944 GeneralizedReturnsNotRetainedAttr>( 945 pd, QT)) { 946 Template->addArg(AF, parm_idx, ArgEffect(UnretainedOutParameter, *K)); 947 return true; 948 } 949 950 if (const auto *MD = dyn_cast<CXXMethodDecl>(FD)) { 951 for (const auto *OD : MD->overridden_methods()) { 952 const ParmVarDecl *OP = OD->parameters()[parm_idx]; 953 if (applyParamAnnotationEffect(OP, parm_idx, OD, Template)) 954 return true; 955 } 956 } 957 958 return false; 959 } 960 961 void 962 RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ, 963 const FunctionDecl *FD) { 964 if (!FD) 965 return; 966 967 assert(Summ && "Must have a summary to add annotations to."); 968 RetainSummaryTemplate Template(Summ, *this); 969 970 // Effects on the parameters. 971 unsigned parm_idx = 0; 972 for (auto pi = FD->param_begin(), 973 pe = FD->param_end(); pi != pe; ++pi, ++parm_idx) 974 applyParamAnnotationEffect(*pi, parm_idx, FD, Template); 975 976 QualType RetTy = FD->getReturnType(); 977 if (Optional<RetEffect> RetE = getRetEffectFromAnnotations(RetTy, FD)) 978 Template->setRetEffect(*RetE); 979 980 if (hasAnyEnabledAttrOf<OSConsumesThisAttr>(FD, RetTy)) 981 Template->setThisEffect(ArgEffect(DecRef, ObjKind::OS)); 982 } 983 984 void 985 RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ, 986 const ObjCMethodDecl *MD) { 987 if (!MD) 988 return; 989 990 assert(Summ && "Must have a valid summary to add annotations to"); 991 RetainSummaryTemplate Template(Summ, *this); 992 993 // Effects on the receiver. 994 if (hasAnyEnabledAttrOf<NSConsumesSelfAttr>(MD, MD->getReturnType())) 995 Template->setReceiverEffect(ArgEffect(DecRef, ObjKind::ObjC)); 996 997 // Effects on the parameters. 998 unsigned parm_idx = 0; 999 for (auto pi = MD->param_begin(), pe = MD->param_end(); pi != pe; 1000 ++pi, ++parm_idx) 1001 applyParamAnnotationEffect(*pi, parm_idx, MD, Template); 1002 1003 QualType RetTy = MD->getReturnType(); 1004 if (Optional<RetEffect> RetE = getRetEffectFromAnnotations(RetTy, MD)) 1005 Template->setRetEffect(*RetE); 1006 } 1007 1008 const RetainSummary * 1009 RetainSummaryManager::getStandardMethodSummary(const ObjCMethodDecl *MD, 1010 Selector S, QualType RetTy) { 1011 // Any special effects? 1012 ArgEffect ReceiverEff = ArgEffect(DoNothing, ObjKind::ObjC); 1013 RetEffect ResultEff = RetEffect::MakeNoRet(); 1014 1015 // Check the method family, and apply any default annotations. 1016 switch (MD ? MD->getMethodFamily() : S.getMethodFamily()) { 1017 case OMF_None: 1018 case OMF_initialize: 1019 case OMF_performSelector: 1020 // Assume all Objective-C methods follow Cocoa Memory Management rules. 1021 // FIXME: Does the non-threaded performSelector family really belong here? 1022 // The selector could be, say, @selector(copy). 1023 if (cocoa::isCocoaObjectRef(RetTy)) 1024 ResultEff = RetEffect::MakeNotOwned(ObjKind::ObjC); 1025 else if (coreFoundation::isCFObjectRef(RetTy)) { 1026 // ObjCMethodDecl currently doesn't consider CF objects as valid return 1027 // values for alloc, new, copy, or mutableCopy, so we have to 1028 // double-check with the selector. This is ugly, but there aren't that 1029 // many Objective-C methods that return CF objects, right? 1030 if (MD) { 1031 switch (S.getMethodFamily()) { 1032 case OMF_alloc: 1033 case OMF_new: 1034 case OMF_copy: 1035 case OMF_mutableCopy: 1036 ResultEff = RetEffect::MakeOwned(ObjKind::CF); 1037 break; 1038 default: 1039 ResultEff = RetEffect::MakeNotOwned(ObjKind::CF); 1040 break; 1041 } 1042 } else { 1043 ResultEff = RetEffect::MakeNotOwned(ObjKind::CF); 1044 } 1045 } 1046 break; 1047 case OMF_init: 1048 ResultEff = ObjCInitRetE; 1049 ReceiverEff = ArgEffect(DecRef, ObjKind::ObjC); 1050 break; 1051 case OMF_alloc: 1052 case OMF_new: 1053 case OMF_copy: 1054 case OMF_mutableCopy: 1055 if (cocoa::isCocoaObjectRef(RetTy)) 1056 ResultEff = ObjCAllocRetE; 1057 else if (coreFoundation::isCFObjectRef(RetTy)) 1058 ResultEff = RetEffect::MakeOwned(ObjKind::CF); 1059 break; 1060 case OMF_autorelease: 1061 ReceiverEff = ArgEffect(Autorelease, ObjKind::ObjC); 1062 break; 1063 case OMF_retain: 1064 ReceiverEff = ArgEffect(IncRef, ObjKind::ObjC); 1065 break; 1066 case OMF_release: 1067 ReceiverEff = ArgEffect(DecRef, ObjKind::ObjC); 1068 break; 1069 case OMF_dealloc: 1070 ReceiverEff = ArgEffect(Dealloc, ObjKind::ObjC); 1071 break; 1072 case OMF_self: 1073 // -self is handled specially by the ExprEngine to propagate the receiver. 1074 break; 1075 case OMF_retainCount: 1076 case OMF_finalize: 1077 // These methods don't return objects. 1078 break; 1079 } 1080 1081 // If one of the arguments in the selector has the keyword 'delegate' we 1082 // should stop tracking the reference count for the receiver. This is 1083 // because the reference count is quite possibly handled by a delegate 1084 // method. 1085 if (S.isKeywordSelector()) { 1086 for (unsigned i = 0, e = S.getNumArgs(); i != e; ++i) { 1087 StringRef Slot = S.getNameForSlot(i); 1088 if (Slot.substr(Slot.size() - 8).equals_lower("delegate")) { 1089 if (ResultEff == ObjCInitRetE) 1090 ResultEff = RetEffect::MakeNoRetHard(); 1091 else 1092 ReceiverEff = ArgEffect(StopTrackingHard, ObjKind::ObjC); 1093 } 1094 } 1095 } 1096 1097 if (ReceiverEff.getKind() == DoNothing && 1098 ResultEff.getKind() == RetEffect::NoRet) 1099 return getDefaultSummary(); 1100 1101 return getPersistentSummary(ResultEff, ArgEffects(AF.getEmptyMap()), 1102 ArgEffect(ReceiverEff), ArgEffect(MayEscape)); 1103 } 1104 1105 const RetainSummary * 1106 RetainSummaryManager::getClassMethodSummary(const ObjCMessageExpr *ME) { 1107 assert(!ME->isInstanceMessage()); 1108 const ObjCInterfaceDecl *Class = ME->getReceiverInterface(); 1109 1110 return getMethodSummary(ME->getSelector(), Class, ME->getMethodDecl(), 1111 ME->getType(), ObjCClassMethodSummaries); 1112 } 1113 1114 const RetainSummary *RetainSummaryManager::getInstanceMethodSummary( 1115 const ObjCMessageExpr *ME, 1116 QualType ReceiverType) { 1117 const ObjCInterfaceDecl *ReceiverClass = nullptr; 1118 1119 // We do better tracking of the type of the object than the core ExprEngine. 1120 // See if we have its type in our private state. 1121 if (!ReceiverType.isNull()) 1122 if (const auto *PT = ReceiverType->getAs<ObjCObjectPointerType>()) 1123 ReceiverClass = PT->getInterfaceDecl(); 1124 1125 // If we don't know what kind of object this is, fall back to its static type. 1126 if (!ReceiverClass) 1127 ReceiverClass = ME->getReceiverInterface(); 1128 1129 // FIXME: The receiver could be a reference to a class, meaning that 1130 // we should use the class method. 1131 // id x = [NSObject class]; 1132 // [x performSelector:... withObject:... afterDelay:...]; 1133 Selector S = ME->getSelector(); 1134 const ObjCMethodDecl *Method = ME->getMethodDecl(); 1135 if (!Method && ReceiverClass) 1136 Method = ReceiverClass->getInstanceMethod(S); 1137 1138 return getMethodSummary(S, ReceiverClass, Method, ME->getType(), 1139 ObjCMethodSummaries); 1140 } 1141 1142 const RetainSummary * 1143 RetainSummaryManager::getMethodSummary(Selector S, 1144 const ObjCInterfaceDecl *ID, 1145 const ObjCMethodDecl *MD, QualType RetTy, 1146 ObjCMethodSummariesTy &CachedSummaries) { 1147 1148 // Objective-C method summaries are only applicable to ObjC and CF objects. 1149 if (!TrackObjCAndCFObjects) 1150 return getDefaultSummary(); 1151 1152 // Look up a summary in our summary cache. 1153 const RetainSummary *Summ = CachedSummaries.find(ID, S); 1154 1155 if (!Summ) { 1156 Summ = getStandardMethodSummary(MD, S, RetTy); 1157 1158 // Annotations override defaults. 1159 updateSummaryFromAnnotations(Summ, MD); 1160 1161 // Memoize the summary. 1162 CachedSummaries[ObjCSummaryKey(ID, S)] = Summ; 1163 } 1164 1165 return Summ; 1166 } 1167 1168 void RetainSummaryManager::InitializeClassMethodSummaries() { 1169 ArgEffects ScratchArgs = AF.getEmptyMap(); 1170 1171 // Create the [NSAssertionHandler currentHander] summary. 1172 addClassMethSummary("NSAssertionHandler", "currentHandler", 1173 getPersistentSummary(RetEffect::MakeNotOwned(ObjKind::ObjC), 1174 ScratchArgs)); 1175 1176 // Create the [NSAutoreleasePool addObject:] summary. 1177 ScratchArgs = AF.add(ScratchArgs, 0, ArgEffect(Autorelease)); 1178 addClassMethSummary("NSAutoreleasePool", "addObject", 1179 getPersistentSummary(RetEffect::MakeNoRet(), ScratchArgs, 1180 ArgEffect(DoNothing), 1181 ArgEffect(Autorelease))); 1182 } 1183 1184 void RetainSummaryManager::InitializeMethodSummaries() { 1185 1186 ArgEffects ScratchArgs = AF.getEmptyMap(); 1187 // Create the "init" selector. It just acts as a pass-through for the 1188 // receiver. 1189 const RetainSummary *InitSumm = getPersistentSummary( 1190 ObjCInitRetE, ScratchArgs, ArgEffect(DecRef, ObjKind::ObjC)); 1191 addNSObjectMethSummary(GetNullarySelector("init", Ctx), InitSumm); 1192 1193 // awakeAfterUsingCoder: behaves basically like an 'init' method. It 1194 // claims the receiver and returns a retained object. 1195 addNSObjectMethSummary(GetUnarySelector("awakeAfterUsingCoder", Ctx), 1196 InitSumm); 1197 1198 // The next methods are allocators. 1199 const RetainSummary *AllocSumm = getPersistentSummary(ObjCAllocRetE, 1200 ScratchArgs); 1201 const RetainSummary *CFAllocSumm = 1202 getPersistentSummary(RetEffect::MakeOwned(ObjKind::CF), ScratchArgs); 1203 1204 // Create the "retain" selector. 1205 RetEffect NoRet = RetEffect::MakeNoRet(); 1206 const RetainSummary *Summ = getPersistentSummary( 1207 NoRet, ScratchArgs, ArgEffect(IncRef, ObjKind::ObjC)); 1208 addNSObjectMethSummary(GetNullarySelector("retain", Ctx), Summ); 1209 1210 // Create the "release" selector. 1211 Summ = getPersistentSummary(NoRet, ScratchArgs, 1212 ArgEffect(DecRef, ObjKind::ObjC)); 1213 addNSObjectMethSummary(GetNullarySelector("release", Ctx), Summ); 1214 1215 // Create the -dealloc summary. 1216 Summ = getPersistentSummary(NoRet, ScratchArgs, ArgEffect(Dealloc, 1217 ObjKind::ObjC)); 1218 addNSObjectMethSummary(GetNullarySelector("dealloc", Ctx), Summ); 1219 1220 // Create the "autorelease" selector. 1221 Summ = getPersistentSummary(NoRet, ScratchArgs, ArgEffect(Autorelease, 1222 ObjKind::ObjC)); 1223 addNSObjectMethSummary(GetNullarySelector("autorelease", Ctx), Summ); 1224 1225 // For NSWindow, allocated objects are (initially) self-owned. 1226 // FIXME: For now we opt for false negatives with NSWindow, as these objects 1227 // self-own themselves. However, they only do this once they are displayed. 1228 // Thus, we need to track an NSWindow's display status. 1229 // This is tracked in <rdar://problem/6062711>. 1230 // See also http://llvm.org/bugs/show_bug.cgi?id=3714. 1231 const RetainSummary *NoTrackYet = 1232 getPersistentSummary(RetEffect::MakeNoRet(), ScratchArgs, 1233 ArgEffect(StopTracking), ArgEffect(StopTracking)); 1234 1235 addClassMethSummary("NSWindow", "alloc", NoTrackYet); 1236 1237 // For NSPanel (which subclasses NSWindow), allocated objects are not 1238 // self-owned. 1239 // FIXME: For now we don't track NSPanels. object for the same reason 1240 // as for NSWindow objects. 1241 addClassMethSummary("NSPanel", "alloc", NoTrackYet); 1242 1243 // For NSNull, objects returned by +null are singletons that ignore 1244 // retain/release semantics. Just don't track them. 1245 // <rdar://problem/12858915> 1246 addClassMethSummary("NSNull", "null", NoTrackYet); 1247 1248 // Don't track allocated autorelease pools, as it is okay to prematurely 1249 // exit a method. 1250 addClassMethSummary("NSAutoreleasePool", "alloc", NoTrackYet); 1251 addClassMethSummary("NSAutoreleasePool", "allocWithZone", NoTrackYet, false); 1252 addClassMethSummary("NSAutoreleasePool", "new", NoTrackYet); 1253 1254 // Create summaries QCRenderer/QCView -createSnapShotImageOfType: 1255 addInstMethSummary("QCRenderer", AllocSumm, "createSnapshotImageOfType"); 1256 addInstMethSummary("QCView", AllocSumm, "createSnapshotImageOfType"); 1257 1258 // Create summaries for CIContext, 'createCGImage' and 1259 // 'createCGLayerWithSize'. These objects are CF objects, and are not 1260 // automatically garbage collected. 1261 addInstMethSummary("CIContext", CFAllocSumm, "createCGImage", "fromRect"); 1262 addInstMethSummary("CIContext", CFAllocSumm, "createCGImage", "fromRect", 1263 "format", "colorSpace"); 1264 addInstMethSummary("CIContext", CFAllocSumm, "createCGLayerWithSize", "info"); 1265 } 1266 1267 const RetainSummary * 1268 RetainSummaryManager::getMethodSummary(const ObjCMethodDecl *MD) { 1269 const ObjCInterfaceDecl *ID = MD->getClassInterface(); 1270 Selector S = MD->getSelector(); 1271 QualType ResultTy = MD->getReturnType(); 1272 1273 ObjCMethodSummariesTy *CachedSummaries; 1274 if (MD->isInstanceMethod()) 1275 CachedSummaries = &ObjCMethodSummaries; 1276 else 1277 CachedSummaries = &ObjCClassMethodSummaries; 1278 1279 return getMethodSummary(S, ID, MD, ResultTy, *CachedSummaries); 1280 } 1281