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