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