Clang Project

clang_source_code/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.h
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/RetainSummaryManager.h"
25#include "clang/Basic/LangOptions.h"
26#include "clang/Basic/SourceManager.h"
27#include "clang/Analysis/SelectorExtras.h"
28#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
29#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.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
46namespace clang {
47namespace ento {
48namespace retaincountchecker {
49
50/// Metadata on reference.
51class RefVal {
52public:
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
81private:
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 kObjKind ounsigned cntunsigned acntQualType 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     (0) . __assert_fail ("getKind() == k && \"not enough bits for the kind\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.h", 115, __PRETTY_FUNCTION__))" file_link="../../../../../include/assert.h.html#88" macro="true">assert(getKind() == k && "not enough bits for the kind");
116     (0) . __assert_fail ("getObjKind() == o && \"not enough bits for the object kind\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.h", 116, __PRETTY_FUNCTION__))" file_link="../../../../../include/assert.h.html#88" macro="true">assert(getObjKind() == o && "not enough bits for the object kind");
117     (0) . __assert_fail ("getIvarAccessHistory() == IvarAccess && \"not enough bits\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.h", 117, __PRETTY_FUNCTION__))" file_link="../../../../../include/assert.h.html#88" macro="true">assert(getIvarAccessHistory() == IvarAccess && "not enough bits");
118  }
119
120public:
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 oQualType t) {
173    return RefVal(Ownedo/*Count=*/10tIvarAccessHistory::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 oQualType t) {
181    return RefVal(NotOwnedo/*Count=*/00tIvarAccessHistory::None);
182  }
183
184  RefVal operator-(size_t iconst {
185    return RefVal(getKind(), getObjKind(), getCount() - i,
186                  getAutoreleaseCount(), getType(), getIvarAccessHistory());
187  }
188
189  RefVal operator+(size_t iconst {
190    return RefVal(getKind(), getObjKind(), getCount() + i,
191                  getAutoreleaseCount(), getType(), getIvarAccessHistory());
192  }
193
194  RefVal operator^(Kind kconst {
195    return RefVal(kgetObjKind(), 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 &Xconst {
218    return getKind() == X.getKind() && Cnt == X.Cnt && ACnt == X.ACnt &&
219           getIvarAccessHistory() == X.getIvarAccessHistory();
220  }
221
222  bool operator==(const RefValXconst {
223    return T == X.T && hasSameState(X) && getObjKind() == X.getObjKind();
224  }
225
226  void Profile(llvm::FoldingSetNodeIDIDconst {
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 &Outconst;
236};
237
238class 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  RefCountBug useAfterRelease{this, RefCountBug::UseAfterRelease};
255  RefCountBug releaseNotOwned{this, RefCountBug::ReleaseNotOwned};
256  RefCountBug deallocNotOwned{this, RefCountBug::DeallocNotOwned};
257  RefCountBug freeNotOwned{this, RefCountBug::FreeNotOwned};
258  RefCountBug overAutorelease{this, RefCountBug::OverAutorelease};
259  RefCountBug returnNotOwnedForOwned{this, RefCountBug::ReturnNotOwnedForOwned};
260  RefCountBug leakWithinFunction{this, RefCountBug::LeakWithinFunction};
261  RefCountBug leakAtReturn{this, RefCountBug::LeakAtReturn};
262
263  CheckerProgramPointTag DeallocSentTag{this"DeallocSent"};
264  CheckerProgramPointTag CastFailTag{this"DynamicCastFail"};
265
266  mutable std::unique_ptr<RetainSummaryManagerSummaries;
267public:
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 &Ctxconst {
281    if (!Summaries)
282      Summaries.reset(
283          new RetainSummaryManager(CtxTrackObjCAndCFObjectsTrackOSObjects));
284    return *Summaries;
285  }
286
287  RetainSummaryManager &getSummaryManager(CheckerContext &Cconst {
288    return getSummaryManager(C.getASTContext());
289  }
290
291  void printState(raw_ostream &OutProgramStateRef State,
292                  const char *NLconst char *Sepconst override;
293
294  void checkBind(SVal locSVal valconst Stmt *SCheckerContext &Cconst;
295  void checkPostStmt(const BlockExpr *BECheckerContext &Cconst;
296  void checkPostStmt(const CastExpr *CECheckerContext &Cconst;
297
298  void checkPostStmt(const ObjCArrayLiteral *ALCheckerContext &Cconst;
299  void checkPostStmt(const ObjCDictionaryLiteral *DLCheckerContext &Cconst;
300  void checkPostStmt(const ObjCBoxedExpr *BECheckerContext &Cconst;
301
302  void checkPostStmt(const ObjCIvarRefExpr *IRECheckerContext &Cconst;
303
304  void checkPostCall(const CallEvent &CallCheckerContext &Cconst;
305
306  void checkSummary(const RetainSummary &Summconst CallEvent &Call,
307                    CheckerContext &Cconst;
308
309  void processSummaryOfInlined(const RetainSummary &Summ,
310                               const CallEvent &Call,
311                               CheckerContext &Cconst;
312
313  bool evalCall(const CallExpr *CECheckerContext &Cconst;
314
315  ProgramStateRef evalAssume(ProgramStateRef stateSVal Cond,
316                                 bool Assumptionconst;
317
318  ProgramStateRef
319  checkRegionChanges(ProgramStateRef state,
320                     const InvalidatedSymbols *invalidated,
321                     ArrayRef<const MemRegion *> ExplicitRegions,
322                     ArrayRef<const MemRegion *> Regions,
323                     const LocationContextLCtx,
324                     const CallEvent *Callconst;
325
326  ExplodedNodecheckReturnWithRetEffect(const ReturnStmt *SCheckerContext &C,
327                                ExplodedNode *PredRetEffect RERefVal X,
328                                SymbolRef SymProgramStateRef stateconst;
329
330  void checkDeadSymbols(SymbolReaper &SymReaperCheckerContext &Cconst;
331  void checkBeginFunction(CheckerContext &Cconst;
332  void checkEndFunction(const ReturnStmt *RSCheckerContext &Cconst;
333
334  ProgramStateRef updateSymbol(ProgramStateRef stateSymbolRef sym,
335                               RefVal VArgEffect ERefVal::Kind &hasErr,
336                               CheckerContext &Cconst;
337
338  const RefCountBug &errorKindToBugKind(RefVal::Kind ErrorKind,
339                                        SymbolRef Symconst;
340
341  void processNonLeakError(ProgramStateRef StSourceRange ErrorRange,
342                           RefVal::Kind ErrorKindSymbolRef Sym,
343                           CheckerContext &Cconst;
344
345  void processObjCLiterals(CheckerContext &Cconst Expr *Exconst;
346
347  ProgramStateRef handleSymbolDeath(ProgramStateRef state,
348                                    SymbolRef sidRefVal V,
349                                    SmallVectorImpl<SymbolRef> &Leakedconst;
350
351  ProgramStateRef
352  handleAutoreleaseCounts(ProgramStateRef stateExplodedNode *Pred,
353                          const ProgramPointTag *TagCheckerContext &Ctx,
354                          SymbolRef Sym,
355                          RefVal V,
356                          const ReturnStmt *S=nullptrconst;
357
358  ExplodedNode *processLeaks(ProgramStateRef state,
359                             SmallVectorImpl<SymbolRef> &Leaked,
360                             CheckerContext &Ctx,
361                             ExplodedNode *Pred = nullptrconst;
362
363  const CheckerProgramPointTag &getDeallocSentTag() const {
364    return DeallocSentTag;
365  }
366
367  const CheckerProgramPointTag &getCastFailTag() const {
368    return CastFailTag;
369  }
370
371private:
372  /// Perform the necessary checks and state adjustments at the end of the
373  /// function.
374  /// \p S Return statement, may be null.
375  ExplodedNode * processReturn(const ReturnStmt *SCheckerContext &Cconst;
376};
377
378//===----------------------------------------------------------------------===//
379// RefBindings - State used to track object reference counts.
380//===----------------------------------------------------------------------===//
381
382const RefVal *getRefBinding(ProgramStateRef StateSymbolRef Sym);
383
384/// Returns true if this stack frame is for an Objective-C method that is a
385/// property getter or setter whose body has been synthesized by the analyzer.
386inline bool isSynthesizedAccessor(const StackFrameContext *SFC) {
387  auto Method = dyn_cast_or_null<ObjCMethodDecl>(SFC->getDecl());
388  if (!Method || !Method->isPropertyAccessor())
389    return false;
390
391  return SFC->getAnalysisDeclContext()->isBodyAutosynthesized();
392}
393
394// end namespace retaincountchecker
395// end namespace ento
396// end namespace clang
397
398#endif
399
clang::ento::retaincountchecker::RefVal::Kind
clang::ento::retaincountchecker::RefVal::IvarAccessHistory
clang::ento::retaincountchecker::RefVal::Cnt
clang::ento::retaincountchecker::RefVal::ACnt
clang::ento::retaincountchecker::RefVal::T
clang::ento::retaincountchecker::RefVal::RawKind
clang::ento::retaincountchecker::RefVal::RawObjectKind
clang::ento::retaincountchecker::RefVal::RawIvarAccessHistory
clang::ento::retaincountchecker::RefVal::getKind
clang::ento::retaincountchecker::RefVal::getObjKind
clang::ento::retaincountchecker::RefVal::getCount
clang::ento::retaincountchecker::RefVal::getAutoreleaseCount
clang::ento::retaincountchecker::RefVal::getCombinedCounts
clang::ento::retaincountchecker::RefVal::clearCounts
clang::ento::retaincountchecker::RefVal::setCount
clang::ento::retaincountchecker::RefVal::setAutoreleaseCount
clang::ento::retaincountchecker::RefVal::getType
clang::ento::retaincountchecker::RefVal::getIvarAccessHistory
clang::ento::retaincountchecker::RefVal::isOwned
clang::ento::retaincountchecker::RefVal::isNotOwned
clang::ento::retaincountchecker::RefVal::isReturnedOwned
clang::ento::retaincountchecker::RefVal::isReturnedNotOwned
clang::ento::retaincountchecker::RefVal::makeOwned
clang::ento::retaincountchecker::RefVal::makeNotOwned
clang::ento::retaincountchecker::RefVal::autorelease
clang::ento::retaincountchecker::RefVal::withIvarAccess
clang::ento::retaincountchecker::RefVal::releaseViaIvar
clang::ento::retaincountchecker::RefVal::hasSameState
clang::ento::retaincountchecker::RefVal::Profile
clang::ento::retaincountchecker::RefVal::print
clang::ento::retaincountchecker::RetainCountChecker::useAfterRelease
clang::ento::retaincountchecker::RetainCountChecker::releaseNotOwned
clang::ento::retaincountchecker::RetainCountChecker::deallocNotOwned
clang::ento::retaincountchecker::RetainCountChecker::freeNotOwned
clang::ento::retaincountchecker::RetainCountChecker::overAutorelease
clang::ento::retaincountchecker::RetainCountChecker::returnNotOwnedForOwned
clang::ento::retaincountchecker::RetainCountChecker::leakWithinFunction
clang::ento::retaincountchecker::RetainCountChecker::leakAtReturn
clang::ento::retaincountchecker::RetainCountChecker::DeallocSentTag
clang::ento::retaincountchecker::RetainCountChecker::CastFailTag
clang::ento::retaincountchecker::RetainCountChecker::Summaries
clang::ento::retaincountchecker::RetainCountChecker::TrackObjCAndCFObjects
clang::ento::retaincountchecker::RetainCountChecker::TrackOSObjects
clang::ento::retaincountchecker::RetainCountChecker::TrackNSCFStartParam
clang::ento::retaincountchecker::RetainCountChecker::getSummaryManager
clang::ento::retaincountchecker::RetainCountChecker::getSummaryManager
clang::ento::retaincountchecker::RetainCountChecker::printState
clang::ento::retaincountchecker::RetainCountChecker::checkBind
clang::ento::retaincountchecker::RetainCountChecker::checkPostStmt
clang::ento::retaincountchecker::RetainCountChecker::checkPostStmt
clang::ento::retaincountchecker::RetainCountChecker::checkPostStmt
clang::ento::retaincountchecker::RetainCountChecker::checkPostStmt
clang::ento::retaincountchecker::RetainCountChecker::checkPostStmt
clang::ento::retaincountchecker::RetainCountChecker::checkPostStmt
clang::ento::retaincountchecker::RetainCountChecker::checkPostCall
clang::ento::retaincountchecker::RetainCountChecker::checkSummary
clang::ento::retaincountchecker::RetainCountChecker::processSummaryOfInlined
clang::ento::retaincountchecker::RetainCountChecker::evalCall
clang::ento::retaincountchecker::RetainCountChecker::evalAssume
clang::ento::retaincountchecker::RetainCountChecker::checkRegionChanges
clang::ento::retaincountchecker::RetainCountChecker::checkReturnWithRetEffect
clang::ento::retaincountchecker::RetainCountChecker::checkDeadSymbols
clang::ento::retaincountchecker::RetainCountChecker::checkBeginFunction
clang::ento::retaincountchecker::RetainCountChecker::checkEndFunction
clang::ento::retaincountchecker::RetainCountChecker::updateSymbol
clang::ento::retaincountchecker::RetainCountChecker::errorKindToBugKind
clang::ento::retaincountchecker::RetainCountChecker::processNonLeakError
clang::ento::retaincountchecker::RetainCountChecker::processObjCLiterals
clang::ento::retaincountchecker::RetainCountChecker::handleSymbolDeath
clang::ento::retaincountchecker::RetainCountChecker::handleAutoreleaseCounts
clang::ento::retaincountchecker::RetainCountChecker::processLeaks
clang::ento::retaincountchecker::RetainCountChecker::getDeallocSentTag
clang::ento::retaincountchecker::RetainCountChecker::getCastFailTag
clang::ento::retaincountchecker::RetainCountChecker::processReturn