1//=== RetainSummaryManager.h - 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 and Cocoa
11//  on (Mac OS X).
12//
13//===----------------------------------------------------------------------===//
14
15#ifndef LLVM_CLANG_ANALYSIS_RETAINSUMMARYMANAGER_H
16#define LLVM_CLANG_ANALYSIS_RETAINSUMMARYMANAGER_H
17
18#include "llvm/ADT/DenseMap.h"
19#include "llvm/ADT/FoldingSet.h"
20#include "llvm/ADT/ImmutableMap.h"
21#include "clang/AST/Attr.h"
22#include "clang/AST/DeclCXX.h"
23#include "clang/AST/DeclObjC.h"
24#include "clang/AST/ParentMap.h"
25#include "clang/Analysis/AnyCall.h"
26#include "clang/Analysis/SelectorExtras.h"
27#include "llvm/ADT/STLExtras.h"
28#include <optional>
29
30using namespace clang;
31
32namespace clang {
33namespace ento {
34
35/// Determines the object kind of a tracked object.
36enum class ObjKind {
37  /// Indicates that the tracked object is a CF object.
38  CF,
39
40  /// Indicates that the tracked object is an Objective-C object.
41  ObjC,
42
43  /// Indicates that the tracked object could be a CF or Objective-C object.
44  AnyObj,
45
46  /// Indicates that the tracked object is a generalized object.
47  Generalized,
48
49  /// Indicates that the tracking object is a descendant of a
50  /// referenced-counted OSObject, used in the Darwin kernel.
51  OS
52};
53
54enum ArgEffectKind {
55  /// There is no effect.
56  DoNothing,
57
58  /// The argument is treated as if an -autorelease message had been sent to
59  /// the referenced object.
60  Autorelease,
61
62  /// The argument is treated as if the referenced object was deallocated.
63  Dealloc,
64
65  /// The argument has its reference count decreased by 1.
66  DecRef,
67
68  /// The argument has its reference count decreased by 1 to model
69  /// a transferred bridge cast under ARC.
70  DecRefBridgedTransferred,
71
72  /// The argument has its reference count increased by 1.
73  IncRef,
74
75  /// The argument is a pointer to a retain-counted object; on exit, the new
76  /// value of the pointer is a +0 value.
77  UnretainedOutParameter,
78
79  /// The argument is a pointer to a retain-counted object; on exit, the new
80  /// value of the pointer is a +1 value.
81  RetainedOutParameter,
82
83  /// The argument is a pointer to a retain-counted object; on exit, the new
84  /// value of the pointer is a +1 value iff the return code is zero.
85  RetainedOutParameterOnZero,
86
87  /// The argument is a pointer to a retain-counted object; on exit, the new
88  /// value of the pointer is a +1 value iff the return code is non-zero.
89  RetainedOutParameterOnNonZero,
90
91  /// The argument is treated as potentially escaping, meaning that
92  /// even when its reference count hits 0 it should be treated as still
93  /// possibly being alive as someone else *may* be holding onto the object.
94  MayEscape,
95
96  /// All typestate tracking of the object ceases.  This is usually employed
97  /// when the effect of the call is completely unknown.
98  StopTracking,
99
100  /// All typestate tracking of the object ceases.  Unlike StopTracking,
101  /// this is also enforced when the method body is inlined.
102  ///
103  /// In some cases, we obtain a better summary for this checker
104  /// by looking at the call site than by inlining the function.
105  /// Signifies that we should stop tracking the symbol even if
106  /// the function is inlined.
107  StopTrackingHard,
108
109  /// Performs the combined functionality of DecRef and StopTrackingHard.
110  ///
111  /// The models the effect that the called function decrements the reference
112  /// count of the argument and all typestate tracking on that argument
113  /// should cease.
114  DecRefAndStopTrackingHard,
115};
116
117/// An ArgEffect summarizes the retain count behavior on an argument or receiver
118/// to a function or method.
119class ArgEffect {
120  ArgEffectKind K;
121  ObjKind O;
122public:
123  explicit ArgEffect(ArgEffectKind K = DoNothing, ObjKind O = ObjKind::AnyObj)
124      : K(K), O(O) {}
125
126  ArgEffectKind getKind() const { return K; }
127  ObjKind getObjKind() const { return O; }
128
129  ArgEffect withKind(ArgEffectKind NewK) {
130    return ArgEffect(NewK, O);
131  }
132
133  bool operator==(const ArgEffect &Other) const {
134    return K == Other.K && O == Other.O;
135  }
136};
137
138/// RetEffect summarizes a call's retain/release behavior with respect
139/// to its return value.
140class RetEffect {
141public:
142  enum Kind {
143    /// Indicates that no retain count information is tracked for
144    /// the return value.
145    NoRet,
146
147    /// Indicates that the returned value is an owned (+1) symbol.
148    OwnedSymbol,
149
150    /// Indicates that the returned value is an object with retain count
151    /// semantics but that it is not owned (+0).  This is the default
152    /// for getters, etc.
153    NotOwnedSymbol,
154
155    /// Indicates that the return value is an owned object when the
156    /// receiver is also a tracked object.
157    OwnedWhenTrackedReceiver,
158
159    // Treat this function as returning a non-tracked symbol even if
160    // the function has been inlined. This is used where the call
161    // site summary is more precise than the summary indirectly produced
162    // by inlining the function
163    NoRetHard
164  };
165
166private:
167  Kind K;
168  ObjKind O;
169
170  RetEffect(Kind k, ObjKind o = ObjKind::AnyObj) : K(k), O(o) {}
171
172public:
173  Kind getKind() const { return K; }
174
175  ObjKind getObjKind() const { return O; }
176
177  bool isOwned() const {
178    return K == OwnedSymbol || K == OwnedWhenTrackedReceiver;
179  }
180
181  bool notOwned() const {
182    return K == NotOwnedSymbol;
183  }
184
185  bool operator==(const RetEffect &Other) const {
186    return K == Other.K && O == Other.O;
187  }
188
189  static RetEffect MakeOwnedWhenTrackedReceiver() {
190    return RetEffect(OwnedWhenTrackedReceiver, ObjKind::ObjC);
191  }
192
193  static RetEffect MakeOwned(ObjKind o) {
194    return RetEffect(OwnedSymbol, o);
195  }
196  static RetEffect MakeNotOwned(ObjKind o) {
197    return RetEffect(NotOwnedSymbol, o);
198  }
199  static RetEffect MakeNoRet() {
200    return RetEffect(NoRet);
201  }
202  static RetEffect MakeNoRetHard() {
203    return RetEffect(NoRetHard);
204  }
205};
206
207/// A key identifying a summary.
208class ObjCSummaryKey {
209  IdentifierInfo* II;
210  Selector S;
211public:
212  ObjCSummaryKey(IdentifierInfo* ii, Selector s)
213    : II(ii), S(s) {}
214
215  ObjCSummaryKey(const ObjCInterfaceDecl *d, Selector s)
216    : II(d ? d->getIdentifier() : nullptr), S(s) {}
217
218  ObjCSummaryKey(Selector s)
219    : II(nullptr), S(s) {}
220
221  IdentifierInfo *getIdentifier() const { return II; }
222  Selector getSelector() const { return S; }
223};
224
225} // end namespace ento
226} // end namespace clang
227
228using namespace ento;
229
230namespace llvm {
231
232//===----------------------------------------------------------------------===//
233// Adapters for FoldingSet.
234//===----------------------------------------------------------------------===//
235template <> struct FoldingSetTrait<ArgEffect> {
236static inline void Profile(const ArgEffect X, FoldingSetNodeID &ID) {
237  ID.AddInteger((unsigned) X.getKind());
238  ID.AddInteger((unsigned) X.getObjKind());
239}
240};
241template <> struct FoldingSetTrait<RetEffect> {
242  static inline void Profile(const RetEffect &X, FoldingSetNodeID &ID) {
243    ID.AddInteger((unsigned) X.getKind());
244    ID.AddInteger((unsigned) X.getObjKind());
245}
246};
247
248template <> struct DenseMapInfo<ObjCSummaryKey> {
249  static inline ObjCSummaryKey getEmptyKey() {
250    return ObjCSummaryKey(DenseMapInfo<IdentifierInfo*>::getEmptyKey(),
251                          DenseMapInfo<Selector>::getEmptyKey());
252  }
253
254  static inline ObjCSummaryKey getTombstoneKey() {
255    return ObjCSummaryKey(DenseMapInfo<IdentifierInfo*>::getTombstoneKey(),
256                          DenseMapInfo<Selector>::getTombstoneKey());
257  }
258
259  static unsigned getHashValue(const ObjCSummaryKey &V) {
260    typedef std::pair<IdentifierInfo*, Selector> PairTy;
261    return DenseMapInfo<PairTy>::getHashValue(PairTy(V.getIdentifier(),
262                                                     V.getSelector()));
263  }
264
265  static bool isEqual(const ObjCSummaryKey& LHS, const ObjCSummaryKey& RHS) {
266    return LHS.getIdentifier() == RHS.getIdentifier() &&
267           LHS.getSelector() == RHS.getSelector();
268  }
269
270};
271
272} // end llvm namespace
273
274
275namespace clang {
276namespace ento {
277
278/// ArgEffects summarizes the effects of a function/method call on all of
279/// its arguments.
280typedef llvm::ImmutableMap<unsigned, ArgEffect> ArgEffects;
281
282/// Summary for a function with respect to ownership changes.
283class RetainSummary {
284  /// Args - a map of (index, ArgEffect) pairs, where index
285  ///  specifies the argument (starting from 0).  This can be sparsely
286  ///  populated; arguments with no entry in Args use 'DefaultArgEffect'.
287  ArgEffects Args;
288
289  /// DefaultArgEffect - The default ArgEffect to apply to arguments that
290  ///  do not have an entry in Args.
291  ArgEffect DefaultArgEffect;
292
293  /// Receiver - If this summary applies to an Objective-C message expression,
294  ///  this is the effect applied to the state of the receiver.
295  ArgEffect Receiver;
296
297  /// Effect on "this" pointer - applicable only to C++ method calls.
298  ArgEffect This;
299
300  /// Ret - The effect on the return value.  Used to indicate if the
301  ///  function/method call returns a new tracked symbol.
302  RetEffect Ret;
303
304public:
305  RetainSummary(ArgEffects A,
306                RetEffect R,
307                ArgEffect defaultEff,
308                ArgEffect ReceiverEff,
309                ArgEffect ThisEff)
310    : Args(A), DefaultArgEffect(defaultEff), Receiver(ReceiverEff),
311      This(ThisEff), Ret(R) {}
312
313  /// getArg - Return the argument effect on the argument specified by
314  ///  idx (starting from 0).
315  ArgEffect getArg(unsigned idx) const {
316    if (const ArgEffect *AE = Args.lookup(idx))
317      return *AE;
318
319    return DefaultArgEffect;
320  }
321
322  void addArg(ArgEffects::Factory &af, unsigned idx, ArgEffect e) {
323    Args = af.add(Args, idx, e);
324  }
325
326  /// setDefaultArgEffect - Set the default argument effect.
327  void setDefaultArgEffect(ArgEffect E) {
328    DefaultArgEffect = E;
329  }
330
331  /// getRetEffect - Returns the effect on the return value of the call.
332  RetEffect getRetEffect() const { return Ret; }
333
334  /// setRetEffect - Set the effect of the return value of the call.
335  void setRetEffect(RetEffect E) { Ret = E; }
336
337
338  /// Sets the effect on the receiver of the message.
339  void setReceiverEffect(ArgEffect e) { Receiver = e; }
340
341  /// getReceiverEffect - Returns the effect on the receiver of the call.
342  ///  This is only meaningful if the summary applies to an ObjCMessageExpr*.
343  ArgEffect getReceiverEffect() const { return Receiver; }
344
345  /// \return the effect on the "this" receiver of the method call.
346  /// This is only meaningful if the summary applies to CXXMethodDecl*.
347  ArgEffect getThisEffect() const { return This; }
348
349  ArgEffect getDefaultEffect() const { return DefaultArgEffect; }
350
351  /// Set the effect of the method on "this".
352  void setThisEffect(ArgEffect e) { This = e; }
353
354  bool isNoop() const {
355    return Ret == RetEffect::MakeNoRet() && Receiver.getKind() == DoNothing
356      && DefaultArgEffect.getKind() == MayEscape && This.getKind() == DoNothing
357      && Args.isEmpty();
358  }
359
360  /// Test if two retain summaries are identical. Note that merely equivalent
361  /// summaries are not necessarily identical (for example, if an explicit
362  /// argument effect matches the default effect).
363  bool operator==(const RetainSummary &Other) const {
364    return Args == Other.Args && DefaultArgEffect == Other.DefaultArgEffect &&
365           Receiver == Other.Receiver && This == Other.This && Ret == Other.Ret;
366  }
367
368  /// Profile this summary for inclusion in a FoldingSet.
369  void Profile(llvm::FoldingSetNodeID& ID) const {
370    ID.Add(Args);
371    ID.Add(DefaultArgEffect);
372    ID.Add(Receiver);
373    ID.Add(This);
374    ID.Add(Ret);
375  }
376
377  /// A retain summary is simple if it has no ArgEffects other than the default.
378  bool isSimple() const {
379    return Args.isEmpty();
380  }
381
382  ArgEffects getArgEffects() const { return Args; }
383
384private:
385  ArgEffect getDefaultArgEffect() const { return DefaultArgEffect; }
386
387  friend class RetainSummaryManager;
388};
389
390class ObjCSummaryCache {
391  typedef llvm::DenseMap<ObjCSummaryKey, const RetainSummary *> MapTy;
392  MapTy M;
393public:
394  ObjCSummaryCache() {}
395
396  const RetainSummary * find(const ObjCInterfaceDecl *D, Selector S) {
397    // Do a lookup with the (D,S) pair.  If we find a match return
398    // the iterator.
399    ObjCSummaryKey K(D, S);
400    MapTy::iterator I = M.find(K);
401
402    if (I != M.end())
403      return I->second;
404    if (!D)
405      return nullptr;
406
407    // Walk the super chain.  If we find a hit with a parent, we'll end
408    // up returning that summary.  We actually allow that key (null,S), as
409    // we cache summaries for the null ObjCInterfaceDecl* to allow us to
410    // generate initial summaries without having to worry about NSObject
411    // being declared.
412    // FIXME: We may change this at some point.
413    for (ObjCInterfaceDecl *C=D->getSuperClass() ;; C=C->getSuperClass()) {
414      if ((I = M.find(ObjCSummaryKey(C, S))) != M.end())
415        break;
416
417      if (!C)
418        return nullptr;
419    }
420
421    // Cache the summary with original key to make the next lookup faster
422    // and return the iterator.
423    const RetainSummary *Summ = I->second;
424    M[K] = Summ;
425    return Summ;
426  }
427
428  const RetainSummary *find(IdentifierInfo* II, Selector S) {
429    // FIXME: Class method lookup.  Right now we don't have a good way
430    // of going between IdentifierInfo* and the class hierarchy.
431    MapTy::iterator I = M.find(ObjCSummaryKey(II, S));
432
433    if (I == M.end())
434      I = M.find(ObjCSummaryKey(S));
435
436    return I == M.end() ? nullptr : I->second;
437  }
438
439  const RetainSummary *& operator[](ObjCSummaryKey K) {
440    return M[K];
441  }
442
443  const RetainSummary *& operator[](Selector S) {
444    return M[ ObjCSummaryKey(S) ];
445  }
446};
447
448class RetainSummaryTemplate;
449
450class RetainSummaryManager {
451  typedef llvm::DenseMap<const FunctionDecl*, const RetainSummary *>
452          FuncSummariesTy;
453
454  typedef ObjCSummaryCache ObjCMethodSummariesTy;
455
456  typedef llvm::FoldingSetNodeWrapper<RetainSummary> CachedSummaryNode;
457
458  /// Ctx - The ASTContext object for the analyzed ASTs.
459  ASTContext &Ctx;
460
461  /// Records whether or not the analyzed code runs in ARC mode.
462  const bool ARCEnabled;
463
464  /// Track Objective-C and CoreFoundation objects.
465  const bool TrackObjCAndCFObjects;
466
467  /// Track sublcasses of OSObject.
468  const bool TrackOSObjects;
469
470  /// FuncSummaries - A map from FunctionDecls to summaries.
471  FuncSummariesTy FuncSummaries;
472
473  /// ObjCClassMethodSummaries - A map from selectors (for instance methods)
474  ///  to summaries.
475  ObjCMethodSummariesTy ObjCClassMethodSummaries;
476
477  /// ObjCMethodSummaries - A map from selectors to summaries.
478  ObjCMethodSummariesTy ObjCMethodSummaries;
479
480  /// BPAlloc - A BumpPtrAllocator used for allocating summaries, ArgEffects,
481  ///  and all other data used by the checker.
482  llvm::BumpPtrAllocator BPAlloc;
483
484  /// AF - A factory for ArgEffects objects.
485  ArgEffects::Factory AF;
486
487  /// ObjCAllocRetE - Default return effect for methods returning Objective-C
488  ///  objects.
489  RetEffect ObjCAllocRetE;
490
491  /// ObjCInitRetE - Default return effect for init methods returning
492  ///   Objective-C objects.
493  RetEffect ObjCInitRetE;
494
495  /// SimpleSummaries - Used for uniquing summaries that don't have special
496  /// effects.
497  llvm::FoldingSet<CachedSummaryNode> SimpleSummaries;
498
499  /// Create an OS object at +1.
500  const RetainSummary *getOSSummaryCreateRule(const FunctionDecl *FD);
501
502  /// Get an OS object at +0.
503  const RetainSummary *getOSSummaryGetRule(const FunctionDecl *FD);
504
505  /// Increment the reference count on OS object.
506  const RetainSummary *getOSSummaryRetainRule(const FunctionDecl *FD);
507
508  /// Decrement the reference count on OS object.
509  const RetainSummary *getOSSummaryReleaseRule(const FunctionDecl *FD);
510
511  /// Free the OS object.
512  const RetainSummary *getOSSummaryFreeRule(const FunctionDecl *FD);
513
514  const RetainSummary *getUnarySummary(const FunctionType* FT,
515                                       ArgEffectKind AE);
516
517  const RetainSummary *getCFSummaryCreateRule(const FunctionDecl *FD);
518  const RetainSummary *getCFSummaryGetRule(const FunctionDecl *FD);
519  const RetainSummary *getCFCreateGetRuleSummary(const FunctionDecl *FD);
520
521  const RetainSummary *getPersistentSummary(const RetainSummary &OldSumm);
522
523  const RetainSummary *
524  getPersistentSummary(RetEffect RetEff, ArgEffects ScratchArgs,
525                       ArgEffect ReceiverEff = ArgEffect(DoNothing),
526                       ArgEffect DefaultEff = ArgEffect(MayEscape),
527                       ArgEffect ThisEff = ArgEffect(DoNothing)) {
528    RetainSummary Summ(ScratchArgs, RetEff, DefaultEff, ReceiverEff, ThisEff);
529    return getPersistentSummary(Summ);
530  }
531
532  const RetainSummary *getDoNothingSummary() {
533    return getPersistentSummary(RetEffect::MakeNoRet(),
534                                ArgEffects(AF.getEmptyMap()),
535                                ArgEffect(DoNothing), ArgEffect(DoNothing));
536  }
537
538  const RetainSummary *getDefaultSummary() {
539    return getPersistentSummary(RetEffect::MakeNoRet(),
540                                ArgEffects(AF.getEmptyMap()),
541                                ArgEffect(DoNothing), ArgEffect(MayEscape));
542  }
543
544  const RetainSummary *getPersistentStopSummary() {
545    return getPersistentSummary(
546        RetEffect::MakeNoRet(), ArgEffects(AF.getEmptyMap()),
547        ArgEffect(StopTracking), ArgEffect(StopTracking));
548  }
549
550  void InitializeClassMethodSummaries();
551  void InitializeMethodSummaries();
552
553  void addNSObjectClsMethSummary(Selector S, const RetainSummary *Summ) {
554    ObjCClassMethodSummaries[S] = Summ;
555  }
556
557  void addNSObjectMethSummary(Selector S, const RetainSummary *Summ) {
558    ObjCMethodSummaries[S] = Summ;
559  }
560
561  void addClassMethSummary(const char* Cls, const char* name,
562                           const RetainSummary *Summ, bool isNullary = true) {
563    IdentifierInfo* ClsII = &Ctx.Idents.get(Cls);
564    Selector S = isNullary ? GetNullarySelector(name, Ctx)
565                           : GetUnarySelector(name, Ctx);
566    ObjCClassMethodSummaries[ObjCSummaryKey(ClsII, S)]  = Summ;
567  }
568
569  void addInstMethSummary(const char* Cls, const char* nullaryName,
570                          const RetainSummary *Summ) {
571    IdentifierInfo* ClsII = &Ctx.Idents.get(Cls);
572    Selector S = GetNullarySelector(nullaryName, Ctx);
573    ObjCMethodSummaries[ObjCSummaryKey(ClsII, S)]  = Summ;
574  }
575
576  template <typename... Keywords>
577  void addMethodSummary(IdentifierInfo *ClsII, ObjCMethodSummariesTy &Summaries,
578                        const RetainSummary *Summ, Keywords *... Kws) {
579    Selector S = getKeywordSelector(Ctx, Kws...);
580    Summaries[ObjCSummaryKey(ClsII, S)] = Summ;
581  }
582
583  template <typename... Keywords>
584  void addInstMethSummary(const char *Cls, const RetainSummary *Summ,
585                          Keywords *... Kws) {
586    addMethodSummary(&Ctx.Idents.get(Cls), ObjCMethodSummaries, Summ, Kws...);
587  }
588
589  template <typename... Keywords>
590  void addClsMethSummary(const char *Cls, const RetainSummary *Summ,
591                         Keywords *... Kws) {
592    addMethodSummary(&Ctx.Idents.get(Cls), ObjCClassMethodSummaries, Summ,
593                     Kws...);
594  }
595
596  template <typename... Keywords>
597  void addClsMethSummary(IdentifierInfo *II, const RetainSummary *Summ,
598                         Keywords *... Kws) {
599    addMethodSummary(II, ObjCClassMethodSummaries, Summ, Kws...);
600  }
601
602  const RetainSummary * generateSummary(const FunctionDecl *FD,
603                                        bool &AllowAnnotations);
604
605  /// Return a summary for OSObject, or nullptr if not found.
606  const RetainSummary *getSummaryForOSObject(const FunctionDecl *FD,
607                                             StringRef FName, QualType RetTy);
608
609  /// Return a summary for Objective-C or CF object, or nullptr if not found.
610  const RetainSummary *getSummaryForObjCOrCFObject(
611    const FunctionDecl *FD,
612    StringRef FName,
613    QualType RetTy,
614    const FunctionType *FT,
615    bool &AllowAnnotations);
616
617  /// Apply the annotation of @c pd in function @c FD
618  /// to the resulting summary stored in out-parameter @c Template.
619  /// \return whether an annotation was applied.
620  bool applyParamAnnotationEffect(const ParmVarDecl *pd, unsigned parm_idx,
621                                  const NamedDecl *FD,
622                                  RetainSummaryTemplate &Template);
623
624public:
625  RetainSummaryManager(ASTContext &ctx, bool trackObjCAndCFObjects,
626                       bool trackOSObjects)
627      : Ctx(ctx), ARCEnabled((bool)Ctx.getLangOpts().ObjCAutoRefCount),
628        TrackObjCAndCFObjects(trackObjCAndCFObjects),
629        TrackOSObjects(trackOSObjects), AF(BPAlloc),
630        ObjCAllocRetE(ARCEnabled ? RetEffect::MakeNotOwned(ObjKind::ObjC)
631                                 : RetEffect::MakeOwned(ObjKind::ObjC)),
632        ObjCInitRetE(ARCEnabled ? RetEffect::MakeNotOwned(ObjKind::ObjC)
633                                : RetEffect::MakeOwnedWhenTrackedReceiver()) {
634    InitializeClassMethodSummaries();
635    InitializeMethodSummaries();
636  }
637
638  enum class BehaviorSummary {
639    // Function does not return.
640    NoOp,
641
642    // Function returns the first argument.
643    Identity,
644
645    // Function returns "this" argument.
646    IdentityThis,
647
648    // Function either returns zero, or the input parameter.
649    IdentityOrZero
650  };
651
652  std::optional<BehaviorSummary>
653  canEval(const CallExpr *CE, const FunctionDecl *FD,
654          bool &hasTrustedImplementationAnnotation);
655
656  /// \return Whether the type corresponds to a known smart pointer
657  /// implementation (that is, everything about it is inlineable).
658  static bool isKnownSmartPointer(QualType QT);
659
660  bool isTrustedReferenceCountImplementation(const Decl *FD);
661
662  const RetainSummary *getSummary(AnyCall C,
663                                  bool HasNonZeroCallbackArg=false,
664                                  bool IsReceiverUnconsumedSelf=false,
665                                  QualType ReceiverType={});
666
667  RetEffect getObjAllocRetEffect() const { return ObjCAllocRetE; }
668
669private:
670
671  /// getMethodSummary - This version of getMethodSummary is used to query
672  ///  the summary for the current method being analyzed.
673  const RetainSummary *getMethodSummary(const ObjCMethodDecl *MD);
674
675  const RetainSummary *getFunctionSummary(const FunctionDecl *FD);
676
677  const RetainSummary *getMethodSummary(Selector S, const ObjCInterfaceDecl *ID,
678                                        const ObjCMethodDecl *MD,
679                                        QualType RetTy,
680                                        ObjCMethodSummariesTy &CachedSummaries);
681
682  const RetainSummary *
683  getInstanceMethodSummary(const ObjCMessageExpr *ME, QualType ReceiverType);
684
685  const RetainSummary *getClassMethodSummary(const ObjCMessageExpr *ME);
686
687  const RetainSummary *getStandardMethodSummary(const ObjCMethodDecl *MD,
688                                                Selector S, QualType RetTy);
689
690  /// Determine if there is a special return effect for this function or method.
691  std::optional<RetEffect> getRetEffectFromAnnotations(QualType RetTy,
692                                                       const Decl *D);
693
694  void updateSummaryFromAnnotations(const RetainSummary *&Summ,
695                                    const ObjCMethodDecl *MD);
696
697  void updateSummaryFromAnnotations(const RetainSummary *&Summ,
698                                    const FunctionDecl *FD);
699
700  const RetainSummary *updateSummaryForNonZeroCallbackArg(const RetainSummary *S,
701                                                          AnyCall &C);
702
703  /// Special case '[super init];' and '[self init];'
704  ///
705  /// Even though calling '[super init]' without assigning the result to self
706  /// and checking if the parent returns 'nil' is a bad pattern, it is common.
707  /// Additionally, our Self Init checker already warns about it. To avoid
708  /// overwhelming the user with messages from both checkers, we model the case
709  /// of '[super init]' in cases when it is not consumed by another expression
710  /// as if the call preserves the value of 'self'; essentially, assuming it can
711  /// never fail and return 'nil'.
712  /// Note, we don't want to just stop tracking the value since we want the
713  /// RetainCount checker to report leaks and use-after-free if SelfInit checker
714  /// is turned off.
715  void updateSummaryForReceiverUnconsumedSelf(const RetainSummary *&S);
716
717  /// Set argument types for arguments which are not doing anything.
718  void updateSummaryForArgumentTypes(const AnyCall &C, const RetainSummary *&RS);
719
720  /// Determine whether a declaration @c D of correspondent type (return
721  /// type for functions/methods) @c QT has any of the given attributes,
722  /// provided they pass necessary validation checks AND tracking the given
723  /// attribute is enabled.
724  /// Returns the object kind corresponding to the present attribute, or
725  /// std::nullopt, if none of the specified attributes are present.
726  /// Crashes if passed an attribute which is not explicitly handled.
727  template <class T>
728  std::optional<ObjKind> hasAnyEnabledAttrOf(const Decl *D, QualType QT);
729
730  template <class T1, class T2, class... Others>
731  std::optional<ObjKind> hasAnyEnabledAttrOf(const Decl *D, QualType QT);
732
733  friend class RetainSummaryTemplate;
734};
735
736
737// Used to avoid allocating long-term (BPAlloc'd) memory for default retain
738// summaries. If a function or method looks like it has a default summary, but
739// it has annotations, the annotations are added to the stack-based template
740// and then copied into managed memory.
741class RetainSummaryTemplate {
742  RetainSummaryManager &Manager;
743  const RetainSummary *&RealSummary;
744  RetainSummary ScratchSummary;
745  bool Accessed;
746public:
747  RetainSummaryTemplate(const RetainSummary *&real, RetainSummaryManager &mgr)
748    : Manager(mgr), RealSummary(real), ScratchSummary(*real), Accessed(false) {}
749
750  ~RetainSummaryTemplate() {
751    if (Accessed)
752      RealSummary = Manager.getPersistentSummary(ScratchSummary);
753  }
754
755  RetainSummary &operator*() {
756    Accessed = true;
757    return ScratchSummary;
758  }
759
760  RetainSummary *operator->() {
761    Accessed = true;
762    return &ScratchSummary;
763  }
764};
765
766} // end namespace ento
767} // end namespace clang
768
769#endif
770