clang 22.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,
313 const LocationContext* LCtx,
314 const CallEvent *Call) const;
315
317 ExplodedNode *Pred, RetEffect RE, RefVal X,
318 SymbolRef Sym, ProgramStateRef state) const;
319
320 void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
322 void checkEndFunction(const ReturnStmt *RS, CheckerContext &C) const;
323
325 RefVal V, ArgEffect E, RefVal::Kind &hasErr,
326 CheckerContext &C) const;
327
329 SymbolRef Sym) const;
330
331 bool isReleaseUnownedError(RefVal::Kind ErrorKind) const;
332
334 RefVal::Kind ErrorKind, SymbolRef Sym,
335 CheckerContext &C) const;
336
337 void processObjCLiterals(CheckerContext &C, const Expr *Ex) const;
338
340 SymbolRef sid, RefVal V,
341 SmallVectorImpl<SymbolRef> &Leaked) const;
342
344 ExplodedNode *Pred,
345 CheckerContext &Ctx, SymbolRef Sym,
346 RefVal V,
347 const ReturnStmt *S = nullptr) const;
348
351 CheckerContext &Ctx,
352 ExplodedNode *Pred = nullptr) const;
353
355 return *DeallocSentTag;
356 }
357
359
360private:
361 /// Perform the necessary checks and state adjustments at the end of the
362 /// function.
363 /// \p S Return statement, may be null.
364 ExplodedNode * processReturn(const ReturnStmt *S, CheckerContext &C) const;
365};
366
367//===----------------------------------------------------------------------===//
368// RefBindings - State used to track object reference counts.
369//===----------------------------------------------------------------------===//
370
371const RefVal *getRefBinding(ProgramStateRef State, SymbolRef Sym);
372
373/// Returns true if this stack frame is for an Objective-C method that is a
374/// property getter or setter whose body has been synthesized by the analyzer.
376 auto Method = dyn_cast_or_null<ObjCMethodDecl>(SFC->getDecl());
377 if (!Method || !Method->isPropertyAccessor())
378 return false;
379
381}
382
383} // end namespace retaincountchecker
384} // end namespace ento
385} // end namespace clang
386
387#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:188
BlockExpr - Adaptor class for mixing a BlockDecl with expressions.
Definition Expr.h:6560
CastExpr - Base class for type casts, including both implicit casts (ImplicitCastExpr) and explicit c...
Definition Expr.h:3612
This represents one expression.
Definition Expr.h:112
It wraps the AnalysisDeclContext to represent both the call stack with the help of StackFrameContext ...
const Decl * getDecl() const
LLVM_ATTRIBUTE_RETURNS_NONNULL AnalysisDeclContext * getAnalysisDeclContext() const
ObjCArrayLiteral - used for objective-c array containers; as in: @["Hello", NSApp,...
Definition ExprObjC.h:192
ObjCBoxedExpr - used for generalized expression boxing.
Definition ExprObjC.h:128
ObjCDictionaryLiteral - AST node to represent objective-c dictionary literals; as in:"name" : NSUserN...
Definition ExprObjC.h:308
ObjCIvarRefExpr - A reference to an ObjC instance variable.
Definition ExprObjC.h:548
A (possibly-)qualified type.
Definition TypeBase.h:937
ReturnStmt - This represents a return, optionally of an expression: return; return 4;.
Definition Stmt.h:3160
A trivial tuple used to represent a source range.
It represents a stack frame of the call stack (based on CallEvent).
Stmt - This represents one statement.
Definition Stmt.h:85
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:153
Checker families (where a single backend class implements multiple related frontends) should derive f...
Definition Checker.h:584
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
void checkPostCall(const CallEvent &Call, CheckerContext &C) const
static std::unique_ptr< SimpleProgramPointTag > CastFailTag
ProgramStateRef checkRegionChanges(ProgramStateRef state, const InvalidatedSymbols *invalidated, ArrayRef< const MemRegion * > ExplicitRegions, ArrayRef< const MemRegion * > Regions, const LocationContext *LCtx, const CallEvent *Call) const
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.
const RefVal * getRefBinding(ProgramStateRef State, SymbolRef Sym)
bool isSynthesizedAccessor(const StackFrameContext *SFC)
Returns true if this stack frame is for an Objective-C method that is a property getter or setter who...
llvm::DenseSet< SymbolRef > InvalidatedSymbols
Definition Store.h:51
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
};
const FunctionProtoType * T