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.
74 enum class IvarAccessHistory {
75 None,
78 };
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.
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.
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
196 }
197
201 }
202
207 }
208
213 }
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>(
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.
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)
Definition: ASTContext.h:3597
Expr * E
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
#define X(type, name)
Definition: Value.h:145
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
Symbolic value.
Definition: SymExpr.h:32
A class responsible for cleaning up unused symbols.
bool operator==(const RefVal &X) const
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.
bool hasSameState(const RefVal &X) const
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
const RefCountFrontend & getPreferredFrontend() 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...
ObjKind
Determines the object kind of a tracked object.
llvm::DenseSet< SymbolRef > InvalidatedSymbols
Definition: Store.h:51
The JSON file list parser is used to communicate input to InstallAPI.
const FunctionProtoType * T