Path: blob/main/contrib/llvm-project/clang/lib/Analysis/RetainSummaryManager.cpp
35233 views
//== RetainSummaryManager.cpp - Summaries for reference counting --*- C++ -*--//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file defines summaries implementation for retain counting, which9// implements a reference count checker for Core Foundation, Cocoa10// and OSObject (on Mac OS X).11//12//===----------------------------------------------------------------------===//1314#include "clang/Analysis/DomainSpecific/CocoaConventions.h"15#include "clang/Analysis/RetainSummaryManager.h"16#include "clang/AST/Attr.h"17#include "clang/AST/DeclCXX.h"18#include "clang/AST/DeclObjC.h"19#include "clang/AST/ParentMap.h"20#include "clang/ASTMatchers/ASTMatchFinder.h"21#include <optional>2223using namespace clang;24using namespace ento;2526template <class T>27constexpr static bool isOneOf() {28return false;29}3031/// Helper function to check whether the class is one of the32/// rest of varargs.33template <class T, class P, class... ToCompare>34constexpr static bool isOneOf() {35return std::is_same_v<T, P> || isOneOf<T, ToCompare...>();36}3738namespace {3940/// Fake attribute class for RC* attributes.41struct GeneralizedReturnsRetainedAttr {42static bool classof(const Attr *A) {43if (auto AA = dyn_cast<AnnotateAttr>(A))44return AA->getAnnotation() == "rc_ownership_returns_retained";45return false;46}47};4849struct GeneralizedReturnsNotRetainedAttr {50static bool classof(const Attr *A) {51if (auto AA = dyn_cast<AnnotateAttr>(A))52return AA->getAnnotation() == "rc_ownership_returns_not_retained";53return false;54}55};5657struct GeneralizedConsumedAttr {58static bool classof(const Attr *A) {59if (auto AA = dyn_cast<AnnotateAttr>(A))60return AA->getAnnotation() == "rc_ownership_consumed";61return false;62}63};6465}6667template <class T>68std::optional<ObjKind> RetainSummaryManager::hasAnyEnabledAttrOf(const Decl *D,69QualType QT) {70ObjKind K;71if (isOneOf<T, CFConsumedAttr, CFReturnsRetainedAttr,72CFReturnsNotRetainedAttr>()) {73if (!TrackObjCAndCFObjects)74return std::nullopt;7576K = ObjKind::CF;77} else if (isOneOf<T, NSConsumedAttr, NSConsumesSelfAttr,78NSReturnsAutoreleasedAttr, NSReturnsRetainedAttr,79NSReturnsNotRetainedAttr, NSConsumesSelfAttr>()) {8081if (!TrackObjCAndCFObjects)82return std::nullopt;8384if (isOneOf<T, NSReturnsRetainedAttr, NSReturnsAutoreleasedAttr,85NSReturnsNotRetainedAttr>() &&86!cocoa::isCocoaObjectRef(QT))87return std::nullopt;88K = ObjKind::ObjC;89} else if (isOneOf<T, OSConsumedAttr, OSConsumesThisAttr,90OSReturnsNotRetainedAttr, OSReturnsRetainedAttr,91OSReturnsRetainedOnZeroAttr,92OSReturnsRetainedOnNonZeroAttr>()) {93if (!TrackOSObjects)94return std::nullopt;95K = ObjKind::OS;96} else if (isOneOf<T, GeneralizedReturnsNotRetainedAttr,97GeneralizedReturnsRetainedAttr,98GeneralizedConsumedAttr>()) {99K = ObjKind::Generalized;100} else {101llvm_unreachable("Unexpected attribute");102}103if (D->hasAttr<T>())104return K;105return std::nullopt;106}107108template <class T1, class T2, class... Others>109std::optional<ObjKind> RetainSummaryManager::hasAnyEnabledAttrOf(const Decl *D,110QualType QT) {111if (auto Out = hasAnyEnabledAttrOf<T1>(D, QT))112return Out;113return hasAnyEnabledAttrOf<T2, Others...>(D, QT);114}115116const RetainSummary *117RetainSummaryManager::getPersistentSummary(const RetainSummary &OldSumm) {118// Unique "simple" summaries -- those without ArgEffects.119if (OldSumm.isSimple()) {120::llvm::FoldingSetNodeID ID;121OldSumm.Profile(ID);122123void *Pos;124CachedSummaryNode *N = SimpleSummaries.FindNodeOrInsertPos(ID, Pos);125126if (!N) {127N = (CachedSummaryNode *) BPAlloc.Allocate<CachedSummaryNode>();128new (N) CachedSummaryNode(OldSumm);129SimpleSummaries.InsertNode(N, Pos);130}131132return &N->getValue();133}134135RetainSummary *Summ = (RetainSummary *) BPAlloc.Allocate<RetainSummary>();136new (Summ) RetainSummary(OldSumm);137return Summ;138}139140static bool isSubclass(const Decl *D,141StringRef ClassName) {142using namespace ast_matchers;143DeclarationMatcher SubclassM =144cxxRecordDecl(isSameOrDerivedFrom(std::string(ClassName)));145return !(match(SubclassM, *D, D->getASTContext()).empty());146}147148static bool isExactClass(const Decl *D, StringRef ClassName) {149using namespace ast_matchers;150DeclarationMatcher sameClassM =151cxxRecordDecl(hasName(std::string(ClassName)));152return !(match(sameClassM, *D, D->getASTContext()).empty());153}154155static bool isOSObjectSubclass(const Decl *D) {156return D && isSubclass(D, "OSMetaClassBase") &&157!isExactClass(D, "OSMetaClass");158}159160static bool isOSObjectDynamicCast(StringRef S) { return S == "safeMetaCast"; }161162static bool isOSObjectRequiredCast(StringRef S) {163return S == "requiredMetaCast";164}165166static bool isOSObjectThisCast(StringRef S) {167return S == "metaCast";168}169170171static bool isOSObjectPtr(QualType QT) {172return isOSObjectSubclass(QT->getPointeeCXXRecordDecl());173}174175static bool isISLObjectRef(QualType Ty) {176return StringRef(Ty.getAsString()).starts_with("isl_");177}178179static bool isOSIteratorSubclass(const Decl *D) {180return isSubclass(D, "OSIterator");181}182183static bool hasRCAnnotation(const Decl *D, StringRef rcAnnotation) {184for (const auto *Ann : D->specific_attrs<AnnotateAttr>()) {185if (Ann->getAnnotation() == rcAnnotation)186return true;187}188return false;189}190191static bool isRetain(const FunctionDecl *FD, StringRef FName) {192return FName.starts_with_insensitive("retain") ||193FName.ends_with_insensitive("retain");194}195196static bool isRelease(const FunctionDecl *FD, StringRef FName) {197return FName.starts_with_insensitive("release") ||198FName.ends_with_insensitive("release");199}200201static bool isAutorelease(const FunctionDecl *FD, StringRef FName) {202return FName.starts_with_insensitive("autorelease") ||203FName.ends_with_insensitive("autorelease");204}205206static bool isMakeCollectable(StringRef FName) {207return FName.contains_insensitive("MakeCollectable");208}209210/// A function is OSObject related if it is declared on a subclass211/// of OSObject, or any of the parameters is a subclass of an OSObject.212static bool isOSObjectRelated(const CXXMethodDecl *MD) {213if (isOSObjectSubclass(MD->getParent()))214return true;215216for (ParmVarDecl *Param : MD->parameters()) {217QualType PT = Param->getType()->getPointeeType();218if (!PT.isNull())219if (CXXRecordDecl *RD = PT->getAsCXXRecordDecl())220if (isOSObjectSubclass(RD))221return true;222}223224return false;225}226227bool228RetainSummaryManager::isKnownSmartPointer(QualType QT) {229QT = QT.getCanonicalType();230const auto *RD = QT->getAsCXXRecordDecl();231if (!RD)232return false;233const IdentifierInfo *II = RD->getIdentifier();234if (II && II->getName() == "smart_ptr")235if (const auto *ND = dyn_cast<NamespaceDecl>(RD->getDeclContext()))236if (ND->getNameAsString() == "os")237return true;238return false;239}240241const RetainSummary *242RetainSummaryManager::getSummaryForOSObject(const FunctionDecl *FD,243StringRef FName, QualType RetTy) {244assert(TrackOSObjects &&245"Requesting a summary for an OSObject but OSObjects are not tracked");246247if (RetTy->isPointerType()) {248const CXXRecordDecl *PD = RetTy->getPointeeType()->getAsCXXRecordDecl();249if (PD && isOSObjectSubclass(PD)) {250if (isOSObjectDynamicCast(FName) || isOSObjectRequiredCast(FName) ||251isOSObjectThisCast(FName))252return getDefaultSummary();253254// TODO: Add support for the slightly common *Matching(table) idiom.255// Cf. IOService::nameMatching() etc. - these function have an unusual256// contract of returning at +0 or +1 depending on their last argument.257if (FName.ends_with("Matching")) {258return getPersistentStopSummary();259}260261// All objects returned with functions *not* starting with 'get',262// or iterators, are returned at +1.263if ((!FName.starts_with("get") && !FName.starts_with("Get")) ||264isOSIteratorSubclass(PD)) {265return getOSSummaryCreateRule(FD);266} else {267return getOSSummaryGetRule(FD);268}269}270}271272if (const auto *MD = dyn_cast<CXXMethodDecl>(FD)) {273const CXXRecordDecl *Parent = MD->getParent();274if (Parent && isOSObjectSubclass(Parent)) {275if (FName == "release" || FName == "taggedRelease")276return getOSSummaryReleaseRule(FD);277278if (FName == "retain" || FName == "taggedRetain")279return getOSSummaryRetainRule(FD);280281if (FName == "free")282return getOSSummaryFreeRule(FD);283284if (MD->getOverloadedOperator() == OO_New)285return getOSSummaryCreateRule(MD);286}287}288289return nullptr;290}291292const RetainSummary *RetainSummaryManager::getSummaryForObjCOrCFObject(293const FunctionDecl *FD,294StringRef FName,295QualType RetTy,296const FunctionType *FT,297bool &AllowAnnotations) {298299ArgEffects ScratchArgs(AF.getEmptyMap());300301std::string RetTyName = RetTy.getAsString();302if (FName == "pthread_create" || FName == "pthread_setspecific") {303// It's not uncommon to pass a tracked object into the thread304// as 'void *arg', and then release it inside the thread.305// FIXME: We could build a much more precise model for these functions.306return getPersistentStopSummary();307} else if(FName == "NSMakeCollectable") {308// Handle: id NSMakeCollectable(CFTypeRef)309AllowAnnotations = false;310return RetTy->isObjCIdType() ? getUnarySummary(FT, DoNothing)311: getPersistentStopSummary();312} else if (FName == "CMBufferQueueDequeueAndRetain" ||313FName == "CMBufferQueueDequeueIfDataReadyAndRetain") {314// These API functions are known to NOT act as a CFRetain wrapper.315// They simply make a new object owned by the caller.316return getPersistentSummary(RetEffect::MakeOwned(ObjKind::CF),317ScratchArgs,318ArgEffect(DoNothing),319ArgEffect(DoNothing));320} else if (FName == "CFPlugInInstanceCreate") {321return getPersistentSummary(RetEffect::MakeNoRet(), ScratchArgs);322} else if (FName == "IORegistryEntrySearchCFProperty" ||323(RetTyName == "CFMutableDictionaryRef" &&324(FName == "IOBSDNameMatching" || FName == "IOServiceMatching" ||325FName == "IOServiceNameMatching" ||326FName == "IORegistryEntryIDMatching" ||327FName == "IOOpenFirmwarePathMatching"))) {328// Yes, these IOKit functions return CF objects.329// They also violate the CF naming convention.330return getPersistentSummary(RetEffect::MakeOwned(ObjKind::CF), ScratchArgs,331ArgEffect(DoNothing), ArgEffect(DoNothing));332} else if (FName == "IOServiceGetMatchingService" ||333FName == "IOServiceGetMatchingServices") {334// These IOKit functions accept CF objects as arguments.335// They also consume them without an appropriate annotation.336ScratchArgs = AF.add(ScratchArgs, 1, ArgEffect(DecRef, ObjKind::CF));337return getPersistentSummary(RetEffect::MakeNoRet(),338ScratchArgs,339ArgEffect(DoNothing), ArgEffect(DoNothing));340} else if (FName == "IOServiceAddNotification" ||341FName == "IOServiceAddMatchingNotification") {342// More IOKit functions suddenly accepting (and even more suddenly,343// consuming) CF objects.344ScratchArgs = AF.add(ScratchArgs, 2, ArgEffect(DecRef, ObjKind::CF));345return getPersistentSummary(RetEffect::MakeNoRet(),346ScratchArgs,347ArgEffect(DoNothing), ArgEffect(DoNothing));348} else if (FName == "CVPixelBufferCreateWithBytes") {349// Eventually this can be improved by recognizing that the pixel350// buffer passed to CVPixelBufferCreateWithBytes is released via351// a callback and doing full IPA to make sure this is done correctly.352// Note that it's passed as a 'void *', so it's hard to annotate.353// FIXME: This function also has an out parameter that returns an354// allocated object.355ScratchArgs = AF.add(ScratchArgs, 7, ArgEffect(StopTracking));356return getPersistentSummary(RetEffect::MakeNoRet(),357ScratchArgs,358ArgEffect(DoNothing), ArgEffect(DoNothing));359} else if (FName == "CGBitmapContextCreateWithData") {360// This is similar to the CVPixelBufferCreateWithBytes situation above.361// Eventually this can be improved by recognizing that 'releaseInfo'362// passed to CGBitmapContextCreateWithData is released via363// a callback and doing full IPA to make sure this is done correctly.364ScratchArgs = AF.add(ScratchArgs, 8, ArgEffect(ArgEffect(StopTracking)));365return getPersistentSummary(RetEffect::MakeOwned(ObjKind::CF), ScratchArgs,366ArgEffect(DoNothing), ArgEffect(DoNothing));367} else if (FName == "CVPixelBufferCreateWithPlanarBytes") {368// Same as CVPixelBufferCreateWithBytes, just more arguments.369ScratchArgs = AF.add(ScratchArgs, 12, ArgEffect(StopTracking));370return getPersistentSummary(RetEffect::MakeNoRet(),371ScratchArgs,372ArgEffect(DoNothing), ArgEffect(DoNothing));373} else if (FName == "VTCompressionSessionEncodeFrame" ||374FName == "VTCompressionSessionEncodeMultiImageFrame") {375// The context argument passed to VTCompressionSessionEncodeFrame() et.al.376// is passed to the callback specified when creating the session377// (e.g. with VTCompressionSessionCreate()) which can release it.378// To account for this possibility, conservatively stop tracking379// the context.380ScratchArgs = AF.add(ScratchArgs, 5, ArgEffect(StopTracking));381return getPersistentSummary(RetEffect::MakeNoRet(),382ScratchArgs,383ArgEffect(DoNothing), ArgEffect(DoNothing));384} else if (FName == "dispatch_set_context" ||385FName == "xpc_connection_set_context") {386// The analyzer currently doesn't have a good way to reason about387// dispatch_set_finalizer_f() which typically cleans up the context.388// If we pass a context object that is memory managed, stop tracking it.389// Same with xpc_connection_set_finalizer_f().390ScratchArgs = AF.add(ScratchArgs, 1, ArgEffect(StopTracking));391return getPersistentSummary(RetEffect::MakeNoRet(),392ScratchArgs,393ArgEffect(DoNothing), ArgEffect(DoNothing));394} else if (FName.starts_with("NSLog")) {395return getDoNothingSummary();396} else if (FName.starts_with("NS") && FName.contains("Insert")) {397// Allowlist NSXXInsertXX, for example NSMapInsertIfAbsent, since they can398// be deallocated by NSMapRemove.399ScratchArgs = AF.add(ScratchArgs, 1, ArgEffect(StopTracking));400ScratchArgs = AF.add(ScratchArgs, 2, ArgEffect(StopTracking));401return getPersistentSummary(RetEffect::MakeNoRet(),402ScratchArgs, ArgEffect(DoNothing),403ArgEffect(DoNothing));404}405406if (RetTy->isPointerType()) {407408// For CoreFoundation ('CF') types.409if (cocoa::isRefType(RetTy, "CF", FName)) {410if (isRetain(FD, FName)) {411// CFRetain isn't supposed to be annotated. However, this may as412// well be a user-made "safe" CFRetain function that is incorrectly413// annotated as cf_returns_retained due to lack of better options.414// We want to ignore such annotation.415AllowAnnotations = false;416417return getUnarySummary(FT, IncRef);418} else if (isAutorelease(FD, FName)) {419// The headers use cf_consumed, but we can fully model CFAutorelease420// ourselves.421AllowAnnotations = false;422423return getUnarySummary(FT, Autorelease);424} else if (isMakeCollectable(FName)) {425AllowAnnotations = false;426return getUnarySummary(FT, DoNothing);427} else {428return getCFCreateGetRuleSummary(FD);429}430}431432// For CoreGraphics ('CG') and CoreVideo ('CV') types.433if (cocoa::isRefType(RetTy, "CG", FName) ||434cocoa::isRefType(RetTy, "CV", FName)) {435if (isRetain(FD, FName))436return getUnarySummary(FT, IncRef);437else438return getCFCreateGetRuleSummary(FD);439}440441// For all other CF-style types, use the Create/Get442// rule for summaries but don't support Retain functions443// with framework-specific prefixes.444if (coreFoundation::isCFObjectRef(RetTy)) {445return getCFCreateGetRuleSummary(FD);446}447448if (FD->hasAttr<CFAuditedTransferAttr>()) {449return getCFCreateGetRuleSummary(FD);450}451}452453// Check for release functions, the only kind of functions that we care454// about that don't return a pointer type.455if (FName.starts_with("CG") || FName.starts_with("CF")) {456// Test for 'CGCF'.457FName = FName.substr(FName.starts_with("CGCF") ? 4 : 2);458459if (isRelease(FD, FName))460return getUnarySummary(FT, DecRef);461else {462assert(ScratchArgs.isEmpty());463// Remaining CoreFoundation and CoreGraphics functions.464// We use to assume that they all strictly followed the ownership idiom465// and that ownership cannot be transferred. While this is technically466// correct, many methods allow a tracked object to escape. For example:467//468// CFMutableDictionaryRef x = CFDictionaryCreateMutable(...);469// CFDictionaryAddValue(y, key, x);470// CFRelease(x);471// ... it is okay to use 'x' since 'y' has a reference to it472//473// We handle this and similar cases with the follow heuristic. If the474// function name contains "InsertValue", "SetValue", "AddValue",475// "AppendValue", or "SetAttribute", then we assume that arguments may476// "escape." This means that something else holds on to the object,477// allowing it be used even after its local retain count drops to 0.478ArgEffectKind E =479(StrInStrNoCase(FName, "InsertValue") != StringRef::npos ||480StrInStrNoCase(FName, "AddValue") != StringRef::npos ||481StrInStrNoCase(FName, "SetValue") != StringRef::npos ||482StrInStrNoCase(FName, "AppendValue") != StringRef::npos ||483StrInStrNoCase(FName, "SetAttribute") != StringRef::npos)484? MayEscape485: DoNothing;486487return getPersistentSummary(RetEffect::MakeNoRet(), ScratchArgs,488ArgEffect(DoNothing), ArgEffect(E, ObjKind::CF));489}490}491492return nullptr;493}494495const RetainSummary *496RetainSummaryManager::generateSummary(const FunctionDecl *FD,497bool &AllowAnnotations) {498// We generate "stop" summaries for implicitly defined functions.499if (FD->isImplicit())500return getPersistentStopSummary();501502const IdentifierInfo *II = FD->getIdentifier();503504StringRef FName = II ? II->getName() : "";505506// Strip away preceding '_'. Doing this here will effect all the checks507// down below.508FName = FName.substr(FName.find_first_not_of('_'));509510// Inspect the result type. Strip away any typedefs.511const auto *FT = FD->getType()->castAs<FunctionType>();512QualType RetTy = FT->getReturnType();513514if (TrackOSObjects)515if (const RetainSummary *S = getSummaryForOSObject(FD, FName, RetTy))516return S;517518if (const auto *MD = dyn_cast<CXXMethodDecl>(FD))519if (!isOSObjectRelated(MD))520return getPersistentSummary(RetEffect::MakeNoRet(),521ArgEffects(AF.getEmptyMap()),522ArgEffect(DoNothing),523ArgEffect(StopTracking),524ArgEffect(DoNothing));525526if (TrackObjCAndCFObjects)527if (const RetainSummary *S =528getSummaryForObjCOrCFObject(FD, FName, RetTy, FT, AllowAnnotations))529return S;530531return getDefaultSummary();532}533534const RetainSummary *535RetainSummaryManager::getFunctionSummary(const FunctionDecl *FD) {536// If we don't know what function we're calling, use our default summary.537if (!FD)538return getDefaultSummary();539540// Look up a summary in our cache of FunctionDecls -> Summaries.541FuncSummariesTy::iterator I = FuncSummaries.find(FD);542if (I != FuncSummaries.end())543return I->second;544545// No summary? Generate one.546bool AllowAnnotations = true;547const RetainSummary *S = generateSummary(FD, AllowAnnotations);548549// Annotations override defaults.550if (AllowAnnotations)551updateSummaryFromAnnotations(S, FD);552553FuncSummaries[FD] = S;554return S;555}556557//===----------------------------------------------------------------------===//558// Summary creation for functions (largely uses of Core Foundation).559//===----------------------------------------------------------------------===//560561static ArgEffect getStopTrackingHardEquivalent(ArgEffect E) {562switch (E.getKind()) {563case DoNothing:564case Autorelease:565case DecRefBridgedTransferred:566case IncRef:567case UnretainedOutParameter:568case RetainedOutParameter:569case RetainedOutParameterOnZero:570case RetainedOutParameterOnNonZero:571case MayEscape:572case StopTracking:573case StopTrackingHard:574return E.withKind(StopTrackingHard);575case DecRef:576case DecRefAndStopTrackingHard:577return E.withKind(DecRefAndStopTrackingHard);578case Dealloc:579return E.withKind(Dealloc);580}581582llvm_unreachable("Unknown ArgEffect kind");583}584585const RetainSummary *586RetainSummaryManager::updateSummaryForNonZeroCallbackArg(const RetainSummary *S,587AnyCall &C) {588ArgEffect RecEffect = getStopTrackingHardEquivalent(S->getReceiverEffect());589ArgEffect DefEffect = getStopTrackingHardEquivalent(S->getDefaultArgEffect());590591ArgEffects ScratchArgs(AF.getEmptyMap());592ArgEffects CustomArgEffects = S->getArgEffects();593for (ArgEffects::iterator I = CustomArgEffects.begin(),594E = CustomArgEffects.end();595I != E; ++I) {596ArgEffect Translated = getStopTrackingHardEquivalent(I->second);597if (Translated.getKind() != DefEffect.getKind())598ScratchArgs = AF.add(ScratchArgs, I->first, Translated);599}600601RetEffect RE = RetEffect::MakeNoRetHard();602603// Special cases where the callback argument CANNOT free the return value.604// This can generally only happen if we know that the callback will only be605// called when the return value is already being deallocated.606if (const IdentifierInfo *Name = C.getIdentifier()) {607// When the CGBitmapContext is deallocated, the callback here will free608// the associated data buffer.609// The callback in dispatch_data_create frees the buffer, but not610// the data object.611if (Name->isStr("CGBitmapContextCreateWithData") ||612Name->isStr("dispatch_data_create"))613RE = S->getRetEffect();614}615616return getPersistentSummary(RE, ScratchArgs, RecEffect, DefEffect);617}618619void RetainSummaryManager::updateSummaryForReceiverUnconsumedSelf(620const RetainSummary *&S) {621622RetainSummaryTemplate Template(S, *this);623624Template->setReceiverEffect(ArgEffect(DoNothing));625Template->setRetEffect(RetEffect::MakeNoRet());626}627628629void RetainSummaryManager::updateSummaryForArgumentTypes(630const AnyCall &C, const RetainSummary *&RS) {631RetainSummaryTemplate Template(RS, *this);632633unsigned parm_idx = 0;634for (auto pi = C.param_begin(), pe = C.param_end(); pi != pe;635++pi, ++parm_idx) {636QualType QT = (*pi)->getType();637638// Skip already created values.639if (RS->getArgEffects().contains(parm_idx))640continue;641642ObjKind K = ObjKind::AnyObj;643644if (isISLObjectRef(QT)) {645K = ObjKind::Generalized;646} else if (isOSObjectPtr(QT)) {647K = ObjKind::OS;648} else if (cocoa::isCocoaObjectRef(QT)) {649K = ObjKind::ObjC;650} else if (coreFoundation::isCFObjectRef(QT)) {651K = ObjKind::CF;652}653654if (K != ObjKind::AnyObj)655Template->addArg(AF, parm_idx,656ArgEffect(RS->getDefaultArgEffect().getKind(), K));657}658}659660const RetainSummary *661RetainSummaryManager::getSummary(AnyCall C,662bool HasNonZeroCallbackArg,663bool IsReceiverUnconsumedSelf,664QualType ReceiverType) {665const RetainSummary *Summ;666switch (C.getKind()) {667case AnyCall::Function:668case AnyCall::Constructor:669case AnyCall::InheritedConstructor:670case AnyCall::Allocator:671case AnyCall::Deallocator:672Summ = getFunctionSummary(cast_or_null<FunctionDecl>(C.getDecl()));673break;674case AnyCall::Block:675case AnyCall::Destructor:676// FIXME: These calls are currently unsupported.677return getPersistentStopSummary();678case AnyCall::ObjCMethod: {679const auto *ME = cast_or_null<ObjCMessageExpr>(C.getExpr());680if (!ME) {681Summ = getMethodSummary(cast<ObjCMethodDecl>(C.getDecl()));682} else if (ME->isInstanceMessage()) {683Summ = getInstanceMethodSummary(ME, ReceiverType);684} else {685Summ = getClassMethodSummary(ME);686}687break;688}689}690691if (HasNonZeroCallbackArg)692Summ = updateSummaryForNonZeroCallbackArg(Summ, C);693694if (IsReceiverUnconsumedSelf)695updateSummaryForReceiverUnconsumedSelf(Summ);696697updateSummaryForArgumentTypes(C, Summ);698699assert(Summ && "Unknown call type?");700return Summ;701}702703704const RetainSummary *705RetainSummaryManager::getCFCreateGetRuleSummary(const FunctionDecl *FD) {706if (coreFoundation::followsCreateRule(FD))707return getCFSummaryCreateRule(FD);708709return getCFSummaryGetRule(FD);710}711712bool RetainSummaryManager::isTrustedReferenceCountImplementation(713const Decl *FD) {714return hasRCAnnotation(FD, "rc_ownership_trusted_implementation");715}716717std::optional<RetainSummaryManager::BehaviorSummary>718RetainSummaryManager::canEval(const CallExpr *CE, const FunctionDecl *FD,719bool &hasTrustedImplementationAnnotation) {720721IdentifierInfo *II = FD->getIdentifier();722if (!II)723return std::nullopt;724725StringRef FName = II->getName();726FName = FName.substr(FName.find_first_not_of('_'));727728QualType ResultTy = CE->getCallReturnType(Ctx);729if (ResultTy->isObjCIdType()) {730if (II->isStr("NSMakeCollectable"))731return BehaviorSummary::Identity;732} else if (ResultTy->isPointerType()) {733// Handle: (CF|CG|CV)Retain734// CFAutorelease735// It's okay to be a little sloppy here.736if (FName == "CMBufferQueueDequeueAndRetain" ||737FName == "CMBufferQueueDequeueIfDataReadyAndRetain") {738// These API functions are known to NOT act as a CFRetain wrapper.739// They simply make a new object owned by the caller.740return std::nullopt;741}742if (CE->getNumArgs() == 1 &&743(cocoa::isRefType(ResultTy, "CF", FName) ||744cocoa::isRefType(ResultTy, "CG", FName) ||745cocoa::isRefType(ResultTy, "CV", FName)) &&746(isRetain(FD, FName) || isAutorelease(FD, FName) ||747isMakeCollectable(FName)))748return BehaviorSummary::Identity;749750// safeMetaCast is called by OSDynamicCast.751// We assume that OSDynamicCast is either an identity (cast is OK,752// the input was non-zero),753// or that it returns zero (when the cast failed, or the input754// was zero).755if (TrackOSObjects) {756if (isOSObjectDynamicCast(FName) && FD->param_size() >= 1) {757return BehaviorSummary::IdentityOrZero;758} else if (isOSObjectRequiredCast(FName) && FD->param_size() >= 1) {759return BehaviorSummary::Identity;760} else if (isOSObjectThisCast(FName) && isa<CXXMethodDecl>(FD) &&761!cast<CXXMethodDecl>(FD)->isStatic()) {762return BehaviorSummary::IdentityThis;763}764}765766const FunctionDecl* FDD = FD->getDefinition();767if (FDD && isTrustedReferenceCountImplementation(FDD)) {768hasTrustedImplementationAnnotation = true;769return BehaviorSummary::Identity;770}771}772773if (const auto *MD = dyn_cast<CXXMethodDecl>(FD)) {774const CXXRecordDecl *Parent = MD->getParent();775if (TrackOSObjects && Parent && isOSObjectSubclass(Parent))776if (FName == "release" || FName == "retain")777return BehaviorSummary::NoOp;778}779780return std::nullopt;781}782783const RetainSummary *784RetainSummaryManager::getUnarySummary(const FunctionType* FT,785ArgEffectKind AE) {786787// Unary functions have no arg effects by definition.788ArgEffects ScratchArgs(AF.getEmptyMap());789790// Verify that this is *really* a unary function. This can791// happen if people do weird things.792const FunctionProtoType* FTP = dyn_cast<FunctionProtoType>(FT);793if (!FTP || FTP->getNumParams() != 1)794return getPersistentStopSummary();795796ArgEffect Effect(AE, ObjKind::CF);797798ScratchArgs = AF.add(ScratchArgs, 0, Effect);799return getPersistentSummary(RetEffect::MakeNoRet(),800ScratchArgs,801ArgEffect(DoNothing), ArgEffect(DoNothing));802}803804const RetainSummary *805RetainSummaryManager::getOSSummaryRetainRule(const FunctionDecl *FD) {806return getPersistentSummary(RetEffect::MakeNoRet(),807AF.getEmptyMap(),808/*ReceiverEff=*/ArgEffect(DoNothing),809/*DefaultEff=*/ArgEffect(DoNothing),810/*ThisEff=*/ArgEffect(IncRef, ObjKind::OS));811}812813const RetainSummary *814RetainSummaryManager::getOSSummaryReleaseRule(const FunctionDecl *FD) {815return getPersistentSummary(RetEffect::MakeNoRet(),816AF.getEmptyMap(),817/*ReceiverEff=*/ArgEffect(DoNothing),818/*DefaultEff=*/ArgEffect(DoNothing),819/*ThisEff=*/ArgEffect(DecRef, ObjKind::OS));820}821822const RetainSummary *823RetainSummaryManager::getOSSummaryFreeRule(const FunctionDecl *FD) {824return getPersistentSummary(RetEffect::MakeNoRet(),825AF.getEmptyMap(),826/*ReceiverEff=*/ArgEffect(DoNothing),827/*DefaultEff=*/ArgEffect(DoNothing),828/*ThisEff=*/ArgEffect(Dealloc, ObjKind::OS));829}830831const RetainSummary *832RetainSummaryManager::getOSSummaryCreateRule(const FunctionDecl *FD) {833return getPersistentSummary(RetEffect::MakeOwned(ObjKind::OS),834AF.getEmptyMap());835}836837const RetainSummary *838RetainSummaryManager::getOSSummaryGetRule(const FunctionDecl *FD) {839return getPersistentSummary(RetEffect::MakeNotOwned(ObjKind::OS),840AF.getEmptyMap());841}842843const RetainSummary *844RetainSummaryManager::getCFSummaryCreateRule(const FunctionDecl *FD) {845return getPersistentSummary(RetEffect::MakeOwned(ObjKind::CF),846ArgEffects(AF.getEmptyMap()));847}848849const RetainSummary *850RetainSummaryManager::getCFSummaryGetRule(const FunctionDecl *FD) {851return getPersistentSummary(RetEffect::MakeNotOwned(ObjKind::CF),852ArgEffects(AF.getEmptyMap()),853ArgEffect(DoNothing), ArgEffect(DoNothing));854}855856857858859//===----------------------------------------------------------------------===//860// Summary creation for Selectors.861//===----------------------------------------------------------------------===//862863std::optional<RetEffect>864RetainSummaryManager::getRetEffectFromAnnotations(QualType RetTy,865const Decl *D) {866if (hasAnyEnabledAttrOf<NSReturnsRetainedAttr>(D, RetTy))867return ObjCAllocRetE;868869if (auto K = hasAnyEnabledAttrOf<CFReturnsRetainedAttr, OSReturnsRetainedAttr,870GeneralizedReturnsRetainedAttr>(D, RetTy))871return RetEffect::MakeOwned(*K);872873if (auto K = hasAnyEnabledAttrOf<874CFReturnsNotRetainedAttr, OSReturnsNotRetainedAttr,875GeneralizedReturnsNotRetainedAttr, NSReturnsNotRetainedAttr,876NSReturnsAutoreleasedAttr>(D, RetTy))877return RetEffect::MakeNotOwned(*K);878879if (const auto *MD = dyn_cast<CXXMethodDecl>(D))880for (const auto *PD : MD->overridden_methods())881if (auto RE = getRetEffectFromAnnotations(RetTy, PD))882return RE;883884return std::nullopt;885}886887/// \return Whether the chain of typedefs starting from @c QT888/// has a typedef with a given name @c Name.889static bool hasTypedefNamed(QualType QT,890StringRef Name) {891while (auto *T = QT->getAs<TypedefType>()) {892const auto &Context = T->getDecl()->getASTContext();893if (T->getDecl()->getIdentifier() == &Context.Idents.get(Name))894return true;895QT = T->getDecl()->getUnderlyingType();896}897return false;898}899900static QualType getCallableReturnType(const NamedDecl *ND) {901if (const auto *FD = dyn_cast<FunctionDecl>(ND)) {902return FD->getReturnType();903} else if (const auto *MD = dyn_cast<ObjCMethodDecl>(ND)) {904return MD->getReturnType();905} else {906llvm_unreachable("Unexpected decl");907}908}909910bool RetainSummaryManager::applyParamAnnotationEffect(911const ParmVarDecl *pd, unsigned parm_idx, const NamedDecl *FD,912RetainSummaryTemplate &Template) {913QualType QT = pd->getType();914if (auto K =915hasAnyEnabledAttrOf<NSConsumedAttr, CFConsumedAttr, OSConsumedAttr,916GeneralizedConsumedAttr>(pd, QT)) {917Template->addArg(AF, parm_idx, ArgEffect(DecRef, *K));918return true;919} else if (auto K = hasAnyEnabledAttrOf<920CFReturnsRetainedAttr, OSReturnsRetainedAttr,921OSReturnsRetainedOnNonZeroAttr, OSReturnsRetainedOnZeroAttr,922GeneralizedReturnsRetainedAttr>(pd, QT)) {923924// For OSObjects, we try to guess whether the object is created based925// on the return value.926if (K == ObjKind::OS) {927QualType QT = getCallableReturnType(FD);928929bool HasRetainedOnZero = pd->hasAttr<OSReturnsRetainedOnZeroAttr>();930bool HasRetainedOnNonZero = pd->hasAttr<OSReturnsRetainedOnNonZeroAttr>();931932// The usual convention is to create an object on non-zero return, but933// it's reverted if the typedef chain has a typedef kern_return_t,934// because kReturnSuccess constant is defined as zero.935// The convention can be overwritten by custom attributes.936bool SuccessOnZero =937HasRetainedOnZero ||938(hasTypedefNamed(QT, "kern_return_t") && !HasRetainedOnNonZero);939bool ShouldSplit = !QT.isNull() && !QT->isVoidType();940ArgEffectKind AK = RetainedOutParameter;941if (ShouldSplit && SuccessOnZero) {942AK = RetainedOutParameterOnZero;943} else if (ShouldSplit && (!SuccessOnZero || HasRetainedOnNonZero)) {944AK = RetainedOutParameterOnNonZero;945}946Template->addArg(AF, parm_idx, ArgEffect(AK, ObjKind::OS));947}948949// For others:950// Do nothing. Retained out parameters will either point to a +1 reference951// or NULL, but the way you check for failure differs depending on the952// API. Consequently, we don't have a good way to track them yet.953return true;954} else if (auto K = hasAnyEnabledAttrOf<CFReturnsNotRetainedAttr,955OSReturnsNotRetainedAttr,956GeneralizedReturnsNotRetainedAttr>(957pd, QT)) {958Template->addArg(AF, parm_idx, ArgEffect(UnretainedOutParameter, *K));959return true;960}961962if (const auto *MD = dyn_cast<CXXMethodDecl>(FD)) {963for (const auto *OD : MD->overridden_methods()) {964const ParmVarDecl *OP = OD->parameters()[parm_idx];965if (applyParamAnnotationEffect(OP, parm_idx, OD, Template))966return true;967}968}969970return false;971}972973void974RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ,975const FunctionDecl *FD) {976if (!FD)977return;978979assert(Summ && "Must have a summary to add annotations to.");980RetainSummaryTemplate Template(Summ, *this);981982// Effects on the parameters.983unsigned parm_idx = 0;984for (auto pi = FD->param_begin(),985pe = FD->param_end(); pi != pe; ++pi, ++parm_idx)986applyParamAnnotationEffect(*pi, parm_idx, FD, Template);987988QualType RetTy = FD->getReturnType();989if (std::optional<RetEffect> RetE = getRetEffectFromAnnotations(RetTy, FD))990Template->setRetEffect(*RetE);991992if (hasAnyEnabledAttrOf<OSConsumesThisAttr>(FD, RetTy))993Template->setThisEffect(ArgEffect(DecRef, ObjKind::OS));994}995996void997RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ,998const ObjCMethodDecl *MD) {999if (!MD)1000return;10011002assert(Summ && "Must have a valid summary to add annotations to");1003RetainSummaryTemplate Template(Summ, *this);10041005// Effects on the receiver.1006if (hasAnyEnabledAttrOf<NSConsumesSelfAttr>(MD, MD->getReturnType()))1007Template->setReceiverEffect(ArgEffect(DecRef, ObjKind::ObjC));10081009// Effects on the parameters.1010unsigned parm_idx = 0;1011for (auto pi = MD->param_begin(), pe = MD->param_end(); pi != pe;1012++pi, ++parm_idx)1013applyParamAnnotationEffect(*pi, parm_idx, MD, Template);10141015QualType RetTy = MD->getReturnType();1016if (std::optional<RetEffect> RetE = getRetEffectFromAnnotations(RetTy, MD))1017Template->setRetEffect(*RetE);1018}10191020const RetainSummary *1021RetainSummaryManager::getStandardMethodSummary(const ObjCMethodDecl *MD,1022Selector S, QualType RetTy) {1023// Any special effects?1024ArgEffect ReceiverEff = ArgEffect(DoNothing, ObjKind::ObjC);1025RetEffect ResultEff = RetEffect::MakeNoRet();10261027// Check the method family, and apply any default annotations.1028switch (MD ? MD->getMethodFamily() : S.getMethodFamily()) {1029case OMF_None:1030case OMF_initialize:1031case OMF_performSelector:1032// Assume all Objective-C methods follow Cocoa Memory Management rules.1033// FIXME: Does the non-threaded performSelector family really belong here?1034// The selector could be, say, @selector(copy).1035if (cocoa::isCocoaObjectRef(RetTy))1036ResultEff = RetEffect::MakeNotOwned(ObjKind::ObjC);1037else if (coreFoundation::isCFObjectRef(RetTy)) {1038// ObjCMethodDecl currently doesn't consider CF objects as valid return1039// values for alloc, new, copy, or mutableCopy, so we have to1040// double-check with the selector. This is ugly, but there aren't that1041// many Objective-C methods that return CF objects, right?1042if (MD) {1043switch (S.getMethodFamily()) {1044case OMF_alloc:1045case OMF_new:1046case OMF_copy:1047case OMF_mutableCopy:1048ResultEff = RetEffect::MakeOwned(ObjKind::CF);1049break;1050default:1051ResultEff = RetEffect::MakeNotOwned(ObjKind::CF);1052break;1053}1054} else {1055ResultEff = RetEffect::MakeNotOwned(ObjKind::CF);1056}1057}1058break;1059case OMF_init:1060ResultEff = ObjCInitRetE;1061ReceiverEff = ArgEffect(DecRef, ObjKind::ObjC);1062break;1063case OMF_alloc:1064case OMF_new:1065case OMF_copy:1066case OMF_mutableCopy:1067if (cocoa::isCocoaObjectRef(RetTy))1068ResultEff = ObjCAllocRetE;1069else if (coreFoundation::isCFObjectRef(RetTy))1070ResultEff = RetEffect::MakeOwned(ObjKind::CF);1071break;1072case OMF_autorelease:1073ReceiverEff = ArgEffect(Autorelease, ObjKind::ObjC);1074break;1075case OMF_retain:1076ReceiverEff = ArgEffect(IncRef, ObjKind::ObjC);1077break;1078case OMF_release:1079ReceiverEff = ArgEffect(DecRef, ObjKind::ObjC);1080break;1081case OMF_dealloc:1082ReceiverEff = ArgEffect(Dealloc, ObjKind::ObjC);1083break;1084case OMF_self:1085// -self is handled specially by the ExprEngine to propagate the receiver.1086break;1087case OMF_retainCount:1088case OMF_finalize:1089// These methods don't return objects.1090break;1091}10921093// If one of the arguments in the selector has the keyword 'delegate' we1094// should stop tracking the reference count for the receiver. This is1095// because the reference count is quite possibly handled by a delegate1096// method.1097if (S.isKeywordSelector()) {1098for (unsigned i = 0, e = S.getNumArgs(); i != e; ++i) {1099StringRef Slot = S.getNameForSlot(i);1100if (Slot.ends_with_insensitive("delegate")) {1101if (ResultEff == ObjCInitRetE)1102ResultEff = RetEffect::MakeNoRetHard();1103else1104ReceiverEff = ArgEffect(StopTrackingHard, ObjKind::ObjC);1105}1106}1107}11081109if (ReceiverEff.getKind() == DoNothing &&1110ResultEff.getKind() == RetEffect::NoRet)1111return getDefaultSummary();11121113return getPersistentSummary(ResultEff, ArgEffects(AF.getEmptyMap()),1114ArgEffect(ReceiverEff), ArgEffect(MayEscape));1115}11161117const RetainSummary *1118RetainSummaryManager::getClassMethodSummary(const ObjCMessageExpr *ME) {1119assert(!ME->isInstanceMessage());1120const ObjCInterfaceDecl *Class = ME->getReceiverInterface();11211122return getMethodSummary(ME->getSelector(), Class, ME->getMethodDecl(),1123ME->getType(), ObjCClassMethodSummaries);1124}11251126const RetainSummary *RetainSummaryManager::getInstanceMethodSummary(1127const ObjCMessageExpr *ME,1128QualType ReceiverType) {1129const ObjCInterfaceDecl *ReceiverClass = nullptr;11301131// We do better tracking of the type of the object than the core ExprEngine.1132// See if we have its type in our private state.1133if (!ReceiverType.isNull())1134if (const auto *PT = ReceiverType->getAs<ObjCObjectPointerType>())1135ReceiverClass = PT->getInterfaceDecl();11361137// If we don't know what kind of object this is, fall back to its static type.1138if (!ReceiverClass)1139ReceiverClass = ME->getReceiverInterface();11401141// FIXME: The receiver could be a reference to a class, meaning that1142// we should use the class method.1143// id x = [NSObject class];1144// [x performSelector:... withObject:... afterDelay:...];1145Selector S = ME->getSelector();1146const ObjCMethodDecl *Method = ME->getMethodDecl();1147if (!Method && ReceiverClass)1148Method = ReceiverClass->getInstanceMethod(S);11491150return getMethodSummary(S, ReceiverClass, Method, ME->getType(),1151ObjCMethodSummaries);1152}11531154const RetainSummary *1155RetainSummaryManager::getMethodSummary(Selector S,1156const ObjCInterfaceDecl *ID,1157const ObjCMethodDecl *MD, QualType RetTy,1158ObjCMethodSummariesTy &CachedSummaries) {11591160// Objective-C method summaries are only applicable to ObjC and CF objects.1161if (!TrackObjCAndCFObjects)1162return getDefaultSummary();11631164// Look up a summary in our summary cache.1165const RetainSummary *Summ = CachedSummaries.find(ID, S);11661167if (!Summ) {1168Summ = getStandardMethodSummary(MD, S, RetTy);11691170// Annotations override defaults.1171updateSummaryFromAnnotations(Summ, MD);11721173// Memoize the summary.1174CachedSummaries[ObjCSummaryKey(ID, S)] = Summ;1175}11761177return Summ;1178}11791180void RetainSummaryManager::InitializeClassMethodSummaries() {1181ArgEffects ScratchArgs = AF.getEmptyMap();11821183// Create the [NSAssertionHandler currentHander] summary.1184addClassMethSummary("NSAssertionHandler", "currentHandler",1185getPersistentSummary(RetEffect::MakeNotOwned(ObjKind::ObjC),1186ScratchArgs));11871188// Create the [NSAutoreleasePool addObject:] summary.1189ScratchArgs = AF.add(ScratchArgs, 0, ArgEffect(Autorelease));1190addClassMethSummary("NSAutoreleasePool", "addObject",1191getPersistentSummary(RetEffect::MakeNoRet(), ScratchArgs,1192ArgEffect(DoNothing),1193ArgEffect(Autorelease)));1194}11951196void RetainSummaryManager::InitializeMethodSummaries() {11971198ArgEffects ScratchArgs = AF.getEmptyMap();1199// Create the "init" selector. It just acts as a pass-through for the1200// receiver.1201const RetainSummary *InitSumm = getPersistentSummary(1202ObjCInitRetE, ScratchArgs, ArgEffect(DecRef, ObjKind::ObjC));1203addNSObjectMethSummary(GetNullarySelector("init", Ctx), InitSumm);12041205// awakeAfterUsingCoder: behaves basically like an 'init' method. It1206// claims the receiver and returns a retained object.1207addNSObjectMethSummary(GetUnarySelector("awakeAfterUsingCoder", Ctx),1208InitSumm);12091210// The next methods are allocators.1211const RetainSummary *AllocSumm = getPersistentSummary(ObjCAllocRetE,1212ScratchArgs);1213const RetainSummary *CFAllocSumm =1214getPersistentSummary(RetEffect::MakeOwned(ObjKind::CF), ScratchArgs);12151216// Create the "retain" selector.1217RetEffect NoRet = RetEffect::MakeNoRet();1218const RetainSummary *Summ = getPersistentSummary(1219NoRet, ScratchArgs, ArgEffect(IncRef, ObjKind::ObjC));1220addNSObjectMethSummary(GetNullarySelector("retain", Ctx), Summ);12211222// Create the "release" selector.1223Summ = getPersistentSummary(NoRet, ScratchArgs,1224ArgEffect(DecRef, ObjKind::ObjC));1225addNSObjectMethSummary(GetNullarySelector("release", Ctx), Summ);12261227// Create the -dealloc summary.1228Summ = getPersistentSummary(NoRet, ScratchArgs, ArgEffect(Dealloc,1229ObjKind::ObjC));1230addNSObjectMethSummary(GetNullarySelector("dealloc", Ctx), Summ);12311232// Create the "autorelease" selector.1233Summ = getPersistentSummary(NoRet, ScratchArgs, ArgEffect(Autorelease,1234ObjKind::ObjC));1235addNSObjectMethSummary(GetNullarySelector("autorelease", Ctx), Summ);12361237// For NSWindow, allocated objects are (initially) self-owned.1238// FIXME: For now we opt for false negatives with NSWindow, as these objects1239// self-own themselves. However, they only do this once they are displayed.1240// Thus, we need to track an NSWindow's display status.1241const RetainSummary *NoTrackYet =1242getPersistentSummary(RetEffect::MakeNoRet(), ScratchArgs,1243ArgEffect(StopTracking), ArgEffect(StopTracking));12441245addClassMethSummary("NSWindow", "alloc", NoTrackYet);12461247// For NSPanel (which subclasses NSWindow), allocated objects are not1248// self-owned.1249// FIXME: For now we don't track NSPanels. object for the same reason1250// as for NSWindow objects.1251addClassMethSummary("NSPanel", "alloc", NoTrackYet);12521253// For NSNull, objects returned by +null are singletons that ignore1254// retain/release semantics. Just don't track them.1255addClassMethSummary("NSNull", "null", NoTrackYet);12561257// Don't track allocated autorelease pools, as it is okay to prematurely1258// exit a method.1259addClassMethSummary("NSAutoreleasePool", "alloc", NoTrackYet);1260addClassMethSummary("NSAutoreleasePool", "allocWithZone", NoTrackYet, false);1261addClassMethSummary("NSAutoreleasePool", "new", NoTrackYet);12621263// Create summaries QCRenderer/QCView -createSnapShotImageOfType:1264addInstMethSummary("QCRenderer", AllocSumm, "createSnapshotImageOfType");1265addInstMethSummary("QCView", AllocSumm, "createSnapshotImageOfType");12661267// Create summaries for CIContext, 'createCGImage' and1268// 'createCGLayerWithSize'. These objects are CF objects, and are not1269// automatically garbage collected.1270addInstMethSummary("CIContext", CFAllocSumm, "createCGImage", "fromRect");1271addInstMethSummary("CIContext", CFAllocSumm, "createCGImage", "fromRect",1272"format", "colorSpace");1273addInstMethSummary("CIContext", CFAllocSumm, "createCGLayerWithSize", "info");1274}12751276const RetainSummary *1277RetainSummaryManager::getMethodSummary(const ObjCMethodDecl *MD) {1278const ObjCInterfaceDecl *ID = MD->getClassInterface();1279Selector S = MD->getSelector();1280QualType ResultTy = MD->getReturnType();12811282ObjCMethodSummariesTy *CachedSummaries;1283if (MD->isInstanceMethod())1284CachedSummaries = &ObjCMethodSummaries;1285else1286CachedSummaries = &ObjCClassMethodSummaries;12871288return getMethodSummary(S, ID, MD, ResultTy, *CachedSummaries);1289}129012911292