clang 19.0.0git
RetainSummaryManager.cpp
Go to the documentation of this file.
1//== RetainSummaryManager.cpp - Summaries for reference counting --*- C++ -*--//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file defines summaries implementation for retain counting, which
10// implements a reference count checker for Core Foundation, Cocoa
11// and OSObject (on Mac OS X).
12//
13//===----------------------------------------------------------------------===//
14
17#include "clang/AST/Attr.h"
18#include "clang/AST/DeclCXX.h"
19#include "clang/AST/DeclObjC.h"
20#include "clang/AST/ParentMap.h"
22#include <optional>
23
24using namespace clang;
25using namespace ento;
26
27template <class T>
28constexpr static bool isOneOf() {
29 return false;
30}
31
32/// Helper function to check whether the class is one of the
33/// rest of varargs.
34template <class T, class P, class... ToCompare>
35constexpr static bool isOneOf() {
36 return std::is_same_v<T, P> || isOneOf<T, ToCompare...>();
37}
38
39namespace {
40
41/// Fake attribute class for RC* attributes.
42struct 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;
47 }
48};
49
50struct 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;
55 }
56};
57
58struct 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;
63 }
64};
65
66}
67
68template <class T>
69std::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;
76
77 K = ObjKind::CF;
78 } else if (isOneOf<T, NSConsumedAttr, NSConsumesSelfAttr,
79 NSReturnsAutoreleasedAttr, NSReturnsRetainedAttr,
80 NSReturnsNotRetainedAttr, NSConsumesSelfAttr>()) {
81
82 if (!TrackObjCAndCFObjects)
83 return std::nullopt;
84
85 if (isOneOf<T, NSReturnsRetainedAttr, NSReturnsAutoreleasedAttr,
86 NSReturnsNotRetainedAttr>() &&
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>()) {
101 } else {
102 llvm_unreachable("Unexpected attribute");
103 }
104 if (D->hasAttr<T>())
105 return K;
106 return std::nullopt;
107}
108
109template <class T1, class T2, class... Others>
110std::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);
115}
116
117const RetainSummary *
118RetainSummaryManager::getPersistentSummary(const RetainSummary &OldSumm) {
119 // Unique "simple" summaries -- those without ArgEffects.
120 if (OldSumm.isSimple()) {
121 ::llvm::FoldingSetNodeID ID;
122 OldSumm.Profile(ID);
123
124 void *Pos;
125 CachedSummaryNode *N = SimpleSummaries.FindNodeOrInsertPos(ID, Pos);
126
127 if (!N) {
128 N = (CachedSummaryNode *) BPAlloc.Allocate<CachedSummaryNode>();
129 new (N) CachedSummaryNode(OldSumm);
130 SimpleSummaries.InsertNode(N, Pos);
131 }
132
133 return &N->getValue();
134 }
135
136 RetainSummary *Summ = (RetainSummary *) BPAlloc.Allocate<RetainSummary>();
137 new (Summ) RetainSummary(OldSumm);
138 return Summ;
139}
140
141static 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());
147}
148
149static 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());
154}
155
156static bool isOSObjectSubclass(const Decl *D) {
157 return D && isSubclass(D, "OSMetaClassBase") &&
158 !isExactClass(D, "OSMetaClass");
159}
160
161static bool isOSObjectDynamicCast(StringRef S) { return S == "safeMetaCast"; }
162
163static bool isOSObjectRequiredCast(StringRef S) {
164 return S == "requiredMetaCast";
165}
166
167static bool isOSObjectThisCast(StringRef S) {
168 return S == "metaCast";
169}
170
171
172static bool isOSObjectPtr(QualType QT) {
174}
175
176static bool isISLObjectRef(QualType Ty) {
177 return StringRef(Ty.getAsString()).starts_with("isl_");
178}
179
180static bool isOSIteratorSubclass(const Decl *D) {
181 return isSubclass(D, "OSIterator");
182}
183
184static bool hasRCAnnotation(const Decl *D, StringRef rcAnnotation) {
185 for (const auto *Ann : D->specific_attrs<AnnotateAttr>()) {
186 if (Ann->getAnnotation() == rcAnnotation)
187 return true;
188 }
189 return false;
190}
191
192static bool isRetain(const FunctionDecl *FD, StringRef FName) {
193 return FName.starts_with_insensitive("retain") ||
194 FName.ends_with_insensitive("retain");
195}
196
197static bool isRelease(const FunctionDecl *FD, StringRef FName) {
198 return FName.starts_with_insensitive("release") ||
199 FName.ends_with_insensitive("release");
200}
201
202static bool isAutorelease(const FunctionDecl *FD, StringRef FName) {
203 return FName.starts_with_insensitive("autorelease") ||
204 FName.ends_with_insensitive("autorelease");
205}
206
207static bool isMakeCollectable(StringRef FName) {
208 return FName.contains_insensitive("MakeCollectable");
209}
210
211/// A function is OSObject related if it is declared on a subclass
212/// of OSObject, or any of the parameters is a subclass of an OSObject.
213static bool isOSObjectRelated(const CXXMethodDecl *MD) {
214 if (isOSObjectSubclass(MD->getParent()))
215 return true;
216
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;
223 }
224
225 return false;
226}
227
228bool
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;
240}
241
242const RetainSummary *
243RetainSummaryManager::getSummaryForOSObject(const FunctionDecl *FD,
244 StringRef FName, QualType RetTy) {
245 assert(TrackOSObjects &&
246 "Requesting a summary for an OSObject but OSObjects are not tracked");
247
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();
254
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();
260 }
261
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")) ||
266 return getOSSummaryCreateRule(FD);
267 } else {
268 return getOSSummaryGetRule(FD);
269 }
270 }
271 }
272
273 if (const auto *MD = dyn_cast<CXXMethodDecl>(FD)) {
274 const CXXRecordDecl *Parent = MD->getParent();
276 if (FName == "release" || FName == "taggedRelease")
277 return getOSSummaryReleaseRule(FD);
278
279 if (FName == "retain" || FName == "taggedRetain")
280 return getOSSummaryRetainRule(FD);
281
282 if (FName == "free")
283 return getOSSummaryFreeRule(FD);
284
285 if (MD->getOverloadedOperator() == OO_New)
286 return getOSSummaryCreateRule(MD);
287 }
288 }
289
290 return nullptr;
291}
292
293const RetainSummary *RetainSummaryManager::getSummaryForObjCOrCFObject(
294 const FunctionDecl *FD,
295 StringRef FName,
296 QualType RetTy,
297 const FunctionType *FT,
298 bool &AllowAnnotations) {
299
300 ArgEffects ScratchArgs(AF.getEmptyMap());
301
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,
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,
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,
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,
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,
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,
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,
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,
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,
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),
405 }
406
407 if (RetTy->isPointerType()) {
408
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;
417
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;
423
424 return getUnarySummary(FT, Autorelease);
425 } else if (isMakeCollectable(FName)) {
426 AllowAnnotations = false;
427 return getUnarySummary(FT, DoNothing);
428 } else {
429 return getCFCreateGetRuleSummary(FD);
430 }
431 }
432
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);
440 }
441
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.
446 return getCFCreateGetRuleSummary(FD);
447 }
448
449 if (FD->hasAttr<CFAuditedTransferAttr>()) {
450 return getCFCreateGetRuleSummary(FD);
451 }
452 }
453
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")) {
457 // Test for 'CGCF'.
458 FName = FName.substr(FName.starts_with("CGCF") ? 4 : 2);
459
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:
468 //
469 // CFMutableDictionaryRef x = CFDictionaryCreateMutable(...);
470 // CFDictionaryAddValue(y, key, x);
471 // CFRelease(x);
472 // ... it is okay to use 'x' since 'y' has a reference to it
473 //
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;
487
488 return getPersistentSummary(RetEffect::MakeNoRet(), ScratchArgs,
490 }
491 }
492
493 return nullptr;
494}
495
496const RetainSummary *
497RetainSummaryManager::generateSummary(const FunctionDecl *FD,
498 bool &AllowAnnotations) {
499 // We generate "stop" summaries for implicitly defined functions.
500 if (FD->isImplicit())
501 return getPersistentStopSummary();
502
503 const IdentifierInfo *II = FD->getIdentifier();
504
505 StringRef FName = II ? II->getName() : "";
506
507 // Strip away preceding '_'. Doing this here will effect all the checks
508 // down below.
509 FName = FName.substr(FName.find_first_not_of('_'));
510
511 // Inspect the result type. Strip away any typedefs.
512 const auto *FT = FD->getType()->castAs<FunctionType>();
513 QualType RetTy = FT->getReturnType();
514
515 if (TrackOSObjects)
516 if (const RetainSummary *S = getSummaryForOSObject(FD, FName, RetTy))
517 return S;
518
519 if (const auto *MD = dyn_cast<CXXMethodDecl>(FD))
520 if (!isOSObjectRelated(MD))
521 return getPersistentSummary(RetEffect::MakeNoRet(),
522 ArgEffects(AF.getEmptyMap()),
526
527 if (TrackObjCAndCFObjects)
528 if (const RetainSummary *S =
529 getSummaryForObjCOrCFObject(FD, FName, RetTy, FT, AllowAnnotations))
530 return S;
531
532 return getDefaultSummary();
533}
534
535const RetainSummary *
536RetainSummaryManager::getFunctionSummary(const FunctionDecl *FD) {
537 // If we don't know what function we're calling, use our default summary.
538 if (!FD)
539 return getDefaultSummary();
540
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;
545
546 // No summary? Generate one.
547 bool AllowAnnotations = true;
548 const RetainSummary *S = generateSummary(FD, AllowAnnotations);
549
550 // Annotations override defaults.
551 if (AllowAnnotations)
552 updateSummaryFromAnnotations(S, FD);
553
554 FuncSummaries[FD] = S;
555 return S;
556}
557
558//===----------------------------------------------------------------------===//
559// Summary creation for functions (largely uses of Core Foundation).
560//===----------------------------------------------------------------------===//
561
563 switch (E.getKind()) {
564 case DoNothing:
565 case Autorelease:
567 case IncRef:
572 case MayEscape:
573 case StopTracking:
574 case StopTrackingHard:
575 return E.withKind(StopTrackingHard);
576 case DecRef:
579 case Dealloc:
580 return E.withKind(Dealloc);
581 }
582
583 llvm_unreachable("Unknown ArgEffect kind");
584}
585
586const RetainSummary *
587RetainSummaryManager::updateSummaryForNonZeroCallbackArg(const RetainSummary *S,
588 AnyCall &C) {
589 ArgEffect RecEffect = getStopTrackingHardEquivalent(S->getReceiverEffect());
590 ArgEffect DefEffect = getStopTrackingHardEquivalent(S->getDefaultArgEffect());
591
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);
600 }
601
603
604 // Special cases where the callback argument CANNOT free the return value.
605 // This can generally only happen if we know that the callback will only 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();
615 }
616
617 return getPersistentSummary(RE, ScratchArgs, RecEffect, DefEffect);
618}
619
620void RetainSummaryManager::updateSummaryForReceiverUnconsumedSelf(
621 const RetainSummary *&S) {
622
623 RetainSummaryTemplate Template(S, *this);
624
625 Template->setReceiverEffect(ArgEffect(DoNothing));
626 Template->setRetEffect(RetEffect::MakeNoRet());
627}
628
629
630void RetainSummaryManager::updateSummaryForArgumentTypes(
631 const AnyCall &C, const RetainSummary *&RS) {
632 RetainSummaryTemplate Template(RS, *this);
633
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();
638
639 // Skip already created values.
640 if (RS->getArgEffects().contains(parm_idx))
641 continue;
642
644
645 if (isISLObjectRef(QT)) {
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;
653 }
654
655 if (K != ObjKind::AnyObj)
656 Template->addArg(AF, parm_idx,
657 ArgEffect(RS->getDefaultArgEffect().getKind(), K));
658 }
659}
660
661const RetainSummary *
663 bool HasNonZeroCallbackArg,
664 bool IsReceiverUnconsumedSelf,
665 QualType ReceiverType) {
666 const RetainSummary *Summ;
667 switch (C.getKind()) {
673 Summ = getFunctionSummary(cast_or_null<FunctionDecl>(C.getDecl()));
674 break;
675 case AnyCall::Block:
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);
687 }
688 break;
689 }
690 }
691
692 if (HasNonZeroCallbackArg)
693 Summ = updateSummaryForNonZeroCallbackArg(Summ, C);
694
695 if (IsReceiverUnconsumedSelf)
696 updateSummaryForReceiverUnconsumedSelf(Summ);
697
698 updateSummaryForArgumentTypes(C, Summ);
699
700 assert(Summ && "Unknown call type?");
701 return Summ;
702}
703
704
705const RetainSummary *
706RetainSummaryManager::getCFCreateGetRuleSummary(const FunctionDecl *FD) {
708 return getCFSummaryCreateRule(FD);
709
710 return getCFSummaryGetRule(FD);
711}
712
714 const Decl *FD) {
715 return hasRCAnnotation(FD, "rc_ownership_trusted_implementation");
716}
717
718std::optional<RetainSummaryManager::BehaviorSummary>
720 bool &hasTrustedImplementationAnnotation) {
721
722 IdentifierInfo *II = FD->getIdentifier();
723 if (!II)
724 return std::nullopt;
725
726 StringRef FName = II->getName();
727 FName = FName.substr(FName.find_first_not_of('_'));
728
729 QualType ResultTy = CE->getCallReturnType(Ctx);
730 if (ResultTy->isObjCIdType()) {
731 if (II->isStr("NSMakeCollectable"))
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;
742 }
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)))
750
751 // safeMetaCast is called by OSDynamicCast.
752 // We assume that OSDynamicCast is either an identity (cast is OK,
753 // the input was non-zero),
754 // or that it returns zero (when the cast failed, or the input
755 // was zero).
756 if (TrackOSObjects) {
757 if (isOSObjectDynamicCast(FName) && FD->param_size() >= 1) {
759 } else if (isOSObjectRequiredCast(FName) && FD->param_size() >= 1) {
761 } else if (isOSObjectThisCast(FName) && isa<CXXMethodDecl>(FD) &&
762 !cast<CXXMethodDecl>(FD)->isStatic()) {
764 }
765 }
766
767 const FunctionDecl* FDD = FD->getDefinition();
769 hasTrustedImplementationAnnotation = true;
771 }
772 }
773
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")
779 }
780
781 return std::nullopt;
782}
783
784const RetainSummary *
785RetainSummaryManager::getUnarySummary(const FunctionType* FT,
786 ArgEffectKind AE) {
787
788 // Unary functions have no arg effects by definition.
789 ArgEffects ScratchArgs(AF.getEmptyMap());
790
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();
796
797 ArgEffect Effect(AE, ObjKind::CF);
798
799 ScratchArgs = AF.add(ScratchArgs, 0, Effect);
800 return getPersistentSummary(RetEffect::MakeNoRet(),
801 ScratchArgs,
803}
804
805const RetainSummary *
806RetainSummaryManager::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));
812}
813
814const RetainSummary *
815RetainSummaryManager::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));
821}
822
823const RetainSummary *
824RetainSummaryManager::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));
830}
831
832const RetainSummary *
833RetainSummaryManager::getOSSummaryCreateRule(const FunctionDecl *FD) {
834 return getPersistentSummary(RetEffect::MakeOwned(ObjKind::OS),
835 AF.getEmptyMap());
836}
837
838const RetainSummary *
839RetainSummaryManager::getOSSummaryGetRule(const FunctionDecl *FD) {
840 return getPersistentSummary(RetEffect::MakeNotOwned(ObjKind::OS),
841 AF.getEmptyMap());
842}
843
844const RetainSummary *
845RetainSummaryManager::getCFSummaryCreateRule(const FunctionDecl *FD) {
846 return getPersistentSummary(RetEffect::MakeOwned(ObjKind::CF),
847 ArgEffects(AF.getEmptyMap()));
848}
849
850const RetainSummary *
851RetainSummaryManager::getCFSummaryGetRule(const FunctionDecl *FD) {
852 return getPersistentSummary(RetEffect::MakeNotOwned(ObjKind::CF),
853 ArgEffects(AF.getEmptyMap()),
855}
856
857
858
859
860//===----------------------------------------------------------------------===//
861// Summary creation for Selectors.
862//===----------------------------------------------------------------------===//
863
864std::optional<RetEffect>
865RetainSummaryManager::getRetEffectFromAnnotations(QualType RetTy,
866 const Decl *D) {
867 if (hasAnyEnabledAttrOf<NSReturnsRetainedAttr>(D, RetTy))
868 return ObjCAllocRetE;
869
870 if (auto K = hasAnyEnabledAttrOf<CFReturnsRetainedAttr, OSReturnsRetainedAttr,
871 GeneralizedReturnsRetainedAttr>(D, RetTy))
872 return RetEffect::MakeOwned(*K);
873
874 if (auto K = hasAnyEnabledAttrOf<
875 CFReturnsNotRetainedAttr, OSReturnsNotRetainedAttr,
876 GeneralizedReturnsNotRetainedAttr, NSReturnsNotRetainedAttr,
877 NSReturnsAutoreleasedAttr>(D, RetTy))
878 return RetEffect::MakeNotOwned(*K);
879
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;
884
885 return std::nullopt;
886}
887
888/// \return Whether the chain of typedefs starting from @c QT
889/// has a typedef with a given name @c Name.
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();
897 }
898 return false;
899}
900
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");
908 }
909}
910
911bool 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)) {
924
925 // For OSObjects, we try to guess whether the object is created based
926 // on the return value.
927 if (K == ObjKind::OS) {
929
930 bool HasRetainedOnZero = pd->hasAttr<OSReturnsRetainedOnZeroAttr>();
931 bool HasRetainedOnNonZero = pd->hasAttr<OSReturnsRetainedOnNonZeroAttr>();
932
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();
942 if (ShouldSplit && SuccessOnZero) {
944 } else if (ShouldSplit && (!SuccessOnZero || HasRetainedOnNonZero)) {
946 }
947 Template->addArg(AF, parm_idx, ArgEffect(AK, ObjKind::OS));
948 }
949
950 // For others:
951 // Do nothing. Retained out parameters will either point to a +1 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;
961 }
962
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;
968 }
969 }
970
971 return false;
972}
973
974void
975RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ,
976 const FunctionDecl *FD) {
977 if (!FD)
978 return;
979
980 assert(Summ && "Must have a summary to add annotations to.");
981 RetainSummaryTemplate Template(Summ, *this);
982
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);
988
989 QualType RetTy = FD->getReturnType();
990 if (std::optional<RetEffect> RetE = getRetEffectFromAnnotations(RetTy, FD))
991 Template->setRetEffect(*RetE);
992
993 if (hasAnyEnabledAttrOf<OSConsumesThisAttr>(FD, RetTy))
995}
996
997void
998RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ,
999 const ObjCMethodDecl *MD) {
1000 if (!MD)
1001 return;
1002
1003 assert(Summ && "Must have a valid summary to add annotations to");
1004 RetainSummaryTemplate Template(Summ, *this);
1005
1006 // Effects on the receiver.
1007 if (hasAnyEnabledAttrOf<NSConsumesSelfAttr>(MD, MD->getReturnType()))
1009
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);
1015
1016 QualType RetTy = MD->getReturnType();
1017 if (std::optional<RetEffect> RetE = getRetEffectFromAnnotations(RetTy, MD))
1018 Template->setRetEffect(*RetE);
1019}
1020
1021const RetainSummary *
1022RetainSummaryManager::getStandardMethodSummary(const ObjCMethodDecl *MD,
1023 Selector S, QualType RetTy) {
1024 // Any special effects?
1026 RetEffect ResultEff = RetEffect::MakeNoRet();
1027
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:
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))
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:
1053 break;
1054 }
1055 } else {
1057 }
1058 }
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;
1092 }
1093
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.ends_with_insensitive("delegate")) {
1102 if (ResultEff == ObjCInitRetE)
1103 ResultEff = RetEffect::MakeNoRetHard();
1104 else
1106 }
1107 }
1108 }
1109
1110 if (ReceiverEff.getKind() == DoNothing &&
1111 ResultEff.getKind() == RetEffect::NoRet)
1112 return getDefaultSummary();
1113
1114 return getPersistentSummary(ResultEff, ArgEffects(AF.getEmptyMap()),
1115 ArgEffect(ReceiverEff), ArgEffect(MayEscape));
1116}
1117
1118const RetainSummary *
1119RetainSummaryManager::getClassMethodSummary(const ObjCMessageExpr *ME) {
1120 assert(!ME->isInstanceMessage());
1122
1123 return getMethodSummary(ME->getSelector(), Class, ME->getMethodDecl(),
1124 ME->getType(), ObjCClassMethodSummaries);
1125}
1126
1127const RetainSummary *RetainSummaryManager::getInstanceMethodSummary(
1128 const ObjCMessageExpr *ME,
1129 QualType ReceiverType) {
1130 const ObjCInterfaceDecl *ReceiverClass = nullptr;
1131
1132 // We do better tracking of the type of the object than the core ExprEngine.
1133 // See if we have its type in our private state.
1134 if (!ReceiverType.isNull())
1135 if (const auto *PT = ReceiverType->getAs<ObjCObjectPointerType>())
1136 ReceiverClass = PT->getInterfaceDecl();
1137
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();
1141
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);
1150
1151 return getMethodSummary(S, ReceiverClass, Method, ME->getType(),
1152 ObjCMethodSummaries);
1153}
1154
1155const RetainSummary *
1156RetainSummaryManager::getMethodSummary(Selector S,
1157 const ObjCInterfaceDecl *ID,
1158 const ObjCMethodDecl *MD, QualType RetTy,
1159 ObjCMethodSummariesTy &CachedSummaries) {
1160
1161 // Objective-C method summaries are only applicable to ObjC and CF objects.
1162 if (!TrackObjCAndCFObjects)
1163 return getDefaultSummary();
1164
1165 // Look up a summary in our summary cache.
1166 const RetainSummary *Summ = CachedSummaries.find(ID, S);
1167
1168 if (!Summ) {
1169 Summ = getStandardMethodSummary(MD, S, RetTy);
1170
1171 // Annotations override defaults.
1172 updateSummaryFromAnnotations(Summ, MD);
1173
1174 // Memoize the summary.
1175 CachedSummaries[ObjCSummaryKey(ID, S)] = Summ;
1176 }
1177
1178 return Summ;
1179}
1180
1181void RetainSummaryManager::InitializeClassMethodSummaries() {
1182 ArgEffects ScratchArgs = AF.getEmptyMap();
1183
1184 // Create the [NSAssertionHandler currentHander] summary.
1185 addClassMethSummary("NSAssertionHandler", "currentHandler",
1186 getPersistentSummary(RetEffect::MakeNotOwned(ObjKind::ObjC),
1187 ScratchArgs));
1188
1189 // Create the [NSAutoreleasePool addObject:] summary.
1190 ScratchArgs = AF.add(ScratchArgs, 0, ArgEffect(Autorelease));
1191 addClassMethSummary("NSAutoreleasePool", "addObject",
1192 getPersistentSummary(RetEffect::MakeNoRet(), ScratchArgs,
1195}
1196
1197void RetainSummaryManager::InitializeMethodSummaries() {
1198
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);
1205
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);
1210
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);
1216
1217 // Create the "retain" selector.
1219 const RetainSummary *Summ = getPersistentSummary(
1220 NoRet, ScratchArgs, ArgEffect(IncRef, ObjKind::ObjC));
1221 addNSObjectMethSummary(GetNullarySelector("retain", Ctx), Summ);
1222
1223 // Create the "release" selector.
1224 Summ = getPersistentSummary(NoRet, ScratchArgs,
1226 addNSObjectMethSummary(GetNullarySelector("release", Ctx), Summ);
1227
1228 // Create the -dealloc summary.
1229 Summ = getPersistentSummary(NoRet, ScratchArgs, ArgEffect(Dealloc,
1230 ObjKind::ObjC));
1231 addNSObjectMethSummary(GetNullarySelector("dealloc", Ctx), Summ);
1232
1233 // Create the "autorelease" selector.
1234 Summ = getPersistentSummary(NoRet, ScratchArgs, ArgEffect(Autorelease,
1235 ObjKind::ObjC));
1236 addNSObjectMethSummary(GetNullarySelector("autorelease", Ctx), Summ);
1237
1238 // For NSWindow, allocated objects are (initially) self-owned.
1239 // FIXME: For now we opt for false negatives with NSWindow, as these 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,
1245
1246 addClassMethSummary("NSWindow", "alloc", NoTrackYet);
1247
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);
1253
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);
1257
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);
1263
1264 // Create summaries QCRenderer/QCView -createSnapShotImageOfType:
1265 addInstMethSummary("QCRenderer", AllocSumm, "createSnapshotImageOfType");
1266 addInstMethSummary("QCView", AllocSumm, "createSnapshotImageOfType");
1267
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");
1275}
1276
1277const RetainSummary *
1278RetainSummaryManager::getMethodSummary(const ObjCMethodDecl *MD) {
1279 const ObjCInterfaceDecl *ID = MD->getClassInterface();
1280 Selector S = MD->getSelector();
1281 QualType ResultTy = MD->getReturnType();
1282
1283 ObjCMethodSummariesTy *CachedSummaries;
1284 if (MD->isInstanceMethod())
1285 CachedSummaries = &ObjCMethodSummaries;
1286 else
1287 CachedSummaries = &ObjCClassMethodSummaries;
1288
1289 return getMethodSummary(S, ID, MD, ResultTy, *CachedSummaries);
1290}
NodeId Parent
Definition: ASTDiff.cpp:191
StringRef P
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
static bool isSubclass(const ObjCInterfaceDecl *Class, const IdentifierInfo *II)
static bool isOSObjectRelated(const CXXMethodDecl *MD)
A function is OSObject related if it is declared on a subclass of OSObject, or any of the parameters ...
static bool isISLObjectRef(QualType Ty)
static bool isRelease(const FunctionDecl *FD, StringRef FName)
static bool hasTypedefNamed(QualType QT, StringRef Name)
static bool isOSObjectRequiredCast(StringRef S)
static ArgEffect getStopTrackingHardEquivalent(ArgEffect E)
static constexpr bool isOneOf()
static bool isOSIteratorSubclass(const Decl *D)
static QualType getCallableReturnType(const NamedDecl *ND)
static bool isAutorelease(const FunctionDecl *FD, StringRef FName)
static bool isExactClass(const Decl *D, StringRef ClassName)
static bool isOSObjectPtr(QualType QT)
static bool hasRCAnnotation(const Decl *D, StringRef rcAnnotation)
static bool isOSObjectSubclass(const Decl *D)
static bool isOSObjectThisCast(StringRef S)
static bool isMakeCollectable(StringRef FName)
static bool isOSObjectDynamicCast(StringRef S)
static bool isRetain(const FunctionDecl *FD, StringRef FName)
IdentifierTable & Idents
Definition: ASTContext.h:644
An instance of this class corresponds to a call.
Definition: AnyCall.h:26
@ Destructor
An implicit C++ destructor call (called implicitly or by operator 'delete')
Definition: AnyCall.h:40
@ ObjCMethod
A call to an Objective-C method.
Definition: AnyCall.h:33
@ Deallocator
A C++ deallocation function call (operator delete), via C++ delete-expression.
Definition: AnyCall.h:53
@ Function
A function, function pointer, or a C++ method call.
Definition: AnyCall.h:30
@ Allocator
A C++ allocation function call (operator new), via C++ new-expression.
Definition: AnyCall.h:49
@ Constructor
An implicit or explicit C++ constructor call.
Definition: AnyCall.h:43
@ InheritedConstructor
A C++ inherited constructor produced by a "using T::T" directive.
Definition: AnyCall.h:46
@ Block
A call to an Objective-C block.
Definition: AnyCall.h:36
Attr - This represents one attribute.
Definition: Attr.h:42
Represents a static or instance method of a struct/union/class.
Definition: DeclCXX.h:2057
const CXXRecordDecl * getParent() const
Return the parent of this method declaration, which is the class in which this method is defined.
Definition: DeclCXX.h:2183
Represents a C++ struct/union/class.
Definition: DeclCXX.h:258
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition: Expr.h:2820
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
Definition: Expr.h:2998
QualType getCallReturnType(const ASTContext &Ctx) const
getCallReturnType - Get the return type of the call expr.
Definition: Expr.cpp:1590
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:85
ASTContext & getASTContext() const LLVM_READONLY
Definition: DeclBase.cpp:501
bool isImplicit() const
isImplicit - Indicates whether the declaration was implicitly generated by the implementation.
Definition: DeclBase.h:601
llvm::iterator_range< specific_attr_iterator< T > > specific_attrs() const
Definition: DeclBase.h:567
bool hasAttr() const
Definition: DeclBase.h:585
QualType getType() const
Definition: Expr.h:142
Represents a function declaration or definition.
Definition: Decl.h:1971
param_iterator param_end()
Definition: Decl.h:2697
QualType getReturnType() const
Definition: Decl.h:2755
ArrayRef< ParmVarDecl * > parameters() const
Definition: Decl.h:2684
param_iterator param_begin()
Definition: Decl.h:2696
FunctionDecl * getDefinition()
Get the definition for this declaration.
Definition: Decl.h:2252
size_t param_size() const
Definition: Decl.h:2700
Represents a prototype with parameter type info, e.g.
Definition: Type.h:4446
unsigned getNumParams() const
Definition: Type.h:4679
FunctionType - C99 6.7.5.3 - Function Declarators.
Definition: Type.h:4046
QualType getReturnType() const
Definition: Type.h:4363
One of these records is kept for each identifier that is lexed.
bool isStr(const char(&Str)[StrLen]) const
Return true if this is the identifier for the specified string.
StringRef getName() const
Return the actual identifier string.
IdentifierInfo & get(StringRef Name)
Return the identifier token info for the specified named identifier.
This represents a decl that may have a name.
Definition: Decl.h:249
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
Definition: Decl.h:270
ObjCMethodDecl * getInstanceMethod(Selector Sel, bool AllowHidden=false) const
Definition: DeclObjC.h:1064
Represents an ObjC class declaration.
Definition: DeclObjC.h:1152
An expression that sends a message to the given Objective-C object or class.
Definition: ExprObjC.h:945
Selector getSelector() const
Definition: ExprObjC.cpp:293
bool isInstanceMessage() const
Determine whether this is an instance message to either a computed object or to super.
Definition: ExprObjC.h:1248
ObjCInterfaceDecl * getReceiverInterface() const
Retrieve the Objective-C interface to which this message is being directed, if known.
Definition: ExprObjC.cpp:314
const ObjCMethodDecl * getMethodDecl() const
Definition: ExprObjC.h:1356
ObjCMethodDecl - Represents an instance or class method declaration.
Definition: DeclObjC.h:140
param_const_iterator param_end() const
Definition: DeclObjC.h:358
param_const_iterator param_begin() const
Definition: DeclObjC.h:354
Selector getSelector() const
Definition: DeclObjC.h:327
bool isInstanceMethod() const
Definition: DeclObjC.h:426
ObjCMethodFamily getMethodFamily() const
Determines the family of this method.
Definition: DeclObjC.cpp:1052
QualType getReturnType() const
Definition: DeclObjC.h:329
ObjCInterfaceDecl * getClassInterface()
Definition: DeclObjC.cpp:1210
Represents a pointer to an Objective C object.
Definition: Type.h:6798
Represents a parameter to a function.
Definition: Decl.h:1761
A (possibly-)qualified type.
Definition: Type.h:738
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Definition: Type.h:805
QualType getCanonicalType() const
Definition: Type.h:7201
static std::string getAsString(SplitQualType split, const PrintingPolicy &Policy)
Definition: Type.h:1125
Smart pointer class that efficiently represents Objective-C method names.
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
Definition: Type.cpp:1870
bool isVoidType() const
Definition: Type.h:7695
bool isPointerType() const
Definition: Type.h:7402
const T * castAs() const
Member-template castAs<specific type>.
Definition: Type.h:7980
const CXXRecordDecl * getPointeeCXXRecordDecl() const
If this is a pointer or reference to a RecordType, return the CXXRecordDecl that the type refers to.
Definition: Type.cpp:1855
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition: Type.cpp:694
bool isObjCIdType() const
Definition: Type.h:7567
const T * getAs() const
Member-template getAs<specific type>'.
Definition: Type.h:7913
QualType getType() const
Definition: Decl.h:717
An ArgEffect summarizes the retain count behavior on an argument or receiver to a function or method.
ArgEffect withKind(ArgEffectKind NewK)
ArgEffectKind getKind() const
A key identifying a summary.
RetEffect summarizes a call's retain/release behavior with respect to its return value.
static RetEffect MakeNotOwned(ObjKind o)
static RetEffect MakeOwned(ObjKind o)
@ NoRet
Indicates that no retain count information is tracked for the return value.
static RetEffect MakeNoRet()
static RetEffect MakeNoRetHard()
bool isTrustedReferenceCountImplementation(const Decl *FD)
std::optional< BehaviorSummary > canEval(const CallExpr *CE, const FunctionDecl *FD, bool &hasTrustedImplementationAnnotation)
static bool isKnownSmartPointer(QualType QT)
const RetainSummary * getSummary(AnyCall C, bool HasNonZeroCallbackArg=false, bool IsReceiverUnconsumedSelf=false, QualType ReceiverType={})
Summary for a function with respect to ownership changes.
void setRetEffect(RetEffect E)
setRetEffect - Set the effect of the return value of the call.
void addArg(ArgEffects::Factory &af, unsigned idx, ArgEffect e)
bool isSimple() const
A retain summary is simple if it has no ArgEffects other than the default.
void setThisEffect(ArgEffect e)
Set the effect of the method on "this".
void setReceiverEffect(ArgEffect e)
Sets the effect on the receiver of the message.
void Profile(llvm::FoldingSetNodeID &ID) const
Profile this summary for inclusion in a FoldingSet.
internal::Matcher< Decl > DeclarationMatcher
Types of matchers for the top-level classes in the AST class hierarchy.
Definition: ASTMatchers.h:143
internal::Matcher< NamedDecl > hasName(StringRef Name)
Matches NamedDecl nodes that have the specified name.
Definition: ASTMatchers.h:3078
SmallVector< BoundNodes, 1 > match(MatcherT Matcher, const NodeT &Node, ASTContext &Context)
Returns the results of matching Matcher on Node.
const internal::VariadicDynCastAllOfMatcher< Decl, CXXRecordDecl > cxxRecordDecl
Matches C++ class declarations.
bool isCocoaObjectRef(QualType T)
bool isRefType(QualType RetTy, StringRef Prefix, StringRef Name=StringRef())
bool followsCreateRule(const FunctionDecl *FD)
llvm::ImmutableMap< unsigned, ArgEffect > ArgEffects
ArgEffects summarizes the effects of a function/method call on all of its arguments.
ObjKind
Determines the object kind of a tracked object.
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
@ Generalized
Indicates that the tracked object is a generalized object.
@ CF
Indicates that the tracked object is a CF object.
@ AnyObj
Indicates that the tracked object could be a CF or Objective-C object.
@ ObjC
Indicates that the tracked object is an Objective-C object.
@ IncRef
The argument has its reference count increased by 1.
@ UnretainedOutParameter
The argument is a pointer to a retain-counted object; on exit, the new value of the pointer is a +0 v...
@ DoNothing
There is no effect.
@ RetainedOutParameter
The argument is a pointer to a retain-counted object; on exit, the new value of the pointer is a +1 v...
@ RetainedOutParameterOnZero
The argument is a pointer to a retain-counted object; on exit, the new value of the pointer is a +1 v...
@ MayEscape
The argument is treated as potentially escaping, meaning that even when its reference count hits 0 it...
@ StopTracking
All typestate tracking of the object ceases.
@ Dealloc
The argument is treated as if the referenced object was deallocated.
@ Autorelease
The argument is treated as if an -autorelease message had been sent to the referenced object.
@ RetainedOutParameterOnNonZero
The argument is a pointer to a retain-counted object; on exit, the new value of the pointer is a +1 v...
@ DecRef
The argument has its reference count decreased by 1.
@ StopTrackingHard
All typestate tracking of the object ceases.
@ DecRefAndStopTrackingHard
Performs the combined functionality of DecRef and StopTrackingHard.
@ DecRefBridgedTransferred
The argument has its reference count decreased by 1 to model a transferred bridge cast under ARC.
bool NoRet(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1983
The JSON file list parser is used to communicate input to InstallAPI.
@ OMF_initialize
@ OMF_autorelease
@ OMF_mutableCopy
@ OMF_performSelector
@ OMF_None
No particular method family.
@ OMF_retainCount
Selector GetUnarySelector(StringRef name, ASTContext &Ctx)
Utility function for constructing an unary selector.
Definition: ASTContext.h:3419
Selector GetNullarySelector(StringRef name, ASTContext &Ctx)
Utility function for constructing a nullary selector.
Definition: ASTContext.h:3413
const FunctionProtoType * T
@ Class
The "class" keyword introduces the elaborated-type-specifier.