1 //== RetainSummaryManager.cpp - Summaries for reference counting --*- C++ -*--//
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
7 //===----------------------------------------------------------------------===//
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"
24 using namespace clang
;
28 constexpr static bool isOneOf() {
32 /// Helper function to check whether the class is one of the
34 template <class T
, class P
, class... ToCompare
>
35 constexpr static bool isOneOf() {
36 return std::is_same_v
<T
, P
> || isOneOf
<T
, ToCompare
...>();
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";
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";
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";
69 std::optional
<ObjKind
> RetainSummaryManager::hasAnyEnabledAttrOf(const Decl
*D
,
72 if (isOneOf
<T
, CFConsumedAttr
, CFReturnsRetainedAttr
,
73 CFReturnsNotRetainedAttr
>()) {
74 if (!TrackObjCAndCFObjects
)
78 } else if (isOneOf
<T
, NSConsumedAttr
, NSConsumesSelfAttr
,
79 NSReturnsAutoreleasedAttr
, NSReturnsRetainedAttr
,
80 NSReturnsNotRetainedAttr
, NSConsumesSelfAttr
>()) {
82 if (!TrackObjCAndCFObjects
)
85 if (isOneOf
<T
, NSReturnsRetainedAttr
, NSReturnsAutoreleasedAttr
,
86 NSReturnsNotRetainedAttr
>() &&
87 !cocoa::isCocoaObjectRef(QT
))
90 } else if (isOneOf
<T
, OSConsumedAttr
, OSConsumesThisAttr
,
91 OSReturnsNotRetainedAttr
, OSReturnsRetainedAttr
,
92 OSReturnsRetainedOnZeroAttr
,
93 OSReturnsRetainedOnNonZeroAttr
>()) {
97 } else if (isOneOf
<T
, GeneralizedReturnsNotRetainedAttr
,
98 GeneralizedReturnsRetainedAttr
,
99 GeneralizedConsumedAttr
>()) {
100 K
= ObjKind::Generalized
;
102 llvm_unreachable("Unexpected attribute");
109 template <class T1
, class T2
, class... Others
>
110 std::optional
<ObjKind
> RetainSummaryManager::hasAnyEnabledAttrOf(const Decl
*D
,
112 if (auto Out
= hasAnyEnabledAttrOf
<T1
>(D
, QT
))
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
;
125 CachedSummaryNode
*N
= SimpleSummaries
.FindNodeOrInsertPos(ID
, Pos
);
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
);
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()).starts_with("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
)
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()))
217 for (ParmVarDecl
*Param
: MD
->parameters()) {
218 QualType PT
= Param
->getType()->getPointeeType();
220 if (CXXRecordDecl
*RD
= PT
->getAsCXXRecordDecl())
221 if (isOSObjectSubclass(RD
))
229 RetainSummaryManager::isKnownSmartPointer(QualType QT
) {
230 QT
= QT
.getCanonicalType();
231 const auto *RD
= QT
->getAsCXXRecordDecl();
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")
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
.ends_with("Matching")) {
259 return getPersistentStopSummary();
262 // All objects returned with functions *not* starting with 'get',
263 // or iterators, are returned at +1.
264 if ((!FName
.starts_with("get") && !FName
.starts_with("Get")) ||
265 isOSIteratorSubclass(PD
)) {
266 return getOSSummaryCreateRule(FD
);
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
);
283 return getOSSummaryFreeRule(FD
);
285 if (MD
->getOverloadedOperator() == OO_New
)
286 return getOSSummaryCreateRule(MD
);
293 const RetainSummary
*RetainSummaryManager::getSummaryForObjCOrCFObject(
294 const FunctionDecl
*FD
,
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
),
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(),
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(),
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
356 ScratchArgs
= AF
.add(ScratchArgs
, 7, ArgEffect(StopTracking
));
357 return getPersistentSummary(RetEffect::MakeNoRet(),
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(),
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
381 ScratchArgs
= AF
.add(ScratchArgs
, 5, ArgEffect(StopTracking
));
382 return getPersistentSummary(RetEffect::MakeNoRet(),
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(),
394 ArgEffect(DoNothing
), ArgEffect(DoNothing
));
395 } else if (FName
.starts_with("NSLog")) {
396 return getDoNothingSummary();
397 } else if (FName
.starts_with("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
422 AllowAnnotations
= false;
424 return getUnarySummary(FT
, Autorelease
);
425 } else if (isMakeCollectable(FName
)) {
426 AllowAnnotations
= false;
427 return getUnarySummary(FT
, DoNothing
);
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
);
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
.starts_with("CG") || FName
.starts_with("CF")) {
458 FName
= FName
.substr(FName
.starts_with("CGCF") ? 4 : 2);
460 if (isRelease(FD
, FName
))
461 return getUnarySummary(FT
, DecRef
);
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);
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.
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
)
488 return getPersistentSummary(RetEffect::MakeNoRet(), ScratchArgs
,
489 ArgEffect(DoNothing
), ArgEffect(E
, ObjKind::CF
));
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
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();
516 if (const RetainSummary
*S
= getSummaryForOSObject(FD
, FName
, RetTy
))
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
))
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.
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())
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
;
558 //===----------------------------------------------------------------------===//
559 // Summary creation for functions (largely uses of Core Foundation).
560 //===----------------------------------------------------------------------===//
562 static ArgEffect
getStopTrackingHardEquivalent(ArgEffect E
) {
563 switch (E
.getKind()) {
566 case DecRefBridgedTransferred
:
568 case UnretainedOutParameter
:
569 case RetainedOutParameter
:
570 case RetainedOutParameterOnZero
:
571 case RetainedOutParameterOnNonZero
:
574 case StopTrackingHard
:
575 return E
.withKind(StopTrackingHard
);
577 case DecRefAndStopTrackingHard
:
578 return E
.withKind(DecRefAndStopTrackingHard
);
580 return E
.withKind(Dealloc
);
583 llvm_unreachable("Unknown ArgEffect kind");
586 const RetainSummary
*
587 RetainSummaryManager::updateSummaryForNonZeroCallbackArg(const RetainSummary
*S
,
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();
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
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
;
637 QualType QT
= (*pi
)->getType();
639 // Skip already created values.
640 if (RS
->getArgEffects().contains(parm_idx
))
643 ObjKind K
= ObjKind::AnyObj
;
645 if (isISLObjectRef(QT
)) {
646 K
= ObjKind::Generalized
;
647 } else if (isOSObjectPtr(QT
)) {
649 } else if (cocoa::isCocoaObjectRef(QT
)) {
651 } else if (coreFoundation::isCFObjectRef(QT
)) {
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()));
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());
682 Summ
= getMethodSummary(cast
<ObjCMethodDecl
>(C
.getDecl()));
683 } else if (ME
->isInstanceMessage()) {
684 Summ
= getInstanceMethodSummary(ME
, ReceiverType
);
686 Summ
= getClassMethodSummary(ME
);
692 if (HasNonZeroCallbackArg
)
693 Summ
= updateSummaryForNonZeroCallbackArg(Summ
, C
);
695 if (IsReceiverUnconsumedSelf
)
696 updateSummaryForReceiverUnconsumedSelf(Summ
);
698 updateSummaryForArgumentTypes(C
, Summ
);
700 assert(Summ
&& "Unknown call type?");
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(
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();
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
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.
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
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
;
784 const RetainSummary
*
785 RetainSummaryManager::getUnarySummary(const FunctionType
* FT
,
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(),
802 ArgEffect(DoNothing
), ArgEffect(DoNothing
));
805 const RetainSummary
*
806 RetainSummaryManager::getOSSummaryRetainRule(const FunctionDecl
*FD
) {
807 return getPersistentSummary(RetEffect::MakeNoRet(),
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(),
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(),
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
),
838 const RetainSummary
*
839 RetainSummaryManager::getOSSummaryGetRule(const FunctionDecl
*FD
) {
840 return getPersistentSummary(RetEffect::MakeNotOwned(ObjKind::OS
),
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
,
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
))
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
,
892 while (auto *T
= QT
->getAs
<TypedefType
>()) {
893 const auto &Context
= T
->getDecl()->getASTContext();
894 if (T
->getDecl()->getIdentifier() == &Context
.Idents
.get(Name
))
896 QT
= T
->getDecl()->getUnderlyingType();
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();
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();
916 hasAnyEnabledAttrOf
<NSConsumedAttr
, CFConsumedAttr
, OSConsumedAttr
,
917 GeneralizedConsumedAttr
>(pd
, QT
)) {
918 Template
->addArg(AF
, parm_idx
, ArgEffect(DecRef
, *K
));
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.
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
));
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.
955 } else if (auto K
= hasAnyEnabledAttrOf
<CFReturnsNotRetainedAttr
,
956 OSReturnsNotRetainedAttr
,
957 GeneralizedReturnsNotRetainedAttr
>(
959 Template
->addArg(AF
, parm_idx
, ArgEffect(UnretainedOutParameter
, *K
));
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
))
975 RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary
*&Summ
,
976 const FunctionDecl
*FD
) {
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
));
998 RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary
*&Summ
,
999 const ObjCMethodDecl
*MD
) {
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
;
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()) {
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?
1044 switch (S
.getMethodFamily()) {
1048 case OMF_mutableCopy
:
1049 ResultEff
= RetEffect::MakeOwned(ObjKind::CF
);
1052 ResultEff
= RetEffect::MakeNotOwned(ObjKind::CF
);
1056 ResultEff
= RetEffect::MakeNotOwned(ObjKind::CF
);
1061 ResultEff
= ObjCInitRetE
;
1062 ReceiverEff
= ArgEffect(DecRef
, ObjKind::ObjC
);
1067 case OMF_mutableCopy
:
1068 if (cocoa::isCocoaObjectRef(RetTy
))
1069 ResultEff
= ObjCAllocRetE
;
1070 else if (coreFoundation::isCFObjectRef(RetTy
))
1071 ResultEff
= RetEffect::MakeOwned(ObjKind::CF
);
1073 case OMF_autorelease
:
1074 ReceiverEff
= ArgEffect(Autorelease
, ObjKind::ObjC
);
1077 ReceiverEff
= ArgEffect(IncRef
, ObjKind::ObjC
);
1080 ReceiverEff
= ArgEffect(DecRef
, ObjKind::ObjC
);
1083 ReceiverEff
= ArgEffect(Dealloc
, ObjKind::ObjC
);
1086 // -self is handled specially by the ExprEngine to propagate the receiver.
1088 case OMF_retainCount
:
1090 // These methods don't return objects.
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
1098 if (S
.isKeywordSelector()) {
1099 for (unsigned i
= 0, e
= S
.getNumArgs(); i
!= e
; ++i
) {
1100 StringRef Slot
= S
.getNameForSlot(i
);
1101 if (Slot
.ends_with_insensitive("delegate")) {
1102 if (ResultEff
== ObjCInitRetE
)
1103 ResultEff
= RetEffect::MakeNoRetHard();
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.
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
);
1169 Summ
= getStandardMethodSummary(MD
, S
, RetTy
);
1171 // Annotations override defaults.
1172 updateSummaryFromAnnotations(Summ
, MD
);
1174 // Memoize the summary.
1175 CachedSummaries
[ObjCSummaryKey(ID
, S
)] = 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
),
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
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
),
1211 // The next methods are allocators.
1212 const RetainSummary
*AllocSumm
= getPersistentSummary(ObjCAllocRetE
,
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
,
1231 addNSObjectMethSummary(GetNullarySelector("dealloc", Ctx
), Summ
);
1233 // Create the "autorelease" selector.
1234 Summ
= getPersistentSummary(NoRet
, ScratchArgs
, ArgEffect(Autorelease
,
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
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
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
;
1287 CachedSummaries
= &ObjCClassMethodSummaries
;
1289 return getMethodSummary(S
, ID
, MD
, ResultTy
, *CachedSummaries
);