File: | tools/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp |
Warning: | line 164, column 26 Returning null reference |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | //===- CheckerManager.cpp - Static Analyzer Checker Manager ---------------===// | |||
2 | // | |||
3 | // The LLVM Compiler Infrastructure | |||
4 | // | |||
5 | // This file is distributed under the University of Illinois Open Source | |||
6 | // License. See LICENSE.TXT for details. | |||
7 | // | |||
8 | //===----------------------------------------------------------------------===// | |||
9 | // | |||
10 | // Defines the Static Analyzer Checker Manager. | |||
11 | // | |||
12 | //===----------------------------------------------------------------------===// | |||
13 | ||||
14 | #include "clang/StaticAnalyzer/Core/CheckerManager.h" | |||
15 | #include "clang/AST/DeclBase.h" | |||
16 | #include "clang/AST/Stmt.h" | |||
17 | #include "clang/Analysis/ProgramPoint.h" | |||
18 | #include "clang/Basic/LLVM.h" | |||
19 | #include "clang/StaticAnalyzer/Core/Checker.h" | |||
20 | #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" | |||
21 | #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" | |||
22 | #include "clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h" | |||
23 | #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" | |||
24 | #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" | |||
25 | #include "llvm/ADT/SmallVector.h" | |||
26 | #include "llvm/Support/Casting.h" | |||
27 | #include "llvm/Support/ErrorHandling.h" | |||
28 | #include <cassert> | |||
29 | #include <vector> | |||
30 | ||||
31 | using namespace clang; | |||
32 | using namespace ento; | |||
33 | ||||
34 | bool CheckerManager::hasPathSensitiveCheckers() const { | |||
35 | return !StmtCheckers.empty() || | |||
36 | !PreObjCMessageCheckers.empty() || | |||
37 | !PostObjCMessageCheckers.empty() || | |||
38 | !PreCallCheckers.empty() || | |||
39 | !PostCallCheckers.empty() || | |||
40 | !LocationCheckers.empty() || | |||
41 | !BindCheckers.empty() || | |||
42 | !EndAnalysisCheckers.empty() || | |||
43 | !EndFunctionCheckers.empty() || | |||
44 | !BranchConditionCheckers.empty() || | |||
45 | !LiveSymbolsCheckers.empty() || | |||
46 | !DeadSymbolsCheckers.empty() || | |||
47 | !RegionChangesCheckers.empty() || | |||
48 | !EvalAssumeCheckers.empty() || | |||
49 | !EvalCallCheckers.empty(); | |||
50 | } | |||
51 | ||||
52 | void CheckerManager::finishedCheckerRegistration() { | |||
53 | #ifndef NDEBUG | |||
54 | // Make sure that for every event that has listeners, there is at least | |||
55 | // one dispatcher registered for it. | |||
56 | for (const auto &Event : Events) | |||
57 | assert(Event.second.HasDispatcher &&(static_cast <bool> (Event.second.HasDispatcher && "No dispatcher registered for an event") ? void (0) : __assert_fail ("Event.second.HasDispatcher && \"No dispatcher registered for an event\"" , "/build/llvm-toolchain-snapshot-7~svn326551/tools/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp" , 58, __extension__ __PRETTY_FUNCTION__)) | |||
58 | "No dispatcher registered for an event")(static_cast <bool> (Event.second.HasDispatcher && "No dispatcher registered for an event") ? void (0) : __assert_fail ("Event.second.HasDispatcher && \"No dispatcher registered for an event\"" , "/build/llvm-toolchain-snapshot-7~svn326551/tools/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp" , 58, __extension__ __PRETTY_FUNCTION__)); | |||
59 | #endif | |||
60 | } | |||
61 | ||||
62 | //===----------------------------------------------------------------------===// | |||
63 | // Functions for running checkers for AST traversing.. | |||
64 | //===----------------------------------------------------------------------===// | |||
65 | ||||
66 | void CheckerManager::runCheckersOnASTDecl(const Decl *D, AnalysisManager& mgr, | |||
67 | BugReporter &BR) { | |||
68 | assert(D)(static_cast <bool> (D) ? void (0) : __assert_fail ("D" , "/build/llvm-toolchain-snapshot-7~svn326551/tools/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp" , 68, __extension__ __PRETTY_FUNCTION__)); | |||
69 | ||||
70 | unsigned DeclKind = D->getKind(); | |||
71 | CachedDeclCheckers *checkers = nullptr; | |||
72 | CachedDeclCheckersMapTy::iterator CCI = CachedDeclCheckersMap.find(DeclKind); | |||
73 | if (CCI != CachedDeclCheckersMap.end()) { | |||
74 | checkers = &(CCI->second); | |||
75 | } else { | |||
76 | // Find the checkers that should run for this Decl and cache them. | |||
77 | checkers = &CachedDeclCheckersMap[DeclKind]; | |||
78 | for (const auto &info : DeclCheckers) | |||
79 | if (info.IsForDeclFn(D)) | |||
80 | checkers->push_back(info.CheckFn); | |||
81 | } | |||
82 | ||||
83 | assert(checkers)(static_cast <bool> (checkers) ? void (0) : __assert_fail ("checkers", "/build/llvm-toolchain-snapshot-7~svn326551/tools/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp" , 83, __extension__ __PRETTY_FUNCTION__)); | |||
84 | for (const auto checker : *checkers) | |||
85 | checker(D, mgr, BR); | |||
86 | } | |||
87 | ||||
88 | void CheckerManager::runCheckersOnASTBody(const Decl *D, AnalysisManager& mgr, | |||
89 | BugReporter &BR) { | |||
90 | assert(D && D->hasBody())(static_cast <bool> (D && D->hasBody()) ? void (0) : __assert_fail ("D && D->hasBody()", "/build/llvm-toolchain-snapshot-7~svn326551/tools/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp" , 90, __extension__ __PRETTY_FUNCTION__)); | |||
91 | ||||
92 | for (const auto BodyChecker : BodyCheckers) | |||
93 | BodyChecker(D, mgr, BR); | |||
94 | } | |||
95 | ||||
96 | //===----------------------------------------------------------------------===// | |||
97 | // Functions for running checkers for path-sensitive checking. | |||
98 | //===----------------------------------------------------------------------===// | |||
99 | ||||
100 | template <typename CHECK_CTX> | |||
101 | static void expandGraphWithCheckers(CHECK_CTX checkCtx, | |||
102 | ExplodedNodeSet &Dst, | |||
103 | const ExplodedNodeSet &Src) { | |||
104 | const NodeBuilderContext &BldrCtx = checkCtx.Eng.getBuilderContext(); | |||
105 | if (Src.empty()) | |||
106 | return; | |||
107 | ||||
108 | typename CHECK_CTX::CheckersTy::const_iterator | |||
109 | I = checkCtx.checkers_begin(), E = checkCtx.checkers_end(); | |||
110 | if (I == E) { | |||
111 | Dst.insert(Src); | |||
112 | return; | |||
113 | } | |||
114 | ||||
115 | ExplodedNodeSet Tmp1, Tmp2; | |||
116 | const ExplodedNodeSet *PrevSet = &Src; | |||
117 | ||||
118 | for (; I != E; ++I) { | |||
119 | ExplodedNodeSet *CurrSet = nullptr; | |||
120 | if (I+1 == E) | |||
121 | CurrSet = &Dst; | |||
122 | else { | |||
123 | CurrSet = (PrevSet == &Tmp1) ? &Tmp2 : &Tmp1; | |||
124 | CurrSet->clear(); | |||
125 | } | |||
126 | ||||
127 | NodeBuilder B(*PrevSet, *CurrSet, BldrCtx); | |||
128 | for (const auto &NI : *PrevSet) | |||
129 | checkCtx.runChecker(*I, B, NI); | |||
130 | ||||
131 | // If all the produced transitions are sinks, stop. | |||
132 | if (CurrSet->empty()) | |||
133 | return; | |||
134 | ||||
135 | // Update which NodeSet is the current one. | |||
136 | PrevSet = CurrSet; | |||
137 | } | |||
138 | } | |||
139 | ||||
140 | namespace { | |||
141 | ||||
142 | struct CheckStmtContext { | |||
143 | using CheckersTy = SmallVectorImpl<CheckerManager::CheckStmtFunc>; | |||
144 | ||||
145 | bool IsPreVisit; | |||
146 | const CheckersTy &Checkers; | |||
147 | const Stmt *S; | |||
148 | ExprEngine &Eng; | |||
149 | bool WasInlined; | |||
150 | ||||
151 | CheckStmtContext(bool isPreVisit, const CheckersTy &checkers, | |||
152 | const Stmt *s, ExprEngine &eng, bool wasInlined = false) | |||
153 | : IsPreVisit(isPreVisit), Checkers(checkers), S(s), Eng(eng), | |||
154 | WasInlined(wasInlined) {} | |||
155 | ||||
156 | CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } | |||
157 | CheckersTy::const_iterator checkers_end() { return Checkers.end(); } | |||
158 | ||||
159 | void runChecker(CheckerManager::CheckStmtFunc checkFn, | |||
160 | NodeBuilder &Bldr, ExplodedNode *Pred) { | |||
161 | // FIXME: Remove respondsToCallback from CheckerContext; | |||
162 | ProgramPoint::Kind K = IsPreVisit ? ProgramPoint::PreStmtKind : | |||
163 | ProgramPoint::PostStmtKind; | |||
164 | const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K, | |||
165 | Pred->getLocationContext(), checkFn.Checker); | |||
166 | CheckerContext C(Bldr, Eng, Pred, L, WasInlined); | |||
167 | checkFn(S, C); | |||
168 | } | |||
169 | }; | |||
170 | ||||
171 | } // namespace | |||
172 | ||||
173 | /// \brief Run checkers for visiting Stmts. | |||
174 | void CheckerManager::runCheckersForStmt(bool isPreVisit, | |||
175 | ExplodedNodeSet &Dst, | |||
176 | const ExplodedNodeSet &Src, | |||
177 | const Stmt *S, | |||
178 | ExprEngine &Eng, | |||
179 | bool WasInlined) { | |||
180 | CheckStmtContext C(isPreVisit, getCachedStmtCheckersFor(S, isPreVisit), | |||
181 | S, Eng, WasInlined); | |||
182 | expandGraphWithCheckers(C, Dst, Src); | |||
183 | } | |||
184 | ||||
185 | namespace { | |||
186 | ||||
187 | struct CheckObjCMessageContext { | |||
188 | using CheckersTy = std::vector<CheckerManager::CheckObjCMessageFunc>; | |||
189 | ||||
190 | ObjCMessageVisitKind Kind; | |||
191 | bool WasInlined; | |||
192 | const CheckersTy &Checkers; | |||
193 | const ObjCMethodCall &Msg; | |||
194 | ExprEngine &Eng; | |||
195 | ||||
196 | CheckObjCMessageContext(ObjCMessageVisitKind visitKind, | |||
197 | const CheckersTy &checkers, | |||
198 | const ObjCMethodCall &msg, ExprEngine &eng, | |||
199 | bool wasInlined) | |||
200 | : Kind(visitKind), WasInlined(wasInlined), Checkers(checkers), Msg(msg), | |||
201 | Eng(eng) {} | |||
202 | ||||
203 | CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } | |||
204 | CheckersTy::const_iterator checkers_end() { return Checkers.end(); } | |||
205 | ||||
206 | void runChecker(CheckerManager::CheckObjCMessageFunc checkFn, | |||
207 | NodeBuilder &Bldr, ExplodedNode *Pred) { | |||
208 | bool IsPreVisit; | |||
209 | ||||
210 | switch (Kind) { | |||
211 | case ObjCMessageVisitKind::Pre: | |||
212 | IsPreVisit = true; | |||
213 | break; | |||
214 | case ObjCMessageVisitKind::MessageNil: | |||
215 | case ObjCMessageVisitKind::Post: | |||
216 | IsPreVisit = false; | |||
217 | break; | |||
218 | } | |||
219 | ||||
220 | const ProgramPoint &L = Msg.getProgramPoint(IsPreVisit,checkFn.Checker); | |||
221 | CheckerContext C(Bldr, Eng, Pred, L, WasInlined); | |||
222 | ||||
223 | checkFn(*Msg.cloneWithState<ObjCMethodCall>(Pred->getState()), C); | |||
224 | } | |||
225 | }; | |||
226 | ||||
227 | } // namespace | |||
228 | ||||
229 | /// \brief Run checkers for visiting obj-c messages. | |||
230 | void CheckerManager::runCheckersForObjCMessage(ObjCMessageVisitKind visitKind, | |||
231 | ExplodedNodeSet &Dst, | |||
232 | const ExplodedNodeSet &Src, | |||
233 | const ObjCMethodCall &msg, | |||
234 | ExprEngine &Eng, | |||
235 | bool WasInlined) { | |||
236 | auto &checkers = getObjCMessageCheckers(visitKind); | |||
237 | CheckObjCMessageContext C(visitKind, checkers, msg, Eng, WasInlined); | |||
238 | expandGraphWithCheckers(C, Dst, Src); | |||
239 | } | |||
240 | ||||
241 | const std::vector<CheckerManager::CheckObjCMessageFunc> & | |||
242 | CheckerManager::getObjCMessageCheckers(ObjCMessageVisitKind Kind) { | |||
243 | switch (Kind) { | |||
244 | case ObjCMessageVisitKind::Pre: | |||
245 | return PreObjCMessageCheckers; | |||
246 | break; | |||
247 | case ObjCMessageVisitKind::Post: | |||
248 | return PostObjCMessageCheckers; | |||
249 | case ObjCMessageVisitKind::MessageNil: | |||
250 | return ObjCMessageNilCheckers; | |||
251 | } | |||
252 | llvm_unreachable("Unknown Kind")::llvm::llvm_unreachable_internal("Unknown Kind", "/build/llvm-toolchain-snapshot-7~svn326551/tools/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp" , 252); | |||
253 | } | |||
254 | ||||
255 | namespace { | |||
256 | ||||
257 | // FIXME: This has all the same signatures as CheckObjCMessageContext. | |||
258 | // Is there a way we can merge the two? | |||
259 | struct CheckCallContext { | |||
260 | using CheckersTy = std::vector<CheckerManager::CheckCallFunc>; | |||
261 | ||||
262 | bool IsPreVisit, WasInlined; | |||
263 | const CheckersTy &Checkers; | |||
264 | const CallEvent &Call; | |||
265 | ExprEngine &Eng; | |||
266 | ||||
267 | CheckCallContext(bool isPreVisit, const CheckersTy &checkers, | |||
268 | const CallEvent &call, ExprEngine &eng, | |||
269 | bool wasInlined) | |||
270 | : IsPreVisit(isPreVisit), WasInlined(wasInlined), Checkers(checkers), | |||
271 | Call(call), Eng(eng) {} | |||
272 | ||||
273 | CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } | |||
274 | CheckersTy::const_iterator checkers_end() { return Checkers.end(); } | |||
275 | ||||
276 | void runChecker(CheckerManager::CheckCallFunc checkFn, | |||
277 | NodeBuilder &Bldr, ExplodedNode *Pred) { | |||
278 | const ProgramPoint &L = Call.getProgramPoint(IsPreVisit,checkFn.Checker); | |||
279 | CheckerContext C(Bldr, Eng, Pred, L, WasInlined); | |||
280 | ||||
281 | checkFn(*Call.cloneWithState(Pred->getState()), C); | |||
282 | } | |||
283 | }; | |||
284 | ||||
285 | } // namespace | |||
286 | ||||
287 | /// \brief Run checkers for visiting an abstract call event. | |||
288 | void CheckerManager::runCheckersForCallEvent(bool isPreVisit, | |||
289 | ExplodedNodeSet &Dst, | |||
290 | const ExplodedNodeSet &Src, | |||
291 | const CallEvent &Call, | |||
292 | ExprEngine &Eng, | |||
293 | bool WasInlined) { | |||
294 | CheckCallContext C(isPreVisit, | |||
295 | isPreVisit ? PreCallCheckers | |||
| ||||
296 | : PostCallCheckers, | |||
297 | Call, Eng, WasInlined); | |||
298 | expandGraphWithCheckers(C, Dst, Src); | |||
299 | } | |||
300 | ||||
301 | namespace { | |||
302 | ||||
303 | struct CheckLocationContext { | |||
304 | using CheckersTy = std::vector<CheckerManager::CheckLocationFunc>; | |||
305 | ||||
306 | const CheckersTy &Checkers; | |||
307 | SVal Loc; | |||
308 | bool IsLoad; | |||
309 | const Stmt *NodeEx; /* Will become a CFGStmt */ | |||
310 | const Stmt *BoundEx; | |||
311 | ExprEngine &Eng; | |||
312 | ||||
313 | CheckLocationContext(const CheckersTy &checkers, | |||
314 | SVal loc, bool isLoad, const Stmt *NodeEx, | |||
315 | const Stmt *BoundEx, | |||
316 | ExprEngine &eng) | |||
317 | : Checkers(checkers), Loc(loc), IsLoad(isLoad), NodeEx(NodeEx), | |||
318 | BoundEx(BoundEx), Eng(eng) {} | |||
319 | ||||
320 | CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } | |||
321 | CheckersTy::const_iterator checkers_end() { return Checkers.end(); } | |||
322 | ||||
323 | void runChecker(CheckerManager::CheckLocationFunc checkFn, | |||
324 | NodeBuilder &Bldr, ExplodedNode *Pred) { | |||
325 | ProgramPoint::Kind K = IsLoad ? ProgramPoint::PreLoadKind : | |||
326 | ProgramPoint::PreStoreKind; | |||
327 | const ProgramPoint &L = | |||
328 | ProgramPoint::getProgramPoint(NodeEx, K, | |||
329 | Pred->getLocationContext(), | |||
330 | checkFn.Checker); | |||
331 | CheckerContext C(Bldr, Eng, Pred, L); | |||
332 | checkFn(Loc, IsLoad, BoundEx, C); | |||
333 | } | |||
334 | }; | |||
335 | ||||
336 | } // namespace | |||
337 | ||||
338 | /// \brief Run checkers for load/store of a location. | |||
339 | ||||
340 | void CheckerManager::runCheckersForLocation(ExplodedNodeSet &Dst, | |||
341 | const ExplodedNodeSet &Src, | |||
342 | SVal location, bool isLoad, | |||
343 | const Stmt *NodeEx, | |||
344 | const Stmt *BoundEx, | |||
345 | ExprEngine &Eng) { | |||
346 | CheckLocationContext C(LocationCheckers, location, isLoad, NodeEx, | |||
347 | BoundEx, Eng); | |||
348 | expandGraphWithCheckers(C, Dst, Src); | |||
349 | } | |||
350 | ||||
351 | namespace { | |||
352 | ||||
353 | struct CheckBindContext { | |||
354 | using CheckersTy = std::vector<CheckerManager::CheckBindFunc>; | |||
355 | ||||
356 | const CheckersTy &Checkers; | |||
357 | SVal Loc; | |||
358 | SVal Val; | |||
359 | const Stmt *S; | |||
360 | ExprEngine &Eng; | |||
361 | const ProgramPoint &PP; | |||
362 | ||||
363 | CheckBindContext(const CheckersTy &checkers, | |||
364 | SVal loc, SVal val, const Stmt *s, ExprEngine &eng, | |||
365 | const ProgramPoint &pp) | |||
366 | : Checkers(checkers), Loc(loc), Val(val), S(s), Eng(eng), PP(pp) {} | |||
367 | ||||
368 | CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } | |||
369 | CheckersTy::const_iterator checkers_end() { return Checkers.end(); } | |||
370 | ||||
371 | void runChecker(CheckerManager::CheckBindFunc checkFn, | |||
372 | NodeBuilder &Bldr, ExplodedNode *Pred) { | |||
373 | const ProgramPoint &L = PP.withTag(checkFn.Checker); | |||
374 | CheckerContext C(Bldr, Eng, Pred, L); | |||
375 | ||||
376 | checkFn(Loc, Val, S, C); | |||
377 | } | |||
378 | }; | |||
379 | ||||
380 | } // namespace | |||
381 | ||||
382 | /// \brief Run checkers for binding of a value to a location. | |||
383 | void CheckerManager::runCheckersForBind(ExplodedNodeSet &Dst, | |||
384 | const ExplodedNodeSet &Src, | |||
385 | SVal location, SVal val, | |||
386 | const Stmt *S, ExprEngine &Eng, | |||
387 | const ProgramPoint &PP) { | |||
388 | CheckBindContext C(BindCheckers, location, val, S, Eng, PP); | |||
389 | expandGraphWithCheckers(C, Dst, Src); | |||
390 | } | |||
391 | ||||
392 | void CheckerManager::runCheckersForEndAnalysis(ExplodedGraph &G, | |||
393 | BugReporter &BR, | |||
394 | ExprEngine &Eng) { | |||
395 | for (const auto EndAnalysisChecker : EndAnalysisCheckers) | |||
396 | EndAnalysisChecker(G, BR, Eng); | |||
397 | } | |||
398 | ||||
399 | namespace { | |||
400 | ||||
401 | struct CheckBeginFunctionContext { | |||
402 | using CheckersTy = std::vector<CheckerManager::CheckBeginFunctionFunc>; | |||
403 | ||||
404 | const CheckersTy &Checkers; | |||
405 | ExprEngine &Eng; | |||
406 | const ProgramPoint &PP; | |||
407 | ||||
408 | CheckBeginFunctionContext(const CheckersTy &Checkers, ExprEngine &Eng, | |||
409 | const ProgramPoint &PP) | |||
410 | : Checkers(Checkers), Eng(Eng), PP(PP) {} | |||
411 | ||||
412 | CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } | |||
413 | CheckersTy::const_iterator checkers_end() { return Checkers.end(); } | |||
414 | ||||
415 | void runChecker(CheckerManager::CheckBeginFunctionFunc checkFn, | |||
416 | NodeBuilder &Bldr, ExplodedNode *Pred) { | |||
417 | const ProgramPoint &L = PP.withTag(checkFn.Checker); | |||
418 | CheckerContext C(Bldr, Eng, Pred, L); | |||
419 | ||||
420 | checkFn(C); | |||
421 | } | |||
422 | }; | |||
423 | ||||
424 | } // namespace | |||
425 | ||||
426 | void CheckerManager::runCheckersForBeginFunction(ExplodedNodeSet &Dst, | |||
427 | const BlockEdge &L, | |||
428 | ExplodedNode *Pred, | |||
429 | ExprEngine &Eng) { | |||
430 | ExplodedNodeSet Src; | |||
431 | Src.insert(Pred); | |||
432 | CheckBeginFunctionContext C(BeginFunctionCheckers, Eng, L); | |||
433 | expandGraphWithCheckers(C, Dst, Src); | |||
434 | } | |||
435 | ||||
436 | /// \brief Run checkers for end of path. | |||
437 | // Note, We do not chain the checker output (like in expandGraphWithCheckers) | |||
438 | // for this callback since end of path nodes are expected to be final. | |||
439 | void CheckerManager::runCheckersForEndFunction(NodeBuilderContext &BC, | |||
440 | ExplodedNodeSet &Dst, | |||
441 | ExplodedNode *Pred, | |||
442 | ExprEngine &Eng) { | |||
443 | // We define the builder outside of the loop bacause if at least one checkers | |||
444 | // creates a sucsessor for Pred, we do not need to generate an | |||
445 | // autotransition for it. | |||
446 | NodeBuilder Bldr(Pred, Dst, BC); | |||
447 | for (const auto checkFn : EndFunctionCheckers) { | |||
448 | const ProgramPoint &L = BlockEntrance(BC.Block, | |||
449 | Pred->getLocationContext(), | |||
450 | checkFn.Checker); | |||
451 | CheckerContext C(Bldr, Eng, Pred, L); | |||
452 | checkFn(C); | |||
453 | } | |||
454 | } | |||
455 | ||||
456 | namespace { | |||
457 | ||||
458 | struct CheckBranchConditionContext { | |||
459 | using CheckersTy = std::vector<CheckerManager::CheckBranchConditionFunc>; | |||
460 | ||||
461 | const CheckersTy &Checkers; | |||
462 | const Stmt *Condition; | |||
463 | ExprEngine &Eng; | |||
464 | ||||
465 | CheckBranchConditionContext(const CheckersTy &checkers, | |||
466 | const Stmt *Cond, ExprEngine &eng) | |||
467 | : Checkers(checkers), Condition(Cond), Eng(eng) {} | |||
468 | ||||
469 | CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } | |||
470 | CheckersTy::const_iterator checkers_end() { return Checkers.end(); } | |||
471 | ||||
472 | void runChecker(CheckerManager::CheckBranchConditionFunc checkFn, | |||
473 | NodeBuilder &Bldr, ExplodedNode *Pred) { | |||
474 | ProgramPoint L = PostCondition(Condition, Pred->getLocationContext(), | |||
475 | checkFn.Checker); | |||
476 | CheckerContext C(Bldr, Eng, Pred, L); | |||
477 | checkFn(Condition, C); | |||
478 | } | |||
479 | }; | |||
480 | ||||
481 | } // namespace | |||
482 | ||||
483 | /// \brief Run checkers for branch condition. | |||
484 | void CheckerManager::runCheckersForBranchCondition(const Stmt *Condition, | |||
485 | ExplodedNodeSet &Dst, | |||
486 | ExplodedNode *Pred, | |||
487 | ExprEngine &Eng) { | |||
488 | ExplodedNodeSet Src; | |||
489 | Src.insert(Pred); | |||
490 | CheckBranchConditionContext C(BranchConditionCheckers, Condition, Eng); | |||
491 | expandGraphWithCheckers(C, Dst, Src); | |||
492 | } | |||
493 | ||||
494 | namespace { | |||
495 | ||||
496 | struct CheckNewAllocatorContext { | |||
497 | using CheckersTy = std::vector<CheckerManager::CheckNewAllocatorFunc>; | |||
498 | ||||
499 | const CheckersTy &Checkers; | |||
500 | const CXXNewExpr *NE; | |||
501 | SVal Target; | |||
502 | bool WasInlined; | |||
503 | ExprEngine &Eng; | |||
504 | ||||
505 | CheckNewAllocatorContext(const CheckersTy &Checkers, const CXXNewExpr *NE, | |||
506 | SVal Target, bool WasInlined, ExprEngine &Eng) | |||
507 | : Checkers(Checkers), NE(NE), Target(Target), WasInlined(WasInlined), | |||
508 | Eng(Eng) {} | |||
509 | ||||
510 | CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } | |||
511 | CheckersTy::const_iterator checkers_end() { return Checkers.end(); } | |||
512 | ||||
513 | void runChecker(CheckerManager::CheckNewAllocatorFunc checkFn, | |||
514 | NodeBuilder &Bldr, ExplodedNode *Pred) { | |||
515 | ProgramPoint L = PostAllocatorCall(NE, Pred->getLocationContext()); | |||
516 | CheckerContext C(Bldr, Eng, Pred, L, WasInlined); | |||
517 | checkFn(NE, Target, C); | |||
518 | } | |||
519 | }; | |||
520 | ||||
521 | } // namespace | |||
522 | ||||
523 | void CheckerManager::runCheckersForNewAllocator( | |||
524 | const CXXNewExpr *NE, SVal Target, ExplodedNodeSet &Dst, ExplodedNode *Pred, | |||
525 | ExprEngine &Eng, bool WasInlined) { | |||
526 | ExplodedNodeSet Src; | |||
527 | Src.insert(Pred); | |||
528 | CheckNewAllocatorContext C(NewAllocatorCheckers, NE, Target, WasInlined, Eng); | |||
529 | expandGraphWithCheckers(C, Dst, Src); | |||
530 | } | |||
531 | ||||
532 | /// \brief Run checkers for live symbols. | |||
533 | void CheckerManager::runCheckersForLiveSymbols(ProgramStateRef state, | |||
534 | SymbolReaper &SymReaper) { | |||
535 | for (const auto LiveSymbolsChecker : LiveSymbolsCheckers) | |||
536 | LiveSymbolsChecker(state, SymReaper); | |||
537 | } | |||
538 | ||||
539 | namespace { | |||
540 | ||||
541 | struct CheckDeadSymbolsContext { | |||
542 | using CheckersTy = std::vector<CheckerManager::CheckDeadSymbolsFunc>; | |||
543 | ||||
544 | const CheckersTy &Checkers; | |||
545 | SymbolReaper &SR; | |||
546 | const Stmt *S; | |||
547 | ExprEngine &Eng; | |||
548 | ProgramPoint::Kind ProgarmPointKind; | |||
549 | ||||
550 | CheckDeadSymbolsContext(const CheckersTy &checkers, SymbolReaper &sr, | |||
551 | const Stmt *s, ExprEngine &eng, | |||
552 | ProgramPoint::Kind K) | |||
553 | : Checkers(checkers), SR(sr), S(s), Eng(eng), ProgarmPointKind(K) {} | |||
554 | ||||
555 | CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } | |||
556 | CheckersTy::const_iterator checkers_end() { return Checkers.end(); } | |||
557 | ||||
558 | void runChecker(CheckerManager::CheckDeadSymbolsFunc checkFn, | |||
559 | NodeBuilder &Bldr, ExplodedNode *Pred) { | |||
560 | const ProgramPoint &L = ProgramPoint::getProgramPoint(S, ProgarmPointKind, | |||
561 | Pred->getLocationContext(), checkFn.Checker); | |||
562 | CheckerContext C(Bldr, Eng, Pred, L); | |||
563 | ||||
564 | // Note, do not pass the statement to the checkers without letting them | |||
565 | // differentiate if we ran remove dead bindings before or after the | |||
566 | // statement. | |||
567 | checkFn(SR, C); | |||
568 | } | |||
569 | }; | |||
570 | ||||
571 | } // namespace | |||
572 | ||||
573 | /// \brief Run checkers for dead symbols. | |||
574 | void CheckerManager::runCheckersForDeadSymbols(ExplodedNodeSet &Dst, | |||
575 | const ExplodedNodeSet &Src, | |||
576 | SymbolReaper &SymReaper, | |||
577 | const Stmt *S, | |||
578 | ExprEngine &Eng, | |||
579 | ProgramPoint::Kind K) { | |||
580 | CheckDeadSymbolsContext C(DeadSymbolsCheckers, SymReaper, S, Eng, K); | |||
581 | expandGraphWithCheckers(C, Dst, Src); | |||
582 | } | |||
583 | ||||
584 | /// \brief Run checkers for region changes. | |||
585 | ProgramStateRef | |||
586 | CheckerManager::runCheckersForRegionChanges(ProgramStateRef state, | |||
587 | const InvalidatedSymbols *invalidated, | |||
588 | ArrayRef<const MemRegion *> ExplicitRegions, | |||
589 | ArrayRef<const MemRegion *> Regions, | |||
590 | const LocationContext *LCtx, | |||
591 | const CallEvent *Call) { | |||
592 | for (const auto RegionChangesChecker : RegionChangesCheckers) { | |||
593 | // If any checker declares the state infeasible (or if it starts that way), | |||
594 | // bail out. | |||
595 | if (!state) | |||
596 | return nullptr; | |||
597 | state = RegionChangesChecker(state, invalidated, ExplicitRegions, Regions, | |||
598 | LCtx, Call); | |||
599 | } | |||
600 | return state; | |||
601 | } | |||
602 | ||||
603 | /// \brief Run checkers to process symbol escape event. | |||
604 | ProgramStateRef | |||
605 | CheckerManager::runCheckersForPointerEscape(ProgramStateRef State, | |||
606 | const InvalidatedSymbols &Escaped, | |||
607 | const CallEvent *Call, | |||
608 | PointerEscapeKind Kind, | |||
609 | RegionAndSymbolInvalidationTraits *ETraits) { | |||
610 | assert((Call != nullptr ||(static_cast <bool> ((Call != nullptr || (Kind != PSK_DirectEscapeOnCall && Kind != PSK_IndirectEscapeOnCall)) && "Call must not be NULL when escaping on call" ) ? void (0) : __assert_fail ("(Call != nullptr || (Kind != PSK_DirectEscapeOnCall && Kind != PSK_IndirectEscapeOnCall)) && \"Call must not be NULL when escaping on call\"" , "/build/llvm-toolchain-snapshot-7~svn326551/tools/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp" , 613, __extension__ __PRETTY_FUNCTION__)) | |||
611 | (Kind != PSK_DirectEscapeOnCall &&(static_cast <bool> ((Call != nullptr || (Kind != PSK_DirectEscapeOnCall && Kind != PSK_IndirectEscapeOnCall)) && "Call must not be NULL when escaping on call" ) ? void (0) : __assert_fail ("(Call != nullptr || (Kind != PSK_DirectEscapeOnCall && Kind != PSK_IndirectEscapeOnCall)) && \"Call must not be NULL when escaping on call\"" , "/build/llvm-toolchain-snapshot-7~svn326551/tools/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp" , 613, __extension__ __PRETTY_FUNCTION__)) | |||
612 | Kind != PSK_IndirectEscapeOnCall)) &&(static_cast <bool> ((Call != nullptr || (Kind != PSK_DirectEscapeOnCall && Kind != PSK_IndirectEscapeOnCall)) && "Call must not be NULL when escaping on call" ) ? void (0) : __assert_fail ("(Call != nullptr || (Kind != PSK_DirectEscapeOnCall && Kind != PSK_IndirectEscapeOnCall)) && \"Call must not be NULL when escaping on call\"" , "/build/llvm-toolchain-snapshot-7~svn326551/tools/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp" , 613, __extension__ __PRETTY_FUNCTION__)) | |||
613 | "Call must not be NULL when escaping on call")(static_cast <bool> ((Call != nullptr || (Kind != PSK_DirectEscapeOnCall && Kind != PSK_IndirectEscapeOnCall)) && "Call must not be NULL when escaping on call" ) ? void (0) : __assert_fail ("(Call != nullptr || (Kind != PSK_DirectEscapeOnCall && Kind != PSK_IndirectEscapeOnCall)) && \"Call must not be NULL when escaping on call\"" , "/build/llvm-toolchain-snapshot-7~svn326551/tools/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp" , 613, __extension__ __PRETTY_FUNCTION__)); | |||
614 | for (const auto PointerEscapeChecker : PointerEscapeCheckers) { | |||
615 | // If any checker declares the state infeasible (or if it starts that | |||
616 | // way), bail out. | |||
617 | if (!State) | |||
618 | return nullptr; | |||
619 | State = PointerEscapeChecker(State, Escaped, Call, Kind, ETraits); | |||
620 | } | |||
621 | return State; | |||
622 | } | |||
623 | ||||
624 | /// \brief Run checkers for handling assumptions on symbolic values. | |||
625 | ProgramStateRef | |||
626 | CheckerManager::runCheckersForEvalAssume(ProgramStateRef state, | |||
627 | SVal Cond, bool Assumption) { | |||
628 | for (const auto EvalAssumeChecker : EvalAssumeCheckers) { | |||
629 | // If any checker declares the state infeasible (or if it starts that way), | |||
630 | // bail out. | |||
631 | if (!state) | |||
632 | return nullptr; | |||
633 | state = EvalAssumeChecker(state, Cond, Assumption); | |||
634 | } | |||
635 | return state; | |||
636 | } | |||
637 | ||||
638 | /// \brief Run checkers for evaluating a call. | |||
639 | /// Only one checker will evaluate the call. | |||
640 | void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst, | |||
641 | const ExplodedNodeSet &Src, | |||
642 | const CallEvent &Call, | |||
643 | ExprEngine &Eng) { | |||
644 | const CallExpr *CE = cast<CallExpr>(Call.getOriginExpr()); | |||
645 | for (const auto Pred : Src) { | |||
646 | bool anyEvaluated = false; | |||
647 | ||||
648 | ExplodedNodeSet checkDst; | |||
649 | NodeBuilder B(Pred, checkDst, Eng.getBuilderContext()); | |||
650 | ||||
651 | // Check if any of the EvalCall callbacks can evaluate the call. | |||
652 | for (const auto EvalCallChecker : EvalCallCheckers) { | |||
653 | ProgramPoint::Kind K = ProgramPoint::PostStmtKind; | |||
654 | const ProgramPoint &L = | |||
655 | ProgramPoint::getProgramPoint(CE, K, Pred->getLocationContext(), | |||
656 | EvalCallChecker.Checker); | |||
657 | bool evaluated = false; | |||
658 | { // CheckerContext generates transitions(populates checkDest) on | |||
659 | // destruction, so introduce the scope to make sure it gets properly | |||
660 | // populated. | |||
661 | CheckerContext C(B, Eng, Pred, L); | |||
662 | evaluated = EvalCallChecker(CE, C); | |||
663 | } | |||
664 | assert(!(evaluated && anyEvaluated)(static_cast <bool> (!(evaluated && anyEvaluated ) && "There are more than one checkers evaluating the call" ) ? void (0) : __assert_fail ("!(evaluated && anyEvaluated) && \"There are more than one checkers evaluating the call\"" , "/build/llvm-toolchain-snapshot-7~svn326551/tools/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp" , 665, __extension__ __PRETTY_FUNCTION__)) | |||
665 | && "There are more than one checkers evaluating the call")(static_cast <bool> (!(evaluated && anyEvaluated ) && "There are more than one checkers evaluating the call" ) ? void (0) : __assert_fail ("!(evaluated && anyEvaluated) && \"There are more than one checkers evaluating the call\"" , "/build/llvm-toolchain-snapshot-7~svn326551/tools/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp" , 665, __extension__ __PRETTY_FUNCTION__)); | |||
666 | if (evaluated) { | |||
667 | anyEvaluated = true; | |||
668 | Dst.insert(checkDst); | |||
669 | #ifdef NDEBUG | |||
670 | break; // on release don't check that no other checker also evals. | |||
671 | #endif | |||
672 | } | |||
673 | } | |||
674 | ||||
675 | // If none of the checkers evaluated the call, ask ExprEngine to handle it. | |||
676 | if (!anyEvaluated) { | |||
677 | NodeBuilder B(Pred, Dst, Eng.getBuilderContext()); | |||
678 | Eng.defaultEvalCall(B, Pred, Call); | |||
679 | } | |||
680 | } | |||
681 | } | |||
682 | ||||
683 | /// \brief Run checkers for the entire Translation Unit. | |||
684 | void CheckerManager::runCheckersOnEndOfTranslationUnit( | |||
685 | const TranslationUnitDecl *TU, | |||
686 | AnalysisManager &mgr, | |||
687 | BugReporter &BR) { | |||
688 | for (const auto EndOfTranslationUnitChecker : EndOfTranslationUnitCheckers) | |||
689 | EndOfTranslationUnitChecker(TU, mgr, BR); | |||
690 | } | |||
691 | ||||
692 | void CheckerManager::runCheckersForPrintState(raw_ostream &Out, | |||
693 | ProgramStateRef State, | |||
694 | const char *NL, const char *Sep) { | |||
695 | for (const auto &CheckerTag : CheckerTags) | |||
696 | CheckerTag.second->printState(Out, State, NL, Sep); | |||
697 | } | |||
698 | ||||
699 | //===----------------------------------------------------------------------===// | |||
700 | // Internal registration functions for AST traversing. | |||
701 | //===----------------------------------------------------------------------===// | |||
702 | ||||
703 | void CheckerManager::_registerForDecl(CheckDeclFunc checkfn, | |||
704 | HandlesDeclFunc isForDeclFn) { | |||
705 | DeclCheckerInfo info = { checkfn, isForDeclFn }; | |||
706 | DeclCheckers.push_back(info); | |||
707 | } | |||
708 | ||||
709 | void CheckerManager::_registerForBody(CheckDeclFunc checkfn) { | |||
710 | BodyCheckers.push_back(checkfn); | |||
711 | } | |||
712 | ||||
713 | //===----------------------------------------------------------------------===// | |||
714 | // Internal registration functions for path-sensitive checking. | |||
715 | //===----------------------------------------------------------------------===// | |||
716 | ||||
717 | void CheckerManager::_registerForPreStmt(CheckStmtFunc checkfn, | |||
718 | HandlesStmtFunc isForStmtFn) { | |||
719 | StmtCheckerInfo info = { checkfn, isForStmtFn, /*IsPreVisit*/true }; | |||
720 | StmtCheckers.push_back(info); | |||
721 | } | |||
722 | ||||
723 | void CheckerManager::_registerForPostStmt(CheckStmtFunc checkfn, | |||
724 | HandlesStmtFunc isForStmtFn) { | |||
725 | StmtCheckerInfo info = { checkfn, isForStmtFn, /*IsPreVisit*/false }; | |||
726 | StmtCheckers.push_back(info); | |||
727 | } | |||
728 | ||||
729 | void CheckerManager::_registerForPreObjCMessage(CheckObjCMessageFunc checkfn) { | |||
730 | PreObjCMessageCheckers.push_back(checkfn); | |||
731 | } | |||
732 | ||||
733 | void CheckerManager::_registerForObjCMessageNil(CheckObjCMessageFunc checkfn) { | |||
734 | ObjCMessageNilCheckers.push_back(checkfn); | |||
735 | } | |||
736 | ||||
737 | void CheckerManager::_registerForPostObjCMessage(CheckObjCMessageFunc checkfn) { | |||
738 | PostObjCMessageCheckers.push_back(checkfn); | |||
739 | } | |||
740 | ||||
741 | void CheckerManager::_registerForPreCall(CheckCallFunc checkfn) { | |||
742 | PreCallCheckers.push_back(checkfn); | |||
743 | } | |||
744 | void CheckerManager::_registerForPostCall(CheckCallFunc checkfn) { | |||
745 | PostCallCheckers.push_back(checkfn); | |||
746 | } | |||
747 | ||||
748 | void CheckerManager::_registerForLocation(CheckLocationFunc checkfn) { | |||
749 | LocationCheckers.push_back(checkfn); | |||
750 | } | |||
751 | ||||
752 | void CheckerManager::_registerForBind(CheckBindFunc checkfn) { | |||
753 | BindCheckers.push_back(checkfn); | |||
754 | } | |||
755 | ||||
756 | void CheckerManager::_registerForEndAnalysis(CheckEndAnalysisFunc checkfn) { | |||
757 | EndAnalysisCheckers.push_back(checkfn); | |||
758 | } | |||
759 | ||||
760 | void CheckerManager::_registerForBeginFunction(CheckBeginFunctionFunc checkfn) { | |||
761 | BeginFunctionCheckers.push_back(checkfn); | |||
762 | } | |||
763 | ||||
764 | void CheckerManager::_registerForEndFunction(CheckEndFunctionFunc checkfn) { | |||
765 | EndFunctionCheckers.push_back(checkfn); | |||
766 | } | |||
767 | ||||
768 | void CheckerManager::_registerForBranchCondition( | |||
769 | CheckBranchConditionFunc checkfn) { | |||
770 | BranchConditionCheckers.push_back(checkfn); | |||
771 | } | |||
772 | ||||
773 | void CheckerManager::_registerForNewAllocator(CheckNewAllocatorFunc checkfn) { | |||
774 | NewAllocatorCheckers.push_back(checkfn); | |||
775 | } | |||
776 | ||||
777 | void CheckerManager::_registerForLiveSymbols(CheckLiveSymbolsFunc checkfn) { | |||
778 | LiveSymbolsCheckers.push_back(checkfn); | |||
779 | } | |||
780 | ||||
781 | void CheckerManager::_registerForDeadSymbols(CheckDeadSymbolsFunc checkfn) { | |||
782 | DeadSymbolsCheckers.push_back(checkfn); | |||
783 | } | |||
784 | ||||
785 | void CheckerManager::_registerForRegionChanges(CheckRegionChangesFunc checkfn) { | |||
786 | RegionChangesCheckers.push_back(checkfn); | |||
787 | } | |||
788 | ||||
789 | void CheckerManager::_registerForPointerEscape(CheckPointerEscapeFunc checkfn){ | |||
790 | PointerEscapeCheckers.push_back(checkfn); | |||
791 | } | |||
792 | ||||
793 | void CheckerManager::_registerForConstPointerEscape( | |||
794 | CheckPointerEscapeFunc checkfn) { | |||
795 | PointerEscapeCheckers.push_back(checkfn); | |||
796 | } | |||
797 | ||||
798 | void CheckerManager::_registerForEvalAssume(EvalAssumeFunc checkfn) { | |||
799 | EvalAssumeCheckers.push_back(checkfn); | |||
800 | } | |||
801 | ||||
802 | void CheckerManager::_registerForEvalCall(EvalCallFunc checkfn) { | |||
803 | EvalCallCheckers.push_back(checkfn); | |||
804 | } | |||
805 | ||||
806 | void CheckerManager::_registerForEndOfTranslationUnit( | |||
807 | CheckEndOfTranslationUnit checkfn) { | |||
808 | EndOfTranslationUnitCheckers.push_back(checkfn); | |||
809 | } | |||
810 | ||||
811 | //===----------------------------------------------------------------------===// | |||
812 | // Implementation details. | |||
813 | //===----------------------------------------------------------------------===// | |||
814 | ||||
815 | const CheckerManager::CachedStmtCheckers & | |||
816 | CheckerManager::getCachedStmtCheckersFor(const Stmt *S, bool isPreVisit) { | |||
817 | assert(S)(static_cast <bool> (S) ? void (0) : __assert_fail ("S" , "/build/llvm-toolchain-snapshot-7~svn326551/tools/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp" , 817, __extension__ __PRETTY_FUNCTION__)); | |||
818 | ||||
819 | unsigned Key = (S->getStmtClass() << 1) | unsigned(isPreVisit); | |||
820 | CachedStmtCheckersMapTy::iterator CCI = CachedStmtCheckersMap.find(Key); | |||
821 | if (CCI != CachedStmtCheckersMap.end()) | |||
822 | return CCI->second; | |||
823 | ||||
824 | // Find the checkers that should run for this Stmt and cache them. | |||
825 | CachedStmtCheckers &Checkers = CachedStmtCheckersMap[Key]; | |||
826 | for (const auto &Info : StmtCheckers) | |||
827 | if (Info.IsPreVisit == isPreVisit && Info.IsForStmtFn(S)) | |||
828 | Checkers.push_back(Info.CheckFn); | |||
829 | return Checkers; | |||
830 | } | |||
831 | ||||
832 | CheckerManager::~CheckerManager() { | |||
833 | for (const auto CheckerDtor : CheckerDtors) | |||
834 | CheckerDtor(); | |||
835 | } |
1 | //==- llvm/ADT/IntrusiveRefCntPtr.h - Smart Refcounting Pointer --*- C++ -*-==// | |||
2 | // | |||
3 | // The LLVM Compiler Infrastructure | |||
4 | // | |||
5 | // This file is distributed under the University of Illinois Open Source | |||
6 | // License. See LICENSE.TXT for details. | |||
7 | // | |||
8 | //===----------------------------------------------------------------------===// | |||
9 | // | |||
10 | // This file defines the RefCountedBase, ThreadSafeRefCountedBase, and | |||
11 | // IntrusiveRefCntPtr classes. | |||
12 | // | |||
13 | // IntrusiveRefCntPtr is a smart pointer to an object which maintains a | |||
14 | // reference count. (ThreadSafe)RefCountedBase is a mixin class that adds a | |||
15 | // refcount member variable and methods for updating the refcount. An object | |||
16 | // that inherits from (ThreadSafe)RefCountedBase deletes itself when its | |||
17 | // refcount hits zero. | |||
18 | // | |||
19 | // For example: | |||
20 | // | |||
21 | // class MyClass : public RefCountedBase<MyClass> {}; | |||
22 | // | |||
23 | // void foo() { | |||
24 | // // Constructing an IntrusiveRefCntPtr increases the pointee's refcount by | |||
25 | // // 1 (from 0 in this case). | |||
26 | // IntrusiveRefCntPtr<MyClass> Ptr1(new MyClass()); | |||
27 | // | |||
28 | // // Copying an IntrusiveRefCntPtr increases the pointee's refcount by 1. | |||
29 | // IntrusiveRefCntPtr<MyClass> Ptr2(Ptr1); | |||
30 | // | |||
31 | // // Constructing an IntrusiveRefCntPtr has no effect on the object's | |||
32 | // // refcount. After a move, the moved-from pointer is null. | |||
33 | // IntrusiveRefCntPtr<MyClass> Ptr3(std::move(Ptr1)); | |||
34 | // assert(Ptr1 == nullptr); | |||
35 | // | |||
36 | // // Clearing an IntrusiveRefCntPtr decreases the pointee's refcount by 1. | |||
37 | // Ptr2.reset(); | |||
38 | // | |||
39 | // // The object deletes itself when we return from the function, because | |||
40 | // // Ptr3's destructor decrements its refcount to 0. | |||
41 | // } | |||
42 | // | |||
43 | // You can use IntrusiveRefCntPtr with isa<T>(), dyn_cast<T>(), etc.: | |||
44 | // | |||
45 | // IntrusiveRefCntPtr<MyClass> Ptr(new MyClass()); | |||
46 | // OtherClass *Other = dyn_cast<OtherClass>(Ptr); // Ptr.get() not required | |||
47 | // | |||
48 | // IntrusiveRefCntPtr works with any class that | |||
49 | // | |||
50 | // - inherits from (ThreadSafe)RefCountedBase, | |||
51 | // - has Retain() and Release() methods, or | |||
52 | // - specializes IntrusiveRefCntPtrInfo. | |||
53 | // | |||
54 | //===----------------------------------------------------------------------===// | |||
55 | ||||
56 | #ifndef LLVM_ADT_INTRUSIVEREFCNTPTR_H | |||
57 | #define LLVM_ADT_INTRUSIVEREFCNTPTR_H | |||
58 | ||||
59 | #include <atomic> | |||
60 | #include <cassert> | |||
61 | #include <cstddef> | |||
62 | ||||
63 | namespace llvm { | |||
64 | ||||
65 | /// A CRTP mixin class that adds reference counting to a type. | |||
66 | /// | |||
67 | /// The lifetime of an object which inherits from RefCountedBase is managed by | |||
68 | /// calls to Release() and Retain(), which increment and decrement the object's | |||
69 | /// refcount, respectively. When a Release() call decrements the refcount to 0, | |||
70 | /// the object deletes itself. | |||
71 | template <class Derived> class RefCountedBase { | |||
72 | mutable unsigned RefCount = 0; | |||
73 | ||||
74 | public: | |||
75 | RefCountedBase() = default; | |||
76 | RefCountedBase(const RefCountedBase &) {} | |||
77 | ||||
78 | void Retain() const { ++RefCount; } | |||
79 | ||||
80 | void Release() const { | |||
81 | assert(RefCount > 0 && "Reference count is already zero.")(static_cast <bool> (RefCount > 0 && "Reference count is already zero." ) ? void (0) : __assert_fail ("RefCount > 0 && \"Reference count is already zero.\"" , "/build/llvm-toolchain-snapshot-7~svn326551/include/llvm/ADT/IntrusiveRefCntPtr.h" , 81, __extension__ __PRETTY_FUNCTION__)); | |||
82 | if (--RefCount == 0) | |||
83 | delete static_cast<const Derived *>(this); | |||
84 | } | |||
85 | }; | |||
86 | ||||
87 | /// A thread-safe version of \c RefCountedBase. | |||
88 | template <class Derived> class ThreadSafeRefCountedBase { | |||
89 | mutable std::atomic<int> RefCount; | |||
90 | ||||
91 | protected: | |||
92 | ThreadSafeRefCountedBase() : RefCount(0) {} | |||
93 | ||||
94 | public: | |||
95 | void Retain() const { RefCount.fetch_add(1, std::memory_order_relaxed); } | |||
96 | ||||
97 | void Release() const { | |||
98 | int NewRefCount = RefCount.fetch_sub(1, std::memory_order_acq_rel) - 1; | |||
99 | assert(NewRefCount >= 0 && "Reference count was already zero.")(static_cast <bool> (NewRefCount >= 0 && "Reference count was already zero." ) ? void (0) : __assert_fail ("NewRefCount >= 0 && \"Reference count was already zero.\"" , "/build/llvm-toolchain-snapshot-7~svn326551/include/llvm/ADT/IntrusiveRefCntPtr.h" , 99, __extension__ __PRETTY_FUNCTION__)); | |||
100 | if (NewRefCount == 0) | |||
101 | delete static_cast<const Derived *>(this); | |||
102 | } | |||
103 | }; | |||
104 | ||||
105 | /// Class you can specialize to provide custom retain/release functionality for | |||
106 | /// a type. | |||
107 | /// | |||
108 | /// Usually specializing this class is not necessary, as IntrusiveRefCntPtr | |||
109 | /// works with any type which defines Retain() and Release() functions -- you | |||
110 | /// can define those functions yourself if RefCountedBase doesn't work for you. | |||
111 | /// | |||
112 | /// One case when you might want to specialize this type is if you have | |||
113 | /// - Foo.h defines type Foo and includes Bar.h, and | |||
114 | /// - Bar.h uses IntrusiveRefCntPtr<Foo> in inline functions. | |||
115 | /// | |||
116 | /// Because Foo.h includes Bar.h, Bar.h can't include Foo.h in order to pull in | |||
117 | /// the declaration of Foo. Without the declaration of Foo, normally Bar.h | |||
118 | /// wouldn't be able to use IntrusiveRefCntPtr<Foo>, which wants to call | |||
119 | /// T::Retain and T::Release. | |||
120 | /// | |||
121 | /// To resolve this, Bar.h could include a third header, FooFwd.h, which | |||
122 | /// forward-declares Foo and specializes IntrusiveRefCntPtrInfo<Foo>. Then | |||
123 | /// Bar.h could use IntrusiveRefCntPtr<Foo>, although it still couldn't call any | |||
124 | /// functions on Foo itself, because Foo would be an incomplete type. | |||
125 | template <typename T> struct IntrusiveRefCntPtrInfo { | |||
126 | static void retain(T *obj) { obj->Retain(); } | |||
127 | static void release(T *obj) { obj->Release(); } | |||
128 | }; | |||
129 | ||||
130 | /// A smart pointer to a reference-counted object that inherits from | |||
131 | /// RefCountedBase or ThreadSafeRefCountedBase. | |||
132 | /// | |||
133 | /// This class increments its pointee's reference count when it is created, and | |||
134 | /// decrements its refcount when it's destroyed (or is changed to point to a | |||
135 | /// different object). | |||
136 | template <typename T> class IntrusiveRefCntPtr { | |||
137 | T *Obj = nullptr; | |||
138 | ||||
139 | public: | |||
140 | using element_type = T; | |||
141 | ||||
142 | explicit IntrusiveRefCntPtr() = default; | |||
143 | IntrusiveRefCntPtr(T *obj) : Obj(obj) { retain(); } | |||
144 | IntrusiveRefCntPtr(const IntrusiveRefCntPtr &S) : Obj(S.Obj) { retain(); } | |||
145 | IntrusiveRefCntPtr(IntrusiveRefCntPtr &&S) : Obj(S.Obj) { S.Obj = nullptr; } | |||
146 | ||||
147 | template <class X> | |||
148 | IntrusiveRefCntPtr(IntrusiveRefCntPtr<X> &&S) : Obj(S.get()) { | |||
149 | S.Obj = nullptr; | |||
150 | } | |||
151 | ||||
152 | template <class X> | |||
153 | IntrusiveRefCntPtr(const IntrusiveRefCntPtr<X> &S) : Obj(S.get()) { | |||
154 | retain(); | |||
155 | } | |||
156 | ||||
157 | ~IntrusiveRefCntPtr() { release(); } | |||
158 | ||||
159 | IntrusiveRefCntPtr &operator=(IntrusiveRefCntPtr S) { | |||
160 | swap(S); | |||
161 | return *this; | |||
162 | } | |||
163 | ||||
164 | T &operator*() const { return *Obj; } | |||
| ||||
165 | T *operator->() const { return Obj; } | |||
166 | T *get() const { return Obj; } | |||
167 | explicit operator bool() const { return Obj; } | |||
168 | ||||
169 | void swap(IntrusiveRefCntPtr &other) { | |||
170 | T *tmp = other.Obj; | |||
171 | other.Obj = Obj; | |||
172 | Obj = tmp; | |||
173 | } | |||
174 | ||||
175 | void reset() { | |||
176 | release(); | |||
177 | Obj = nullptr; | |||
178 | } | |||
179 | ||||
180 | void resetWithoutRelease() { Obj = nullptr; } | |||
181 | ||||
182 | private: | |||
183 | void retain() { | |||
184 | if (Obj) | |||
185 | IntrusiveRefCntPtrInfo<T>::retain(Obj); | |||
186 | } | |||
187 | ||||
188 | void release() { | |||
189 | if (Obj) | |||
190 | IntrusiveRefCntPtrInfo<T>::release(Obj); | |||
191 | } | |||
192 | ||||
193 | template <typename X> friend class IntrusiveRefCntPtr; | |||
194 | }; | |||
195 | ||||
196 | template <class T, class U> | |||
197 | inline bool operator==(const IntrusiveRefCntPtr<T> &A, | |||
198 | const IntrusiveRefCntPtr<U> &B) { | |||
199 | return A.get() == B.get(); | |||
200 | } | |||
201 | ||||
202 | template <class T, class U> | |||
203 | inline bool operator!=(const IntrusiveRefCntPtr<T> &A, | |||
204 | const IntrusiveRefCntPtr<U> &B) { | |||
205 | return A.get() != B.get(); | |||
206 | } | |||
207 | ||||
208 | template <class T, class U> | |||
209 | inline bool operator==(const IntrusiveRefCntPtr<T> &A, U *B) { | |||
210 | return A.get() == B; | |||
211 | } | |||
212 | ||||
213 | template <class T, class U> | |||
214 | inline bool operator!=(const IntrusiveRefCntPtr<T> &A, U *B) { | |||
215 | return A.get() != B; | |||
216 | } | |||
217 | ||||
218 | template <class T, class U> | |||
219 | inline bool operator==(T *A, const IntrusiveRefCntPtr<U> &B) { | |||
220 | return A == B.get(); | |||
221 | } | |||
222 | ||||
223 | template <class T, class U> | |||
224 | inline bool operator!=(T *A, const IntrusiveRefCntPtr<U> &B) { | |||
225 | return A != B.get(); | |||
226 | } | |||
227 | ||||
228 | template <class T> | |||
229 | bool operator==(std::nullptr_t A, const IntrusiveRefCntPtr<T> &B) { | |||
230 | return !B; | |||
231 | } | |||
232 | ||||
233 | template <class T> | |||
234 | bool operator==(const IntrusiveRefCntPtr<T> &A, std::nullptr_t B) { | |||
235 | return B == A; | |||
236 | } | |||
237 | ||||
238 | template <class T> | |||
239 | bool operator!=(std::nullptr_t A, const IntrusiveRefCntPtr<T> &B) { | |||
240 | return !(A == B); | |||
241 | } | |||
242 | ||||
243 | template <class T> | |||
244 | bool operator!=(const IntrusiveRefCntPtr<T> &A, std::nullptr_t B) { | |||
245 | return !(A == B); | |||
246 | } | |||
247 | ||||
248 | // Make IntrusiveRefCntPtr work with dyn_cast, isa, and the other idioms from | |||
249 | // Casting.h. | |||
250 | template <typename From> struct simplify_type; | |||
251 | ||||
252 | template <class T> struct simplify_type<IntrusiveRefCntPtr<T>> { | |||
253 | using SimpleType = T *; | |||
254 | ||||
255 | static SimpleType getSimplifiedValue(IntrusiveRefCntPtr<T> &Val) { | |||
256 | return Val.get(); | |||
257 | } | |||
258 | }; | |||
259 | ||||
260 | template <class T> struct simplify_type<const IntrusiveRefCntPtr<T>> { | |||
261 | using SimpleType = /*const*/ T *; | |||
262 | ||||
263 | static SimpleType getSimplifiedValue(const IntrusiveRefCntPtr<T> &Val) { | |||
264 | return Val.get(); | |||
265 | } | |||
266 | }; | |||
267 | ||||
268 | } // end namespace llvm | |||
269 | ||||
270 | #endif // LLVM_ADT_INTRUSIVEREFCNTPTR_H |