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/STLExtras.h" |
40 | #include "llvm/ADT/SmallString.h" |
41 | #include "llvm/ADT/StringExtras.h" |
42 | #include <cstdarg> |
43 | #include <utility> |
44 | |
45 | namespace clang { |
46 | namespace ento { |
47 | namespace retaincountchecker { |
48 | |
49 | /// Metadata on reference. |
50 | class RefVal { |
51 | public: |
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. |
58 | ERROR_START, |
59 | ErrorDeallocNotOwned, // -dealloc called on non-owned object. |
60 | ErrorUseAfterRelease, // Object used after released. |
61 | ErrorReleaseNotOwned, // Release of an object that was not owned. |
62 | ERROR_LEAK_START, |
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. |
66 | ErrorOverAutorelease, |
67 | ErrorReturnedNotOwned |
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, |
76 | AccessedDirectly, |
77 | ReleasedAfterDirectAccess |
78 | }; |
79 | |
80 | private: |
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 | |
119 | public: |
120 | Kind getKind() const { return static_cast<Kind>(RawKind); } |
121 | |
122 | ObjKind getObjKind() const { |
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. |
147 | IvarAccessHistory getIvarAccessHistory() const { |
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, |
185 | getAutoreleaseCount(), getType(), getIvarAccessHistory()); |
186 | } |
187 | |
188 | RefVal operator+(size_t i) const { |
189 | return RefVal(getKind(), getObjKind(), getCount() + i, |
190 | getAutoreleaseCount(), getType(), getIvarAccessHistory()); |
191 | } |
192 | |
193 | RefVal operator^(Kind k) const { |
194 | return RefVal(k, getObjKind(), getCount(), getAutoreleaseCount(), |
195 | getType(), getIvarAccessHistory()); |
196 | } |
197 | |
198 | RefVal autorelease() const { |
199 | return RefVal(getKind(), getObjKind(), getCount(), getAutoreleaseCount()+1, |
200 | getType(), getIvarAccessHistory()); |
201 | } |
202 | |
203 | RefVal withIvarAccess() const { |
204 | assert(getIvarAccessHistory() == IvarAccessHistory::None); |
205 | return RefVal(getKind(), getObjKind(), getCount(), getAutoreleaseCount(), |
206 | getType(), IvarAccessHistory::AccessedDirectly); |
207 | } |
208 | |
209 | RefVal releaseViaIvar() const { |
210 | assert(getIvarAccessHistory() == IvarAccessHistory::AccessedDirectly); |
211 | return RefVal(getKind(), getObjKind(), getCount(), getAutoreleaseCount(), |
212 | getType(), IvarAccessHistory::ReleasedAfterDirectAccess); |
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(x: T); |
227 | ID.AddInteger(I: RawKind); |
228 | ID.AddInteger(I: Cnt); |
229 | ID.AddInteger(I: ACnt); |
230 | ID.AddInteger(I: RawObjectKind); |
231 | ID.AddInteger(I: RawIvarAccessHistory); |
232 | } |
233 | |
234 | void print(raw_ostream &Out) const; |
235 | }; |
236 | |
237 | class RetainCountChecker |
238 | : public Checker< check::Bind, |
239 | check::DeadSymbols, |
240 | check::BeginFunction, |
241 | check::EndFunction, |
242 | check::PostStmt<BlockExpr>, |
243 | check::PostStmt<CastExpr>, |
244 | check::PostStmt<ObjCArrayLiteral>, |
245 | check::PostStmt<ObjCDictionaryLiteral>, |
246 | check::PostStmt<ObjCBoxedExpr>, |
247 | check::PostStmt<ObjCIvarRefExpr>, |
248 | check::PostCall, |
249 | check::RegionChanges, |
250 | eval::Assume, |
251 | eval::Call > { |
252 | |
253 | public: |
254 | std::unique_ptr<RefCountBug> UseAfterRelease; |
255 | std::unique_ptr<RefCountBug> ReleaseNotOwned; |
256 | std::unique_ptr<RefCountBug> DeallocNotOwned; |
257 | std::unique_ptr<RefCountBug> FreeNotOwned; |
258 | std::unique_ptr<RefCountBug> OverAutorelease; |
259 | std::unique_ptr<RefCountBug> ReturnNotOwnedForOwned; |
260 | std::unique_ptr<RefCountBug> LeakWithinFunction; |
261 | std::unique_ptr<RefCountBug> LeakAtReturn; |
262 | |
263 | mutable std::unique_ptr<RetainSummaryManager> Summaries; |
264 | |
265 | static std::unique_ptr<CheckerProgramPointTag> DeallocSentTag; |
266 | static std::unique_ptr<CheckerProgramPointTag> CastFailTag; |
267 | |
268 | /// Track Objective-C and CoreFoundation objects. |
269 | bool TrackObjCAndCFObjects = false; |
270 | |
271 | /// Track sublcasses of OSObject. |
272 | bool TrackOSObjects = false; |
273 | |
274 | /// Track initial parameters (for the entry point) for NS/CF objects. |
275 | bool TrackNSCFStartParam = false; |
276 | |
277 | RetainCountChecker() {}; |
278 | |
279 | RetainSummaryManager &getSummaryManager(ASTContext &Ctx) const { |
280 | if (!Summaries) |
281 | Summaries.reset( |
282 | p: new RetainSummaryManager(Ctx, TrackObjCAndCFObjects, TrackOSObjects)); |
283 | return *Summaries; |
284 | } |
285 | |
286 | RetainSummaryManager &getSummaryManager(CheckerContext &C) const { |
287 | return getSummaryManager(Ctx&: C.getASTContext()); |
288 | } |
289 | |
290 | void printState(raw_ostream &Out, ProgramStateRef State, |
291 | const char *NL, const char *Sep) const override; |
292 | |
293 | void checkBind(SVal loc, SVal val, const Stmt *S, CheckerContext &C) const; |
294 | void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const; |
295 | void checkPostStmt(const CastExpr *CE, CheckerContext &C) const; |
296 | |
297 | void checkPostStmt(const ObjCArrayLiteral *AL, CheckerContext &C) const; |
298 | void checkPostStmt(const ObjCDictionaryLiteral *DL, CheckerContext &C) const; |
299 | void checkPostStmt(const ObjCBoxedExpr *BE, CheckerContext &C) const; |
300 | |
301 | void checkPostStmt(const ObjCIvarRefExpr *IRE, CheckerContext &C) const; |
302 | |
303 | void checkPostCall(const CallEvent &Call, CheckerContext &C) const; |
304 | |
305 | void checkSummary(const RetainSummary &Summ, const CallEvent &Call, |
306 | CheckerContext &C) const; |
307 | |
308 | void processSummaryOfInlined(const RetainSummary &Summ, |
309 | const CallEvent &Call, |
310 | CheckerContext &C) const; |
311 | |
312 | bool evalCall(const CallEvent &Call, CheckerContext &C) const; |
313 | |
314 | ProgramStateRef evalAssume(ProgramStateRef state, SVal Cond, |
315 | bool Assumption) const; |
316 | |
317 | ProgramStateRef |
318 | checkRegionChanges(ProgramStateRef state, |
319 | const InvalidatedSymbols *invalidated, |
320 | ArrayRef<const MemRegion *> ExplicitRegions, |
321 | ArrayRef<const MemRegion *> Regions, |
322 | const LocationContext* LCtx, |
323 | const CallEvent *Call) const; |
324 | |
325 | ExplodedNode* checkReturnWithRetEffect(const ReturnStmt *S, CheckerContext &C, |
326 | ExplodedNode *Pred, RetEffect RE, RefVal X, |
327 | SymbolRef Sym, ProgramStateRef state) const; |
328 | |
329 | void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const; |
330 | void checkBeginFunction(CheckerContext &C) const; |
331 | void checkEndFunction(const ReturnStmt *RS, CheckerContext &C) const; |
332 | |
333 | ProgramStateRef updateSymbol(ProgramStateRef state, SymbolRef sym, |
334 | RefVal V, ArgEffect E, RefVal::Kind &hasErr, |
335 | CheckerContext &C) const; |
336 | |
337 | const RefCountBug &errorKindToBugKind(RefVal::Kind ErrorKind, |
338 | SymbolRef Sym) const; |
339 | |
340 | void processNonLeakError(ProgramStateRef St, SourceRange ErrorRange, |
341 | RefVal::Kind ErrorKind, SymbolRef Sym, |
342 | CheckerContext &C) const; |
343 | |
344 | void processObjCLiterals(CheckerContext &C, const Expr *Ex) const; |
345 | |
346 | ProgramStateRef handleSymbolDeath(ProgramStateRef state, |
347 | SymbolRef sid, RefVal V, |
348 | SmallVectorImpl<SymbolRef> &Leaked) const; |
349 | |
350 | ProgramStateRef |
351 | handleAutoreleaseCounts(ProgramStateRef state, ExplodedNode *Pred, |
352 | const ProgramPointTag *Tag, CheckerContext &Ctx, |
353 | SymbolRef Sym, |
354 | RefVal V, |
355 | const ReturnStmt *S=nullptr) const; |
356 | |
357 | ExplodedNode *processLeaks(ProgramStateRef state, |
358 | SmallVectorImpl<SymbolRef> &Leaked, |
359 | CheckerContext &Ctx, |
360 | ExplodedNode *Pred = nullptr) const; |
361 | |
362 | static const CheckerProgramPointTag &getDeallocSentTag() { |
363 | return *DeallocSentTag; |
364 | } |
365 | |
366 | static const CheckerProgramPointTag &getCastFailTag() { return *CastFailTag; } |
367 | |
368 | private: |
369 | /// Perform the necessary checks and state adjustments at the end of the |
370 | /// function. |
371 | /// \p S Return statement, may be null. |
372 | ExplodedNode * processReturn(const ReturnStmt *S, CheckerContext &C) const; |
373 | }; |
374 | |
375 | //===----------------------------------------------------------------------===// |
376 | // RefBindings - State used to track object reference counts. |
377 | //===----------------------------------------------------------------------===// |
378 | |
379 | const RefVal *getRefBinding(ProgramStateRef State, SymbolRef Sym); |
380 | |
381 | /// Returns true if this stack frame is for an Objective-C method that is a |
382 | /// property getter or setter whose body has been synthesized by the analyzer. |
383 | inline bool isSynthesizedAccessor(const StackFrameContext *SFC) { |
384 | auto Method = dyn_cast_or_null<ObjCMethodDecl>(Val: SFC->getDecl()); |
385 | if (!Method || !Method->isPropertyAccessor()) |
386 | return false; |
387 | |
388 | return SFC->getAnalysisDeclContext()->isBodyAutosynthesized(); |
389 | } |
390 | |
391 | } // end namespace retaincountchecker |
392 | } // end namespace ento |
393 | } // end namespace clang |
394 | |
395 | #endif |
396 | |