clang 17.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()).startswith("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.startswith_insensitive("retain") ||
194 FName.endswith_insensitive("retain");
195}
196
197static bool isRelease(const FunctionDecl *FD, StringRef FName) {
198 return FName.startswith_insensitive("release") ||
199 FName.endswith_insensitive("release");
200}
201
202static bool isAutorelease(const FunctionDecl *FD, StringRef FName) {
203 return FName.startswith_insensitive("autorelease") ||
204 FName.endswith_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.endswith("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.startswith("get") && !FName.startswith("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 // Part of: <rdar://problem/7299394> and <rdar://problem/11282706>.
305 // This will be addressed better with IPA.
306 return getPersistentStopSummary();
307 } else if(FName == "NSMakeCollectable") {
308 // Handle: id NSMakeCollectable(CFTypeRef)
309 AllowAnnotations = false;
310 return RetTy->isObjCIdType() ? getUnarySummary(FT, DoNothing)
311 : getPersistentStopSummary();
312 } else if (FName == "CMBufferQueueDequeueAndRetain" ||
313 FName == "CMBufferQueueDequeueIfDataReadyAndRetain") {
314 // Part of: <rdar://problem/39390714>.
315 return getPersistentSummary(RetEffect::MakeOwned(ObjKind::CF),
316 ScratchArgs,
319 } else if (FName == "CFPlugInInstanceCreate") {
320 return getPersistentSummary(RetEffect::MakeNoRet(), ScratchArgs);
321 } else if (FName == "IORegistryEntrySearchCFProperty" ||
322 (RetTyName == "CFMutableDictionaryRef" &&
323 (FName == "IOBSDNameMatching" || FName == "IOServiceMatching" ||
324 FName == "IOServiceNameMatching" ||
325 FName == "IORegistryEntryIDMatching" ||
326 FName == "IOOpenFirmwarePathMatching"))) {
327 // Part of <rdar://problem/6961230>. (IOKit)
328 // This should be addressed using a API table.
329 return getPersistentSummary(RetEffect::MakeOwned(ObjKind::CF), ScratchArgs,
331 } else if (FName == "IOServiceGetMatchingService" ||
332 FName == "IOServiceGetMatchingServices") {
333 // FIXES: <rdar://problem/6326900>
334 // This should be addressed using a API table. This strcmp is also
335 // a little gross, but there is no need to super optimize here.
336 ScratchArgs = AF.add(ScratchArgs, 1, ArgEffect(DecRef, ObjKind::CF));
337 return getPersistentSummary(RetEffect::MakeNoRet(),
338 ScratchArgs,
340 } else if (FName == "IOServiceAddNotification" ||
341 FName == "IOServiceAddMatchingNotification") {
342 // Part of <rdar://problem/6961230>. (IOKit)
343 // This should be addressed using a API table.
344 ScratchArgs = AF.add(ScratchArgs, 2, ArgEffect(DecRef, ObjKind::CF));
345 return getPersistentSummary(RetEffect::MakeNoRet(),
346 ScratchArgs,
348 } else if (FName == "CVPixelBufferCreateWithBytes") {
349 // FIXES: <rdar://problem/7283567>
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 // FIXME: This function has an out parameter that returns an
354 // allocated object.
355 ScratchArgs = AF.add(ScratchArgs, 7, ArgEffect(StopTracking));
356 return getPersistentSummary(RetEffect::MakeNoRet(),
357 ScratchArgs,
359 } else if (FName == "CGBitmapContextCreateWithData") {
360 // FIXES: <rdar://problem/7358899>
361 // Eventually this can be improved by recognizing that 'releaseInfo'
362 // passed to CGBitmapContextCreateWithData is released via
363 // a callback and doing full IPA to make sure this is done correctly.
364 ScratchArgs = AF.add(ScratchArgs, 8, ArgEffect(ArgEffect(StopTracking)));
365 return getPersistentSummary(RetEffect::MakeOwned(ObjKind::CF), ScratchArgs,
367 } else if (FName == "CVPixelBufferCreateWithPlanarBytes") {
368 // FIXES: <rdar://problem/7283567>
369 // Eventually this can be improved by recognizing that the pixel
370 // buffer passed to CVPixelBufferCreateWithPlanarBytes is released
371 // via a callback and doing full IPA to make sure this is done
372 // correctly.
373 ScratchArgs = AF.add(ScratchArgs, 12, ArgEffect(StopTracking));
374 return getPersistentSummary(RetEffect::MakeNoRet(),
375 ScratchArgs,
377 } else if (FName == "VTCompressionSessionEncodeFrame") {
378 // The context argument passed to VTCompressionSessionEncodeFrame()
379 // is passed to the callback specified when creating the session
380 // (e.g. with VTCompressionSessionCreate()) which can release it.
381 // To account for this possibility, conservatively stop tracking
382 // the context.
383 ScratchArgs = AF.add(ScratchArgs, 5, ArgEffect(StopTracking));
384 return getPersistentSummary(RetEffect::MakeNoRet(),
385 ScratchArgs,
387 } else if (FName == "dispatch_set_context" ||
388 FName == "xpc_connection_set_context") {
389 // <rdar://problem/11059275> - The analyzer currently doesn't have
390 // a good way to reason about the finalizer function for libdispatch.
391 // If we pass a context object that is memory managed, stop tracking it.
392 // <rdar://problem/13783514> - Same problem, but for XPC.
393 // FIXME: this hack should possibly go away once we can handle
394 // libdispatch and XPC finalizers.
395 ScratchArgs = AF.add(ScratchArgs, 1, ArgEffect(StopTracking));
396 return getPersistentSummary(RetEffect::MakeNoRet(),
397 ScratchArgs,
399 } else if (FName.startswith("NSLog")) {
400 return getDoNothingSummary();
401 } else if (FName.startswith("NS") && FName.contains("Insert")) {
402 // Allowlist NSXXInsertXX, for example NSMapInsertIfAbsent, since they can
403 // be deallocated by NSMapRemove. (radar://11152419)
404 ScratchArgs = AF.add(ScratchArgs, 1, ArgEffect(StopTracking));
405 ScratchArgs = AF.add(ScratchArgs, 2, ArgEffect(StopTracking));
406 return getPersistentSummary(RetEffect::MakeNoRet(),
407 ScratchArgs, ArgEffect(DoNothing),
409 }
410
411 if (RetTy->isPointerType()) {
412
413 // For CoreFoundation ('CF') types.
414 if (cocoa::isRefType(RetTy, "CF", FName)) {
415 if (isRetain(FD, FName)) {
416 // CFRetain isn't supposed to be annotated. However, this may as
417 // well be a user-made "safe" CFRetain function that is incorrectly
418 // annotated as cf_returns_retained due to lack of better options.
419 // We want to ignore such annotation.
420 AllowAnnotations = false;
421
422 return getUnarySummary(FT, IncRef);
423 } else if (isAutorelease(FD, FName)) {
424 // The headers use cf_consumed, but we can fully model CFAutorelease
425 // ourselves.
426 AllowAnnotations = false;
427
428 return getUnarySummary(FT, Autorelease);
429 } else if (isMakeCollectable(FName)) {
430 AllowAnnotations = false;
431 return getUnarySummary(FT, DoNothing);
432 } else {
433 return getCFCreateGetRuleSummary(FD);
434 }
435 }
436
437 // For CoreGraphics ('CG') and CoreVideo ('CV') types.
438 if (cocoa::isRefType(RetTy, "CG", FName) ||
439 cocoa::isRefType(RetTy, "CV", FName)) {
440 if (isRetain(FD, FName))
441 return getUnarySummary(FT, IncRef);
442 else
443 return getCFCreateGetRuleSummary(FD);
444 }
445
446 // For all other CF-style types, use the Create/Get
447 // rule for summaries but don't support Retain functions
448 // with framework-specific prefixes.
450 return getCFCreateGetRuleSummary(FD);
451 }
452
453 if (FD->hasAttr<CFAuditedTransferAttr>()) {
454 return getCFCreateGetRuleSummary(FD);
455 }
456 }
457
458 // Check for release functions, the only kind of functions that we care
459 // about that don't return a pointer type.
460 if (FName.startswith("CG") || FName.startswith("CF")) {
461 // Test for 'CGCF'.
462 FName = FName.substr(FName.startswith("CGCF") ? 4 : 2);
463
464 if (isRelease(FD, FName))
465 return getUnarySummary(FT, DecRef);
466 else {
467 assert(ScratchArgs.isEmpty());
468 // Remaining CoreFoundation and CoreGraphics functions.
469 // We use to assume that they all strictly followed the ownership idiom
470 // and that ownership cannot be transferred. While this is technically
471 // correct, many methods allow a tracked object to escape. For example:
472 //
473 // CFMutableDictionaryRef x = CFDictionaryCreateMutable(...);
474 // CFDictionaryAddValue(y, key, x);
475 // CFRelease(x);
476 // ... it is okay to use 'x' since 'y' has a reference to it
477 //
478 // We handle this and similar cases with the follow heuristic. If the
479 // function name contains "InsertValue", "SetValue", "AddValue",
480 // "AppendValue", or "SetAttribute", then we assume that arguments may
481 // "escape." This means that something else holds on to the object,
482 // allowing it be used even after its local retain count drops to 0.
483 ArgEffectKind E =
484 (StrInStrNoCase(FName, "InsertValue") != StringRef::npos ||
485 StrInStrNoCase(FName, "AddValue") != StringRef::npos ||
486 StrInStrNoCase(FName, "SetValue") != StringRef::npos ||
487 StrInStrNoCase(FName, "AppendValue") != StringRef::npos ||
488 StrInStrNoCase(FName, "SetAttribute") != StringRef::npos)
489 ? MayEscape
490 : DoNothing;
491
492 return getPersistentSummary(RetEffect::MakeNoRet(), ScratchArgs,
494 }
495 }
496
497 return nullptr;
498}
499
500const RetainSummary *
501RetainSummaryManager::generateSummary(const FunctionDecl *FD,
502 bool &AllowAnnotations) {
503 // We generate "stop" summaries for implicitly defined functions.
504 if (FD->isImplicit())
505 return getPersistentStopSummary();
506
507 const IdentifierInfo *II = FD->getIdentifier();
508
509 StringRef FName = II ? II->getName() : "";
510
511 // Strip away preceding '_'. Doing this here will effect all the checks
512 // down below.
513 FName = FName.substr(FName.find_first_not_of('_'));
514
515 // Inspect the result type. Strip away any typedefs.
516 const auto *FT = FD->getType()->castAs<FunctionType>();
517 QualType RetTy = FT->getReturnType();
518
519 if (TrackOSObjects)
520 if (const RetainSummary *S = getSummaryForOSObject(FD, FName, RetTy))
521 return S;
522
523 if (const auto *MD = dyn_cast<CXXMethodDecl>(FD))
524 if (!isOSObjectRelated(MD))
525 return getPersistentSummary(RetEffect::MakeNoRet(),
526 ArgEffects(AF.getEmptyMap()),
530
531 if (TrackObjCAndCFObjects)
532 if (const RetainSummary *S =
533 getSummaryForObjCOrCFObject(FD, FName, RetTy, FT, AllowAnnotations))
534 return S;
535
536 return getDefaultSummary();
537}
538
539const RetainSummary *
540RetainSummaryManager::getFunctionSummary(const FunctionDecl *FD) {
541 // If we don't know what function we're calling, use our default summary.
542 if (!FD)
543 return getDefaultSummary();
544
545 // Look up a summary in our cache of FunctionDecls -> Summaries.
546 FuncSummariesTy::iterator I = FuncSummaries.find(FD);
547 if (I != FuncSummaries.end())
548 return I->second;
549
550 // No summary? Generate one.
551 bool AllowAnnotations = true;
552 const RetainSummary *S = generateSummary(FD, AllowAnnotations);
553
554 // Annotations override defaults.
555 if (AllowAnnotations)
556 updateSummaryFromAnnotations(S, FD);
557
558 FuncSummaries[FD] = S;
559 return S;
560}
561
562//===----------------------------------------------------------------------===//
563// Summary creation for functions (largely uses of Core Foundation).
564//===----------------------------------------------------------------------===//
565
567 switch (E.getKind()) {
568 case DoNothing:
569 case Autorelease:
571 case IncRef:
576 case MayEscape:
577 case StopTracking:
578 case StopTrackingHard:
579 return E.withKind(StopTrackingHard);
580 case DecRef:
583 case Dealloc:
584 return E.withKind(Dealloc);
585 }
586
587 llvm_unreachable("Unknown ArgEffect kind");
588}
589
590const RetainSummary *
591RetainSummaryManager::updateSummaryForNonZeroCallbackArg(const RetainSummary *S,
592 AnyCall &C) {
593 ArgEffect RecEffect = getStopTrackingHardEquivalent(S->getReceiverEffect());
594 ArgEffect DefEffect = getStopTrackingHardEquivalent(S->getDefaultArgEffect());
595
596 ArgEffects ScratchArgs(AF.getEmptyMap());
597 ArgEffects CustomArgEffects = S->getArgEffects();
598 for (ArgEffects::iterator I = CustomArgEffects.begin(),
599 E = CustomArgEffects.end();
600 I != E; ++I) {
601 ArgEffect Translated = getStopTrackingHardEquivalent(I->second);
602 if (Translated.getKind() != DefEffect.getKind())
603 ScratchArgs = AF.add(ScratchArgs, I->first, Translated);
604 }
605
607
608 // Special cases where the callback argument CANNOT free the return value.
609 // This can generally only happen if we know that the callback will only be
610 // called when the return value is already being deallocated.
611 if (const IdentifierInfo *Name = C.getIdentifier()) {
612 // When the CGBitmapContext is deallocated, the callback here will free
613 // the associated data buffer.
614 // The callback in dispatch_data_create frees the buffer, but not
615 // the data object.
616 if (Name->isStr("CGBitmapContextCreateWithData") ||
617 Name->isStr("dispatch_data_create"))
618 RE = S->getRetEffect();
619 }
620
621 return getPersistentSummary(RE, ScratchArgs, RecEffect, DefEffect);
622}
623
624void RetainSummaryManager::updateSummaryForReceiverUnconsumedSelf(
625 const RetainSummary *&S) {
626
627 RetainSummaryTemplate Template(S, *this);
628
629 Template->setReceiverEffect(ArgEffect(DoNothing));
630 Template->setRetEffect(RetEffect::MakeNoRet());
631}
632
633
634void RetainSummaryManager::updateSummaryForArgumentTypes(
635 const AnyCall &C, const RetainSummary *&RS) {
636 RetainSummaryTemplate Template(RS, *this);
637
638 unsigned parm_idx = 0;
639 for (auto pi = C.param_begin(), pe = C.param_end(); pi != pe;
640 ++pi, ++parm_idx) {
641 QualType QT = (*pi)->getType();
642
643 // Skip already created values.
644 if (RS->getArgEffects().contains(parm_idx))
645 continue;
646
648
649 if (isISLObjectRef(QT)) {
651 } else if (isOSObjectPtr(QT)) {
652 K = ObjKind::OS;
653 } else if (cocoa::isCocoaObjectRef(QT)) {
654 K = ObjKind::ObjC;
655 } else if (coreFoundation::isCFObjectRef(QT)) {
656 K = ObjKind::CF;
657 }
658
659 if (K != ObjKind::AnyObj)
660 Template->addArg(AF, parm_idx,
661 ArgEffect(RS->getDefaultArgEffect().getKind(), K));
662 }
663}
664
665const RetainSummary *
667 bool HasNonZeroCallbackArg,
668 bool IsReceiverUnconsumedSelf,
669 QualType ReceiverType) {
670 const RetainSummary *Summ;
671 switch (C.getKind()) {
677 Summ = getFunctionSummary(cast_or_null<FunctionDecl>(C.getDecl()));
678 break;
679 case AnyCall::Block:
681 // FIXME: These calls are currently unsupported.
682 return getPersistentStopSummary();
683 case AnyCall::ObjCMethod: {
684 const auto *ME = cast_or_null<ObjCMessageExpr>(C.getExpr());
685 if (!ME) {
686 Summ = getMethodSummary(cast<ObjCMethodDecl>(C.getDecl()));
687 } else if (ME->isInstanceMessage()) {
688 Summ = getInstanceMethodSummary(ME, ReceiverType);
689 } else {
690 Summ = getClassMethodSummary(ME);
691 }
692 break;
693 }
694 }
695
696 if (HasNonZeroCallbackArg)
697 Summ = updateSummaryForNonZeroCallbackArg(Summ, C);
698
699 if (IsReceiverUnconsumedSelf)
700 updateSummaryForReceiverUnconsumedSelf(Summ);
701
702 updateSummaryForArgumentTypes(C, Summ);
703
704 assert(Summ && "Unknown call type?");
705 return Summ;
706}
707
708
709const RetainSummary *
710RetainSummaryManager::getCFCreateGetRuleSummary(const FunctionDecl *FD) {
712 return getCFSummaryCreateRule(FD);
713
714 return getCFSummaryGetRule(FD);
715}
716
718 const Decl *FD) {
719 return hasRCAnnotation(FD, "rc_ownership_trusted_implementation");
720}
721
722std::optional<RetainSummaryManager::BehaviorSummary>
724 bool &hasTrustedImplementationAnnotation) {
725
726 IdentifierInfo *II = FD->getIdentifier();
727 if (!II)
728 return std::nullopt;
729
730 StringRef FName = II->getName();
731 FName = FName.substr(FName.find_first_not_of('_'));
732
733 QualType ResultTy = CE->getCallReturnType(Ctx);
734 if (ResultTy->isObjCIdType()) {
735 if (II->isStr("NSMakeCollectable"))
737 } else if (ResultTy->isPointerType()) {
738 // Handle: (CF|CG|CV)Retain
739 // CFAutorelease
740 // It's okay to be a little sloppy here.
741 if (FName == "CMBufferQueueDequeueAndRetain" ||
742 FName == "CMBufferQueueDequeueIfDataReadyAndRetain") {
743 // Part of: <rdar://problem/39390714>.
744 // These are not retain. They just return something and retain it.
745 return std::nullopt;
746 }
747 if (CE->getNumArgs() == 1 &&
748 (cocoa::isRefType(ResultTy, "CF", FName) ||
749 cocoa::isRefType(ResultTy, "CG", FName) ||
750 cocoa::isRefType(ResultTy, "CV", FName)) &&
751 (isRetain(FD, FName) || isAutorelease(FD, FName) ||
752 isMakeCollectable(FName)))
754
755 // safeMetaCast is called by OSDynamicCast.
756 // We assume that OSDynamicCast is either an identity (cast is OK,
757 // the input was non-zero),
758 // or that it returns zero (when the cast failed, or the input
759 // was zero).
760 if (TrackOSObjects) {
761 if (isOSObjectDynamicCast(FName) && FD->param_size() >= 1) {
763 } else if (isOSObjectRequiredCast(FName) && FD->param_size() >= 1) {
765 } else if (isOSObjectThisCast(FName) && isa<CXXMethodDecl>(FD) &&
766 !cast<CXXMethodDecl>(FD)->isStatic()) {
768 }
769 }
770
771 const FunctionDecl* FDD = FD->getDefinition();
773 hasTrustedImplementationAnnotation = true;
775 }
776 }
777
778 if (const auto *MD = dyn_cast<CXXMethodDecl>(FD)) {
779 const CXXRecordDecl *Parent = MD->getParent();
780 if (TrackOSObjects && Parent && isOSObjectSubclass(Parent))
781 if (FName == "release" || FName == "retain")
783 }
784
785 return std::nullopt;
786}
787
788const RetainSummary *
789RetainSummaryManager::getUnarySummary(const FunctionType* FT,
790 ArgEffectKind AE) {
791
792 // Unary functions have no arg effects by definition.
793 ArgEffects ScratchArgs(AF.getEmptyMap());
794
795 // Verify that this is *really* a unary function. This can
796 // happen if people do weird things.
797 const FunctionProtoType* FTP = dyn_cast<FunctionProtoType>(FT);
798 if (!FTP || FTP->getNumParams() != 1)
799 return getPersistentStopSummary();
800
801 ArgEffect Effect(AE, ObjKind::CF);
802
803 ScratchArgs = AF.add(ScratchArgs, 0, Effect);
804 return getPersistentSummary(RetEffect::MakeNoRet(),
805 ScratchArgs,
807}
808
809const RetainSummary *
810RetainSummaryManager::getOSSummaryRetainRule(const FunctionDecl *FD) {
811 return getPersistentSummary(RetEffect::MakeNoRet(),
812 AF.getEmptyMap(),
813 /*ReceiverEff=*/ArgEffect(DoNothing),
814 /*DefaultEff=*/ArgEffect(DoNothing),
815 /*ThisEff=*/ArgEffect(IncRef, ObjKind::OS));
816}
817
818const RetainSummary *
819RetainSummaryManager::getOSSummaryReleaseRule(const FunctionDecl *FD) {
820 return getPersistentSummary(RetEffect::MakeNoRet(),
821 AF.getEmptyMap(),
822 /*ReceiverEff=*/ArgEffect(DoNothing),
823 /*DefaultEff=*/ArgEffect(DoNothing),
824 /*ThisEff=*/ArgEffect(DecRef, ObjKind::OS));
825}
826
827const RetainSummary *
828RetainSummaryManager::getOSSummaryFreeRule(const FunctionDecl *FD) {
829 return getPersistentSummary(RetEffect::MakeNoRet(),
830 AF.getEmptyMap(),
831 /*ReceiverEff=*/ArgEffect(DoNothing),
832 /*DefaultEff=*/ArgEffect(DoNothing),
833 /*ThisEff=*/ArgEffect(Dealloc, ObjKind::OS));
834}
835
836const RetainSummary *
837RetainSummaryManager::getOSSummaryCreateRule(const FunctionDecl *FD) {
838 return getPersistentSummary(RetEffect::MakeOwned(ObjKind::OS),
839 AF.getEmptyMap());
840}
841
842const RetainSummary *
843RetainSummaryManager::getOSSummaryGetRule(const FunctionDecl *FD) {
844 return getPersistentSummary(RetEffect::MakeNotOwned(ObjKind::OS),
845 AF.getEmptyMap());
846}
847
848const RetainSummary *
849RetainSummaryManager::getCFSummaryCreateRule(const FunctionDecl *FD) {
850 return getPersistentSummary(RetEffect::MakeOwned(ObjKind::CF),
851 ArgEffects(AF.getEmptyMap()));
852}
853
854const RetainSummary *
855RetainSummaryManager::getCFSummaryGetRule(const FunctionDecl *FD) {
856 return getPersistentSummary(RetEffect::MakeNotOwned(ObjKind::CF),
857 ArgEffects(AF.getEmptyMap()),
859}
860
861
862
863
864//===----------------------------------------------------------------------===//
865// Summary creation for Selectors.
866//===----------------------------------------------------------------------===//
867
868std::optional<RetEffect>
869RetainSummaryManager::getRetEffectFromAnnotations(QualType RetTy,
870 const Decl *D) {
871 if (hasAnyEnabledAttrOf<NSReturnsRetainedAttr>(D, RetTy))
872 return ObjCAllocRetE;
873
874 if (auto K = hasAnyEnabledAttrOf<CFReturnsRetainedAttr, OSReturnsRetainedAttr,
875 GeneralizedReturnsRetainedAttr>(D, RetTy))
876 return RetEffect::MakeOwned(*K);
877
878 if (auto K = hasAnyEnabledAttrOf<
879 CFReturnsNotRetainedAttr, OSReturnsNotRetainedAttr,
880 GeneralizedReturnsNotRetainedAttr, NSReturnsNotRetainedAttr,
881 NSReturnsAutoreleasedAttr>(D, RetTy))
882 return RetEffect::MakeNotOwned(*K);
883
884 if (const auto *MD = dyn_cast<CXXMethodDecl>(D))
885 for (const auto *PD : MD->overridden_methods())
886 if (auto RE = getRetEffectFromAnnotations(RetTy, PD))
887 return RE;
888
889 return std::nullopt;
890}
891
892/// \return Whether the chain of typedefs starting from @c QT
893/// has a typedef with a given name @c Name.
895 StringRef Name) {
896 while (auto *T = QT->getAs<TypedefType>()) {
897 const auto &Context = T->getDecl()->getASTContext();
898 if (T->getDecl()->getIdentifier() == &Context.Idents.get(Name))
899 return true;
900 QT = T->getDecl()->getUnderlyingType();
901 }
902 return false;
903}
904
906 if (const auto *FD = dyn_cast<FunctionDecl>(ND)) {
907 return FD->getReturnType();
908 } else if (const auto *MD = dyn_cast<ObjCMethodDecl>(ND)) {
909 return MD->getReturnType();
910 } else {
911 llvm_unreachable("Unexpected decl");
912 }
913}
914
915bool RetainSummaryManager::applyParamAnnotationEffect(
916 const ParmVarDecl *pd, unsigned parm_idx, const NamedDecl *FD,
917 RetainSummaryTemplate &Template) {
918 QualType QT = pd->getType();
919 if (auto K =
920 hasAnyEnabledAttrOf<NSConsumedAttr, CFConsumedAttr, OSConsumedAttr,
921 GeneralizedConsumedAttr>(pd, QT)) {
922 Template->addArg(AF, parm_idx, ArgEffect(DecRef, *K));
923 return true;
924 } else if (auto K = hasAnyEnabledAttrOf<
925 CFReturnsRetainedAttr, OSReturnsRetainedAttr,
926 OSReturnsRetainedOnNonZeroAttr, OSReturnsRetainedOnZeroAttr,
927 GeneralizedReturnsRetainedAttr>(pd, QT)) {
928
929 // For OSObjects, we try to guess whether the object is created based
930 // on the return value.
931 if (K == ObjKind::OS) {
933
934 bool HasRetainedOnZero = pd->hasAttr<OSReturnsRetainedOnZeroAttr>();
935 bool HasRetainedOnNonZero = pd->hasAttr<OSReturnsRetainedOnNonZeroAttr>();
936
937 // The usual convention is to create an object on non-zero return, but
938 // it's reverted if the typedef chain has a typedef kern_return_t,
939 // because kReturnSuccess constant is defined as zero.
940 // The convention can be overwritten by custom attributes.
941 bool SuccessOnZero =
942 HasRetainedOnZero ||
943 (hasTypedefNamed(QT, "kern_return_t") && !HasRetainedOnNonZero);
944 bool ShouldSplit = !QT.isNull() && !QT->isVoidType();
946 if (ShouldSplit && SuccessOnZero) {
948 } else if (ShouldSplit && (!SuccessOnZero || HasRetainedOnNonZero)) {
950 }
951 Template->addArg(AF, parm_idx, ArgEffect(AK, ObjKind::OS));
952 }
953
954 // For others:
955 // Do nothing. Retained out parameters will either point to a +1 reference
956 // or NULL, but the way you check for failure differs depending on the
957 // API. Consequently, we don't have a good way to track them yet.
958 return true;
959 } else if (auto K = hasAnyEnabledAttrOf<CFReturnsNotRetainedAttr,
960 OSReturnsNotRetainedAttr,
961 GeneralizedReturnsNotRetainedAttr>(
962 pd, QT)) {
963 Template->addArg(AF, parm_idx, ArgEffect(UnretainedOutParameter, *K));
964 return true;
965 }
966
967 if (const auto *MD = dyn_cast<CXXMethodDecl>(FD)) {
968 for (const auto *OD : MD->overridden_methods()) {
969 const ParmVarDecl *OP = OD->parameters()[parm_idx];
970 if (applyParamAnnotationEffect(OP, parm_idx, OD, Template))
971 return true;
972 }
973 }
974
975 return false;
976}
977
978void
979RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ,
980 const FunctionDecl *FD) {
981 if (!FD)
982 return;
983
984 assert(Summ && "Must have a summary to add annotations to.");
985 RetainSummaryTemplate Template(Summ, *this);
986
987 // Effects on the parameters.
988 unsigned parm_idx = 0;
989 for (auto pi = FD->param_begin(),
990 pe = FD->param_end(); pi != pe; ++pi, ++parm_idx)
991 applyParamAnnotationEffect(*pi, parm_idx, FD, Template);
992
993 QualType RetTy = FD->getReturnType();
994 if (std::optional<RetEffect> RetE = getRetEffectFromAnnotations(RetTy, FD))
995 Template->setRetEffect(*RetE);
996
997 if (hasAnyEnabledAttrOf<OSConsumesThisAttr>(FD, RetTy))
999}
1000
1001void
1002RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ,
1003 const ObjCMethodDecl *MD) {
1004 if (!MD)
1005 return;
1006
1007 assert(Summ && "Must have a valid summary to add annotations to");
1008 RetainSummaryTemplate Template(Summ, *this);
1009
1010 // Effects on the receiver.
1011 if (hasAnyEnabledAttrOf<NSConsumesSelfAttr>(MD, MD->getReturnType()))
1013
1014 // Effects on the parameters.
1015 unsigned parm_idx = 0;
1016 for (auto pi = MD->param_begin(), pe = MD->param_end(); pi != pe;
1017 ++pi, ++parm_idx)
1018 applyParamAnnotationEffect(*pi, parm_idx, MD, Template);
1019
1020 QualType RetTy = MD->getReturnType();
1021 if (std::optional<RetEffect> RetE = getRetEffectFromAnnotations(RetTy, MD))
1022 Template->setRetEffect(*RetE);
1023}
1024
1025const RetainSummary *
1026RetainSummaryManager::getStandardMethodSummary(const ObjCMethodDecl *MD,
1027 Selector S, QualType RetTy) {
1028 // Any special effects?
1030 RetEffect ResultEff = RetEffect::MakeNoRet();
1031
1032 // Check the method family, and apply any default annotations.
1033 switch (MD ? MD->getMethodFamily() : S.getMethodFamily()) {
1034 case OMF_None:
1035 case OMF_initialize:
1037 // Assume all Objective-C methods follow Cocoa Memory Management rules.
1038 // FIXME: Does the non-threaded performSelector family really belong here?
1039 // The selector could be, say, @selector(copy).
1040 if (cocoa::isCocoaObjectRef(RetTy))
1042 else if (coreFoundation::isCFObjectRef(RetTy)) {
1043 // ObjCMethodDecl currently doesn't consider CF objects as valid return
1044 // values for alloc, new, copy, or mutableCopy, so we have to
1045 // double-check with the selector. This is ugly, but there aren't that
1046 // many Objective-C methods that return CF objects, right?
1047 if (MD) {
1048 switch (S.getMethodFamily()) {
1049 case OMF_alloc:
1050 case OMF_new:
1051 case OMF_copy:
1052 case OMF_mutableCopy:
1053 ResultEff = RetEffect::MakeOwned(ObjKind::CF);
1054 break;
1055 default:
1057 break;
1058 }
1059 } else {
1061 }
1062 }
1063 break;
1064 case OMF_init:
1065 ResultEff = ObjCInitRetE;
1066 ReceiverEff = ArgEffect(DecRef, ObjKind::ObjC);
1067 break;
1068 case OMF_alloc:
1069 case OMF_new:
1070 case OMF_copy:
1071 case OMF_mutableCopy:
1072 if (cocoa::isCocoaObjectRef(RetTy))
1073 ResultEff = ObjCAllocRetE;
1074 else if (coreFoundation::isCFObjectRef(RetTy))
1075 ResultEff = RetEffect::MakeOwned(ObjKind::CF);
1076 break;
1077 case OMF_autorelease:
1078 ReceiverEff = ArgEffect(Autorelease, ObjKind::ObjC);
1079 break;
1080 case OMF_retain:
1081 ReceiverEff = ArgEffect(IncRef, ObjKind::ObjC);
1082 break;
1083 case OMF_release:
1084 ReceiverEff = ArgEffect(DecRef, ObjKind::ObjC);
1085 break;
1086 case OMF_dealloc:
1087 ReceiverEff = ArgEffect(Dealloc, ObjKind::ObjC);
1088 break;
1089 case OMF_self:
1090 // -self is handled specially by the ExprEngine to propagate the receiver.
1091 break;
1092 case OMF_retainCount:
1093 case OMF_finalize:
1094 // These methods don't return objects.
1095 break;
1096 }
1097
1098 // If one of the arguments in the selector has the keyword 'delegate' we
1099 // should stop tracking the reference count for the receiver. This is
1100 // because the reference count is quite possibly handled by a delegate
1101 // method.
1102 if (S.isKeywordSelector()) {
1103 for (unsigned i = 0, e = S.getNumArgs(); i != e; ++i) {
1104 StringRef Slot = S.getNameForSlot(i);
1105 if (Slot.substr(Slot.size() - 8).equals_insensitive("delegate")) {
1106 if (ResultEff == ObjCInitRetE)
1107 ResultEff = RetEffect::MakeNoRetHard();
1108 else
1110 }
1111 }
1112 }
1113
1114 if (ReceiverEff.getKind() == DoNothing &&
1115 ResultEff.getKind() == RetEffect::NoRet)
1116 return getDefaultSummary();
1117
1118 return getPersistentSummary(ResultEff, ArgEffects(AF.getEmptyMap()),
1119 ArgEffect(ReceiverEff), ArgEffect(MayEscape));
1120}
1121
1122const RetainSummary *
1123RetainSummaryManager::getClassMethodSummary(const ObjCMessageExpr *ME) {
1124 assert(!ME->isInstanceMessage());
1126
1127 return getMethodSummary(ME->getSelector(), Class, ME->getMethodDecl(),
1128 ME->getType(), ObjCClassMethodSummaries);
1129}
1130
1131const RetainSummary *RetainSummaryManager::getInstanceMethodSummary(
1132 const ObjCMessageExpr *ME,
1133 QualType ReceiverType) {
1134 const ObjCInterfaceDecl *ReceiverClass = nullptr;
1135
1136 // We do better tracking of the type of the object than the core ExprEngine.
1137 // See if we have its type in our private state.
1138 if (!ReceiverType.isNull())
1139 if (const auto *PT = ReceiverType->getAs<ObjCObjectPointerType>())
1140 ReceiverClass = PT->getInterfaceDecl();
1141
1142 // If we don't know what kind of object this is, fall back to its static type.
1143 if (!ReceiverClass)
1144 ReceiverClass = ME->getReceiverInterface();
1145
1146 // FIXME: The receiver could be a reference to a class, meaning that
1147 // we should use the class method.
1148 // id x = [NSObject class];
1149 // [x performSelector:... withObject:... afterDelay:...];
1150 Selector S = ME->getSelector();
1151 const ObjCMethodDecl *Method = ME->getMethodDecl();
1152 if (!Method && ReceiverClass)
1153 Method = ReceiverClass->getInstanceMethod(S);
1154
1155 return getMethodSummary(S, ReceiverClass, Method, ME->getType(),
1156 ObjCMethodSummaries);
1157}
1158
1159const RetainSummary *
1160RetainSummaryManager::getMethodSummary(Selector S,
1161 const ObjCInterfaceDecl *ID,
1162 const ObjCMethodDecl *MD, QualType RetTy,
1163 ObjCMethodSummariesTy &CachedSummaries) {
1164
1165 // Objective-C method summaries are only applicable to ObjC and CF objects.
1166 if (!TrackObjCAndCFObjects)
1167 return getDefaultSummary();
1168
1169 // Look up a summary in our summary cache.
1170 const RetainSummary *Summ = CachedSummaries.find(ID, S);
1171
1172 if (!Summ) {
1173 Summ = getStandardMethodSummary(MD, S, RetTy);
1174
1175 // Annotations override defaults.
1176 updateSummaryFromAnnotations(Summ, MD);
1177
1178 // Memoize the summary.
1179 CachedSummaries[ObjCSummaryKey(ID, S)] = Summ;
1180 }
1181
1182 return Summ;
1183}
1184
1185void RetainSummaryManager::InitializeClassMethodSummaries() {
1186 ArgEffects ScratchArgs = AF.getEmptyMap();
1187
1188 // Create the [NSAssertionHandler currentHander] summary.
1189 addClassMethSummary("NSAssertionHandler", "currentHandler",
1190 getPersistentSummary(RetEffect::MakeNotOwned(ObjKind::ObjC),
1191 ScratchArgs));
1192
1193 // Create the [NSAutoreleasePool addObject:] summary.
1194 ScratchArgs = AF.add(ScratchArgs, 0, ArgEffect(Autorelease));
1195 addClassMethSummary("NSAutoreleasePool", "addObject",
1196 getPersistentSummary(RetEffect::MakeNoRet(), ScratchArgs,
1199}
1200
1201void RetainSummaryManager::InitializeMethodSummaries() {
1202
1203 ArgEffects ScratchArgs = AF.getEmptyMap();
1204 // Create the "init" selector. It just acts as a pass-through for the
1205 // receiver.
1206 const RetainSummary *InitSumm = getPersistentSummary(
1207 ObjCInitRetE, ScratchArgs, ArgEffect(DecRef, ObjKind::ObjC));
1208 addNSObjectMethSummary(GetNullarySelector("init", Ctx), InitSumm);
1209
1210 // awakeAfterUsingCoder: behaves basically like an 'init' method. It
1211 // claims the receiver and returns a retained object.
1212 addNSObjectMethSummary(GetUnarySelector("awakeAfterUsingCoder", Ctx),
1213 InitSumm);
1214
1215 // The next methods are allocators.
1216 const RetainSummary *AllocSumm = getPersistentSummary(ObjCAllocRetE,
1217 ScratchArgs);
1218 const RetainSummary *CFAllocSumm =
1219 getPersistentSummary(RetEffect::MakeOwned(ObjKind::CF), ScratchArgs);
1220
1221 // Create the "retain" selector.
1223 const RetainSummary *Summ = getPersistentSummary(
1224 NoRet, ScratchArgs, ArgEffect(IncRef, ObjKind::ObjC));
1225 addNSObjectMethSummary(GetNullarySelector("retain", Ctx), Summ);
1226
1227 // Create the "release" selector.
1228 Summ = getPersistentSummary(NoRet, ScratchArgs,
1230 addNSObjectMethSummary(GetNullarySelector("release", Ctx), Summ);
1231
1232 // Create the -dealloc summary.
1233 Summ = getPersistentSummary(NoRet, ScratchArgs, ArgEffect(Dealloc,
1234 ObjKind::ObjC));
1235 addNSObjectMethSummary(GetNullarySelector("dealloc", Ctx), Summ);
1236
1237 // Create the "autorelease" selector.
1238 Summ = getPersistentSummary(NoRet, ScratchArgs, ArgEffect(Autorelease,
1239 ObjKind::ObjC));
1240 addNSObjectMethSummary(GetNullarySelector("autorelease", Ctx), Summ);
1241
1242 // For NSWindow, allocated objects are (initially) self-owned.
1243 // FIXME: For now we opt for false negatives with NSWindow, as these objects
1244 // self-own themselves. However, they only do this once they are displayed.
1245 // Thus, we need to track an NSWindow's display status.
1246 // This is tracked in <rdar://problem/6062711>.
1247 // See also http://llvm.org/bugs/show_bug.cgi?id=3714.
1248 const RetainSummary *NoTrackYet =
1249 getPersistentSummary(RetEffect::MakeNoRet(), ScratchArgs,
1251
1252 addClassMethSummary("NSWindow", "alloc", NoTrackYet);
1253
1254 // For NSPanel (which subclasses NSWindow), allocated objects are not
1255 // self-owned.
1256 // FIXME: For now we don't track NSPanels. object for the same reason
1257 // as for NSWindow objects.
1258 addClassMethSummary("NSPanel", "alloc", NoTrackYet);
1259
1260 // For NSNull, objects returned by +null are singletons that ignore
1261 // retain/release semantics. Just don't track them.
1262 // <rdar://problem/12858915>
1263 addClassMethSummary("NSNull", "null", NoTrackYet);
1264
1265 // Don't track allocated autorelease pools, as it is okay to prematurely
1266 // exit a method.
1267 addClassMethSummary("NSAutoreleasePool", "alloc", NoTrackYet);
1268 addClassMethSummary("NSAutoreleasePool", "allocWithZone", NoTrackYet, false);
1269 addClassMethSummary("NSAutoreleasePool", "new", NoTrackYet);
1270
1271 // Create summaries QCRenderer/QCView -createSnapShotImageOfType:
1272 addInstMethSummary("QCRenderer", AllocSumm, "createSnapshotImageOfType");
1273 addInstMethSummary("QCView", AllocSumm, "createSnapshotImageOfType");
1274
1275 // Create summaries for CIContext, 'createCGImage' and
1276 // 'createCGLayerWithSize'. These objects are CF objects, and are not
1277 // automatically garbage collected.
1278 addInstMethSummary("CIContext", CFAllocSumm, "createCGImage", "fromRect");
1279 addInstMethSummary("CIContext", CFAllocSumm, "createCGImage", "fromRect",
1280 "format", "colorSpace");
1281 addInstMethSummary("CIContext", CFAllocSumm, "createCGLayerWithSize", "info");
1282}
1283
1284const RetainSummary *
1285RetainSummaryManager::getMethodSummary(const ObjCMethodDecl *MD) {
1286 const ObjCInterfaceDecl *ID = MD->getClassInterface();
1287 Selector S = MD->getSelector();
1288 QualType ResultTy = MD->getReturnType();
1289
1290 ObjCMethodSummariesTy *CachedSummaries;
1291 if (MD->isInstanceMethod())
1292 CachedSummaries = &ObjCMethodSummaries;
1293 else
1294 CachedSummaries = &ObjCClassMethodSummaries;
1295
1296 return getMethodSummary(S, ID, MD, ResultTy, *CachedSummaries);
1297}
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, 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:631
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:40
Represents a static or instance method of a struct/union/class.
Definition: DeclCXX.h:2018
const CXXRecordDecl * getParent() const
Return the parent of this method declaration, which is the class in which this method is defined.
Definition: DeclCXX.h:2133
Represents a C++ struct/union/class.
Definition: DeclCXX.h:254
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition: Expr.h:2812
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
Definition: Expr.h:2990
QualType getCallReturnType(const ASTContext &Ctx) const
getCallReturnType - Get the return type of the call expr.
Definition: Expr.cpp:1576
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:83
ASTContext & getASTContext() const LLVM_READONLY
Definition: DeclBase.cpp:428
bool isImplicit() const
isImplicit - Indicates whether the declaration was implicitly generated by the implementation.
Definition: DeclBase.h:576
llvm::iterator_range< specific_attr_iterator< T > > specific_attrs() const
Definition: DeclBase.h:542
bool hasAttr() const
Definition: DeclBase.h:560
QualType getType() const
Definition: Expr.h:142
Represents a function declaration or definition.
Definition: Decl.h:1917
param_iterator param_end()
Definition: Decl.h:2595
QualType getReturnType() const
Definition: Decl.h:2636
ArrayRef< ParmVarDecl * > parameters() const
Definition: Decl.h:2582
param_iterator param_begin()
Definition: Decl.h:2594
FunctionDecl * getDefinition()
Get the definition for this declaration.
Definition: Decl.h:2184
size_t param_size() const
Definition: Decl.h:2598
Represents a prototype with parameter type info, e.g.
Definition: Type.h:4041
unsigned getNumParams() const
Definition: Type.h:4246
FunctionType - C99 6.7.5.3 - Function Declarators.
Definition: Type.h:3694
QualType getReturnType() const
Definition: Type.h:3959
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:247
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
Definition: Decl.h:268
ObjCMethodDecl * getInstanceMethod(Selector Sel, bool AllowHidden=false) const
Definition: DeclObjC.h:1059
Represents an ObjC class declaration.
Definition: DeclObjC.h:1147
An expression that sends a message to the given Objective-C object or class.
Definition: ExprObjC.h:942
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:1238
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:1346
ObjCMethodDecl - Represents an instance or class method declaration.
Definition: DeclObjC.h:138
param_const_iterator param_end() const
Definition: DeclObjC.h:360
param_const_iterator param_begin() const
Definition: DeclObjC.h:356
Selector getSelector() const
Definition: DeclObjC.h:329
bool isInstanceMethod() const
Definition: DeclObjC.h:428
ObjCMethodFamily getMethodFamily() const
Determines the family of this method.
Definition: DeclObjC.cpp:1053
QualType getReturnType() const
Definition: DeclObjC.h:331
ObjCInterfaceDecl * getClassInterface()
Definition: DeclObjC.cpp:1211
Represents a pointer to an Objective C object.
Definition: Type.h:6297
Represents a parameter to a function.
Definition: Decl.h:1722
A (possibly-)qualified type.
Definition: Type.h:736
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Definition: Type.h:803
QualType getCanonicalType() const
Definition: Type.h:6701
static std::string getAsString(SplitQualType split, const PrintingPolicy &Policy)
Definition: Type.h:1089
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:1783
bool isVoidType() const
Definition: Type.h:7218
bool isPointerType() const
Definition: Type.h:6910
const T * castAs() const
Member-template castAs<specific type>.
Definition: Type.h:7491
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:1768
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition: Type.cpp:629
bool isObjCIdType() const
Definition: Type.h:7071
const T * getAs() const
Member-template getAs<specific type>'.
Definition: Type.h:7424
QualType getType() const
Definition: Decl.h:712
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:142
internal::Matcher< NamedDecl > hasName(StringRef Name)
Matches NamedDecl nodes that have the specified name.
Definition: ASTMatchers.h:3012
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:1437
@ OMF_initialize
@ OMF_autorelease
@ OMF_mutableCopy
@ OMF_performSelector
@ OMF_None
No particular method family.
@ OMF_retainCount
@ C
Languages that the frontend can parse and compile.
Selector GetUnarySelector(StringRef name, ASTContext &Ctx)
Utility function for constructing an unary selector.
Definition: ASTContext.h:3363
Selector GetNullarySelector(StringRef name, ASTContext &Ctx)
Utility function for constructing a nullary selector.
Definition: ASTContext.h:3357