123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296 |
- //== RetainSummaryManager.cpp - Summaries for reference counting --*- C++ -*--//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- //
- // This file defines summaries implementation for retain counting, which
- // implements a reference count checker for Core Foundation, Cocoa
- // and OSObject (on Mac OS X).
- //
- //===----------------------------------------------------------------------===//
- #include "clang/Analysis/DomainSpecific/CocoaConventions.h"
- #include "clang/Analysis/RetainSummaryManager.h"
- #include "clang/AST/Attr.h"
- #include "clang/AST/DeclCXX.h"
- #include "clang/AST/DeclObjC.h"
- #include "clang/AST/ParentMap.h"
- #include "clang/ASTMatchers/ASTMatchFinder.h"
- using namespace clang;
- using namespace ento;
- template <class T>
- constexpr static bool isOneOf() {
- return false;
- }
- /// Helper function to check whether the class is one of the
- /// rest of varargs.
- template <class T, class P, class... ToCompare>
- constexpr static bool isOneOf() {
- return std::is_same<T, P>::value || isOneOf<T, ToCompare...>();
- }
- namespace {
- /// Fake attribute class for RC* attributes.
- struct GeneralizedReturnsRetainedAttr {
- static bool classof(const Attr *A) {
- if (auto AA = dyn_cast<AnnotateAttr>(A))
- return AA->getAnnotation() == "rc_ownership_returns_retained";
- return false;
- }
- };
- struct GeneralizedReturnsNotRetainedAttr {
- static bool classof(const Attr *A) {
- if (auto AA = dyn_cast<AnnotateAttr>(A))
- return AA->getAnnotation() == "rc_ownership_returns_not_retained";
- return false;
- }
- };
- struct GeneralizedConsumedAttr {
- static bool classof(const Attr *A) {
- if (auto AA = dyn_cast<AnnotateAttr>(A))
- return AA->getAnnotation() == "rc_ownership_consumed";
- return false;
- }
- };
- }
- template <class T>
- Optional<ObjKind> RetainSummaryManager::hasAnyEnabledAttrOf(const Decl *D,
- QualType QT) {
- ObjKind K;
- if (isOneOf<T, CFConsumedAttr, CFReturnsRetainedAttr,
- CFReturnsNotRetainedAttr>()) {
- if (!TrackObjCAndCFObjects)
- return None;
- K = ObjKind::CF;
- } else if (isOneOf<T, NSConsumedAttr, NSConsumesSelfAttr,
- NSReturnsAutoreleasedAttr, NSReturnsRetainedAttr,
- NSReturnsNotRetainedAttr, NSConsumesSelfAttr>()) {
- if (!TrackObjCAndCFObjects)
- return None;
- if (isOneOf<T, NSReturnsRetainedAttr, NSReturnsAutoreleasedAttr,
- NSReturnsNotRetainedAttr>() &&
- !cocoa::isCocoaObjectRef(QT))
- return None;
- K = ObjKind::ObjC;
- } else if (isOneOf<T, OSConsumedAttr, OSConsumesThisAttr,
- OSReturnsNotRetainedAttr, OSReturnsRetainedAttr,
- OSReturnsRetainedOnZeroAttr,
- OSReturnsRetainedOnNonZeroAttr>()) {
- if (!TrackOSObjects)
- return None;
- K = ObjKind::OS;
- } else if (isOneOf<T, GeneralizedReturnsNotRetainedAttr,
- GeneralizedReturnsRetainedAttr,
- GeneralizedConsumedAttr>()) {
- K = ObjKind::Generalized;
- } else {
- llvm_unreachable("Unexpected attribute");
- }
- if (D->hasAttr<T>())
- return K;
- return None;
- }
- template <class T1, class T2, class... Others>
- Optional<ObjKind> RetainSummaryManager::hasAnyEnabledAttrOf(const Decl *D,
- QualType QT) {
- if (auto Out = hasAnyEnabledAttrOf<T1>(D, QT))
- return Out;
- return hasAnyEnabledAttrOf<T2, Others...>(D, QT);
- }
- const RetainSummary *
- RetainSummaryManager::getPersistentSummary(const RetainSummary &OldSumm) {
- // Unique "simple" summaries -- those without ArgEffects.
- if (OldSumm.isSimple()) {
- ::llvm::FoldingSetNodeID ID;
- OldSumm.Profile(ID);
- void *Pos;
- CachedSummaryNode *N = SimpleSummaries.FindNodeOrInsertPos(ID, Pos);
- if (!N) {
- N = (CachedSummaryNode *) BPAlloc.Allocate<CachedSummaryNode>();
- new (N) CachedSummaryNode(OldSumm);
- SimpleSummaries.InsertNode(N, Pos);
- }
- return &N->getValue();
- }
- RetainSummary *Summ = (RetainSummary *) BPAlloc.Allocate<RetainSummary>();
- new (Summ) RetainSummary(OldSumm);
- return Summ;
- }
- static bool isSubclass(const Decl *D,
- StringRef ClassName) {
- using namespace ast_matchers;
- DeclarationMatcher SubclassM =
- cxxRecordDecl(isSameOrDerivedFrom(std::string(ClassName)));
- return !(match(SubclassM, *D, D->getASTContext()).empty());
- }
- static bool isExactClass(const Decl *D, StringRef ClassName) {
- using namespace ast_matchers;
- DeclarationMatcher sameClassM =
- cxxRecordDecl(hasName(std::string(ClassName)));
- return !(match(sameClassM, *D, D->getASTContext()).empty());
- }
- static bool isOSObjectSubclass(const Decl *D) {
- return D && isSubclass(D, "OSMetaClassBase") &&
- !isExactClass(D, "OSMetaClass");
- }
- static bool isOSObjectDynamicCast(StringRef S) { return S == "safeMetaCast"; }
- static bool isOSObjectRequiredCast(StringRef S) {
- return S == "requiredMetaCast";
- }
- static bool isOSObjectThisCast(StringRef S) {
- return S == "metaCast";
- }
- static bool isOSObjectPtr(QualType QT) {
- return isOSObjectSubclass(QT->getPointeeCXXRecordDecl());
- }
- static bool isISLObjectRef(QualType Ty) {
- return StringRef(Ty.getAsString()).startswith("isl_");
- }
- static bool isOSIteratorSubclass(const Decl *D) {
- return isSubclass(D, "OSIterator");
- }
- static bool hasRCAnnotation(const Decl *D, StringRef rcAnnotation) {
- for (const auto *Ann : D->specific_attrs<AnnotateAttr>()) {
- if (Ann->getAnnotation() == rcAnnotation)
- return true;
- }
- return false;
- }
- static bool isRetain(const FunctionDecl *FD, StringRef FName) {
- return FName.startswith_insensitive("retain") ||
- FName.endswith_insensitive("retain");
- }
- static bool isRelease(const FunctionDecl *FD, StringRef FName) {
- return FName.startswith_insensitive("release") ||
- FName.endswith_insensitive("release");
- }
- static bool isAutorelease(const FunctionDecl *FD, StringRef FName) {
- return FName.startswith_insensitive("autorelease") ||
- FName.endswith_insensitive("autorelease");
- }
- static bool isMakeCollectable(StringRef FName) {
- return FName.contains_insensitive("MakeCollectable");
- }
- /// A function is OSObject related if it is declared on a subclass
- /// of OSObject, or any of the parameters is a subclass of an OSObject.
- static bool isOSObjectRelated(const CXXMethodDecl *MD) {
- if (isOSObjectSubclass(MD->getParent()))
- return true;
- for (ParmVarDecl *Param : MD->parameters()) {
- QualType PT = Param->getType()->getPointeeType();
- if (!PT.isNull())
- if (CXXRecordDecl *RD = PT->getAsCXXRecordDecl())
- if (isOSObjectSubclass(RD))
- return true;
- }
- return false;
- }
- bool
- RetainSummaryManager::isKnownSmartPointer(QualType QT) {
- QT = QT.getCanonicalType();
- const auto *RD = QT->getAsCXXRecordDecl();
- if (!RD)
- return false;
- const IdentifierInfo *II = RD->getIdentifier();
- if (II && II->getName() == "smart_ptr")
- if (const auto *ND = dyn_cast<NamespaceDecl>(RD->getDeclContext()))
- if (ND->getNameAsString() == "os")
- return true;
- return false;
- }
- const RetainSummary *
- RetainSummaryManager::getSummaryForOSObject(const FunctionDecl *FD,
- StringRef FName, QualType RetTy) {
- assert(TrackOSObjects &&
- "Requesting a summary for an OSObject but OSObjects are not tracked");
- if (RetTy->isPointerType()) {
- const CXXRecordDecl *PD = RetTy->getPointeeType()->getAsCXXRecordDecl();
- if (PD && isOSObjectSubclass(PD)) {
- if (isOSObjectDynamicCast(FName) || isOSObjectRequiredCast(FName) ||
- isOSObjectThisCast(FName))
- return getDefaultSummary();
- // TODO: Add support for the slightly common *Matching(table) idiom.
- // Cf. IOService::nameMatching() etc. - these function have an unusual
- // contract of returning at +0 or +1 depending on their last argument.
- if (FName.endswith("Matching")) {
- return getPersistentStopSummary();
- }
- // All objects returned with functions *not* starting with 'get',
- // or iterators, are returned at +1.
- if ((!FName.startswith("get") && !FName.startswith("Get")) ||
- isOSIteratorSubclass(PD)) {
- return getOSSummaryCreateRule(FD);
- } else {
- return getOSSummaryGetRule(FD);
- }
- }
- }
- if (const auto *MD = dyn_cast<CXXMethodDecl>(FD)) {
- const CXXRecordDecl *Parent = MD->getParent();
- if (Parent && isOSObjectSubclass(Parent)) {
- if (FName == "release" || FName == "taggedRelease")
- return getOSSummaryReleaseRule(FD);
- if (FName == "retain" || FName == "taggedRetain")
- return getOSSummaryRetainRule(FD);
- if (FName == "free")
- return getOSSummaryFreeRule(FD);
- if (MD->getOverloadedOperator() == OO_New)
- return getOSSummaryCreateRule(MD);
- }
- }
- return nullptr;
- }
- const RetainSummary *RetainSummaryManager::getSummaryForObjCOrCFObject(
- const FunctionDecl *FD,
- StringRef FName,
- QualType RetTy,
- const FunctionType *FT,
- bool &AllowAnnotations) {
- ArgEffects ScratchArgs(AF.getEmptyMap());
- std::string RetTyName = RetTy.getAsString();
- if (FName == "pthread_create" || FName == "pthread_setspecific") {
- // Part of: <rdar://problem/7299394> and <rdar://problem/11282706>.
- // This will be addressed better with IPA.
- return getPersistentStopSummary();
- } else if(FName == "NSMakeCollectable") {
- // Handle: id NSMakeCollectable(CFTypeRef)
- AllowAnnotations = false;
- return RetTy->isObjCIdType() ? getUnarySummary(FT, DoNothing)
- : getPersistentStopSummary();
- } else if (FName == "CMBufferQueueDequeueAndRetain" ||
- FName == "CMBufferQueueDequeueIfDataReadyAndRetain") {
- // Part of: <rdar://problem/39390714>.
- return getPersistentSummary(RetEffect::MakeOwned(ObjKind::CF),
- ScratchArgs,
- ArgEffect(DoNothing),
- ArgEffect(DoNothing));
- } else if (FName == "CFPlugInInstanceCreate") {
- return getPersistentSummary(RetEffect::MakeNoRet(), ScratchArgs);
- } else if (FName == "IORegistryEntrySearchCFProperty" ||
- (RetTyName == "CFMutableDictionaryRef" &&
- (FName == "IOBSDNameMatching" || FName == "IOServiceMatching" ||
- FName == "IOServiceNameMatching" ||
- FName == "IORegistryEntryIDMatching" ||
- FName == "IOOpenFirmwarePathMatching"))) {
- // Part of <rdar://problem/6961230>. (IOKit)
- // This should be addressed using a API table.
- return getPersistentSummary(RetEffect::MakeOwned(ObjKind::CF), ScratchArgs,
- ArgEffect(DoNothing), ArgEffect(DoNothing));
- } else if (FName == "IOServiceGetMatchingService" ||
- FName == "IOServiceGetMatchingServices") {
- // FIXES: <rdar://problem/6326900>
- // This should be addressed using a API table. This strcmp is also
- // a little gross, but there is no need to super optimize here.
- ScratchArgs = AF.add(ScratchArgs, 1, ArgEffect(DecRef, ObjKind::CF));
- return getPersistentSummary(RetEffect::MakeNoRet(),
- ScratchArgs,
- ArgEffect(DoNothing), ArgEffect(DoNothing));
- } else if (FName == "IOServiceAddNotification" ||
- FName == "IOServiceAddMatchingNotification") {
- // Part of <rdar://problem/6961230>. (IOKit)
- // This should be addressed using a API table.
- ScratchArgs = AF.add(ScratchArgs, 2, ArgEffect(DecRef, ObjKind::CF));
- return getPersistentSummary(RetEffect::MakeNoRet(),
- ScratchArgs,
- ArgEffect(DoNothing), ArgEffect(DoNothing));
- } else if (FName == "CVPixelBufferCreateWithBytes") {
- // FIXES: <rdar://problem/7283567>
- // Eventually this can be improved by recognizing that the pixel
- // buffer passed to CVPixelBufferCreateWithBytes is released via
- // a callback and doing full IPA to make sure this is done correctly.
- // FIXME: This function has an out parameter that returns an
- // allocated object.
- ScratchArgs = AF.add(ScratchArgs, 7, ArgEffect(StopTracking));
- return getPersistentSummary(RetEffect::MakeNoRet(),
- ScratchArgs,
- ArgEffect(DoNothing), ArgEffect(DoNothing));
- } else if (FName == "CGBitmapContextCreateWithData") {
- // FIXES: <rdar://problem/7358899>
- // Eventually this can be improved by recognizing that 'releaseInfo'
- // passed to CGBitmapContextCreateWithData is released via
- // a callback and doing full IPA to make sure this is done correctly.
- ScratchArgs = AF.add(ScratchArgs, 8, ArgEffect(ArgEffect(StopTracking)));
- return getPersistentSummary(RetEffect::MakeOwned(ObjKind::CF), ScratchArgs,
- ArgEffect(DoNothing), ArgEffect(DoNothing));
- } else if (FName == "CVPixelBufferCreateWithPlanarBytes") {
- // FIXES: <rdar://problem/7283567>
- // Eventually this can be improved by recognizing that the pixel
- // buffer passed to CVPixelBufferCreateWithPlanarBytes is released
- // via a callback and doing full IPA to make sure this is done
- // correctly.
- ScratchArgs = AF.add(ScratchArgs, 12, ArgEffect(StopTracking));
- return getPersistentSummary(RetEffect::MakeNoRet(),
- ScratchArgs,
- ArgEffect(DoNothing), ArgEffect(DoNothing));
- } else if (FName == "VTCompressionSessionEncodeFrame") {
- // The context argument passed to VTCompressionSessionEncodeFrame()
- // is passed to the callback specified when creating the session
- // (e.g. with VTCompressionSessionCreate()) which can release it.
- // To account for this possibility, conservatively stop tracking
- // the context.
- ScratchArgs = AF.add(ScratchArgs, 5, ArgEffect(StopTracking));
- return getPersistentSummary(RetEffect::MakeNoRet(),
- ScratchArgs,
- ArgEffect(DoNothing), ArgEffect(DoNothing));
- } else if (FName == "dispatch_set_context" ||
- FName == "xpc_connection_set_context") {
- // <rdar://problem/11059275> - The analyzer currently doesn't have
- // a good way to reason about the finalizer function for libdispatch.
- // If we pass a context object that is memory managed, stop tracking it.
- // <rdar://problem/13783514> - Same problem, but for XPC.
- // FIXME: this hack should possibly go away once we can handle
- // libdispatch and XPC finalizers.
- ScratchArgs = AF.add(ScratchArgs, 1, ArgEffect(StopTracking));
- return getPersistentSummary(RetEffect::MakeNoRet(),
- ScratchArgs,
- ArgEffect(DoNothing), ArgEffect(DoNothing));
- } else if (FName.startswith("NSLog")) {
- return getDoNothingSummary();
- } else if (FName.startswith("NS") && FName.contains("Insert")) {
- // Whitelist NSXXInsertXX, for example NSMapInsertIfAbsent, since they can
- // be deallocated by NSMapRemove. (radar://11152419)
- ScratchArgs = AF.add(ScratchArgs, 1, ArgEffect(StopTracking));
- ScratchArgs = AF.add(ScratchArgs, 2, ArgEffect(StopTracking));
- return getPersistentSummary(RetEffect::MakeNoRet(),
- ScratchArgs, ArgEffect(DoNothing),
- ArgEffect(DoNothing));
- }
- if (RetTy->isPointerType()) {
- // For CoreFoundation ('CF') types.
- if (cocoa::isRefType(RetTy, "CF", FName)) {
- if (isRetain(FD, FName)) {
- // CFRetain isn't supposed to be annotated. However, this may as
- // well be a user-made "safe" CFRetain function that is incorrectly
- // annotated as cf_returns_retained due to lack of better options.
- // We want to ignore such annotation.
- AllowAnnotations = false;
- return getUnarySummary(FT, IncRef);
- } else if (isAutorelease(FD, FName)) {
- // The headers use cf_consumed, but we can fully model CFAutorelease
- // ourselves.
- AllowAnnotations = false;
- return getUnarySummary(FT, Autorelease);
- } else if (isMakeCollectable(FName)) {
- AllowAnnotations = false;
- return getUnarySummary(FT, DoNothing);
- } else {
- return getCFCreateGetRuleSummary(FD);
- }
- }
- // For CoreGraphics ('CG') and CoreVideo ('CV') types.
- if (cocoa::isRefType(RetTy, "CG", FName) ||
- cocoa::isRefType(RetTy, "CV", FName)) {
- if (isRetain(FD, FName))
- return getUnarySummary(FT, IncRef);
- else
- return getCFCreateGetRuleSummary(FD);
- }
- // For all other CF-style types, use the Create/Get
- // rule for summaries but don't support Retain functions
- // with framework-specific prefixes.
- if (coreFoundation::isCFObjectRef(RetTy)) {
- return getCFCreateGetRuleSummary(FD);
- }
- if (FD->hasAttr<CFAuditedTransferAttr>()) {
- return getCFCreateGetRuleSummary(FD);
- }
- }
- // Check for release functions, the only kind of functions that we care
- // about that don't return a pointer type.
- if (FName.startswith("CG") || FName.startswith("CF")) {
- // Test for 'CGCF'.
- FName = FName.substr(FName.startswith("CGCF") ? 4 : 2);
- if (isRelease(FD, FName))
- return getUnarySummary(FT, DecRef);
- else {
- assert(ScratchArgs.isEmpty());
- // Remaining CoreFoundation and CoreGraphics functions.
- // We use to assume that they all strictly followed the ownership idiom
- // and that ownership cannot be transferred. While this is technically
- // correct, many methods allow a tracked object to escape. For example:
- //
- // CFMutableDictionaryRef x = CFDictionaryCreateMutable(...);
- // CFDictionaryAddValue(y, key, x);
- // CFRelease(x);
- // ... it is okay to use 'x' since 'y' has a reference to it
- //
- // We handle this and similar cases with the follow heuristic. If the
- // function name contains "InsertValue", "SetValue", "AddValue",
- // "AppendValue", or "SetAttribute", then we assume that arguments may
- // "escape." This means that something else holds on to the object,
- // allowing it be used even after its local retain count drops to 0.
- ArgEffectKind E =
- (StrInStrNoCase(FName, "InsertValue") != StringRef::npos ||
- StrInStrNoCase(FName, "AddValue") != StringRef::npos ||
- StrInStrNoCase(FName, "SetValue") != StringRef::npos ||
- StrInStrNoCase(FName, "AppendValue") != StringRef::npos ||
- StrInStrNoCase(FName, "SetAttribute") != StringRef::npos)
- ? MayEscape
- : DoNothing;
- return getPersistentSummary(RetEffect::MakeNoRet(), ScratchArgs,
- ArgEffect(DoNothing), ArgEffect(E, ObjKind::CF));
- }
- }
- return nullptr;
- }
- const RetainSummary *
- RetainSummaryManager::generateSummary(const FunctionDecl *FD,
- bool &AllowAnnotations) {
- // We generate "stop" summaries for implicitly defined functions.
- if (FD->isImplicit())
- return getPersistentStopSummary();
- const IdentifierInfo *II = FD->getIdentifier();
- StringRef FName = II ? II->getName() : "";
- // Strip away preceding '_'. Doing this here will effect all the checks
- // down below.
- FName = FName.substr(FName.find_first_not_of('_'));
- // Inspect the result type. Strip away any typedefs.
- const auto *FT = FD->getType()->castAs<FunctionType>();
- QualType RetTy = FT->getReturnType();
- if (TrackOSObjects)
- if (const RetainSummary *S = getSummaryForOSObject(FD, FName, RetTy))
- return S;
- if (const auto *MD = dyn_cast<CXXMethodDecl>(FD))
- if (!isOSObjectRelated(MD))
- return getPersistentSummary(RetEffect::MakeNoRet(),
- ArgEffects(AF.getEmptyMap()),
- ArgEffect(DoNothing),
- ArgEffect(StopTracking),
- ArgEffect(DoNothing));
- if (TrackObjCAndCFObjects)
- if (const RetainSummary *S =
- getSummaryForObjCOrCFObject(FD, FName, RetTy, FT, AllowAnnotations))
- return S;
- return getDefaultSummary();
- }
- const RetainSummary *
- RetainSummaryManager::getFunctionSummary(const FunctionDecl *FD) {
- // If we don't know what function we're calling, use our default summary.
- if (!FD)
- return getDefaultSummary();
- // Look up a summary in our cache of FunctionDecls -> Summaries.
- FuncSummariesTy::iterator I = FuncSummaries.find(FD);
- if (I != FuncSummaries.end())
- return I->second;
- // No summary? Generate one.
- bool AllowAnnotations = true;
- const RetainSummary *S = generateSummary(FD, AllowAnnotations);
- // Annotations override defaults.
- if (AllowAnnotations)
- updateSummaryFromAnnotations(S, FD);
- FuncSummaries[FD] = S;
- return S;
- }
- //===----------------------------------------------------------------------===//
- // Summary creation for functions (largely uses of Core Foundation).
- //===----------------------------------------------------------------------===//
- static ArgEffect getStopTrackingHardEquivalent(ArgEffect E) {
- switch (E.getKind()) {
- case DoNothing:
- case Autorelease:
- case DecRefBridgedTransferred:
- case IncRef:
- case UnretainedOutParameter:
- case RetainedOutParameter:
- case RetainedOutParameterOnZero:
- case RetainedOutParameterOnNonZero:
- case MayEscape:
- case StopTracking:
- case StopTrackingHard:
- return E.withKind(StopTrackingHard);
- case DecRef:
- case DecRefAndStopTrackingHard:
- return E.withKind(DecRefAndStopTrackingHard);
- case Dealloc:
- return E.withKind(Dealloc);
- }
- llvm_unreachable("Unknown ArgEffect kind");
- }
- const RetainSummary *
- RetainSummaryManager::updateSummaryForNonZeroCallbackArg(const RetainSummary *S,
- AnyCall &C) {
- ArgEffect RecEffect = getStopTrackingHardEquivalent(S->getReceiverEffect());
- ArgEffect DefEffect = getStopTrackingHardEquivalent(S->getDefaultArgEffect());
- ArgEffects ScratchArgs(AF.getEmptyMap());
- ArgEffects CustomArgEffects = S->getArgEffects();
- for (ArgEffects::iterator I = CustomArgEffects.begin(),
- E = CustomArgEffects.end();
- I != E; ++I) {
- ArgEffect Translated = getStopTrackingHardEquivalent(I->second);
- if (Translated.getKind() != DefEffect.getKind())
- ScratchArgs = AF.add(ScratchArgs, I->first, Translated);
- }
- RetEffect RE = RetEffect::MakeNoRetHard();
- // Special cases where the callback argument CANNOT free the return value.
- // This can generally only happen if we know that the callback will only be
- // called when the return value is already being deallocated.
- if (const IdentifierInfo *Name = C.getIdentifier()) {
- // When the CGBitmapContext is deallocated, the callback here will free
- // the associated data buffer.
- // The callback in dispatch_data_create frees the buffer, but not
- // the data object.
- if (Name->isStr("CGBitmapContextCreateWithData") ||
- Name->isStr("dispatch_data_create"))
- RE = S->getRetEffect();
- }
- return getPersistentSummary(RE, ScratchArgs, RecEffect, DefEffect);
- }
- void RetainSummaryManager::updateSummaryForReceiverUnconsumedSelf(
- const RetainSummary *&S) {
- RetainSummaryTemplate Template(S, *this);
- Template->setReceiverEffect(ArgEffect(DoNothing));
- Template->setRetEffect(RetEffect::MakeNoRet());
- }
- void RetainSummaryManager::updateSummaryForArgumentTypes(
- const AnyCall &C, const RetainSummary *&RS) {
- RetainSummaryTemplate Template(RS, *this);
- unsigned parm_idx = 0;
- for (auto pi = C.param_begin(), pe = C.param_end(); pi != pe;
- ++pi, ++parm_idx) {
- QualType QT = (*pi)->getType();
- // Skip already created values.
- if (RS->getArgEffects().contains(parm_idx))
- continue;
- ObjKind K = ObjKind::AnyObj;
- if (isISLObjectRef(QT)) {
- K = ObjKind::Generalized;
- } else if (isOSObjectPtr(QT)) {
- K = ObjKind::OS;
- } else if (cocoa::isCocoaObjectRef(QT)) {
- K = ObjKind::ObjC;
- } else if (coreFoundation::isCFObjectRef(QT)) {
- K = ObjKind::CF;
- }
- if (K != ObjKind::AnyObj)
- Template->addArg(AF, parm_idx,
- ArgEffect(RS->getDefaultArgEffect().getKind(), K));
- }
- }
- const RetainSummary *
- RetainSummaryManager::getSummary(AnyCall C,
- bool HasNonZeroCallbackArg,
- bool IsReceiverUnconsumedSelf,
- QualType ReceiverType) {
- const RetainSummary *Summ;
- switch (C.getKind()) {
- case AnyCall::Function:
- case AnyCall::Constructor:
- case AnyCall::InheritedConstructor:
- case AnyCall::Allocator:
- case AnyCall::Deallocator:
- Summ = getFunctionSummary(cast_or_null<FunctionDecl>(C.getDecl()));
- break;
- case AnyCall::Block:
- case AnyCall::Destructor:
- // FIXME: These calls are currently unsupported.
- return getPersistentStopSummary();
- case AnyCall::ObjCMethod: {
- const auto *ME = cast_or_null<ObjCMessageExpr>(C.getExpr());
- if (!ME) {
- Summ = getMethodSummary(cast<ObjCMethodDecl>(C.getDecl()));
- } else if (ME->isInstanceMessage()) {
- Summ = getInstanceMethodSummary(ME, ReceiverType);
- } else {
- Summ = getClassMethodSummary(ME);
- }
- break;
- }
- }
- if (HasNonZeroCallbackArg)
- Summ = updateSummaryForNonZeroCallbackArg(Summ, C);
- if (IsReceiverUnconsumedSelf)
- updateSummaryForReceiverUnconsumedSelf(Summ);
- updateSummaryForArgumentTypes(C, Summ);
- assert(Summ && "Unknown call type?");
- return Summ;
- }
- const RetainSummary *
- RetainSummaryManager::getCFCreateGetRuleSummary(const FunctionDecl *FD) {
- if (coreFoundation::followsCreateRule(FD))
- return getCFSummaryCreateRule(FD);
- return getCFSummaryGetRule(FD);
- }
- bool RetainSummaryManager::isTrustedReferenceCountImplementation(
- const Decl *FD) {
- return hasRCAnnotation(FD, "rc_ownership_trusted_implementation");
- }
- Optional<RetainSummaryManager::BehaviorSummary>
- RetainSummaryManager::canEval(const CallExpr *CE, const FunctionDecl *FD,
- bool &hasTrustedImplementationAnnotation) {
- IdentifierInfo *II = FD->getIdentifier();
- if (!II)
- return None;
- StringRef FName = II->getName();
- FName = FName.substr(FName.find_first_not_of('_'));
- QualType ResultTy = CE->getCallReturnType(Ctx);
- if (ResultTy->isObjCIdType()) {
- if (II->isStr("NSMakeCollectable"))
- return BehaviorSummary::Identity;
- } else if (ResultTy->isPointerType()) {
- // Handle: (CF|CG|CV)Retain
- // CFAutorelease
- // It's okay to be a little sloppy here.
- if (FName == "CMBufferQueueDequeueAndRetain" ||
- FName == "CMBufferQueueDequeueIfDataReadyAndRetain") {
- // Part of: <rdar://problem/39390714>.
- // These are not retain. They just return something and retain it.
- return None;
- }
- if (CE->getNumArgs() == 1 &&
- (cocoa::isRefType(ResultTy, "CF", FName) ||
- cocoa::isRefType(ResultTy, "CG", FName) ||
- cocoa::isRefType(ResultTy, "CV", FName)) &&
- (isRetain(FD, FName) || isAutorelease(FD, FName) ||
- isMakeCollectable(FName)))
- return BehaviorSummary::Identity;
- // safeMetaCast is called by OSDynamicCast.
- // We assume that OSDynamicCast is either an identity (cast is OK,
- // the input was non-zero),
- // or that it returns zero (when the cast failed, or the input
- // was zero).
- if (TrackOSObjects) {
- if (isOSObjectDynamicCast(FName) && FD->param_size() >= 1) {
- return BehaviorSummary::IdentityOrZero;
- } else if (isOSObjectRequiredCast(FName) && FD->param_size() >= 1) {
- return BehaviorSummary::Identity;
- } else if (isOSObjectThisCast(FName) && isa<CXXMethodDecl>(FD) &&
- !cast<CXXMethodDecl>(FD)->isStatic()) {
- return BehaviorSummary::IdentityThis;
- }
- }
- const FunctionDecl* FDD = FD->getDefinition();
- if (FDD && isTrustedReferenceCountImplementation(FDD)) {
- hasTrustedImplementationAnnotation = true;
- return BehaviorSummary::Identity;
- }
- }
- if (const auto *MD = dyn_cast<CXXMethodDecl>(FD)) {
- const CXXRecordDecl *Parent = MD->getParent();
- if (TrackOSObjects && Parent && isOSObjectSubclass(Parent))
- if (FName == "release" || FName == "retain")
- return BehaviorSummary::NoOp;
- }
- return None;
- }
- const RetainSummary *
- RetainSummaryManager::getUnarySummary(const FunctionType* FT,
- ArgEffectKind AE) {
- // Unary functions have no arg effects by definition.
- ArgEffects ScratchArgs(AF.getEmptyMap());
- // Verify that this is *really* a unary function. This can
- // happen if people do weird things.
- const FunctionProtoType* FTP = dyn_cast<FunctionProtoType>(FT);
- if (!FTP || FTP->getNumParams() != 1)
- return getPersistentStopSummary();
- ArgEffect Effect(AE, ObjKind::CF);
- ScratchArgs = AF.add(ScratchArgs, 0, Effect);
- return getPersistentSummary(RetEffect::MakeNoRet(),
- ScratchArgs,
- ArgEffect(DoNothing), ArgEffect(DoNothing));
- }
- const RetainSummary *
- RetainSummaryManager::getOSSummaryRetainRule(const FunctionDecl *FD) {
- return getPersistentSummary(RetEffect::MakeNoRet(),
- AF.getEmptyMap(),
- /*ReceiverEff=*/ArgEffect(DoNothing),
- /*DefaultEff=*/ArgEffect(DoNothing),
- /*ThisEff=*/ArgEffect(IncRef, ObjKind::OS));
- }
- const RetainSummary *
- RetainSummaryManager::getOSSummaryReleaseRule(const FunctionDecl *FD) {
- return getPersistentSummary(RetEffect::MakeNoRet(),
- AF.getEmptyMap(),
- /*ReceiverEff=*/ArgEffect(DoNothing),
- /*DefaultEff=*/ArgEffect(DoNothing),
- /*ThisEff=*/ArgEffect(DecRef, ObjKind::OS));
- }
- const RetainSummary *
- RetainSummaryManager::getOSSummaryFreeRule(const FunctionDecl *FD) {
- return getPersistentSummary(RetEffect::MakeNoRet(),
- AF.getEmptyMap(),
- /*ReceiverEff=*/ArgEffect(DoNothing),
- /*DefaultEff=*/ArgEffect(DoNothing),
- /*ThisEff=*/ArgEffect(Dealloc, ObjKind::OS));
- }
- const RetainSummary *
- RetainSummaryManager::getOSSummaryCreateRule(const FunctionDecl *FD) {
- return getPersistentSummary(RetEffect::MakeOwned(ObjKind::OS),
- AF.getEmptyMap());
- }
- const RetainSummary *
- RetainSummaryManager::getOSSummaryGetRule(const FunctionDecl *FD) {
- return getPersistentSummary(RetEffect::MakeNotOwned(ObjKind::OS),
- AF.getEmptyMap());
- }
- const RetainSummary *
- RetainSummaryManager::getCFSummaryCreateRule(const FunctionDecl *FD) {
- return getPersistentSummary(RetEffect::MakeOwned(ObjKind::CF),
- ArgEffects(AF.getEmptyMap()));
- }
- const RetainSummary *
- RetainSummaryManager::getCFSummaryGetRule(const FunctionDecl *FD) {
- return getPersistentSummary(RetEffect::MakeNotOwned(ObjKind::CF),
- ArgEffects(AF.getEmptyMap()),
- ArgEffect(DoNothing), ArgEffect(DoNothing));
- }
- //===----------------------------------------------------------------------===//
- // Summary creation for Selectors.
- //===----------------------------------------------------------------------===//
- Optional<RetEffect>
- RetainSummaryManager::getRetEffectFromAnnotations(QualType RetTy,
- const Decl *D) {
- if (hasAnyEnabledAttrOf<NSReturnsRetainedAttr>(D, RetTy))
- return ObjCAllocRetE;
- if (auto K = hasAnyEnabledAttrOf<CFReturnsRetainedAttr, OSReturnsRetainedAttr,
- GeneralizedReturnsRetainedAttr>(D, RetTy))
- return RetEffect::MakeOwned(*K);
- if (auto K = hasAnyEnabledAttrOf<
- CFReturnsNotRetainedAttr, OSReturnsNotRetainedAttr,
- GeneralizedReturnsNotRetainedAttr, NSReturnsNotRetainedAttr,
- NSReturnsAutoreleasedAttr>(D, RetTy))
- return RetEffect::MakeNotOwned(*K);
- if (const auto *MD = dyn_cast<CXXMethodDecl>(D))
- for (const auto *PD : MD->overridden_methods())
- if (auto RE = getRetEffectFromAnnotations(RetTy, PD))
- return RE;
- return None;
- }
- /// \return Whether the chain of typedefs starting from @c QT
- /// has a typedef with a given name @c Name.
- static bool hasTypedefNamed(QualType QT,
- StringRef Name) {
- while (auto *T = dyn_cast<TypedefType>(QT)) {
- const auto &Context = T->getDecl()->getASTContext();
- if (T->getDecl()->getIdentifier() == &Context.Idents.get(Name))
- return true;
- QT = T->getDecl()->getUnderlyingType();
- }
- return false;
- }
- static QualType getCallableReturnType(const NamedDecl *ND) {
- if (const auto *FD = dyn_cast<FunctionDecl>(ND)) {
- return FD->getReturnType();
- } else if (const auto *MD = dyn_cast<ObjCMethodDecl>(ND)) {
- return MD->getReturnType();
- } else {
- llvm_unreachable("Unexpected decl");
- }
- }
- bool RetainSummaryManager::applyParamAnnotationEffect(
- const ParmVarDecl *pd, unsigned parm_idx, const NamedDecl *FD,
- RetainSummaryTemplate &Template) {
- QualType QT = pd->getType();
- if (auto K =
- hasAnyEnabledAttrOf<NSConsumedAttr, CFConsumedAttr, OSConsumedAttr,
- GeneralizedConsumedAttr>(pd, QT)) {
- Template->addArg(AF, parm_idx, ArgEffect(DecRef, *K));
- return true;
- } else if (auto K = hasAnyEnabledAttrOf<
- CFReturnsRetainedAttr, OSReturnsRetainedAttr,
- OSReturnsRetainedOnNonZeroAttr, OSReturnsRetainedOnZeroAttr,
- GeneralizedReturnsRetainedAttr>(pd, QT)) {
- // For OSObjects, we try to guess whether the object is created based
- // on the return value.
- if (K == ObjKind::OS) {
- QualType QT = getCallableReturnType(FD);
- bool HasRetainedOnZero = pd->hasAttr<OSReturnsRetainedOnZeroAttr>();
- bool HasRetainedOnNonZero = pd->hasAttr<OSReturnsRetainedOnNonZeroAttr>();
- // The usual convention is to create an object on non-zero return, but
- // it's reverted if the typedef chain has a typedef kern_return_t,
- // because kReturnSuccess constant is defined as zero.
- // The convention can be overwritten by custom attributes.
- bool SuccessOnZero =
- HasRetainedOnZero ||
- (hasTypedefNamed(QT, "kern_return_t") && !HasRetainedOnNonZero);
- bool ShouldSplit = !QT.isNull() && !QT->isVoidType();
- ArgEffectKind AK = RetainedOutParameter;
- if (ShouldSplit && SuccessOnZero) {
- AK = RetainedOutParameterOnZero;
- } else if (ShouldSplit && (!SuccessOnZero || HasRetainedOnNonZero)) {
- AK = RetainedOutParameterOnNonZero;
- }
- Template->addArg(AF, parm_idx, ArgEffect(AK, ObjKind::OS));
- }
- // For others:
- // Do nothing. Retained out parameters will either point to a +1 reference
- // or NULL, but the way you check for failure differs depending on the
- // API. Consequently, we don't have a good way to track them yet.
- return true;
- } else if (auto K = hasAnyEnabledAttrOf<CFReturnsNotRetainedAttr,
- OSReturnsNotRetainedAttr,
- GeneralizedReturnsNotRetainedAttr>(
- pd, QT)) {
- Template->addArg(AF, parm_idx, ArgEffect(UnretainedOutParameter, *K));
- return true;
- }
- if (const auto *MD = dyn_cast<CXXMethodDecl>(FD)) {
- for (const auto *OD : MD->overridden_methods()) {
- const ParmVarDecl *OP = OD->parameters()[parm_idx];
- if (applyParamAnnotationEffect(OP, parm_idx, OD, Template))
- return true;
- }
- }
- return false;
- }
- void
- RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ,
- const FunctionDecl *FD) {
- if (!FD)
- return;
- assert(Summ && "Must have a summary to add annotations to.");
- RetainSummaryTemplate Template(Summ, *this);
- // Effects on the parameters.
- unsigned parm_idx = 0;
- for (auto pi = FD->param_begin(),
- pe = FD->param_end(); pi != pe; ++pi, ++parm_idx)
- applyParamAnnotationEffect(*pi, parm_idx, FD, Template);
- QualType RetTy = FD->getReturnType();
- if (Optional<RetEffect> RetE = getRetEffectFromAnnotations(RetTy, FD))
- Template->setRetEffect(*RetE);
- if (hasAnyEnabledAttrOf<OSConsumesThisAttr>(FD, RetTy))
- Template->setThisEffect(ArgEffect(DecRef, ObjKind::OS));
- }
- void
- RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ,
- const ObjCMethodDecl *MD) {
- if (!MD)
- return;
- assert(Summ && "Must have a valid summary to add annotations to");
- RetainSummaryTemplate Template(Summ, *this);
- // Effects on the receiver.
- if (hasAnyEnabledAttrOf<NSConsumesSelfAttr>(MD, MD->getReturnType()))
- Template->setReceiverEffect(ArgEffect(DecRef, ObjKind::ObjC));
- // Effects on the parameters.
- unsigned parm_idx = 0;
- for (auto pi = MD->param_begin(), pe = MD->param_end(); pi != pe;
- ++pi, ++parm_idx)
- applyParamAnnotationEffect(*pi, parm_idx, MD, Template);
- QualType RetTy = MD->getReturnType();
- if (Optional<RetEffect> RetE = getRetEffectFromAnnotations(RetTy, MD))
- Template->setRetEffect(*RetE);
- }
- const RetainSummary *
- RetainSummaryManager::getStandardMethodSummary(const ObjCMethodDecl *MD,
- Selector S, QualType RetTy) {
- // Any special effects?
- ArgEffect ReceiverEff = ArgEffect(DoNothing, ObjKind::ObjC);
- RetEffect ResultEff = RetEffect::MakeNoRet();
- // Check the method family, and apply any default annotations.
- switch (MD ? MD->getMethodFamily() : S.getMethodFamily()) {
- case OMF_None:
- case OMF_initialize:
- case OMF_performSelector:
- // Assume all Objective-C methods follow Cocoa Memory Management rules.
- // FIXME: Does the non-threaded performSelector family really belong here?
- // The selector could be, say, @selector(copy).
- if (cocoa::isCocoaObjectRef(RetTy))
- ResultEff = RetEffect::MakeNotOwned(ObjKind::ObjC);
- else if (coreFoundation::isCFObjectRef(RetTy)) {
- // ObjCMethodDecl currently doesn't consider CF objects as valid return
- // values for alloc, new, copy, or mutableCopy, so we have to
- // double-check with the selector. This is ugly, but there aren't that
- // many Objective-C methods that return CF objects, right?
- if (MD) {
- switch (S.getMethodFamily()) {
- case OMF_alloc:
- case OMF_new:
- case OMF_copy:
- case OMF_mutableCopy:
- ResultEff = RetEffect::MakeOwned(ObjKind::CF);
- break;
- default:
- ResultEff = RetEffect::MakeNotOwned(ObjKind::CF);
- break;
- }
- } else {
- ResultEff = RetEffect::MakeNotOwned(ObjKind::CF);
- }
- }
- break;
- case OMF_init:
- ResultEff = ObjCInitRetE;
- ReceiverEff = ArgEffect(DecRef, ObjKind::ObjC);
- break;
- case OMF_alloc:
- case OMF_new:
- case OMF_copy:
- case OMF_mutableCopy:
- if (cocoa::isCocoaObjectRef(RetTy))
- ResultEff = ObjCAllocRetE;
- else if (coreFoundation::isCFObjectRef(RetTy))
- ResultEff = RetEffect::MakeOwned(ObjKind::CF);
- break;
- case OMF_autorelease:
- ReceiverEff = ArgEffect(Autorelease, ObjKind::ObjC);
- break;
- case OMF_retain:
- ReceiverEff = ArgEffect(IncRef, ObjKind::ObjC);
- break;
- case OMF_release:
- ReceiverEff = ArgEffect(DecRef, ObjKind::ObjC);
- break;
- case OMF_dealloc:
- ReceiverEff = ArgEffect(Dealloc, ObjKind::ObjC);
- break;
- case OMF_self:
- // -self is handled specially by the ExprEngine to propagate the receiver.
- break;
- case OMF_retainCount:
- case OMF_finalize:
- // These methods don't return objects.
- break;
- }
- // If one of the arguments in the selector has the keyword 'delegate' we
- // should stop tracking the reference count for the receiver. This is
- // because the reference count is quite possibly handled by a delegate
- // method.
- if (S.isKeywordSelector()) {
- for (unsigned i = 0, e = S.getNumArgs(); i != e; ++i) {
- StringRef Slot = S.getNameForSlot(i);
- if (Slot.substr(Slot.size() - 8).equals_insensitive("delegate")) {
- if (ResultEff == ObjCInitRetE)
- ResultEff = RetEffect::MakeNoRetHard();
- else
- ReceiverEff = ArgEffect(StopTrackingHard, ObjKind::ObjC);
- }
- }
- }
- if (ReceiverEff.getKind() == DoNothing &&
- ResultEff.getKind() == RetEffect::NoRet)
- return getDefaultSummary();
- return getPersistentSummary(ResultEff, ArgEffects(AF.getEmptyMap()),
- ArgEffect(ReceiverEff), ArgEffect(MayEscape));
- }
- const RetainSummary *
- RetainSummaryManager::getClassMethodSummary(const ObjCMessageExpr *ME) {
- assert(!ME->isInstanceMessage());
- const ObjCInterfaceDecl *Class = ME->getReceiverInterface();
- return getMethodSummary(ME->getSelector(), Class, ME->getMethodDecl(),
- ME->getType(), ObjCClassMethodSummaries);
- }
- const RetainSummary *RetainSummaryManager::getInstanceMethodSummary(
- const ObjCMessageExpr *ME,
- QualType ReceiverType) {
- const ObjCInterfaceDecl *ReceiverClass = nullptr;
- // We do better tracking of the type of the object than the core ExprEngine.
- // See if we have its type in our private state.
- if (!ReceiverType.isNull())
- if (const auto *PT = ReceiverType->getAs<ObjCObjectPointerType>())
- ReceiverClass = PT->getInterfaceDecl();
- // If we don't know what kind of object this is, fall back to its static type.
- if (!ReceiverClass)
- ReceiverClass = ME->getReceiverInterface();
- // FIXME: The receiver could be a reference to a class, meaning that
- // we should use the class method.
- // id x = [NSObject class];
- // [x performSelector:... withObject:... afterDelay:...];
- Selector S = ME->getSelector();
- const ObjCMethodDecl *Method = ME->getMethodDecl();
- if (!Method && ReceiverClass)
- Method = ReceiverClass->getInstanceMethod(S);
- return getMethodSummary(S, ReceiverClass, Method, ME->getType(),
- ObjCMethodSummaries);
- }
- const RetainSummary *
- RetainSummaryManager::getMethodSummary(Selector S,
- const ObjCInterfaceDecl *ID,
- const ObjCMethodDecl *MD, QualType RetTy,
- ObjCMethodSummariesTy &CachedSummaries) {
- // Objective-C method summaries are only applicable to ObjC and CF objects.
- if (!TrackObjCAndCFObjects)
- return getDefaultSummary();
- // Look up a summary in our summary cache.
- const RetainSummary *Summ = CachedSummaries.find(ID, S);
- if (!Summ) {
- Summ = getStandardMethodSummary(MD, S, RetTy);
- // Annotations override defaults.
- updateSummaryFromAnnotations(Summ, MD);
- // Memoize the summary.
- CachedSummaries[ObjCSummaryKey(ID, S)] = Summ;
- }
- return Summ;
- }
- void RetainSummaryManager::InitializeClassMethodSummaries() {
- ArgEffects ScratchArgs = AF.getEmptyMap();
- // Create the [NSAssertionHandler currentHander] summary.
- addClassMethSummary("NSAssertionHandler", "currentHandler",
- getPersistentSummary(RetEffect::MakeNotOwned(ObjKind::ObjC),
- ScratchArgs));
- // Create the [NSAutoreleasePool addObject:] summary.
- ScratchArgs = AF.add(ScratchArgs, 0, ArgEffect(Autorelease));
- addClassMethSummary("NSAutoreleasePool", "addObject",
- getPersistentSummary(RetEffect::MakeNoRet(), ScratchArgs,
- ArgEffect(DoNothing),
- ArgEffect(Autorelease)));
- }
- void RetainSummaryManager::InitializeMethodSummaries() {
- ArgEffects ScratchArgs = AF.getEmptyMap();
- // Create the "init" selector. It just acts as a pass-through for the
- // receiver.
- const RetainSummary *InitSumm = getPersistentSummary(
- ObjCInitRetE, ScratchArgs, ArgEffect(DecRef, ObjKind::ObjC));
- addNSObjectMethSummary(GetNullarySelector("init", Ctx), InitSumm);
- // awakeAfterUsingCoder: behaves basically like an 'init' method. It
- // claims the receiver and returns a retained object.
- addNSObjectMethSummary(GetUnarySelector("awakeAfterUsingCoder", Ctx),
- InitSumm);
- // The next methods are allocators.
- const RetainSummary *AllocSumm = getPersistentSummary(ObjCAllocRetE,
- ScratchArgs);
- const RetainSummary *CFAllocSumm =
- getPersistentSummary(RetEffect::MakeOwned(ObjKind::CF), ScratchArgs);
- // Create the "retain" selector.
- RetEffect NoRet = RetEffect::MakeNoRet();
- const RetainSummary *Summ = getPersistentSummary(
- NoRet, ScratchArgs, ArgEffect(IncRef, ObjKind::ObjC));
- addNSObjectMethSummary(GetNullarySelector("retain", Ctx), Summ);
- // Create the "release" selector.
- Summ = getPersistentSummary(NoRet, ScratchArgs,
- ArgEffect(DecRef, ObjKind::ObjC));
- addNSObjectMethSummary(GetNullarySelector("release", Ctx), Summ);
- // Create the -dealloc summary.
- Summ = getPersistentSummary(NoRet, ScratchArgs, ArgEffect(Dealloc,
- ObjKind::ObjC));
- addNSObjectMethSummary(GetNullarySelector("dealloc", Ctx), Summ);
- // Create the "autorelease" selector.
- Summ = getPersistentSummary(NoRet, ScratchArgs, ArgEffect(Autorelease,
- ObjKind::ObjC));
- addNSObjectMethSummary(GetNullarySelector("autorelease", Ctx), Summ);
- // For NSWindow, allocated objects are (initially) self-owned.
- // FIXME: For now we opt for false negatives with NSWindow, as these objects
- // self-own themselves. However, they only do this once they are displayed.
- // Thus, we need to track an NSWindow's display status.
- // This is tracked in <rdar://problem/6062711>.
- // See also http://llvm.org/bugs/show_bug.cgi?id=3714.
- const RetainSummary *NoTrackYet =
- getPersistentSummary(RetEffect::MakeNoRet(), ScratchArgs,
- ArgEffect(StopTracking), ArgEffect(StopTracking));
- addClassMethSummary("NSWindow", "alloc", NoTrackYet);
- // For NSPanel (which subclasses NSWindow), allocated objects are not
- // self-owned.
- // FIXME: For now we don't track NSPanels. object for the same reason
- // as for NSWindow objects.
- addClassMethSummary("NSPanel", "alloc", NoTrackYet);
- // For NSNull, objects returned by +null are singletons that ignore
- // retain/release semantics. Just don't track them.
- // <rdar://problem/12858915>
- addClassMethSummary("NSNull", "null", NoTrackYet);
- // Don't track allocated autorelease pools, as it is okay to prematurely
- // exit a method.
- addClassMethSummary("NSAutoreleasePool", "alloc", NoTrackYet);
- addClassMethSummary("NSAutoreleasePool", "allocWithZone", NoTrackYet, false);
- addClassMethSummary("NSAutoreleasePool", "new", NoTrackYet);
- // Create summaries QCRenderer/QCView -createSnapShotImageOfType:
- addInstMethSummary("QCRenderer", AllocSumm, "createSnapshotImageOfType");
- addInstMethSummary("QCView", AllocSumm, "createSnapshotImageOfType");
- // Create summaries for CIContext, 'createCGImage' and
- // 'createCGLayerWithSize'. These objects are CF objects, and are not
- // automatically garbage collected.
- addInstMethSummary("CIContext", CFAllocSumm, "createCGImage", "fromRect");
- addInstMethSummary("CIContext", CFAllocSumm, "createCGImage", "fromRect",
- "format", "colorSpace");
- addInstMethSummary("CIContext", CFAllocSumm, "createCGLayerWithSize", "info");
- }
- const RetainSummary *
- RetainSummaryManager::getMethodSummary(const ObjCMethodDecl *MD) {
- const ObjCInterfaceDecl *ID = MD->getClassInterface();
- Selector S = MD->getSelector();
- QualType ResultTy = MD->getReturnType();
- ObjCMethodSummariesTy *CachedSummaries;
- if (MD->isInstanceMethod())
- CachedSummaries = &ObjCMethodSummaries;
- else
- CachedSummaries = &ObjCClassMethodSummaries;
- return getMethodSummary(S, ID, MD, ResultTy, *CachedSummaries);
- }
|