Home | History | Annotate | Line # | Download | only in RetainCountChecker
      1 //==--- RetainCountChecker.h - Checks for leaks and other issues -*- 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 the methods for RetainCountChecker, which implements
     10 //  a reference count checker for Core Foundation and Cocoa on (Mac OS X).
     11 //
     12 //===----------------------------------------------------------------------===//
     13 
     14 #ifndef LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_RETAINCOUNTCHECKER_H
     15 #define LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_RETAINCOUNTCHECKER_H
     16 
     17 #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
     18 #include "RetainCountDiagnostics.h"
     19 #include "clang/AST/Attr.h"
     20 #include "clang/AST/DeclCXX.h"
     21 #include "clang/AST/DeclObjC.h"
     22 #include "clang/AST/ParentMap.h"
     23 #include "clang/Analysis/DomainSpecific/CocoaConventions.h"
     24 #include "clang/Analysis/PathDiagnostic.h"
     25 #include "clang/Analysis/RetainSummaryManager.h"
     26 #include "clang/Basic/LangOptions.h"
     27 #include "clang/Basic/SourceManager.h"
     28 #include "clang/Analysis/SelectorExtras.h"
     29 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
     30 #include "clang/StaticAnalyzer/Core/Checker.h"
     31 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
     32 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
     33 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
     34 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
     35 #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
     36 #include "llvm/ADT/DenseMap.h"
     37 #include "llvm/ADT/FoldingSet.h"
     38 #include "llvm/ADT/ImmutableList.h"
     39 #include "llvm/ADT/ImmutableMap.h"
     40 #include "llvm/ADT/STLExtras.h"
     41 #include "llvm/ADT/SmallString.h"
     42 #include "llvm/ADT/StringExtras.h"
     43 #include <cstdarg>
     44 #include <utility>
     45 
     46 namespace clang {
     47 namespace ento {
     48 namespace retaincountchecker {
     49 
     50 /// Metadata on reference.
     51 class RefVal {
     52 public:
     53   enum Kind {
     54     Owned = 0, // Owning reference.
     55     NotOwned,  // Reference is not owned by still valid (not freed).
     56     Released,  // Object has been released.
     57     ReturnedOwned, // Returned object passes ownership to caller.
     58     ReturnedNotOwned, // Return object does not pass ownership to caller.
     59     ERROR_START,
     60     ErrorDeallocNotOwned, // -dealloc called on non-owned object.
     61     ErrorUseAfterRelease, // Object used after released.
     62     ErrorReleaseNotOwned, // Release of an object that was not owned.
     63     ERROR_LEAK_START,
     64     ErrorLeak,  // A memory leak due to excessive reference counts.
     65     ErrorLeakReturned, // A memory leak due to the returning method not having
     66                        // the correct naming conventions.
     67     ErrorOverAutorelease,
     68     ErrorReturnedNotOwned
     69   };
     70 
     71   /// Tracks how an object referenced by an ivar has been used.
     72   ///
     73   /// This accounts for us not knowing if an arbitrary ivar is supposed to be
     74   /// stored at +0 or +1.
     75   enum class IvarAccessHistory {
     76     None,
     77     AccessedDirectly,
     78     ReleasedAfterDirectAccess
     79   };
     80 
     81 private:
     82   /// The number of outstanding retains.
     83   unsigned Cnt;
     84   /// The number of outstanding autoreleases.
     85   unsigned ACnt;
     86   /// The (static) type of the object at the time we started tracking it.
     87   QualType T;
     88 
     89   /// The current state of the object.
     90   ///
     91   /// See the RefVal::Kind enum for possible values.
     92   unsigned RawKind : 5;
     93 
     94   /// The kind of object being tracked (CF or ObjC or OSObject), if known.
     95   ///
     96   /// See the ObjKind enum for possible values.
     97   unsigned RawObjectKind : 3;
     98 
     99   /// True if the current state and/or retain count may turn out to not be the
    100   /// best possible approximation of the reference counting state.
    101   ///
    102   /// If true, the checker may decide to throw away ("override") this state
    103   /// in favor of something else when it sees the object being used in new ways.
    104   ///
    105   /// This setting should not be propagated to state derived from this state.
    106   /// Once we start deriving new states, it would be inconsistent to override
    107   /// them.
    108   unsigned RawIvarAccessHistory : 2;
    109 
    110   RefVal(Kind k, ObjKind o, unsigned cnt, unsigned acnt, QualType t,
    111          IvarAccessHistory IvarAccess)
    112     : Cnt(cnt), ACnt(acnt), T(t), RawKind(static_cast<unsigned>(k)),
    113       RawObjectKind(static_cast<unsigned>(o)),
    114       RawIvarAccessHistory(static_cast<unsigned>(IvarAccess)) {
    115     assert(getKind() == k && "not enough bits for the kind");
    116     assert(getObjKind() == o && "not enough bits for the object kind");
    117     assert(getIvarAccessHistory() == IvarAccess && "not enough bits");
    118   }
    119 
    120 public:
    121   Kind getKind() const { return static_cast<Kind>(RawKind); }
    122 
    123   ObjKind getObjKind() const {
    124     return static_cast<ObjKind>(RawObjectKind);
    125   }
    126 
    127   unsigned getCount() const { return Cnt; }
    128   unsigned getAutoreleaseCount() const { return ACnt; }
    129   unsigned getCombinedCounts() const { return Cnt + ACnt; }
    130   void clearCounts() {
    131     Cnt = 0;
    132     ACnt = 0;
    133   }
    134   void setCount(unsigned i) {
    135     Cnt = i;
    136   }
    137   void setAutoreleaseCount(unsigned i) {
    138     ACnt = i;
    139   }
    140 
    141   QualType getType() const { return T; }
    142 
    143   /// Returns what the analyzer knows about direct accesses to a particular
    144   /// instance variable.
    145   ///
    146   /// If the object with this refcount wasn't originally from an Objective-C
    147   /// ivar region, this should always return IvarAccessHistory::None.
    148   IvarAccessHistory getIvarAccessHistory() const {
    149     return static_cast<IvarAccessHistory>(RawIvarAccessHistory);
    150   }
    151 
    152   bool isOwned() const {
    153     return getKind() == Owned;
    154   }
    155 
    156   bool isNotOwned() const {
    157     return getKind() == NotOwned;
    158   }
    159 
    160   bool isReturnedOwned() const {
    161     return getKind() == ReturnedOwned;
    162   }
    163 
    164   bool isReturnedNotOwned() const {
    165     return getKind() == ReturnedNotOwned;
    166   }
    167 
    168   /// Create a state for an object whose lifetime is the responsibility of the
    169   /// current function, at least partially.
    170   ///
    171   /// Most commonly, this is an owned object with a retain count of +1.
    172   static RefVal makeOwned(ObjKind o, QualType t) {
    173     return RefVal(Owned, o, /*Count=*/1, 0, t, IvarAccessHistory::None);
    174   }
    175 
    176   /// Create a state for an object whose lifetime is not the responsibility of
    177   /// the current function.
    178   ///
    179   /// Most commonly, this is an unowned object with a retain count of +0.
    180   static RefVal makeNotOwned(ObjKind o, QualType t) {
    181     return RefVal(NotOwned, o, /*Count=*/0, 0, t, IvarAccessHistory::None);
    182   }
    183 
    184   RefVal operator-(size_t i) const {
    185     return RefVal(getKind(), getObjKind(), getCount() - i,
    186                   getAutoreleaseCount(), getType(), getIvarAccessHistory());
    187   }
    188 
    189   RefVal operator+(size_t i) const {
    190     return RefVal(getKind(), getObjKind(), getCount() + i,
    191                   getAutoreleaseCount(), getType(), getIvarAccessHistory());
    192   }
    193 
    194   RefVal operator^(Kind k) const {
    195     return RefVal(k, getObjKind(), getCount(), getAutoreleaseCount(),
    196                   getType(), getIvarAccessHistory());
    197   }
    198 
    199   RefVal autorelease() const {
    200     return RefVal(getKind(), getObjKind(), getCount(), getAutoreleaseCount()+1,
    201                   getType(), getIvarAccessHistory());
    202   }
    203 
    204   RefVal withIvarAccess() const {
    205     assert(getIvarAccessHistory() == IvarAccessHistory::None);
    206     return RefVal(getKind(), getObjKind(), getCount(), getAutoreleaseCount(),
    207                   getType(), IvarAccessHistory::AccessedDirectly);
    208   }
    209 
    210   RefVal releaseViaIvar() const {
    211     assert(getIvarAccessHistory() == IvarAccessHistory::AccessedDirectly);
    212     return RefVal(getKind(), getObjKind(), getCount(), getAutoreleaseCount(),
    213                   getType(), IvarAccessHistory::ReleasedAfterDirectAccess);
    214   }
    215 
    216   // Comparison, profiling, and pretty-printing.
    217   bool hasSameState(const RefVal &X) const {
    218     return getKind() == X.getKind() && Cnt == X.Cnt && ACnt == X.ACnt &&
    219            getIvarAccessHistory() == X.getIvarAccessHistory();
    220   }
    221 
    222   bool operator==(const RefVal& X) const {
    223     return T == X.T && hasSameState(X) && getObjKind() == X.getObjKind();
    224   }
    225 
    226   void Profile(llvm::FoldingSetNodeID& ID) const {
    227     ID.Add(T);
    228     ID.AddInteger(RawKind);
    229     ID.AddInteger(Cnt);
    230     ID.AddInteger(ACnt);
    231     ID.AddInteger(RawObjectKind);
    232     ID.AddInteger(RawIvarAccessHistory);
    233   }
    234 
    235   void print(raw_ostream &Out) const;
    236 };
    237 
    238 class RetainCountChecker
    239   : public Checker< check::Bind,
    240                     check::DeadSymbols,
    241                     check::BeginFunction,
    242                     check::EndFunction,
    243                     check::PostStmt<BlockExpr>,
    244                     check::PostStmt<CastExpr>,
    245                     check::PostStmt<ObjCArrayLiteral>,
    246                     check::PostStmt<ObjCDictionaryLiteral>,
    247                     check::PostStmt<ObjCBoxedExpr>,
    248                     check::PostStmt<ObjCIvarRefExpr>,
    249                     check::PostCall,
    250                     check::RegionChanges,
    251                     eval::Assume,
    252                     eval::Call > {
    253 
    254 public:
    255   std::unique_ptr<RefCountBug> UseAfterRelease;
    256   std::unique_ptr<RefCountBug> ReleaseNotOwned;
    257   std::unique_ptr<RefCountBug> DeallocNotOwned;
    258   std::unique_ptr<RefCountBug> FreeNotOwned;
    259   std::unique_ptr<RefCountBug> OverAutorelease;
    260   std::unique_ptr<RefCountBug> ReturnNotOwnedForOwned;
    261   std::unique_ptr<RefCountBug> LeakWithinFunction;
    262   std::unique_ptr<RefCountBug> LeakAtReturn;
    263 
    264   mutable std::unique_ptr<RetainSummaryManager> Summaries;
    265 
    266   static std::unique_ptr<CheckerProgramPointTag> DeallocSentTag;
    267   static std::unique_ptr<CheckerProgramPointTag> CastFailTag;
    268 
    269   /// Track Objective-C and CoreFoundation objects.
    270   bool TrackObjCAndCFObjects = false;
    271 
    272   /// Track sublcasses of OSObject.
    273   bool TrackOSObjects = false;
    274 
    275   /// Track initial parameters (for the entry point) for NS/CF objects.
    276   bool TrackNSCFStartParam = false;
    277 
    278   RetainCountChecker() {};
    279 
    280   RetainSummaryManager &getSummaryManager(ASTContext &Ctx) const {
    281     if (!Summaries)
    282       Summaries.reset(
    283           new RetainSummaryManager(Ctx, TrackObjCAndCFObjects, TrackOSObjects));
    284     return *Summaries;
    285   }
    286 
    287   RetainSummaryManager &getSummaryManager(CheckerContext &C) const {
    288     return getSummaryManager(C.getASTContext());
    289   }
    290 
    291   void printState(raw_ostream &Out, ProgramStateRef State,
    292                   const char *NL, const char *Sep) const override;
    293 
    294   void checkBind(SVal loc, SVal val, const Stmt *S, CheckerContext &C) const;
    295   void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const;
    296   void checkPostStmt(const CastExpr *CE, CheckerContext &C) const;
    297 
    298   void checkPostStmt(const ObjCArrayLiteral *AL, CheckerContext &C) const;
    299   void checkPostStmt(const ObjCDictionaryLiteral *DL, CheckerContext &C) const;
    300   void checkPostStmt(const ObjCBoxedExpr *BE, CheckerContext &C) const;
    301 
    302   void checkPostStmt(const ObjCIvarRefExpr *IRE, CheckerContext &C) const;
    303 
    304   void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
    305 
    306   void checkSummary(const RetainSummary &Summ, const CallEvent &Call,
    307                     CheckerContext &C) const;
    308 
    309   void processSummaryOfInlined(const RetainSummary &Summ,
    310                                const CallEvent &Call,
    311                                CheckerContext &C) const;
    312 
    313   bool evalCall(const CallEvent &Call, CheckerContext &C) const;
    314 
    315   ProgramStateRef evalAssume(ProgramStateRef state, SVal Cond,
    316                                  bool Assumption) const;
    317 
    318   ProgramStateRef
    319   checkRegionChanges(ProgramStateRef state,
    320                      const InvalidatedSymbols *invalidated,
    321                      ArrayRef<const MemRegion *> ExplicitRegions,
    322                      ArrayRef<const MemRegion *> Regions,
    323                      const LocationContext* LCtx,
    324                      const CallEvent *Call) const;
    325 
    326   ExplodedNode* checkReturnWithRetEffect(const ReturnStmt *S, CheckerContext &C,
    327                                 ExplodedNode *Pred, RetEffect RE, RefVal X,
    328                                 SymbolRef Sym, ProgramStateRef state) const;
    329 
    330   void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
    331   void checkBeginFunction(CheckerContext &C) const;
    332   void checkEndFunction(const ReturnStmt *RS, CheckerContext &C) const;
    333 
    334   ProgramStateRef updateSymbol(ProgramStateRef state, SymbolRef sym,
    335                                RefVal V, ArgEffect E, RefVal::Kind &hasErr,
    336                                CheckerContext &C) const;
    337 
    338   const RefCountBug &errorKindToBugKind(RefVal::Kind ErrorKind,
    339                                         SymbolRef Sym) const;
    340 
    341   void processNonLeakError(ProgramStateRef St, SourceRange ErrorRange,
    342                            RefVal::Kind ErrorKind, SymbolRef Sym,
    343                            CheckerContext &C) const;
    344 
    345   void processObjCLiterals(CheckerContext &C, const Expr *Ex) const;
    346 
    347   ProgramStateRef handleSymbolDeath(ProgramStateRef state,
    348                                     SymbolRef sid, RefVal V,
    349                                     SmallVectorImpl<SymbolRef> &Leaked) const;
    350 
    351   ProgramStateRef
    352   handleAutoreleaseCounts(ProgramStateRef state, ExplodedNode *Pred,
    353                           const ProgramPointTag *Tag, CheckerContext &Ctx,
    354                           SymbolRef Sym,
    355                           RefVal V,
    356                           const ReturnStmt *S=nullptr) const;
    357 
    358   ExplodedNode *processLeaks(ProgramStateRef state,
    359                              SmallVectorImpl<SymbolRef> &Leaked,
    360                              CheckerContext &Ctx,
    361                              ExplodedNode *Pred = nullptr) const;
    362 
    363   static const CheckerProgramPointTag &getDeallocSentTag() {
    364     return *DeallocSentTag;
    365   }
    366 
    367   static const CheckerProgramPointTag &getCastFailTag() { return *CastFailTag; }
    368 
    369 private:
    370   /// Perform the necessary checks and state adjustments at the end of the
    371   /// function.
    372   /// \p S Return statement, may be null.
    373   ExplodedNode * processReturn(const ReturnStmt *S, CheckerContext &C) const;
    374 };
    375 
    376 //===----------------------------------------------------------------------===//
    377 // RefBindings - State used to track object reference counts.
    378 //===----------------------------------------------------------------------===//
    379 
    380 const RefVal *getRefBinding(ProgramStateRef State, SymbolRef Sym);
    381 
    382 /// Returns true if this stack frame is for an Objective-C method that is a
    383 /// property getter or setter whose body has been synthesized by the analyzer.
    384 inline bool isSynthesizedAccessor(const StackFrameContext *SFC) {
    385   auto Method = dyn_cast_or_null<ObjCMethodDecl>(SFC->getDecl());
    386   if (!Method || !Method->isPropertyAccessor())
    387     return false;
    388 
    389   return SFC->getAnalysisDeclContext()->isBodyAutosynthesized();
    390 }
    391 
    392 } // end namespace retaincountchecker
    393 } // end namespace ento
    394 } // end namespace clang
    395 
    396 #endif
    397