clang 23.0.0git
RetainCountChecker.h
Go to the documentation of this file.
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
19#include "clang/AST/Attr.h"
20#include "clang/AST/DeclCXX.h"
21#include "clang/AST/DeclObjC.h"
22#include "clang/AST/ParentMap.h"
36#include "llvm/ADT/DenseMap.h"
37#include "llvm/ADT/FoldingSet.h"
38#include "llvm/ADT/ImmutableList.h"
39#include "llvm/ADT/STLExtras.h"
40#include "llvm/ADT/SmallString.h"
41#include "llvm/ADT/StringExtras.h"
42#include <cstdarg>
43#include <utility>
44
45namespace clang {
46namespace ento {
47namespace retaincountchecker {
48
49/// Metadata on reference.
50class RefVal {
51public:
52 enum Kind {
53 Owned = 0, // Owning reference.
54 NotOwned, // Reference is not owned by still valid (not freed).
55 Released, // Object has been released.
56 ReturnedOwned, // Returned object passes ownership to caller.
57 ReturnedNotOwned, // Return object does not pass ownership to caller.
59 ErrorDeallocNotOwned, // -dealloc called on non-owned object.
60 ErrorUseAfterRelease, // Object used after released.
61 ErrorReleaseNotOwned, // Release of an object that was not owned.
63 ErrorLeak, // A memory leak due to excessive reference counts.
64 ErrorLeakReturned, // A memory leak due to the returning method not having
65 // the correct naming conventions.
68 };
69
70 /// Tracks how an object referenced by an ivar has been used.
71 ///
72 /// This accounts for us not knowing if an arbitrary ivar is supposed to be
73 /// stored at +0 or +1.
79
80private:
81 /// The number of outstanding retains.
82 unsigned Cnt;
83 /// The number of outstanding autoreleases.
84 unsigned ACnt;
85 /// The (static) type of the object at the time we started tracking it.
86 QualType T;
87
88 /// The current state of the object.
89 ///
90 /// See the RefVal::Kind enum for possible values.
91 unsigned RawKind : 5;
92
93 /// The kind of object being tracked (CF or ObjC or OSObject), if known.
94 ///
95 /// See the ObjKind enum for possible values.
96 unsigned RawObjectKind : 3;
97
98 /// True if the current state and/or retain count may turn out to not be the
99 /// best possible approximation of the reference counting state.
100 ///
101 /// If true, the checker may decide to throw away ("override") this state
102 /// in favor of something else when it sees the object being used in new ways.
103 ///
104 /// This setting should not be propagated to state derived from this state.
105 /// Once we start deriving new states, it would be inconsistent to override
106 /// them.
107 unsigned RawIvarAccessHistory : 2;
108
109 RefVal(Kind k, ObjKind o, unsigned cnt, unsigned acnt, QualType t,
110 IvarAccessHistory IvarAccess)
111 : Cnt(cnt), ACnt(acnt), T(t), RawKind(static_cast<unsigned>(k)),
112 RawObjectKind(static_cast<unsigned>(o)),
113 RawIvarAccessHistory(static_cast<unsigned>(IvarAccess)) {
114 assert(getKind() == k && "not enough bits for the kind");
115 assert(getObjKind() == o && "not enough bits for the object kind");
116 assert(getIvarAccessHistory() == IvarAccess && "not enough bits");
117 }
118
119public:
120 Kind getKind() const { return static_cast<Kind>(RawKind); }
121
123 return static_cast<ObjKind>(RawObjectKind);
124 }
125
126 unsigned getCount() const { return Cnt; }
127 unsigned getAutoreleaseCount() const { return ACnt; }
128 unsigned getCombinedCounts() const { return Cnt + ACnt; }
129 void clearCounts() {
130 Cnt = 0;
131 ACnt = 0;
132 }
133 void setCount(unsigned i) {
134 Cnt = i;
135 }
136 void setAutoreleaseCount(unsigned i) {
137 ACnt = i;
138 }
139
140 QualType getType() const { return T; }
141
142 /// Returns what the analyzer knows about direct accesses to a particular
143 /// instance variable.
144 ///
145 /// If the object with this refcount wasn't originally from an Objective-C
146 /// ivar region, this should always return IvarAccessHistory::None.
148 return static_cast<IvarAccessHistory>(RawIvarAccessHistory);
149 }
150
151 bool isOwned() const {
152 return getKind() == Owned;
153 }
154
155 bool isNotOwned() const {
156 return getKind() == NotOwned;
157 }
158
159 bool isReturnedOwned() const {
160 return getKind() == ReturnedOwned;
161 }
162
163 bool isReturnedNotOwned() const {
164 return getKind() == ReturnedNotOwned;
165 }
166
167 /// Create a state for an object whose lifetime is the responsibility of the
168 /// current function, at least partially.
169 ///
170 /// Most commonly, this is an owned object with a retain count of +1.
171 static RefVal makeOwned(ObjKind o, QualType t) {
172 return RefVal(Owned, o, /*Count=*/1, 0, t, IvarAccessHistory::None);
173 }
174
175 /// Create a state for an object whose lifetime is not the responsibility of
176 /// the current function.
177 ///
178 /// Most commonly, this is an unowned object with a retain count of +0.
179 static RefVal makeNotOwned(ObjKind o, QualType t) {
180 return RefVal(NotOwned, o, /*Count=*/0, 0, t, IvarAccessHistory::None);
181 }
182
183 RefVal operator-(size_t i) const {
184 return RefVal(getKind(), getObjKind(), getCount() - i,
186 }
187
188 RefVal operator+(size_t i) const {
189 return RefVal(getKind(), getObjKind(), getCount() + i,
191 }
192
193 RefVal operator^(Kind k) const {
194 return RefVal(k, getObjKind(), getCount(), getAutoreleaseCount(),
196 }
197
198 RefVal autorelease() const {
199 return RefVal(getKind(), getObjKind(), getCount(), getAutoreleaseCount()+1,
201 }
202
208
214
215 // Comparison, profiling, and pretty-printing.
216 bool hasSameState(const RefVal &X) const {
217 return getKind() == X.getKind() && Cnt == X.Cnt && ACnt == X.ACnt &&
218 getIvarAccessHistory() == X.getIvarAccessHistory();
219 }
220
221 bool operator==(const RefVal& X) const {
222 return T == X.T && hasSameState(X) && getObjKind() == X.getObjKind();
223 }
224
225 void Profile(llvm::FoldingSetNodeID& ID) const {
226 ID.Add(T);
227 ID.AddInteger(RawKind);
228 ID.AddInteger(Cnt);
229 ID.AddInteger(ACnt);
230 ID.AddInteger(RawObjectKind);
231 ID.AddInteger(RawIvarAccessHistory);
232 }
233
234 void print(raw_ostream &Out) const;
235};
236
238 : public CheckerFamily<
239 check::Bind, check::DeadSymbols, check::BeginFunction,
240 check::EndFunction, check::PostStmt<BlockExpr>,
241 check::PostStmt<CastExpr>, check::PostStmt<ObjCArrayLiteral>,
242 check::PostStmt<ObjCDictionaryLiteral>,
243 check::PostStmt<ObjCBoxedExpr>, check::PostStmt<ObjCIvarRefExpr>,
244 check::PostCall, check::RegionChanges, eval::Assume, eval::Call> {
245
246public:
249
250 mutable std::unique_ptr<RetainSummaryManager> Summaries;
251
252 static std::unique_ptr<SimpleProgramPointTag> DeallocSentTag;
253 static std::unique_ptr<SimpleProgramPointTag> CastFailTag;
254
255 /// Track initial parameters (for the entry point) for NS/CF objects.
257
258 StringRef getDebugTag() const override { return "RetainCountChecker"; }
259
261 if (!Summaries)
262 Summaries = std::make_unique<RetainSummaryManager>(
263 Ctx, RetainCount.isEnabled(), OSObjectRetainCount.isEnabled());
264 return *Summaries;
265 }
266
268 return getSummaryManager(C.getASTContext());
269 }
270
272 // FIXME: The two frontends of this checker family are in an unusual
273 // relationship: if they are both enabled, then all bug reports are
274 // reported by RetainCount (i.e. `osx.cocoa.RetainCount`), even the bugs
275 // that "belong to" OSObjectRetainCount (i.e. `osx.OSObjectRetainCount`).
276 // This is counter-intuitive and should be fixed to avoid confusion.
277 return RetainCount.isEnabled() ? RetainCount : OSObjectRetainCount;
278 }
279
280 void printState(raw_ostream &Out, ProgramStateRef State,
281 const char *NL, const char *Sep) const override;
282
283 void checkBind(SVal loc, SVal val, const Stmt *S, bool AtDeclInit,
284 CheckerContext &C) const;
285 void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const;
286 void checkPostStmt(const CastExpr *CE, CheckerContext &C) const;
287
288 void checkPostStmt(const ObjCArrayLiteral *AL, CheckerContext &C) const;
289 void checkPostStmt(const ObjCDictionaryLiteral *DL, CheckerContext &C) const;
290 void checkPostStmt(const ObjCBoxedExpr *BE, CheckerContext &C) const;
291
292 void checkPostStmt(const ObjCIvarRefExpr *IRE, CheckerContext &C) const;
293
294 void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
295
296 void checkSummary(const RetainSummary &Summ, const CallEvent &Call,
297 CheckerContext &C) const;
298
299 void processSummaryOfInlined(const RetainSummary &Summ,
300 const CallEvent &Call,
301 CheckerContext &C) const;
302
303 bool evalCall(const CallEvent &Call, CheckerContext &C) const;
304
306 bool Assumption) const;
307
310 const InvalidatedSymbols *invalidated,
311 ArrayRef<const MemRegion *> ExplicitRegions,
312 ArrayRef<const MemRegion *> Regions, const StackFrame *SF,
313 const CallEvent *Call) const;
314
316 ExplodedNode *Pred, RetEffect RE, RefVal X,
317 SymbolRef Sym, ProgramStateRef state) const;
318
319 void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
321 void checkEndFunction(const ReturnStmt *RS, CheckerContext &C) const;
322
324 RefVal V, ArgEffect E, RefVal::Kind &hasErr,
325 CheckerContext &C) const;
326
328 SymbolRef Sym) const;
329
330 bool isReleaseUnownedError(RefVal::Kind ErrorKind) const;
331
333 RefVal::Kind ErrorKind, SymbolRef Sym,
334 CheckerContext &C) const;
335
336 void processObjCLiterals(CheckerContext &C, const Expr *Ex) const;
337
339 SymbolRef sid, RefVal V,
340 SmallVectorImpl<SymbolRef> &Leaked) const;
341
343 ExplodedNode *Pred,
344 CheckerContext &Ctx, SymbolRef Sym,
345 RefVal V,
346 const ReturnStmt *S = nullptr) const;
347
350 CheckerContext &Ctx,
351 ExplodedNode *Pred = nullptr) const;
352
354 return *DeallocSentTag;
355 }
356
358
359private:
360 /// Perform the necessary checks and state adjustments at the end of the
361 /// function.
362 /// \p S Return statement, may be null.
363 ExplodedNode * processReturn(const ReturnStmt *S, CheckerContext &C) const;
364};
365
366//===----------------------------------------------------------------------===//
367// RefBindings - State used to track object reference counts.
368//===----------------------------------------------------------------------===//
369
370const RefVal *getRefBinding(ProgramStateRef State, SymbolRef Sym);
371
372/// Returns true if this stack frame is for an Objective-C method that is a
373/// property getter or setter whose body has been synthesized by the analyzer.
374inline bool isSynthesizedAccessor(const StackFrame *SF) {
375 auto Method = dyn_cast_or_null<ObjCMethodDecl>(SF->getDecl());
376 if (!Method || !Method->isPropertyAccessor())
377 return false;
378
380}
381
382} // end namespace retaincountchecker
383} // end namespace ento
384} // end namespace clang
385
386#endif
#define V(N, I)
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
#define X(type, name)
Definition Value.h:97
Defines the clang::LangOptions interface.
Defines the SourceManager interface.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:223
BlockExpr - Adaptor class for mixing a BlockDecl with expressions.
Definition Expr.h:6672
CastExpr - Base class for type casts, including both implicit casts (ImplicitCastExpr) and explicit c...
Definition Expr.h:3679
This represents one expression.
Definition Expr.h:112
ObjCArrayLiteral - used for objective-c array containers; as in: @["Hello", NSApp,...
Definition ExprObjC.h:220
ObjCBoxedExpr - used for generalized expression boxing.
Definition ExprObjC.h:159
ObjCDictionaryLiteral - AST node to represent objective-c dictionary literals; as in:"name" : NSUserN...
Definition ExprObjC.h:342
ObjCIvarRefExpr - A reference to an ObjC instance variable.
Definition ExprObjC.h:580
A (possibly-)qualified type.
Definition TypeBase.h:937
ReturnStmt - This represents a return, optionally of an expression: return; return 4;.
Definition Stmt.h:3170
A trivial tuple used to represent a source range.
It represents a stack frame of the call stack.
LLVM_ATTRIBUTE_RETURNS_NONNULL AnalysisDeclContext * getAnalysisDeclContext() const
const Decl * getDecl() const
Stmt - This represents one statement.
Definition Stmt.h:86
An ArgEffect summarizes the retain count behavior on an argument or receiver to a function or method.
Represents an abstract call to a function or method along a particular path.
Definition CallEvent.h:152
Checker families (where a single backend class implements multiple related frontends) should derive f...
Definition Checker.h:596
RetEffect summarizes a call's retain/release behavior with respect to its return value.
Summary for a function with respect to ownership changes.
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
Definition SVals.h:56
A class responsible for cleaning up unused symbols.
IvarAccessHistory
Tracks how an object referenced by an ivar has been used.
IvarAccessHistory getIvarAccessHistory() const
Returns what the analyzer knows about direct accesses to a particular instance variable.
static RefVal makeOwned(ObjKind o, QualType t)
Create a state for an object whose lifetime is the responsibility of the current function,...
void Profile(llvm::FoldingSetNodeID &ID) const
static RefVal makeNotOwned(ObjKind o, QualType t)
Create a state for an object whose lifetime is not the responsibility of the current function.
void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const
void checkSummary(const RetainSummary &Summ, const CallEvent &Call, CheckerContext &C) const
ProgramStateRef handleSymbolDeath(ProgramStateRef state, SymbolRef sid, RefVal V, SmallVectorImpl< SymbolRef > &Leaked) const
ProgramStateRef evalAssume(ProgramStateRef state, SVal Cond, bool Assumption) const
static const SimpleProgramPointTag & getCastFailTag()
void processNonLeakError(ProgramStateRef St, SourceRange ErrorRange, RefVal::Kind ErrorKind, SymbolRef Sym, CheckerContext &C) const
const RefCountBug & errorKindToBugKind(RefVal::Kind ErrorKind, SymbolRef Sym) const
static std::unique_ptr< SimpleProgramPointTag > DeallocSentTag
ExplodedNode * checkReturnWithRetEffect(const ReturnStmt *S, CheckerContext &C, ExplodedNode *Pred, RetEffect RE, RefVal X, SymbolRef Sym, ProgramStateRef state) const
ProgramStateRef handleAutoreleaseCounts(ProgramStateRef state, ExplodedNode *Pred, CheckerContext &Ctx, SymbolRef Sym, RefVal V, const ReturnStmt *S=nullptr) const
bool isReleaseUnownedError(RefVal::Kind ErrorKind) const
ExplodedNode * processLeaks(ProgramStateRef state, SmallVectorImpl< SymbolRef > &Leaked, CheckerContext &Ctx, ExplodedNode *Pred=nullptr) const
void checkBind(SVal loc, SVal val, const Stmt *S, bool AtDeclInit, CheckerContext &C) const
ProgramStateRef updateSymbol(ProgramStateRef state, SymbolRef sym, RefVal V, ArgEffect E, RefVal::Kind &hasErr, CheckerContext &C) const
void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const
std::unique_ptr< RetainSummaryManager > Summaries
void printState(raw_ostream &Out, ProgramStateRef State, const char *NL, const char *Sep) const override
Debug state dump callback, see CheckerManager::runCheckersForPrintState.
bool evalCall(const CallEvent &Call, CheckerContext &C) const
ProgramStateRef checkRegionChanges(ProgramStateRef state, const InvalidatedSymbols *invalidated, ArrayRef< const MemRegion * > ExplicitRegions, ArrayRef< const MemRegion * > Regions, const StackFrame *SF, const CallEvent *Call) const
void checkPostCall(const CallEvent &Call, CheckerContext &C) const
static std::unique_ptr< SimpleProgramPointTag > CastFailTag
static const SimpleProgramPointTag & getDeallocSentTag()
void processObjCLiterals(CheckerContext &C, const Expr *Ex) const
void checkEndFunction(const ReturnStmt *RS, CheckerContext &C) const
RetainSummaryManager & getSummaryManager(CheckerContext &C) const
void processSummaryOfInlined(const RetainSummary &Summ, const CallEvent &Call, CheckerContext &C) const
RetainSummaryManager & getSummaryManager(ASTContext &Ctx) const
StringRef getDebugTag() const override
The description of this program point which will be dumped for debugging purposes.
bool TrackNSCFStartParam
Track initial parameters (for the entry point) for NS/CF objects.
bool isSynthesizedAccessor(const StackFrame *SF)
Returns true if this stack frame is for an Objective-C method that is a property getter or setter who...
const RefVal * getRefBinding(ProgramStateRef State, SymbolRef Sym)
llvm::DenseSet< SymbolRef > InvalidatedSymbols
Definition Store.h:50
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
const SymExpr * SymbolRef
Definition SymExpr.h:133
ObjKind
Determines the object kind of a tracked object.
The JSON file list parser is used to communicate input to InstallAPI.
Expr * Cond
};