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