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