RetainSummaryManager.cpp revision 360784
1719Swollman//== RetainSummaryManager.cpp - Summaries for reference counting --*- C++ -*--//
21402Sache//
3652Sjkh// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4652Sjkh// See https://llvm.org/LICENSE.txt for license information.
5652Sjkh// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6652Sjkh//
7652Sjkh//===----------------------------------------------------------------------===//
8652Sjkh//
9652Sjkh//  This file defines summaries implementation for retain counting, which
10652Sjkh//  implements a reference count checker for Core Foundation, Cocoa
11652Sjkh//  and OSObject (on Mac OS X).
12652Sjkh//
13652Sjkh//===----------------------------------------------------------------------===//
14652Sjkh
15805Sache#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
16652Sjkh#include "clang/Analysis/RetainSummaryManager.h"
17652Sjkh#include "clang/AST/Attr.h"
18805Sache#include "clang/AST/DeclCXX.h"
19652Sjkh#include "clang/AST/DeclObjC.h"
20652Sjkh#include "clang/AST/ParentMap.h"
21652Sjkh#include "clang/ASTMatchers/ASTMatchFinder.h"
22652Sjkh
23652Sjkhusing namespace clang;
24652Sjkhusing namespace ento;
25652Sjkh
26652Sjkhtemplate <class T>
27652Sjkhconstexpr static bool isOneOf() {
28652Sjkh  return false;
29652Sjkh}
30652Sjkh
31652Sjkh/// Helper function to check whether the class is one of the
32652Sjkh/// rest of varargs.
331258Sswallacetemplate <class T, class P, class... ToCompare>
34652Sjkhconstexpr static bool isOneOf() {
35652Sjkh  return std::is_same<T, P>::value || isOneOf<T, ToCompare...>();
36652Sjkh}
371402Sache
38652Sjkhnamespace {
39652Sjkh
401402Sache/// Fake attribute class for RC* attributes.
411258Sswallacestruct GeneralizedReturnsRetainedAttr {
42652Sjkh  static bool classof(const Attr *A) {
43652Sjkh    if (auto AA = dyn_cast<AnnotateAttr>(A))
44652Sjkh      return AA->getAnnotation() == "rc_ownership_returns_retained";
45652Sjkh    return false;
46652Sjkh  }
47652Sjkh};
48652Sjkh
49652Sjkhstruct GeneralizedReturnsNotRetainedAttr {
50652Sjkh  static bool classof(const Attr *A) {
51652Sjkh    if (auto AA = dyn_cast<AnnotateAttr>(A))
52652Sjkh      return AA->getAnnotation() == "rc_ownership_returns_not_retained";
53652Sjkh    return false;
541258Sswallace  }
551258Sswallace};
56652Sjkh
57652Sjkhstruct GeneralizedConsumedAttr {
58652Sjkh  static bool classof(const Attr *A) {
59652Sjkh    if (auto AA = dyn_cast<AnnotateAttr>(A))
60652Sjkh      return AA->getAnnotation() == "rc_ownership_consumed";
61652Sjkh    return false;
62652Sjkh  }
63652Sjkh};
64652Sjkh
65652Sjkh}
66652Sjkh
67652Sjkhtemplate <class T>
68652SjkhOptional<ObjKind> RetainSummaryManager::hasAnyEnabledAttrOf(const Decl *D,
69652Sjkh                                                            QualType QT) {
70652Sjkh  ObjKind K;
71652Sjkh  if (isOneOf<T, CFConsumedAttr, CFReturnsRetainedAttr,
721258Sswallace              CFReturnsNotRetainedAttr>()) {
731258Sswallace    if (!TrackObjCAndCFObjects)
741258Sswallace      return None;
75652Sjkh
76652Sjkh    K = ObjKind::CF;
77652Sjkh  } else if (isOneOf<T, NSConsumedAttr, NSConsumesSelfAttr,
78652Sjkh                     NSReturnsAutoreleasedAttr, NSReturnsRetainedAttr,
79652Sjkh                     NSReturnsNotRetainedAttr, NSConsumesSelfAttr>()) {
80652Sjkh
81652Sjkh    if (!TrackObjCAndCFObjects)
82652Sjkh      return None;
83652Sjkh
84652Sjkh    if (isOneOf<T, NSReturnsRetainedAttr, NSReturnsAutoreleasedAttr,
85652Sjkh                NSReturnsNotRetainedAttr>() &&
86652Sjkh        !cocoa::isCocoaObjectRef(QT))
87652Sjkh      return None;
88652Sjkh    K = ObjKind::ObjC;
89652Sjkh  } else if (isOneOf<T, OSConsumedAttr, OSConsumesThisAttr,
90652Sjkh                     OSReturnsNotRetainedAttr, OSReturnsRetainedAttr,
91652Sjkh                     OSReturnsRetainedOnZeroAttr,
92652Sjkh                     OSReturnsRetainedOnNonZeroAttr>()) {
93652Sjkh    if (!TrackOSObjects)
94652Sjkh      return None;
95652Sjkh    K = ObjKind::OS;
96652Sjkh  } else if (isOneOf<T, GeneralizedReturnsNotRetainedAttr,
97652Sjkh                     GeneralizedReturnsRetainedAttr,
98652Sjkh                     GeneralizedConsumedAttr>()) {
99652Sjkh    K = ObjKind::Generalized;
100652Sjkh  } else {
101652Sjkh    llvm_unreachable("Unexpected attribute");
102652Sjkh  }
103652Sjkh  if (D->hasAttr<T>())
104652Sjkh    return K;
105652Sjkh  return None;
106652Sjkh}
107652Sjkh
108652Sjkhtemplate <class T1, class T2, class... Others>
109652SjkhOptional<ObjKind> RetainSummaryManager::hasAnyEnabledAttrOf(const Decl *D,
110652Sjkh                                                            QualType QT) {
111652Sjkh  if (auto Out = hasAnyEnabledAttrOf<T1>(D, QT))
112652Sjkh    return Out;
113652Sjkh  return hasAnyEnabledAttrOf<T2, Others...>(D, QT);
114652Sjkh}
115652Sjkh
116652Sjkhconst RetainSummary *
117652SjkhRetainSummaryManager::getPersistentSummary(const RetainSummary &OldSumm) {
118652Sjkh  // Unique "simple" summaries -- those without ArgEffects.
119652Sjkh  if (OldSumm.isSimple()) {
120652Sjkh    ::llvm::FoldingSetNodeID ID;
121652Sjkh    OldSumm.Profile(ID);
122652Sjkh
123652Sjkh    void *Pos;
124652Sjkh    CachedSummaryNode *N = SimpleSummaries.FindNodeOrInsertPos(ID, Pos);
125652Sjkh
126652Sjkh    if (!N) {
127652Sjkh      N = (CachedSummaryNode *) BPAlloc.Allocate<CachedSummaryNode>();
128652Sjkh      new (N) CachedSummaryNode(OldSumm);
129652Sjkh      SimpleSummaries.InsertNode(N, Pos);
130652Sjkh    }
131652Sjkh
132652Sjkh    return &N->getValue();
133652Sjkh  }
134652Sjkh
135652Sjkh  RetainSummary *Summ = (RetainSummary *) BPAlloc.Allocate<RetainSummary>();
136652Sjkh  new (Summ) RetainSummary(OldSumm);
137652Sjkh  return Summ;
138652Sjkh}
139652Sjkh
140652Sjkhstatic bool isSubclass(const Decl *D,
141652Sjkh                       StringRef ClassName) {
142652Sjkh  using namespace ast_matchers;
143652Sjkh  DeclarationMatcher SubclassM = cxxRecordDecl(isSameOrDerivedFrom(ClassName));
144652Sjkh  return !(match(SubclassM, *D, D->getASTContext()).empty());
145652Sjkh}
146652Sjkh
147652Sjkhstatic bool isOSObjectSubclass(const Decl *D) {
148652Sjkh  return D && isSubclass(D, "OSMetaClassBase");
149652Sjkh}
150652Sjkh
151652Sjkhstatic bool isOSObjectDynamicCast(StringRef S) {
152652Sjkh  return S == "safeMetaCast";
153652Sjkh}
154652Sjkh
155652Sjkhstatic bool isOSObjectRequiredCast(StringRef S) {
156652Sjkh  return S == "requiredMetaCast";
157652Sjkh}
158652Sjkh
159652Sjkhstatic bool isOSObjectThisCast(StringRef S) {
160652Sjkh  return S == "metaCast";
161652Sjkh}
162652Sjkh
163652Sjkh
164652Sjkhstatic bool isOSObjectPtr(QualType QT) {
165652Sjkh  return isOSObjectSubclass(QT->getPointeeCXXRecordDecl());
166652Sjkh}
167652Sjkh
168652Sjkhstatic bool isISLObjectRef(QualType Ty) {
169652Sjkh  return StringRef(Ty.getAsString()).startswith("isl_");
170652Sjkh}
171652Sjkh
172652Sjkhstatic bool isOSIteratorSubclass(const Decl *D) {
173652Sjkh  return isSubclass(D, "OSIterator");
174652Sjkh}
175652Sjkh
176652Sjkhstatic bool hasRCAnnotation(const Decl *D, StringRef rcAnnotation) {
177652Sjkh  for (const auto *Ann : D->specific_attrs<AnnotateAttr>()) {
178652Sjkh    if (Ann->getAnnotation() == rcAnnotation)
179652Sjkh      return true;
180652Sjkh  }
181652Sjkh  return false;
182652Sjkh}
183652Sjkh
184652Sjkhstatic bool isRetain(const FunctionDecl *FD, StringRef FName) {
185652Sjkh  return FName.startswith_lower("retain") || FName.endswith_lower("retain");
1861258Sswallace}
187652Sjkh
188652Sjkhstatic bool isRelease(const FunctionDecl *FD, StringRef FName) {
189652Sjkh  return FName.startswith_lower("release") || FName.endswith_lower("release");
190652Sjkh}
191652Sjkh
192652Sjkhstatic bool isAutorelease(const FunctionDecl *FD, StringRef FName) {
193652Sjkh  return FName.startswith_lower("autorelease") ||
194652Sjkh         FName.endswith_lower("autorelease");
195652Sjkh}
196652Sjkh
197652Sjkhstatic bool isMakeCollectable(StringRef FName) {
198652Sjkh  return FName.contains_lower("MakeCollectable");
199652Sjkh}
200652Sjkh
201652Sjkh/// A function is OSObject related if it is declared on a subclass
202652Sjkh/// of OSObject, or any of the parameters is a subclass of an OSObject.
203652Sjkhstatic bool isOSObjectRelated(const CXXMethodDecl *MD) {
204652Sjkh  if (isOSObjectSubclass(MD->getParent()))
205652Sjkh    return true;
206652Sjkh
207652Sjkh  for (ParmVarDecl *Param : MD->parameters()) {
208652Sjkh    QualType PT = Param->getType()->getPointeeType();
209652Sjkh    if (!PT.isNull())
210652Sjkh      if (CXXRecordDecl *RD = PT->getAsCXXRecordDecl())
211652Sjkh        if (isOSObjectSubclass(RD))
212652Sjkh          return true;
213652Sjkh  }
214652Sjkh
215652Sjkh  return false;
216652Sjkh}
217652Sjkh
218652Sjkhbool
219652SjkhRetainSummaryManager::isKnownSmartPointer(QualType QT) {
220652Sjkh  QT = QT.getCanonicalType();
221652Sjkh  const auto *RD = QT->getAsCXXRecordDecl();
222652Sjkh  if (!RD)
223652Sjkh    return false;
224652Sjkh  const IdentifierInfo *II = RD->getIdentifier();
225652Sjkh  if (II && II->getName() == "smart_ptr")
226652Sjkh    if (const auto *ND = dyn_cast<NamespaceDecl>(RD->getDeclContext()))
227652Sjkh      if (ND->getNameAsString() == "os")
228652Sjkh        return true;
229652Sjkh  return false;
230652Sjkh}
231652Sjkh
232652Sjkhconst RetainSummary *
233652SjkhRetainSummaryManager::getSummaryForOSObject(const FunctionDecl *FD,
234652Sjkh                                            StringRef FName, QualType RetTy) {
235652Sjkh  assert(TrackOSObjects &&
236652Sjkh         "Requesting a summary for an OSObject but OSObjects are not tracked");
237652Sjkh
238652Sjkh  if (RetTy->isPointerType()) {
239652Sjkh    const CXXRecordDecl *PD = RetTy->getPointeeType()->getAsCXXRecordDecl();
240652Sjkh    if (PD && isOSObjectSubclass(PD)) {
241652Sjkh      if (isOSObjectDynamicCast(FName) || isOSObjectRequiredCast(FName) ||
242652Sjkh          isOSObjectThisCast(FName))
243652Sjkh        return getDefaultSummary();
244652Sjkh
245652Sjkh      // TODO: Add support for the slightly common *Matching(table) idiom.
246652Sjkh      // Cf. IOService::nameMatching() etc. - these function have an unusual
247652Sjkh      // contract of returning at +0 or +1 depending on their last argument.
248652Sjkh      if (FName.endswith("Matching")) {
249652Sjkh        return getPersistentStopSummary();
250652Sjkh      }
251652Sjkh
252652Sjkh      // All objects returned with functions *not* starting with 'get',
253652Sjkh      // or iterators, are returned at +1.
254652Sjkh      if ((!FName.startswith("get") && !FName.startswith("Get")) ||
255652Sjkh          isOSIteratorSubclass(PD)) {
256652Sjkh        return getOSSummaryCreateRule(FD);
257652Sjkh      } else {
258652Sjkh        return getOSSummaryGetRule(FD);
259652Sjkh      }
260652Sjkh    }
261652Sjkh  }
262652Sjkh
263652Sjkh  if (const auto *MD = dyn_cast<CXXMethodDecl>(FD)) {
264652Sjkh    const CXXRecordDecl *Parent = MD->getParent();
265652Sjkh    if (Parent && isOSObjectSubclass(Parent)) {
266652Sjkh      if (FName == "release" || FName == "taggedRelease")
267652Sjkh        return getOSSummaryReleaseRule(FD);
268652Sjkh
269652Sjkh      if (FName == "retain" || FName == "taggedRetain")
270652Sjkh        return getOSSummaryRetainRule(FD);
271652Sjkh
272652Sjkh      if (FName == "free")
273652Sjkh        return getOSSummaryFreeRule(FD);
274652Sjkh
275652Sjkh      if (MD->getOverloadedOperator() == OO_New)
276652Sjkh        return getOSSummaryCreateRule(MD);
277652Sjkh    }
278652Sjkh  }
279652Sjkh
280652Sjkh  return nullptr;
281652Sjkh}
282652Sjkh
283652Sjkhconst RetainSummary *RetainSummaryManager::getSummaryForObjCOrCFObject(
284652Sjkh    const FunctionDecl *FD,
285652Sjkh    StringRef FName,
286652Sjkh    QualType RetTy,
287652Sjkh    const FunctionType *FT,
288652Sjkh    bool &AllowAnnotations) {
289652Sjkh
290652Sjkh  ArgEffects ScratchArgs(AF.getEmptyMap());
291652Sjkh
292652Sjkh  std::string RetTyName = RetTy.getAsString();
293652Sjkh  if (FName == "pthread_create" || FName == "pthread_setspecific") {
294652Sjkh    // Part of: <rdar://problem/7299394> and <rdar://problem/11282706>.
295652Sjkh    // This will be addressed better with IPA.
296652Sjkh    return getPersistentStopSummary();
297652Sjkh  } else if(FName == "NSMakeCollectable") {
298652Sjkh    // Handle: id NSMakeCollectable(CFTypeRef)
299652Sjkh    AllowAnnotations = false;
300652Sjkh    return RetTy->isObjCIdType() ? getUnarySummary(FT, DoNothing)
301652Sjkh                                 : getPersistentStopSummary();
302652Sjkh  } else if (FName == "CMBufferQueueDequeueAndRetain" ||
303652Sjkh             FName == "CMBufferQueueDequeueIfDataReadyAndRetain") {
304652Sjkh    // Part of: <rdar://problem/39390714>.
305652Sjkh    return getPersistentSummary(RetEffect::MakeOwned(ObjKind::CF),
306652Sjkh                                ScratchArgs,
307652Sjkh                                ArgEffect(DoNothing),
308652Sjkh                                ArgEffect(DoNothing));
309652Sjkh  } else if (FName == "CFPlugInInstanceCreate") {
310652Sjkh    return getPersistentSummary(RetEffect::MakeNoRet(), ScratchArgs);
311652Sjkh  } else if (FName == "IORegistryEntrySearchCFProperty" ||
312652Sjkh             (RetTyName == "CFMutableDictionaryRef" &&
3131402Sache              (FName == "IOBSDNameMatching" || FName == "IOServiceMatching" ||
314652Sjkh               FName == "IOServiceNameMatching" ||
315652Sjkh               FName == "IORegistryEntryIDMatching" ||
3161402Sache               FName == "IOOpenFirmwarePathMatching"))) {
3171402Sache    // Part of <rdar://problem/6961230>. (IOKit)
3181402Sache    // This should be addressed using a API table.
3191402Sache    return getPersistentSummary(RetEffect::MakeOwned(ObjKind::CF), ScratchArgs,
3201402Sache                                ArgEffect(DoNothing), ArgEffect(DoNothing));
3211402Sache  } else if (FName == "IOServiceGetMatchingService" ||
3221402Sache             FName == "IOServiceGetMatchingServices") {
323652Sjkh    // FIXES: <rdar://problem/6326900>
324652Sjkh    // This should be addressed using a API table.  This strcmp is also
325652Sjkh    // a little gross, but there is no need to super optimize here.
326652Sjkh    ScratchArgs = AF.add(ScratchArgs, 1, ArgEffect(DecRef, ObjKind::CF));
327652Sjkh    return getPersistentSummary(RetEffect::MakeNoRet(),
328652Sjkh                                ScratchArgs,
329652Sjkh                                ArgEffect(DoNothing), ArgEffect(DoNothing));
330652Sjkh  } else if (FName == "IOServiceAddNotification" ||
331652Sjkh             FName == "IOServiceAddMatchingNotification") {
332652Sjkh    // Part of <rdar://problem/6961230>. (IOKit)
333652Sjkh    // This should be addressed using a API table.
334652Sjkh    ScratchArgs = AF.add(ScratchArgs, 2, ArgEffect(DecRef, ObjKind::CF));
335652Sjkh    return getPersistentSummary(RetEffect::MakeNoRet(),
336652Sjkh                                ScratchArgs,
337652Sjkh                                ArgEffect(DoNothing), ArgEffect(DoNothing));
338652Sjkh  } else if (FName == "CVPixelBufferCreateWithBytes") {
339652Sjkh    // FIXES: <rdar://problem/7283567>
340652Sjkh    // Eventually this can be improved by recognizing that the pixel
341652Sjkh    // buffer passed to CVPixelBufferCreateWithBytes is released via
342652Sjkh    // a callback and doing full IPA to make sure this is done correctly.
343652Sjkh    // FIXME: This function has an out parameter that returns an
344652Sjkh    // allocated object.
345652Sjkh    ScratchArgs = AF.add(ScratchArgs, 7, ArgEffect(StopTracking));
346652Sjkh    return getPersistentSummary(RetEffect::MakeNoRet(),
347652Sjkh                                ScratchArgs,
348652Sjkh                                ArgEffect(DoNothing), ArgEffect(DoNothing));
349652Sjkh  } else if (FName == "CGBitmapContextCreateWithData") {
350652Sjkh    // FIXES: <rdar://problem/7358899>
351652Sjkh    // Eventually this can be improved by recognizing that 'releaseInfo'
352652Sjkh    // passed to CGBitmapContextCreateWithData is released via
353652Sjkh    // a callback and doing full IPA to make sure this is done correctly.
354652Sjkh    ScratchArgs = AF.add(ScratchArgs, 8, ArgEffect(ArgEffect(StopTracking)));
355652Sjkh    return getPersistentSummary(RetEffect::MakeOwned(ObjKind::CF), ScratchArgs,
356652Sjkh                                ArgEffect(DoNothing), ArgEffect(DoNothing));
357652Sjkh  } else if (FName == "CVPixelBufferCreateWithPlanarBytes") {
358652Sjkh    // FIXES: <rdar://problem/7283567>
359652Sjkh    // Eventually this can be improved by recognizing that the pixel
360652Sjkh    // buffer passed to CVPixelBufferCreateWithPlanarBytes is released
361652Sjkh    // via a callback and doing full IPA to make sure this is done
362652Sjkh    // correctly.
363652Sjkh    ScratchArgs = AF.add(ScratchArgs, 12, ArgEffect(StopTracking));
364652Sjkh    return getPersistentSummary(RetEffect::MakeNoRet(),
365652Sjkh                                ScratchArgs,
366652Sjkh                                ArgEffect(DoNothing), ArgEffect(DoNothing));
367652Sjkh  } else if (FName == "VTCompressionSessionEncodeFrame") {
368652Sjkh    // The context argument passed to VTCompressionSessionEncodeFrame()
369652Sjkh    // is passed to the callback specified when creating the session
370652Sjkh    // (e.g. with VTCompressionSessionCreate()) which can release it.
371652Sjkh    // To account for this possibility, conservatively stop tracking
372652Sjkh    // the context.
373652Sjkh    ScratchArgs = AF.add(ScratchArgs, 5, ArgEffect(StopTracking));
374652Sjkh    return getPersistentSummary(RetEffect::MakeNoRet(),
375652Sjkh                                ScratchArgs,
376652Sjkh                                ArgEffect(DoNothing), ArgEffect(DoNothing));
377652Sjkh  } else if (FName == "dispatch_set_context" ||
378652Sjkh             FName == "xpc_connection_set_context") {
379652Sjkh    // <rdar://problem/11059275> - The analyzer currently doesn't have
380652Sjkh    // a good way to reason about the finalizer function for libdispatch.
381652Sjkh    // If we pass a context object that is memory managed, stop tracking it.
382652Sjkh    // <rdar://problem/13783514> - Same problem, but for XPC.
383652Sjkh    // FIXME: this hack should possibly go away once we can handle
384652Sjkh    // libdispatch and XPC finalizers.
385652Sjkh    ScratchArgs = AF.add(ScratchArgs, 1, ArgEffect(StopTracking));
386652Sjkh    return getPersistentSummary(RetEffect::MakeNoRet(),
387652Sjkh                                ScratchArgs,
388652Sjkh                                ArgEffect(DoNothing), ArgEffect(DoNothing));
389652Sjkh  } else if (FName.startswith("NSLog")) {
390652Sjkh    return getDoNothingSummary();
391652Sjkh  } else if (FName.startswith("NS") &&
392652Sjkh             (FName.find("Insert") != StringRef::npos)) {
393652Sjkh    // Whitelist NSXXInsertXX, for example NSMapInsertIfAbsent, since they can
394652Sjkh    // be deallocated by NSMapRemove. (radar://11152419)
395652Sjkh    ScratchArgs = AF.add(ScratchArgs, 1, ArgEffect(StopTracking));
396652Sjkh    ScratchArgs = AF.add(ScratchArgs, 2, ArgEffect(StopTracking));
397652Sjkh    return getPersistentSummary(RetEffect::MakeNoRet(),
398652Sjkh                                ScratchArgs, ArgEffect(DoNothing),
399652Sjkh                                ArgEffect(DoNothing));
400652Sjkh  }
401652Sjkh
402652Sjkh  if (RetTy->isPointerType()) {
403652Sjkh
404652Sjkh    // For CoreFoundation ('CF') types.
405652Sjkh    if (cocoa::isRefType(RetTy, "CF", FName)) {
406652Sjkh      if (isRetain(FD, FName)) {
407652Sjkh        // CFRetain isn't supposed to be annotated. However, this may as
408652Sjkh        // well be a user-made "safe" CFRetain function that is incorrectly
409652Sjkh        // annotated as cf_returns_retained due to lack of better options.
410652Sjkh        // We want to ignore such annotation.
411652Sjkh        AllowAnnotations = false;
412652Sjkh
413652Sjkh        return getUnarySummary(FT, IncRef);
414652Sjkh      } else if (isAutorelease(FD, FName)) {
415652Sjkh        // The headers use cf_consumed, but we can fully model CFAutorelease
4161258Sswallace        // ourselves.
4171258Sswallace        AllowAnnotations = false;
418652Sjkh
419652Sjkh        return getUnarySummary(FT, Autorelease);
420652Sjkh      } else if (isMakeCollectable(FName)) {
421652Sjkh        AllowAnnotations = false;
422652Sjkh        return getUnarySummary(FT, DoNothing);
423652Sjkh      } else {
424652Sjkh        return getCFCreateGetRuleSummary(FD);
425652Sjkh      }
426652Sjkh    }
427652Sjkh
428652Sjkh    // For CoreGraphics ('CG') and CoreVideo ('CV') types.
429652Sjkh    if (cocoa::isRefType(RetTy, "CG", FName) ||
430652Sjkh        cocoa::isRefType(RetTy, "CV", FName)) {
431652Sjkh      if (isRetain(FD, FName))
432652Sjkh        return getUnarySummary(FT, IncRef);
4331258Sswallace      else
434652Sjkh        return getCFCreateGetRuleSummary(FD);
435652Sjkh    }
436652Sjkh
437652Sjkh    // For all other CF-style types, use the Create/Get
438652Sjkh    // rule for summaries but don't support Retain functions
439652Sjkh    // with framework-specific prefixes.
440652Sjkh    if (coreFoundation::isCFObjectRef(RetTy)) {
441652Sjkh      return getCFCreateGetRuleSummary(FD);
442652Sjkh    }
443652Sjkh
444652Sjkh    if (FD->hasAttr<CFAuditedTransferAttr>()) {
445652Sjkh      return getCFCreateGetRuleSummary(FD);
4461258Sswallace    }
447652Sjkh  }
448652Sjkh
449652Sjkh  // Check for release functions, the only kind of functions that we care
450652Sjkh  // about that don't return a pointer type.
451652Sjkh  if (FName.startswith("CG") || FName.startswith("CF")) {
452652Sjkh    // Test for 'CGCF'.
453652Sjkh    FName = FName.substr(FName.startswith("CGCF") ? 4 : 2);
454652Sjkh
455652Sjkh    if (isRelease(FD, FName))
456652Sjkh      return getUnarySummary(FT, DecRef);
457652Sjkh    else {
458652Sjkh      assert(ScratchArgs.isEmpty());
459652Sjkh      // Remaining CoreFoundation and CoreGraphics functions.
460652Sjkh      // We use to assume that they all strictly followed the ownership idiom
461652Sjkh      // and that ownership cannot be transferred.  While this is technically
462652Sjkh      // correct, many methods allow a tracked object to escape.  For example:
463652Sjkh      //
464652Sjkh      //   CFMutableDictionaryRef x = CFDictionaryCreateMutable(...);
465652Sjkh      //   CFDictionaryAddValue(y, key, x);
466652Sjkh      //   CFRelease(x);
467652Sjkh      //   ... it is okay to use 'x' since 'y' has a reference to it
468652Sjkh      //
469652Sjkh      // We handle this and similar cases with the follow heuristic.  If the
470652Sjkh      // function name contains "InsertValue", "SetValue", "AddValue",
471652Sjkh      // "AppendValue", or "SetAttribute", then we assume that arguments may
472652Sjkh      // "escape."  This means that something else holds on to the object,
473652Sjkh      // allowing it be used even after its local retain count drops to 0.
474652Sjkh      ArgEffectKind E =
475652Sjkh          (StrInStrNoCase(FName, "InsertValue") != StringRef::npos ||
476652Sjkh           StrInStrNoCase(FName, "AddValue") != StringRef::npos ||
477652Sjkh           StrInStrNoCase(FName, "SetValue") != StringRef::npos ||
478652Sjkh           StrInStrNoCase(FName, "AppendValue") != StringRef::npos ||
479652Sjkh           StrInStrNoCase(FName, "SetAttribute") != StringRef::npos)
480652Sjkh              ? MayEscape
481652Sjkh              : DoNothing;
482652Sjkh
483652Sjkh      return getPersistentSummary(RetEffect::MakeNoRet(), ScratchArgs,
484652Sjkh                                  ArgEffect(DoNothing), ArgEffect(E, ObjKind::CF));
485652Sjkh    }
486652Sjkh  }
487652Sjkh
488652Sjkh  return nullptr;
489652Sjkh}
490652Sjkh
491652Sjkhconst RetainSummary *
492652SjkhRetainSummaryManager::generateSummary(const FunctionDecl *FD,
493652Sjkh                                      bool &AllowAnnotations) {
494652Sjkh  // We generate "stop" summaries for implicitly defined functions.
495652Sjkh  if (FD->isImplicit())
496652Sjkh    return getPersistentStopSummary();
497652Sjkh
498652Sjkh  const IdentifierInfo *II = FD->getIdentifier();
499652Sjkh
500652Sjkh  StringRef FName = II ? II->getName() : "";
501652Sjkh
502652Sjkh  // Strip away preceding '_'.  Doing this here will effect all the checks
503652Sjkh  // down below.
504652Sjkh  FName = FName.substr(FName.find_first_not_of('_'));
505652Sjkh
506652Sjkh  // Inspect the result type. Strip away any typedefs.
507652Sjkh  const auto *FT = FD->getType()->castAs<FunctionType>();
508652Sjkh  QualType RetTy = FT->getReturnType();
509652Sjkh
510652Sjkh  if (TrackOSObjects)
511652Sjkh    if (const RetainSummary *S = getSummaryForOSObject(FD, FName, RetTy))
512652Sjkh      return S;
513652Sjkh
514652Sjkh  if (const auto *MD = dyn_cast<CXXMethodDecl>(FD))
515652Sjkh    if (!isOSObjectRelated(MD))
516652Sjkh      return getPersistentSummary(RetEffect::MakeNoRet(),
517652Sjkh                                  ArgEffects(AF.getEmptyMap()),
518652Sjkh                                  ArgEffect(DoNothing),
519652Sjkh                                  ArgEffect(StopTracking),
520652Sjkh                                  ArgEffect(DoNothing));
521652Sjkh
522652Sjkh  if (TrackObjCAndCFObjects)
523652Sjkh    if (const RetainSummary *S =
524652Sjkh            getSummaryForObjCOrCFObject(FD, FName, RetTy, FT, AllowAnnotations))
525652Sjkh      return S;
526652Sjkh
527652Sjkh  return getDefaultSummary();
528652Sjkh}
529652Sjkh
530652Sjkhconst RetainSummary *
531652SjkhRetainSummaryManager::getFunctionSummary(const FunctionDecl *FD) {
532652Sjkh  // If we don't know what function we're calling, use our default summary.
533652Sjkh  if (!FD)
534652Sjkh    return getDefaultSummary();
535652Sjkh
536652Sjkh  // Look up a summary in our cache of FunctionDecls -> Summaries.
537652Sjkh  FuncSummariesTy::iterator I = FuncSummaries.find(FD);
538652Sjkh  if (I != FuncSummaries.end())
539652Sjkh    return I->second;
540652Sjkh
541652Sjkh  // No summary?  Generate one.
542652Sjkh  bool AllowAnnotations = true;
543652Sjkh  const RetainSummary *S = generateSummary(FD, AllowAnnotations);
544652Sjkh
545652Sjkh  // Annotations override defaults.
546652Sjkh  if (AllowAnnotations)
547652Sjkh    updateSummaryFromAnnotations(S, FD);
548652Sjkh
549652Sjkh  FuncSummaries[FD] = S;
550652Sjkh  return S;
551652Sjkh}
552652Sjkh
553652Sjkh//===----------------------------------------------------------------------===//
554652Sjkh// Summary creation for functions (largely uses of Core Foundation).
555652Sjkh//===----------------------------------------------------------------------===//
556652Sjkh
557652Sjkhstatic ArgEffect getStopTrackingHardEquivalent(ArgEffect E) {
558652Sjkh  switch (E.getKind()) {
559652Sjkh  case DoNothing:
560652Sjkh  case Autorelease:
561652Sjkh  case DecRefBridgedTransferred:
562652Sjkh  case IncRef:
563652Sjkh  case UnretainedOutParameter:
564652Sjkh  case RetainedOutParameter:
565652Sjkh  case RetainedOutParameterOnZero:
566652Sjkh  case RetainedOutParameterOnNonZero:
567652Sjkh  case MayEscape:
568652Sjkh  case StopTracking:
569652Sjkh  case StopTrackingHard:
570652Sjkh    return E.withKind(StopTrackingHard);
571652Sjkh  case DecRef:
572652Sjkh  case DecRefAndStopTrackingHard:
573652Sjkh    return E.withKind(DecRefAndStopTrackingHard);
574652Sjkh  case Dealloc:
575652Sjkh    return E.withKind(Dealloc);
576652Sjkh  }
577652Sjkh
578652Sjkh  llvm_unreachable("Unknown ArgEffect kind");
579652Sjkh}
580652Sjkh
581652Sjkhconst RetainSummary *
582652SjkhRetainSummaryManager::updateSummaryForNonZeroCallbackArg(const RetainSummary *S,
583652Sjkh                                                         AnyCall &C) {
584652Sjkh  ArgEffect RecEffect = getStopTrackingHardEquivalent(S->getReceiverEffect());
585652Sjkh  ArgEffect DefEffect = getStopTrackingHardEquivalent(S->getDefaultArgEffect());
586652Sjkh
587652Sjkh  ArgEffects ScratchArgs(AF.getEmptyMap());
588652Sjkh  ArgEffects CustomArgEffects = S->getArgEffects();
589652Sjkh  for (ArgEffects::iterator I = CustomArgEffects.begin(),
590652Sjkh                            E = CustomArgEffects.end();
591652Sjkh       I != E; ++I) {
592652Sjkh    ArgEffect Translated = getStopTrackingHardEquivalent(I->second);
593652Sjkh    if (Translated.getKind() != DefEffect.getKind())
594652Sjkh      ScratchArgs = AF.add(ScratchArgs, I->first, Translated);
595652Sjkh  }
596652Sjkh
597652Sjkh  RetEffect RE = RetEffect::MakeNoRetHard();
598652Sjkh
599652Sjkh  // Special cases where the callback argument CANNOT free the return value.
600652Sjkh  // This can generally only happen if we know that the callback will only be
601652Sjkh  // called when the return value is already being deallocated.
602652Sjkh  if (const IdentifierInfo *Name = C.getIdentifier()) {
603652Sjkh    // When the CGBitmapContext is deallocated, the callback here will free
604652Sjkh    // the associated data buffer.
605652Sjkh    // The callback in dispatch_data_create frees the buffer, but not
606652Sjkh    // the data object.
607652Sjkh    if (Name->isStr("CGBitmapContextCreateWithData") ||
608652Sjkh        Name->isStr("dispatch_data_create"))
609652Sjkh      RE = S->getRetEffect();
610652Sjkh  }
611652Sjkh
612652Sjkh  return getPersistentSummary(RE, ScratchArgs, RecEffect, DefEffect);
613652Sjkh}
614652Sjkh
615652Sjkhvoid RetainSummaryManager::updateSummaryForReceiverUnconsumedSelf(
616652Sjkh    const RetainSummary *&S) {
617652Sjkh
618652Sjkh  RetainSummaryTemplate Template(S, *this);
619652Sjkh
620805Sache  Template->setReceiverEffect(ArgEffect(DoNothing));
621652Sjkh  Template->setRetEffect(RetEffect::MakeNoRet());
622652Sjkh}
623652Sjkh
624652Sjkh
625652Sjkhvoid RetainSummaryManager::updateSummaryForArgumentTypes(
626652Sjkh  const AnyCall &C, const RetainSummary *&RS) {
627652Sjkh  RetainSummaryTemplate Template(RS, *this);
628652Sjkh
629652Sjkh  unsigned parm_idx = 0;
630652Sjkh  for (auto pi = C.param_begin(), pe = C.param_end(); pi != pe;
631652Sjkh       ++pi, ++parm_idx) {
632652Sjkh    QualType QT = (*pi)->getType();
633652Sjkh
634652Sjkh    // Skip already created values.
635652Sjkh    if (RS->getArgEffects().contains(parm_idx))
636652Sjkh      continue;
637652Sjkh
638652Sjkh    ObjKind K = ObjKind::AnyObj;
639652Sjkh
640652Sjkh    if (isISLObjectRef(QT)) {
6411402Sache      K = ObjKind::Generalized;
6421402Sache    } else if (isOSObjectPtr(QT)) {
643652Sjkh      K = ObjKind::OS;
644652Sjkh    } else if (cocoa::isCocoaObjectRef(QT)) {
645652Sjkh      K = ObjKind::ObjC;
646652Sjkh    } else if (coreFoundation::isCFObjectRef(QT)) {
647652Sjkh      K = ObjKind::CF;
648652Sjkh    }
649652Sjkh
650652Sjkh    if (K != ObjKind::AnyObj)
651652Sjkh      Template->addArg(AF, parm_idx,
652652Sjkh                       ArgEffect(RS->getDefaultArgEffect().getKind(), K));
653652Sjkh  }
654652Sjkh}
655652Sjkh
6561402Sacheconst RetainSummary *
6571402SacheRetainSummaryManager::getSummary(AnyCall C,
6581402Sache                                 bool HasNonZeroCallbackArg,
6591402Sache                                 bool IsReceiverUnconsumedSelf,
6601402Sache                                 QualType ReceiverType) {
6611402Sache  const RetainSummary *Summ;
6621402Sache  switch (C.getKind()) {
6631402Sache  case AnyCall::Function:
6641402Sache  case AnyCall::Constructor:
6651402Sache  case AnyCall::Allocator:
6661402Sache  case AnyCall::Deallocator:
667652Sjkh    Summ = getFunctionSummary(cast_or_null<FunctionDecl>(C.getDecl()));
668652Sjkh    break;
669652Sjkh  case AnyCall::Block:
670652Sjkh  case AnyCall::Destructor:
671652Sjkh    // FIXME: These calls are currently unsupported.
672652Sjkh    return getPersistentStopSummary();
673652Sjkh  case AnyCall::ObjCMethod: {
674652Sjkh    const auto *ME = cast_or_null<ObjCMessageExpr>(C.getExpr());
675652Sjkh    if (!ME) {
676652Sjkh      Summ = getMethodSummary(cast<ObjCMethodDecl>(C.getDecl()));
677652Sjkh    } else if (ME->isInstanceMessage()) {
678652Sjkh      Summ = getInstanceMethodSummary(ME, ReceiverType);
679652Sjkh    } else {
680652Sjkh      Summ = getClassMethodSummary(ME);
681652Sjkh    }
682652Sjkh    break;
683652Sjkh  }
684652Sjkh  }
685652Sjkh
686652Sjkh  if (HasNonZeroCallbackArg)
687652Sjkh    Summ = updateSummaryForNonZeroCallbackArg(Summ, C);
688652Sjkh
689652Sjkh  if (IsReceiverUnconsumedSelf)
690652Sjkh    updateSummaryForReceiverUnconsumedSelf(Summ);
691652Sjkh
692652Sjkh  updateSummaryForArgumentTypes(C, Summ);
693652Sjkh
694652Sjkh  assert(Summ && "Unknown call type?");
695652Sjkh  return Summ;
696652Sjkh}
697652Sjkh
698652Sjkh
699652Sjkhconst RetainSummary *
700652SjkhRetainSummaryManager::getCFCreateGetRuleSummary(const FunctionDecl *FD) {
701652Sjkh  if (coreFoundation::followsCreateRule(FD))
702652Sjkh    return getCFSummaryCreateRule(FD);
703652Sjkh
704652Sjkh  return getCFSummaryGetRule(FD);
705652Sjkh}
706652Sjkh
707652Sjkhbool RetainSummaryManager::isTrustedReferenceCountImplementation(
708652Sjkh    const Decl *FD) {
709652Sjkh  return hasRCAnnotation(FD, "rc_ownership_trusted_implementation");
710652Sjkh}
711652Sjkh
712652SjkhOptional<RetainSummaryManager::BehaviorSummary>
713652SjkhRetainSummaryManager::canEval(const CallExpr *CE, const FunctionDecl *FD,
714652Sjkh                              bool &hasTrustedImplementationAnnotation) {
715652Sjkh
716652Sjkh  IdentifierInfo *II = FD->getIdentifier();
717652Sjkh  if (!II)
718652Sjkh    return None;
719652Sjkh
720652Sjkh  StringRef FName = II->getName();
721652Sjkh  FName = FName.substr(FName.find_first_not_of('_'));
722652Sjkh
723652Sjkh  QualType ResultTy = CE->getCallReturnType(Ctx);
724652Sjkh  if (ResultTy->isObjCIdType()) {
725652Sjkh    if (II->isStr("NSMakeCollectable"))
726652Sjkh      return BehaviorSummary::Identity;
727652Sjkh  } else if (ResultTy->isPointerType()) {
728652Sjkh    // Handle: (CF|CG|CV)Retain
729652Sjkh    //         CFAutorelease
730652Sjkh    // It's okay to be a little sloppy here.
731652Sjkh    if (FName == "CMBufferQueueDequeueAndRetain" ||
732652Sjkh        FName == "CMBufferQueueDequeueIfDataReadyAndRetain") {
733652Sjkh      // Part of: <rdar://problem/39390714>.
734652Sjkh      // These are not retain. They just return something and retain it.
735652Sjkh      return None;
736652Sjkh    }
737652Sjkh    if (CE->getNumArgs() == 1 &&
738652Sjkh        (cocoa::isRefType(ResultTy, "CF", FName) ||
739652Sjkh         cocoa::isRefType(ResultTy, "CG", FName) ||
740652Sjkh         cocoa::isRefType(ResultTy, "CV", FName)) &&
741652Sjkh        (isRetain(FD, FName) || isAutorelease(FD, FName) ||
742652Sjkh         isMakeCollectable(FName)))
743652Sjkh      return BehaviorSummary::Identity;
744652Sjkh
745652Sjkh    // safeMetaCast is called by OSDynamicCast.
746652Sjkh    // We assume that OSDynamicCast is either an identity (cast is OK,
747652Sjkh    // the input was non-zero),
748652Sjkh    // or that it returns zero (when the cast failed, or the input
749652Sjkh    // was zero).
750652Sjkh    if (TrackOSObjects) {
751652Sjkh      if (isOSObjectDynamicCast(FName) && FD->param_size() >= 1) {
752652Sjkh        return BehaviorSummary::IdentityOrZero;
753652Sjkh      } else if (isOSObjectRequiredCast(FName) && FD->param_size() >= 1) {
754652Sjkh        return BehaviorSummary::Identity;
755652Sjkh      } else if (isOSObjectThisCast(FName) && isa<CXXMethodDecl>(FD) &&
756652Sjkh                 !cast<CXXMethodDecl>(FD)->isStatic()) {
7571402Sache        return BehaviorSummary::IdentityThis;
7581402Sache      }
759652Sjkh    }
760652Sjkh
761652Sjkh    const FunctionDecl* FDD = FD->getDefinition();
762652Sjkh    if (FDD && isTrustedReferenceCountImplementation(FDD)) {
763719Swollman      hasTrustedImplementationAnnotation = true;
764      return BehaviorSummary::Identity;
765    }
766  }
767
768  if (const auto *MD = dyn_cast<CXXMethodDecl>(FD)) {
769    const CXXRecordDecl *Parent = MD->getParent();
770    if (TrackOSObjects && Parent && isOSObjectSubclass(Parent))
771      if (FName == "release" || FName == "retain")
772        return BehaviorSummary::NoOp;
773  }
774
775  return None;
776}
777
778const RetainSummary *
779RetainSummaryManager::getUnarySummary(const FunctionType* FT,
780                                      ArgEffectKind AE) {
781
782  // Unary functions have no arg effects by definition.
783  ArgEffects ScratchArgs(AF.getEmptyMap());
784
785  // Sanity check that this is *really* a unary function.  This can
786  // happen if people do weird things.
787  const FunctionProtoType* FTP = dyn_cast<FunctionProtoType>(FT);
788  if (!FTP || FTP->getNumParams() != 1)
789    return getPersistentStopSummary();
790
791  ArgEffect Effect(AE, ObjKind::CF);
792
793  ScratchArgs = AF.add(ScratchArgs, 0, Effect);
794  return getPersistentSummary(RetEffect::MakeNoRet(),
795                              ScratchArgs,
796                              ArgEffect(DoNothing), ArgEffect(DoNothing));
797}
798
799const RetainSummary *
800RetainSummaryManager::getOSSummaryRetainRule(const FunctionDecl *FD) {
801  return getPersistentSummary(RetEffect::MakeNoRet(),
802                              AF.getEmptyMap(),
803                              /*ReceiverEff=*/ArgEffect(DoNothing),
804                              /*DefaultEff=*/ArgEffect(DoNothing),
805                              /*ThisEff=*/ArgEffect(IncRef, ObjKind::OS));
806}
807
808const RetainSummary *
809RetainSummaryManager::getOSSummaryReleaseRule(const FunctionDecl *FD) {
810  return getPersistentSummary(RetEffect::MakeNoRet(),
811                              AF.getEmptyMap(),
812                              /*ReceiverEff=*/ArgEffect(DoNothing),
813                              /*DefaultEff=*/ArgEffect(DoNothing),
814                              /*ThisEff=*/ArgEffect(DecRef, ObjKind::OS));
815}
816
817const RetainSummary *
818RetainSummaryManager::getOSSummaryFreeRule(const FunctionDecl *FD) {
819  return getPersistentSummary(RetEffect::MakeNoRet(),
820                              AF.getEmptyMap(),
821                              /*ReceiverEff=*/ArgEffect(DoNothing),
822                              /*DefaultEff=*/ArgEffect(DoNothing),
823                              /*ThisEff=*/ArgEffect(Dealloc, ObjKind::OS));
824}
825
826const RetainSummary *
827RetainSummaryManager::getOSSummaryCreateRule(const FunctionDecl *FD) {
828  return getPersistentSummary(RetEffect::MakeOwned(ObjKind::OS),
829                              AF.getEmptyMap());
830}
831
832const RetainSummary *
833RetainSummaryManager::getOSSummaryGetRule(const FunctionDecl *FD) {
834  return getPersistentSummary(RetEffect::MakeNotOwned(ObjKind::OS),
835                              AF.getEmptyMap());
836}
837
838const RetainSummary *
839RetainSummaryManager::getCFSummaryCreateRule(const FunctionDecl *FD) {
840  return getPersistentSummary(RetEffect::MakeOwned(ObjKind::CF),
841                              ArgEffects(AF.getEmptyMap()));
842}
843
844const RetainSummary *
845RetainSummaryManager::getCFSummaryGetRule(const FunctionDecl *FD) {
846  return getPersistentSummary(RetEffect::MakeNotOwned(ObjKind::CF),
847                              ArgEffects(AF.getEmptyMap()),
848                              ArgEffect(DoNothing), ArgEffect(DoNothing));
849}
850
851
852
853
854//===----------------------------------------------------------------------===//
855// Summary creation for Selectors.
856//===----------------------------------------------------------------------===//
857
858Optional<RetEffect>
859RetainSummaryManager::getRetEffectFromAnnotations(QualType RetTy,
860                                                  const Decl *D) {
861  if (hasAnyEnabledAttrOf<NSReturnsRetainedAttr>(D, RetTy))
862    return ObjCAllocRetE;
863
864  if (auto K = hasAnyEnabledAttrOf<CFReturnsRetainedAttr, OSReturnsRetainedAttr,
865                                   GeneralizedReturnsRetainedAttr>(D, RetTy))
866    return RetEffect::MakeOwned(*K);
867
868  if (auto K = hasAnyEnabledAttrOf<
869          CFReturnsNotRetainedAttr, OSReturnsNotRetainedAttr,
870          GeneralizedReturnsNotRetainedAttr, NSReturnsNotRetainedAttr,
871          NSReturnsAutoreleasedAttr>(D, RetTy))
872    return RetEffect::MakeNotOwned(*K);
873
874  if (const auto *MD = dyn_cast<CXXMethodDecl>(D))
875    for (const auto *PD : MD->overridden_methods())
876      if (auto RE = getRetEffectFromAnnotations(RetTy, PD))
877        return RE;
878
879  return None;
880}
881
882/// \return Whether the chain of typedefs starting from {@code QT}
883/// has a typedef with a given name {@code Name}.
884static bool hasTypedefNamed(QualType QT,
885                            StringRef Name) {
886  while (auto *T = dyn_cast<TypedefType>(QT)) {
887    const auto &Context = T->getDecl()->getASTContext();
888    if (T->getDecl()->getIdentifier() == &Context.Idents.get(Name))
889      return true;
890    QT = T->getDecl()->getUnderlyingType();
891  }
892  return false;
893}
894
895static QualType getCallableReturnType(const NamedDecl *ND) {
896  if (const auto *FD = dyn_cast<FunctionDecl>(ND)) {
897    return FD->getReturnType();
898  } else if (const auto *MD = dyn_cast<ObjCMethodDecl>(ND)) {
899    return MD->getReturnType();
900  } else {
901    llvm_unreachable("Unexpected decl");
902  }
903}
904
905bool RetainSummaryManager::applyParamAnnotationEffect(
906    const ParmVarDecl *pd, unsigned parm_idx, const NamedDecl *FD,
907    RetainSummaryTemplate &Template) {
908  QualType QT = pd->getType();
909  if (auto K =
910          hasAnyEnabledAttrOf<NSConsumedAttr, CFConsumedAttr, OSConsumedAttr,
911                              GeneralizedConsumedAttr>(pd, QT)) {
912    Template->addArg(AF, parm_idx, ArgEffect(DecRef, *K));
913    return true;
914  } else if (auto K = hasAnyEnabledAttrOf<
915                 CFReturnsRetainedAttr, OSReturnsRetainedAttr,
916                 OSReturnsRetainedOnNonZeroAttr, OSReturnsRetainedOnZeroAttr,
917                 GeneralizedReturnsRetainedAttr>(pd, QT)) {
918
919    // For OSObjects, we try to guess whether the object is created based
920    // on the return value.
921    if (K == ObjKind::OS) {
922      QualType QT = getCallableReturnType(FD);
923
924      bool HasRetainedOnZero = pd->hasAttr<OSReturnsRetainedOnZeroAttr>();
925      bool HasRetainedOnNonZero = pd->hasAttr<OSReturnsRetainedOnNonZeroAttr>();
926
927      // The usual convention is to create an object on non-zero return, but
928      // it's reverted if the typedef chain has a typedef kern_return_t,
929      // because kReturnSuccess constant is defined as zero.
930      // The convention can be overwritten by custom attributes.
931      bool SuccessOnZero =
932          HasRetainedOnZero ||
933          (hasTypedefNamed(QT, "kern_return_t") && !HasRetainedOnNonZero);
934      bool ShouldSplit = !QT.isNull() && !QT->isVoidType();
935      ArgEffectKind AK = RetainedOutParameter;
936      if (ShouldSplit && SuccessOnZero) {
937        AK = RetainedOutParameterOnZero;
938      } else if (ShouldSplit && (!SuccessOnZero || HasRetainedOnNonZero)) {
939        AK = RetainedOutParameterOnNonZero;
940      }
941      Template->addArg(AF, parm_idx, ArgEffect(AK, ObjKind::OS));
942    }
943
944    // For others:
945    // Do nothing. Retained out parameters will either point to a +1 reference
946    // or NULL, but the way you check for failure differs depending on the
947    // API. Consequently, we don't have a good way to track them yet.
948    return true;
949  } else if (auto K = hasAnyEnabledAttrOf<CFReturnsNotRetainedAttr,
950                                          OSReturnsNotRetainedAttr,
951                                          GeneralizedReturnsNotRetainedAttr>(
952                 pd, QT)) {
953    Template->addArg(AF, parm_idx, ArgEffect(UnretainedOutParameter, *K));
954    return true;
955  }
956
957  if (const auto *MD = dyn_cast<CXXMethodDecl>(FD)) {
958    for (const auto *OD : MD->overridden_methods()) {
959      const ParmVarDecl *OP = OD->parameters()[parm_idx];
960      if (applyParamAnnotationEffect(OP, parm_idx, OD, Template))
961        return true;
962    }
963  }
964
965  return false;
966}
967
968void
969RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ,
970                                                   const FunctionDecl *FD) {
971  if (!FD)
972    return;
973
974  assert(Summ && "Must have a summary to add annotations to.");
975  RetainSummaryTemplate Template(Summ, *this);
976
977  // Effects on the parameters.
978  unsigned parm_idx = 0;
979  for (auto pi = FD->param_begin(),
980         pe = FD->param_end(); pi != pe; ++pi, ++parm_idx)
981    applyParamAnnotationEffect(*pi, parm_idx, FD, Template);
982
983  QualType RetTy = FD->getReturnType();
984  if (Optional<RetEffect> RetE = getRetEffectFromAnnotations(RetTy, FD))
985    Template->setRetEffect(*RetE);
986
987  if (hasAnyEnabledAttrOf<OSConsumesThisAttr>(FD, RetTy))
988    Template->setThisEffect(ArgEffect(DecRef, ObjKind::OS));
989}
990
991void
992RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ,
993                                                   const ObjCMethodDecl *MD) {
994  if (!MD)
995    return;
996
997  assert(Summ && "Must have a valid summary to add annotations to");
998  RetainSummaryTemplate Template(Summ, *this);
999
1000  // Effects on the receiver.
1001  if (hasAnyEnabledAttrOf<NSConsumesSelfAttr>(MD, MD->getReturnType()))
1002    Template->setReceiverEffect(ArgEffect(DecRef, ObjKind::ObjC));
1003
1004  // Effects on the parameters.
1005  unsigned parm_idx = 0;
1006  for (auto pi = MD->param_begin(), pe = MD->param_end(); pi != pe;
1007       ++pi, ++parm_idx)
1008    applyParamAnnotationEffect(*pi, parm_idx, MD, Template);
1009
1010  QualType RetTy = MD->getReturnType();
1011  if (Optional<RetEffect> RetE = getRetEffectFromAnnotations(RetTy, MD))
1012    Template->setRetEffect(*RetE);
1013}
1014
1015const RetainSummary *
1016RetainSummaryManager::getStandardMethodSummary(const ObjCMethodDecl *MD,
1017                                               Selector S, QualType RetTy) {
1018  // Any special effects?
1019  ArgEffect ReceiverEff = ArgEffect(DoNothing, ObjKind::ObjC);
1020  RetEffect ResultEff = RetEffect::MakeNoRet();
1021
1022  // Check the method family, and apply any default annotations.
1023  switch (MD ? MD->getMethodFamily() : S.getMethodFamily()) {
1024    case OMF_None:
1025    case OMF_initialize:
1026    case OMF_performSelector:
1027      // Assume all Objective-C methods follow Cocoa Memory Management rules.
1028      // FIXME: Does the non-threaded performSelector family really belong here?
1029      // The selector could be, say, @selector(copy).
1030      if (cocoa::isCocoaObjectRef(RetTy))
1031        ResultEff = RetEffect::MakeNotOwned(ObjKind::ObjC);
1032      else if (coreFoundation::isCFObjectRef(RetTy)) {
1033        // ObjCMethodDecl currently doesn't consider CF objects as valid return
1034        // values for alloc, new, copy, or mutableCopy, so we have to
1035        // double-check with the selector. This is ugly, but there aren't that
1036        // many Objective-C methods that return CF objects, right?
1037        if (MD) {
1038          switch (S.getMethodFamily()) {
1039          case OMF_alloc:
1040          case OMF_new:
1041          case OMF_copy:
1042          case OMF_mutableCopy:
1043            ResultEff = RetEffect::MakeOwned(ObjKind::CF);
1044            break;
1045          default:
1046            ResultEff = RetEffect::MakeNotOwned(ObjKind::CF);
1047            break;
1048          }
1049        } else {
1050          ResultEff = RetEffect::MakeNotOwned(ObjKind::CF);
1051        }
1052      }
1053      break;
1054    case OMF_init:
1055      ResultEff = ObjCInitRetE;
1056      ReceiverEff = ArgEffect(DecRef, ObjKind::ObjC);
1057      break;
1058    case OMF_alloc:
1059    case OMF_new:
1060    case OMF_copy:
1061    case OMF_mutableCopy:
1062      if (cocoa::isCocoaObjectRef(RetTy))
1063        ResultEff = ObjCAllocRetE;
1064      else if (coreFoundation::isCFObjectRef(RetTy))
1065        ResultEff = RetEffect::MakeOwned(ObjKind::CF);
1066      break;
1067    case OMF_autorelease:
1068      ReceiverEff = ArgEffect(Autorelease, ObjKind::ObjC);
1069      break;
1070    case OMF_retain:
1071      ReceiverEff = ArgEffect(IncRef, ObjKind::ObjC);
1072      break;
1073    case OMF_release:
1074      ReceiverEff = ArgEffect(DecRef, ObjKind::ObjC);
1075      break;
1076    case OMF_dealloc:
1077      ReceiverEff = ArgEffect(Dealloc, ObjKind::ObjC);
1078      break;
1079    case OMF_self:
1080      // -self is handled specially by the ExprEngine to propagate the receiver.
1081      break;
1082    case OMF_retainCount:
1083    case OMF_finalize:
1084      // These methods don't return objects.
1085      break;
1086  }
1087
1088  // If one of the arguments in the selector has the keyword 'delegate' we
1089  // should stop tracking the reference count for the receiver.  This is
1090  // because the reference count is quite possibly handled by a delegate
1091  // method.
1092  if (S.isKeywordSelector()) {
1093    for (unsigned i = 0, e = S.getNumArgs(); i != e; ++i) {
1094      StringRef Slot = S.getNameForSlot(i);
1095      if (Slot.substr(Slot.size() - 8).equals_lower("delegate")) {
1096        if (ResultEff == ObjCInitRetE)
1097          ResultEff = RetEffect::MakeNoRetHard();
1098        else
1099          ReceiverEff = ArgEffect(StopTrackingHard, ObjKind::ObjC);
1100      }
1101    }
1102  }
1103
1104  if (ReceiverEff.getKind() == DoNothing &&
1105      ResultEff.getKind() == RetEffect::NoRet)
1106    return getDefaultSummary();
1107
1108  return getPersistentSummary(ResultEff, ArgEffects(AF.getEmptyMap()),
1109                              ArgEffect(ReceiverEff), ArgEffect(MayEscape));
1110}
1111
1112const RetainSummary *
1113RetainSummaryManager::getClassMethodSummary(const ObjCMessageExpr *ME) {
1114  assert(!ME->isInstanceMessage());
1115  const ObjCInterfaceDecl *Class = ME->getReceiverInterface();
1116
1117  return getMethodSummary(ME->getSelector(), Class, ME->getMethodDecl(),
1118                          ME->getType(), ObjCClassMethodSummaries);
1119}
1120
1121const RetainSummary *RetainSummaryManager::getInstanceMethodSummary(
1122    const ObjCMessageExpr *ME,
1123    QualType ReceiverType) {
1124  const ObjCInterfaceDecl *ReceiverClass = nullptr;
1125
1126  // We do better tracking of the type of the object than the core ExprEngine.
1127  // See if we have its type in our private state.
1128  if (!ReceiverType.isNull())
1129    if (const auto *PT = ReceiverType->getAs<ObjCObjectPointerType>())
1130      ReceiverClass = PT->getInterfaceDecl();
1131
1132  // If we don't know what kind of object this is, fall back to its static type.
1133  if (!ReceiverClass)
1134    ReceiverClass = ME->getReceiverInterface();
1135
1136  // FIXME: The receiver could be a reference to a class, meaning that
1137  //  we should use the class method.
1138  // id x = [NSObject class];
1139  // [x performSelector:... withObject:... afterDelay:...];
1140  Selector S = ME->getSelector();
1141  const ObjCMethodDecl *Method = ME->getMethodDecl();
1142  if (!Method && ReceiverClass)
1143    Method = ReceiverClass->getInstanceMethod(S);
1144
1145  return getMethodSummary(S, ReceiverClass, Method, ME->getType(),
1146                          ObjCMethodSummaries);
1147}
1148
1149const RetainSummary *
1150RetainSummaryManager::getMethodSummary(Selector S,
1151                                       const ObjCInterfaceDecl *ID,
1152                                       const ObjCMethodDecl *MD, QualType RetTy,
1153                                       ObjCMethodSummariesTy &CachedSummaries) {
1154
1155  // Objective-C method summaries are only applicable to ObjC and CF objects.
1156  if (!TrackObjCAndCFObjects)
1157    return getDefaultSummary();
1158
1159  // Look up a summary in our summary cache.
1160  const RetainSummary *Summ = CachedSummaries.find(ID, S);
1161
1162  if (!Summ) {
1163    Summ = getStandardMethodSummary(MD, S, RetTy);
1164
1165    // Annotations override defaults.
1166    updateSummaryFromAnnotations(Summ, MD);
1167
1168    // Memoize the summary.
1169    CachedSummaries[ObjCSummaryKey(ID, S)] = Summ;
1170  }
1171
1172  return Summ;
1173}
1174
1175void RetainSummaryManager::InitializeClassMethodSummaries() {
1176  ArgEffects ScratchArgs = AF.getEmptyMap();
1177
1178  // Create the [NSAssertionHandler currentHander] summary.
1179  addClassMethSummary("NSAssertionHandler", "currentHandler",
1180                getPersistentSummary(RetEffect::MakeNotOwned(ObjKind::ObjC),
1181                                     ScratchArgs));
1182
1183  // Create the [NSAutoreleasePool addObject:] summary.
1184  ScratchArgs = AF.add(ScratchArgs, 0, ArgEffect(Autorelease));
1185  addClassMethSummary("NSAutoreleasePool", "addObject",
1186                      getPersistentSummary(RetEffect::MakeNoRet(), ScratchArgs,
1187                                           ArgEffect(DoNothing),
1188                                           ArgEffect(Autorelease)));
1189}
1190
1191void RetainSummaryManager::InitializeMethodSummaries() {
1192
1193  ArgEffects ScratchArgs = AF.getEmptyMap();
1194  // Create the "init" selector.  It just acts as a pass-through for the
1195  // receiver.
1196  const RetainSummary *InitSumm = getPersistentSummary(
1197      ObjCInitRetE, ScratchArgs, ArgEffect(DecRef, ObjKind::ObjC));
1198  addNSObjectMethSummary(GetNullarySelector("init", Ctx), InitSumm);
1199
1200  // awakeAfterUsingCoder: behaves basically like an 'init' method.  It
1201  // claims the receiver and returns a retained object.
1202  addNSObjectMethSummary(GetUnarySelector("awakeAfterUsingCoder", Ctx),
1203                         InitSumm);
1204
1205  // The next methods are allocators.
1206  const RetainSummary *AllocSumm = getPersistentSummary(ObjCAllocRetE,
1207                                                        ScratchArgs);
1208  const RetainSummary *CFAllocSumm =
1209    getPersistentSummary(RetEffect::MakeOwned(ObjKind::CF), ScratchArgs);
1210
1211  // Create the "retain" selector.
1212  RetEffect NoRet = RetEffect::MakeNoRet();
1213  const RetainSummary *Summ = getPersistentSummary(
1214      NoRet, ScratchArgs, ArgEffect(IncRef, ObjKind::ObjC));
1215  addNSObjectMethSummary(GetNullarySelector("retain", Ctx), Summ);
1216
1217  // Create the "release" selector.
1218  Summ = getPersistentSummary(NoRet, ScratchArgs,
1219                              ArgEffect(DecRef, ObjKind::ObjC));
1220  addNSObjectMethSummary(GetNullarySelector("release", Ctx), Summ);
1221
1222  // Create the -dealloc summary.
1223  Summ = getPersistentSummary(NoRet, ScratchArgs, ArgEffect(Dealloc,
1224                                                            ObjKind::ObjC));
1225  addNSObjectMethSummary(GetNullarySelector("dealloc", Ctx), Summ);
1226
1227  // Create the "autorelease" selector.
1228  Summ = getPersistentSummary(NoRet, ScratchArgs, ArgEffect(Autorelease,
1229                                                            ObjKind::ObjC));
1230  addNSObjectMethSummary(GetNullarySelector("autorelease", Ctx), Summ);
1231
1232  // For NSWindow, allocated objects are (initially) self-owned.
1233  // FIXME: For now we opt for false negatives with NSWindow, as these objects
1234  //  self-own themselves.  However, they only do this once they are displayed.
1235  //  Thus, we need to track an NSWindow's display status.
1236  //  This is tracked in <rdar://problem/6062711>.
1237  //  See also http://llvm.org/bugs/show_bug.cgi?id=3714.
1238  const RetainSummary *NoTrackYet =
1239      getPersistentSummary(RetEffect::MakeNoRet(), ScratchArgs,
1240                           ArgEffect(StopTracking), ArgEffect(StopTracking));
1241
1242  addClassMethSummary("NSWindow", "alloc", NoTrackYet);
1243
1244  // For NSPanel (which subclasses NSWindow), allocated objects are not
1245  //  self-owned.
1246  // FIXME: For now we don't track NSPanels. object for the same reason
1247  //   as for NSWindow objects.
1248  addClassMethSummary("NSPanel", "alloc", NoTrackYet);
1249
1250  // For NSNull, objects returned by +null are singletons that ignore
1251  // retain/release semantics.  Just don't track them.
1252  // <rdar://problem/12858915>
1253  addClassMethSummary("NSNull", "null", NoTrackYet);
1254
1255  // Don't track allocated autorelease pools, as it is okay to prematurely
1256  // exit a method.
1257  addClassMethSummary("NSAutoreleasePool", "alloc", NoTrackYet);
1258  addClassMethSummary("NSAutoreleasePool", "allocWithZone", NoTrackYet, false);
1259  addClassMethSummary("NSAutoreleasePool", "new", NoTrackYet);
1260
1261  // Create summaries QCRenderer/QCView -createSnapShotImageOfType:
1262  addInstMethSummary("QCRenderer", AllocSumm, "createSnapshotImageOfType");
1263  addInstMethSummary("QCView", AllocSumm, "createSnapshotImageOfType");
1264
1265  // Create summaries for CIContext, 'createCGImage' and
1266  // 'createCGLayerWithSize'.  These objects are CF objects, and are not
1267  // automatically garbage collected.
1268  addInstMethSummary("CIContext", CFAllocSumm, "createCGImage", "fromRect");
1269  addInstMethSummary("CIContext", CFAllocSumm, "createCGImage", "fromRect",
1270                     "format", "colorSpace");
1271  addInstMethSummary("CIContext", CFAllocSumm, "createCGLayerWithSize", "info");
1272}
1273
1274const RetainSummary *
1275RetainSummaryManager::getMethodSummary(const ObjCMethodDecl *MD) {
1276  const ObjCInterfaceDecl *ID = MD->getClassInterface();
1277  Selector S = MD->getSelector();
1278  QualType ResultTy = MD->getReturnType();
1279
1280  ObjCMethodSummariesTy *CachedSummaries;
1281  if (MD->isInstanceMethod())
1282    CachedSummaries = &ObjCMethodSummaries;
1283  else
1284    CachedSummaries = &ObjCClassMethodSummaries;
1285
1286  return getMethodSummary(S, ID, MD, ResultTy, *CachedSummaries);
1287}
1288