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