1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | #include "clang/StaticAnalyzer/Core/CheckerManager.h" |
14 | #include "clang/AST/DeclBase.h" |
15 | #include "clang/AST/Stmt.h" |
16 | #include "clang/Analysis/ProgramPoint.h" |
17 | #include "clang/Basic/LLVM.h" |
18 | #include "clang/Driver/DriverDiagnostic.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 | |
55 | |
56 | for (const auto &Event : Events) |
57 | (0) . __assert_fail ("Event.second.HasDispatcher && \"No dispatcher registered for an event\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp", 58, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(Event.second.HasDispatcher && |
58 | (0) . __assert_fail ("Event.second.HasDispatcher && \"No dispatcher registered for an event\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp", 58, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true"> "No dispatcher registered for an event"); |
59 | #endif |
60 | } |
61 | |
62 | void CheckerManager::reportInvalidCheckerOptionValue( |
63 | const CheckerBase *C, StringRef OptionName, StringRef ExpectedValueDesc) { |
64 | |
65 | Context.getDiagnostics() |
66 | .Report(diag::err_analyzer_checker_option_invalid_input) |
67 | << (llvm::Twine() + C->getTagDescription() + ":" + OptionName).str() |
68 | << ExpectedValueDesc; |
69 | } |
70 | |
71 | |
72 | |
73 | |
74 | |
75 | void CheckerManager::runCheckersOnASTDecl(const Decl *D, AnalysisManager& mgr, |
76 | BugReporter &BR) { |
77 | assert(D); |
78 | |
79 | unsigned DeclKind = D->getKind(); |
80 | CachedDeclCheckers *checkers = nullptr; |
81 | CachedDeclCheckersMapTy::iterator CCI = CachedDeclCheckersMap.find(DeclKind); |
82 | if (CCI != CachedDeclCheckersMap.end()) { |
83 | checkers = &(CCI->second); |
84 | } else { |
85 | |
86 | checkers = &CachedDeclCheckersMap[DeclKind]; |
87 | for (const auto &info : DeclCheckers) |
88 | if (info.IsForDeclFn(D)) |
89 | checkers->push_back(info.CheckFn); |
90 | } |
91 | |
92 | assert(checkers); |
93 | for (const auto checker : *checkers) |
94 | checker(D, mgr, BR); |
95 | } |
96 | |
97 | void CheckerManager::runCheckersOnASTBody(const Decl *D, AnalysisManager& mgr, |
98 | BugReporter &BR) { |
99 | hasBody()", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp", 99, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(D && D->hasBody()); |
100 | |
101 | for (const auto BodyChecker : BodyCheckers) |
102 | BodyChecker(D, mgr, BR); |
103 | } |
104 | |
105 | |
106 | |
107 | |
108 | |
109 | template <typename CHECK_CTX> |
110 | static void expandGraphWithCheckers(CHECK_CTX checkCtx, |
111 | ExplodedNodeSet &Dst, |
112 | const ExplodedNodeSet &Src) { |
113 | const NodeBuilderContext &BldrCtx = checkCtx.Eng.getBuilderContext(); |
114 | if (Src.empty()) |
115 | return; |
116 | |
117 | typename CHECK_CTX::CheckersTy::const_iterator |
118 | I = checkCtx.checkers_begin(), E = checkCtx.checkers_end(); |
119 | if (I == E) { |
120 | Dst.insert(Src); |
121 | return; |
122 | } |
123 | |
124 | ExplodedNodeSet Tmp1, Tmp2; |
125 | const ExplodedNodeSet *PrevSet = &Src; |
126 | |
127 | for (; I != E; ++I) { |
128 | ExplodedNodeSet *CurrSet = nullptr; |
129 | if (I+1 == E) |
130 | CurrSet = &Dst; |
131 | else { |
132 | CurrSet = (PrevSet == &Tmp1) ? &Tmp2 : &Tmp1; |
133 | CurrSet->clear(); |
134 | } |
135 | |
136 | NodeBuilder B(*PrevSet, *CurrSet, BldrCtx); |
137 | for (const auto &NI : *PrevSet) |
138 | checkCtx.runChecker(*I, B, NI); |
139 | |
140 | |
141 | if (CurrSet->empty()) |
142 | return; |
143 | |
144 | |
145 | PrevSet = CurrSet; |
146 | } |
147 | } |
148 | |
149 | namespace { |
150 | |
151 | struct CheckStmtContext { |
152 | using CheckersTy = SmallVectorImpl<CheckerManager::CheckStmtFunc>; |
153 | |
154 | bool IsPreVisit; |
155 | const CheckersTy &Checkers; |
156 | const Stmt *S; |
157 | ExprEngine &Eng; |
158 | bool WasInlined; |
159 | |
160 | CheckStmtContext(bool isPreVisit, const CheckersTy &checkers, |
161 | const Stmt *s, ExprEngine &eng, bool wasInlined = false) |
162 | : IsPreVisit(isPreVisit), Checkers(checkers), S(s), Eng(eng), |
163 | WasInlined(wasInlined) {} |
164 | |
165 | CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } |
166 | CheckersTy::const_iterator checkers_end() { return Checkers.end(); } |
167 | |
168 | void runChecker(CheckerManager::CheckStmtFunc checkFn, |
169 | NodeBuilder &Bldr, ExplodedNode *Pred) { |
170 | |
171 | ProgramPoint::Kind K = IsPreVisit ? ProgramPoint::PreStmtKind : |
172 | ProgramPoint::PostStmtKind; |
173 | const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K, |
174 | Pred->getLocationContext(), checkFn.Checker); |
175 | CheckerContext C(Bldr, Eng, Pred, L, WasInlined); |
176 | checkFn(S, C); |
177 | } |
178 | }; |
179 | |
180 | } |
181 | |
182 | |
183 | void CheckerManager::runCheckersForStmt(bool isPreVisit, |
184 | ExplodedNodeSet &Dst, |
185 | const ExplodedNodeSet &Src, |
186 | const Stmt *S, |
187 | ExprEngine &Eng, |
188 | bool WasInlined) { |
189 | CheckStmtContext C(isPreVisit, getCachedStmtCheckersFor(S, isPreVisit), |
190 | S, Eng, WasInlined); |
191 | expandGraphWithCheckers(C, Dst, Src); |
192 | } |
193 | |
194 | namespace { |
195 | |
196 | struct CheckObjCMessageContext { |
197 | using CheckersTy = std::vector<CheckerManager::CheckObjCMessageFunc>; |
198 | |
199 | ObjCMessageVisitKind Kind; |
200 | bool WasInlined; |
201 | const CheckersTy &Checkers; |
202 | const ObjCMethodCall &Msg; |
203 | ExprEngine &Eng; |
204 | |
205 | CheckObjCMessageContext(ObjCMessageVisitKind visitKind, |
206 | const CheckersTy &checkers, |
207 | const ObjCMethodCall &msg, ExprEngine &eng, |
208 | bool wasInlined) |
209 | : Kind(visitKind), WasInlined(wasInlined), Checkers(checkers), Msg(msg), |
210 | Eng(eng) {} |
211 | |
212 | CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } |
213 | CheckersTy::const_iterator checkers_end() { return Checkers.end(); } |
214 | |
215 | void runChecker(CheckerManager::CheckObjCMessageFunc checkFn, |
216 | NodeBuilder &Bldr, ExplodedNode *Pred) { |
217 | bool IsPreVisit; |
218 | |
219 | switch (Kind) { |
220 | case ObjCMessageVisitKind::Pre: |
221 | IsPreVisit = true; |
222 | break; |
223 | case ObjCMessageVisitKind::MessageNil: |
224 | case ObjCMessageVisitKind::Post: |
225 | IsPreVisit = false; |
226 | break; |
227 | } |
228 | |
229 | const ProgramPoint &L = Msg.getProgramPoint(IsPreVisit,checkFn.Checker); |
230 | CheckerContext C(Bldr, Eng, Pred, L, WasInlined); |
231 | |
232 | checkFn(*Msg.cloneWithState<ObjCMethodCall>(Pred->getState()), C); |
233 | } |
234 | }; |
235 | |
236 | } |
237 | |
238 | |
239 | void CheckerManager::runCheckersForObjCMessage(ObjCMessageVisitKind visitKind, |
240 | ExplodedNodeSet &Dst, |
241 | const ExplodedNodeSet &Src, |
242 | const ObjCMethodCall &msg, |
243 | ExprEngine &Eng, |
244 | bool WasInlined) { |
245 | auto &checkers = getObjCMessageCheckers(visitKind); |
246 | CheckObjCMessageContext C(visitKind, checkers, msg, Eng, WasInlined); |
247 | expandGraphWithCheckers(C, Dst, Src); |
248 | } |
249 | |
250 | const std::vector<CheckerManager::CheckObjCMessageFunc> & |
251 | CheckerManager::getObjCMessageCheckers(ObjCMessageVisitKind Kind) { |
252 | switch (Kind) { |
253 | case ObjCMessageVisitKind::Pre: |
254 | return PreObjCMessageCheckers; |
255 | break; |
256 | case ObjCMessageVisitKind::Post: |
257 | return PostObjCMessageCheckers; |
258 | case ObjCMessageVisitKind::MessageNil: |
259 | return ObjCMessageNilCheckers; |
260 | } |
261 | llvm_unreachable("Unknown Kind"); |
262 | } |
263 | |
264 | namespace { |
265 | |
266 | |
267 | |
268 | struct CheckCallContext { |
269 | using CheckersTy = std::vector<CheckerManager::CheckCallFunc>; |
270 | |
271 | bool IsPreVisit, WasInlined; |
272 | const CheckersTy &Checkers; |
273 | const CallEvent &Call; |
274 | ExprEngine &Eng; |
275 | |
276 | CheckCallContext(bool isPreVisit, const CheckersTy &checkers, |
277 | const CallEvent &call, ExprEngine &eng, |
278 | bool wasInlined) |
279 | : IsPreVisit(isPreVisit), WasInlined(wasInlined), Checkers(checkers), |
280 | Call(call), Eng(eng) {} |
281 | |
282 | CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } |
283 | CheckersTy::const_iterator checkers_end() { return Checkers.end(); } |
284 | |
285 | void runChecker(CheckerManager::CheckCallFunc checkFn, |
286 | NodeBuilder &Bldr, ExplodedNode *Pred) { |
287 | const ProgramPoint &L = Call.getProgramPoint(IsPreVisit,checkFn.Checker); |
288 | CheckerContext C(Bldr, Eng, Pred, L, WasInlined); |
289 | |
290 | checkFn(*Call.cloneWithState(Pred->getState()), C); |
291 | } |
292 | }; |
293 | |
294 | } |
295 | |
296 | |
297 | void CheckerManager::runCheckersForCallEvent(bool isPreVisit, |
298 | ExplodedNodeSet &Dst, |
299 | const ExplodedNodeSet &Src, |
300 | const CallEvent &Call, |
301 | ExprEngine &Eng, |
302 | bool WasInlined) { |
303 | CheckCallContext C(isPreVisit, |
304 | isPreVisit ? PreCallCheckers |
305 | : PostCallCheckers, |
306 | Call, Eng, WasInlined); |
307 | expandGraphWithCheckers(C, Dst, Src); |
308 | } |
309 | |
310 | namespace { |
311 | |
312 | struct CheckLocationContext { |
313 | using CheckersTy = std::vector<CheckerManager::CheckLocationFunc>; |
314 | |
315 | const CheckersTy &Checkers; |
316 | SVal Loc; |
317 | bool IsLoad; |
318 | const Stmt *NodeEx; |
319 | const Stmt *BoundEx; |
320 | ExprEngine &Eng; |
321 | |
322 | CheckLocationContext(const CheckersTy &checkers, |
323 | SVal loc, bool isLoad, const Stmt *NodeEx, |
324 | const Stmt *BoundEx, |
325 | ExprEngine &eng) |
326 | : Checkers(checkers), Loc(loc), IsLoad(isLoad), NodeEx(NodeEx), |
327 | BoundEx(BoundEx), Eng(eng) {} |
328 | |
329 | CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } |
330 | CheckersTy::const_iterator checkers_end() { return Checkers.end(); } |
331 | |
332 | void runChecker(CheckerManager::CheckLocationFunc checkFn, |
333 | NodeBuilder &Bldr, ExplodedNode *Pred) { |
334 | ProgramPoint::Kind K = IsLoad ? ProgramPoint::PreLoadKind : |
335 | ProgramPoint::PreStoreKind; |
336 | const ProgramPoint &L = |
337 | ProgramPoint::getProgramPoint(NodeEx, K, |
338 | Pred->getLocationContext(), |
339 | checkFn.Checker); |
340 | CheckerContext C(Bldr, Eng, Pred, L); |
341 | checkFn(Loc, IsLoad, BoundEx, C); |
342 | } |
343 | }; |
344 | |
345 | } |
346 | |
347 | |
348 | |
349 | void CheckerManager::runCheckersForLocation(ExplodedNodeSet &Dst, |
350 | const ExplodedNodeSet &Src, |
351 | SVal location, bool isLoad, |
352 | const Stmt *NodeEx, |
353 | const Stmt *BoundEx, |
354 | ExprEngine &Eng) { |
355 | CheckLocationContext C(LocationCheckers, location, isLoad, NodeEx, |
356 | BoundEx, Eng); |
357 | expandGraphWithCheckers(C, Dst, Src); |
358 | } |
359 | |
360 | namespace { |
361 | |
362 | struct CheckBindContext { |
363 | using CheckersTy = std::vector<CheckerManager::CheckBindFunc>; |
364 | |
365 | const CheckersTy &Checkers; |
366 | SVal Loc; |
367 | SVal Val; |
368 | const Stmt *S; |
369 | ExprEngine &Eng; |
370 | const ProgramPoint &PP; |
371 | |
372 | CheckBindContext(const CheckersTy &checkers, |
373 | SVal loc, SVal val, const Stmt *s, ExprEngine &eng, |
374 | const ProgramPoint &pp) |
375 | : Checkers(checkers), Loc(loc), Val(val), S(s), Eng(eng), PP(pp) {} |
376 | |
377 | CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } |
378 | CheckersTy::const_iterator checkers_end() { return Checkers.end(); } |
379 | |
380 | void runChecker(CheckerManager::CheckBindFunc checkFn, |
381 | NodeBuilder &Bldr, ExplodedNode *Pred) { |
382 | const ProgramPoint &L = PP.withTag(checkFn.Checker); |
383 | CheckerContext C(Bldr, Eng, Pred, L); |
384 | |
385 | checkFn(Loc, Val, S, C); |
386 | } |
387 | }; |
388 | |
389 | } |
390 | |
391 | |
392 | void CheckerManager::runCheckersForBind(ExplodedNodeSet &Dst, |
393 | const ExplodedNodeSet &Src, |
394 | SVal location, SVal val, |
395 | const Stmt *S, ExprEngine &Eng, |
396 | const ProgramPoint &PP) { |
397 | CheckBindContext C(BindCheckers, location, val, S, Eng, PP); |
398 | expandGraphWithCheckers(C, Dst, Src); |
399 | } |
400 | |
401 | void CheckerManager::runCheckersForEndAnalysis(ExplodedGraph &G, |
402 | BugReporter &BR, |
403 | ExprEngine &Eng) { |
404 | for (const auto EndAnalysisChecker : EndAnalysisCheckers) |
405 | EndAnalysisChecker(G, BR, Eng); |
406 | } |
407 | |
408 | namespace { |
409 | |
410 | struct CheckBeginFunctionContext { |
411 | using CheckersTy = std::vector<CheckerManager::CheckBeginFunctionFunc>; |
412 | |
413 | const CheckersTy &Checkers; |
414 | ExprEngine &Eng; |
415 | const ProgramPoint &PP; |
416 | |
417 | CheckBeginFunctionContext(const CheckersTy &Checkers, ExprEngine &Eng, |
418 | const ProgramPoint &PP) |
419 | : Checkers(Checkers), Eng(Eng), PP(PP) {} |
420 | |
421 | CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } |
422 | CheckersTy::const_iterator checkers_end() { return Checkers.end(); } |
423 | |
424 | void runChecker(CheckerManager::CheckBeginFunctionFunc checkFn, |
425 | NodeBuilder &Bldr, ExplodedNode *Pred) { |
426 | const ProgramPoint &L = PP.withTag(checkFn.Checker); |
427 | CheckerContext C(Bldr, Eng, Pred, L); |
428 | |
429 | checkFn(C); |
430 | } |
431 | }; |
432 | |
433 | } |
434 | |
435 | void CheckerManager::runCheckersForBeginFunction(ExplodedNodeSet &Dst, |
436 | const BlockEdge &L, |
437 | ExplodedNode *Pred, |
438 | ExprEngine &Eng) { |
439 | ExplodedNodeSet Src; |
440 | Src.insert(Pred); |
441 | CheckBeginFunctionContext C(BeginFunctionCheckers, Eng, L); |
442 | expandGraphWithCheckers(C, Dst, Src); |
443 | } |
444 | |
445 | |
446 | |
447 | |
448 | void CheckerManager::runCheckersForEndFunction(NodeBuilderContext &BC, |
449 | ExplodedNodeSet &Dst, |
450 | ExplodedNode *Pred, |
451 | ExprEngine &Eng, |
452 | const ReturnStmt *RS) { |
453 | |
454 | |
455 | |
456 | NodeBuilder Bldr(Pred, Dst, BC); |
457 | for (const auto checkFn : EndFunctionCheckers) { |
458 | const ProgramPoint &L = |
459 | FunctionExitPoint(RS, Pred->getLocationContext(), checkFn.Checker); |
460 | CheckerContext C(Bldr, Eng, Pred, L); |
461 | checkFn(RS, C); |
462 | } |
463 | } |
464 | |
465 | namespace { |
466 | |
467 | struct CheckBranchConditionContext { |
468 | using CheckersTy = std::vector<CheckerManager::CheckBranchConditionFunc>; |
469 | |
470 | const CheckersTy &Checkers; |
471 | const Stmt *Condition; |
472 | ExprEngine &Eng; |
473 | |
474 | CheckBranchConditionContext(const CheckersTy &checkers, |
475 | const Stmt *Cond, ExprEngine &eng) |
476 | : Checkers(checkers), Condition(Cond), Eng(eng) {} |
477 | |
478 | CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } |
479 | CheckersTy::const_iterator checkers_end() { return Checkers.end(); } |
480 | |
481 | void runChecker(CheckerManager::CheckBranchConditionFunc checkFn, |
482 | NodeBuilder &Bldr, ExplodedNode *Pred) { |
483 | ProgramPoint L = PostCondition(Condition, Pred->getLocationContext(), |
484 | checkFn.Checker); |
485 | CheckerContext C(Bldr, Eng, Pred, L); |
486 | checkFn(Condition, C); |
487 | } |
488 | }; |
489 | |
490 | } |
491 | |
492 | |
493 | void CheckerManager::runCheckersForBranchCondition(const Stmt *Condition, |
494 | ExplodedNodeSet &Dst, |
495 | ExplodedNode *Pred, |
496 | ExprEngine &Eng) { |
497 | ExplodedNodeSet Src; |
498 | Src.insert(Pred); |
499 | CheckBranchConditionContext C(BranchConditionCheckers, Condition, Eng); |
500 | expandGraphWithCheckers(C, Dst, Src); |
501 | } |
502 | |
503 | namespace { |
504 | |
505 | struct CheckNewAllocatorContext { |
506 | using CheckersTy = std::vector<CheckerManager::CheckNewAllocatorFunc>; |
507 | |
508 | const CheckersTy &Checkers; |
509 | const CXXNewExpr *NE; |
510 | SVal Target; |
511 | bool WasInlined; |
512 | ExprEngine &Eng; |
513 | |
514 | CheckNewAllocatorContext(const CheckersTy &Checkers, const CXXNewExpr *NE, |
515 | SVal Target, bool WasInlined, ExprEngine &Eng) |
516 | : Checkers(Checkers), NE(NE), Target(Target), WasInlined(WasInlined), |
517 | Eng(Eng) {} |
518 | |
519 | CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } |
520 | CheckersTy::const_iterator checkers_end() { return Checkers.end(); } |
521 | |
522 | void runChecker(CheckerManager::CheckNewAllocatorFunc checkFn, |
523 | NodeBuilder &Bldr, ExplodedNode *Pred) { |
524 | ProgramPoint L = PostAllocatorCall(NE, Pred->getLocationContext()); |
525 | CheckerContext C(Bldr, Eng, Pred, L, WasInlined); |
526 | checkFn(NE, Target, C); |
527 | } |
528 | }; |
529 | |
530 | } |
531 | |
532 | void CheckerManager::runCheckersForNewAllocator( |
533 | const CXXNewExpr *NE, SVal Target, ExplodedNodeSet &Dst, ExplodedNode *Pred, |
534 | ExprEngine &Eng, bool WasInlined) { |
535 | ExplodedNodeSet Src; |
536 | Src.insert(Pred); |
537 | CheckNewAllocatorContext C(NewAllocatorCheckers, NE, Target, WasInlined, Eng); |
538 | expandGraphWithCheckers(C, Dst, Src); |
539 | } |
540 | |
541 | |
542 | void CheckerManager::runCheckersForLiveSymbols(ProgramStateRef state, |
543 | SymbolReaper &SymReaper) { |
544 | for (const auto LiveSymbolsChecker : LiveSymbolsCheckers) |
545 | LiveSymbolsChecker(state, SymReaper); |
546 | } |
547 | |
548 | namespace { |
549 | |
550 | struct CheckDeadSymbolsContext { |
551 | using CheckersTy = std::vector<CheckerManager::CheckDeadSymbolsFunc>; |
552 | |
553 | const CheckersTy &Checkers; |
554 | SymbolReaper &SR; |
555 | const Stmt *S; |
556 | ExprEngine &Eng; |
557 | ProgramPoint::Kind ProgarmPointKind; |
558 | |
559 | CheckDeadSymbolsContext(const CheckersTy &checkers, SymbolReaper &sr, |
560 | const Stmt *s, ExprEngine &eng, |
561 | ProgramPoint::Kind K) |
562 | : Checkers(checkers), SR(sr), S(s), Eng(eng), ProgarmPointKind(K) {} |
563 | |
564 | CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } |
565 | CheckersTy::const_iterator checkers_end() { return Checkers.end(); } |
566 | |
567 | void runChecker(CheckerManager::CheckDeadSymbolsFunc checkFn, |
568 | NodeBuilder &Bldr, ExplodedNode *Pred) { |
569 | const ProgramPoint &L = ProgramPoint::getProgramPoint(S, ProgarmPointKind, |
570 | Pred->getLocationContext(), checkFn.Checker); |
571 | CheckerContext C(Bldr, Eng, Pred, L); |
572 | |
573 | |
574 | |
575 | |
576 | checkFn(SR, C); |
577 | } |
578 | }; |
579 | |
580 | } |
581 | |
582 | |
583 | void CheckerManager::runCheckersForDeadSymbols(ExplodedNodeSet &Dst, |
584 | const ExplodedNodeSet &Src, |
585 | SymbolReaper &SymReaper, |
586 | const Stmt *S, |
587 | ExprEngine &Eng, |
588 | ProgramPoint::Kind K) { |
589 | CheckDeadSymbolsContext C(DeadSymbolsCheckers, SymReaper, S, Eng, K); |
590 | expandGraphWithCheckers(C, Dst, Src); |
591 | } |
592 | |
593 | |
594 | ProgramStateRef |
595 | CheckerManager::runCheckersForRegionChanges(ProgramStateRef state, |
596 | const InvalidatedSymbols *invalidated, |
597 | ArrayRef<const MemRegion *> ExplicitRegions, |
598 | ArrayRef<const MemRegion *> Regions, |
599 | const LocationContext *LCtx, |
600 | const CallEvent *Call) { |
601 | for (const auto RegionChangesChecker : RegionChangesCheckers) { |
602 | |
603 | |
604 | if (!state) |
605 | return nullptr; |
606 | state = RegionChangesChecker(state, invalidated, ExplicitRegions, Regions, |
607 | LCtx, Call); |
608 | } |
609 | return state; |
610 | } |
611 | |
612 | |
613 | ProgramStateRef |
614 | CheckerManager::runCheckersForPointerEscape(ProgramStateRef State, |
615 | const InvalidatedSymbols &Escaped, |
616 | const CallEvent *Call, |
617 | PointerEscapeKind Kind, |
618 | RegionAndSymbolInvalidationTraits *ETraits) { |
619 | (0) . __assert_fail ("(Call != nullptr || (Kind != PSK_DirectEscapeOnCall && Kind != PSK_IndirectEscapeOnCall)) && \"Call must not be NULL when escaping on call\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp", 622, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert((Call != nullptr || |
620 | (0) . __assert_fail ("(Call != nullptr || (Kind != PSK_DirectEscapeOnCall && Kind != PSK_IndirectEscapeOnCall)) && \"Call must not be NULL when escaping on call\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp", 622, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true"> (Kind != PSK_DirectEscapeOnCall && |
621 | (0) . __assert_fail ("(Call != nullptr || (Kind != PSK_DirectEscapeOnCall && Kind != PSK_IndirectEscapeOnCall)) && \"Call must not be NULL when escaping on call\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp", 622, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true"> Kind != PSK_IndirectEscapeOnCall)) && |
622 | (0) . __assert_fail ("(Call != nullptr || (Kind != PSK_DirectEscapeOnCall && Kind != PSK_IndirectEscapeOnCall)) && \"Call must not be NULL when escaping on call\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp", 622, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true"> "Call must not be NULL when escaping on call"); |
623 | for (const auto PointerEscapeChecker : PointerEscapeCheckers) { |
624 | |
625 | |
626 | if (!State) |
627 | return nullptr; |
628 | State = PointerEscapeChecker(State, Escaped, Call, Kind, ETraits); |
629 | } |
630 | return State; |
631 | } |
632 | |
633 | |
634 | ProgramStateRef |
635 | CheckerManager::runCheckersForEvalAssume(ProgramStateRef state, |
636 | SVal Cond, bool Assumption) { |
637 | for (const auto EvalAssumeChecker : EvalAssumeCheckers) { |
638 | |
639 | |
640 | if (!state) |
641 | return nullptr; |
642 | state = EvalAssumeChecker(state, Cond, Assumption); |
643 | } |
644 | return state; |
645 | } |
646 | |
647 | |
648 | |
649 | void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst, |
650 | const ExplodedNodeSet &Src, |
651 | const CallEvent &Call, |
652 | ExprEngine &Eng) { |
653 | const CallExpr *CE = cast<CallExpr>(Call.getOriginExpr()); |
654 | for (const auto Pred : Src) { |
655 | bool anyEvaluated = false; |
656 | |
657 | ExplodedNodeSet checkDst; |
658 | NodeBuilder B(Pred, checkDst, Eng.getBuilderContext()); |
659 | |
660 | |
661 | for (const auto EvalCallChecker : EvalCallCheckers) { |
662 | ProgramPoint::Kind K = ProgramPoint::PostStmtKind; |
663 | const ProgramPoint &L = |
664 | ProgramPoint::getProgramPoint(CE, K, Pred->getLocationContext(), |
665 | EvalCallChecker.Checker); |
666 | bool evaluated = false; |
667 | { |
668 | |
669 | |
670 | CheckerContext C(B, Eng, Pred, L); |
671 | evaluated = EvalCallChecker(CE, C); |
672 | } |
673 | (0) . __assert_fail ("!(evaluated && anyEvaluated) && \"There are more than one checkers evaluating the call\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp", 674, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(!(evaluated && anyEvaluated) |
674 | (0) . __assert_fail ("!(evaluated && anyEvaluated) && \"There are more than one checkers evaluating the call\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp", 674, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true"> && "There are more than one checkers evaluating the call"); |
675 | if (evaluated) { |
676 | anyEvaluated = true; |
677 | Dst.insert(checkDst); |
678 | #ifdef NDEBUG |
679 | break; |
680 | #endif |
681 | } |
682 | } |
683 | |
684 | |
685 | if (!anyEvaluated) { |
686 | NodeBuilder B(Pred, Dst, Eng.getBuilderContext()); |
687 | Eng.defaultEvalCall(B, Pred, Call); |
688 | } |
689 | } |
690 | } |
691 | |
692 | |
693 | void CheckerManager::runCheckersOnEndOfTranslationUnit( |
694 | const TranslationUnitDecl *TU, |
695 | AnalysisManager &mgr, |
696 | BugReporter &BR) { |
697 | for (const auto EndOfTranslationUnitChecker : EndOfTranslationUnitCheckers) |
698 | EndOfTranslationUnitChecker(TU, mgr, BR); |
699 | } |
700 | |
701 | void CheckerManager::runCheckersForPrintState(raw_ostream &Out, |
702 | ProgramStateRef State, |
703 | const char *NL, const char *Sep) { |
704 | for (const auto &CheckerTag : CheckerTags) |
705 | CheckerTag.second->printState(Out, State, NL, Sep); |
706 | } |
707 | |
708 | |
709 | |
710 | |
711 | |
712 | void CheckerManager::_registerForDecl(CheckDeclFunc checkfn, |
713 | HandlesDeclFunc isForDeclFn) { |
714 | DeclCheckerInfo info = { checkfn, isForDeclFn }; |
715 | DeclCheckers.push_back(info); |
716 | } |
717 | |
718 | void CheckerManager::_registerForBody(CheckDeclFunc checkfn) { |
719 | BodyCheckers.push_back(checkfn); |
720 | } |
721 | |
722 | |
723 | |
724 | |
725 | |
726 | void CheckerManager::_registerForPreStmt(CheckStmtFunc checkfn, |
727 | HandlesStmtFunc isForStmtFn) { |
728 | StmtCheckerInfo info = { checkfn, isForStmtFn, }; |
729 | StmtCheckers.push_back(info); |
730 | } |
731 | |
732 | void CheckerManager::_registerForPostStmt(CheckStmtFunc checkfn, |
733 | HandlesStmtFunc isForStmtFn) { |
734 | StmtCheckerInfo info = { checkfn, isForStmtFn, }; |
735 | StmtCheckers.push_back(info); |
736 | } |
737 | |
738 | void CheckerManager::_registerForPreObjCMessage(CheckObjCMessageFunc checkfn) { |
739 | PreObjCMessageCheckers.push_back(checkfn); |
740 | } |
741 | |
742 | void CheckerManager::_registerForObjCMessageNil(CheckObjCMessageFunc checkfn) { |
743 | ObjCMessageNilCheckers.push_back(checkfn); |
744 | } |
745 | |
746 | void CheckerManager::_registerForPostObjCMessage(CheckObjCMessageFunc checkfn) { |
747 | PostObjCMessageCheckers.push_back(checkfn); |
748 | } |
749 | |
750 | void CheckerManager::_registerForPreCall(CheckCallFunc checkfn) { |
751 | PreCallCheckers.push_back(checkfn); |
752 | } |
753 | void CheckerManager::_registerForPostCall(CheckCallFunc checkfn) { |
754 | PostCallCheckers.push_back(checkfn); |
755 | } |
756 | |
757 | void CheckerManager::_registerForLocation(CheckLocationFunc checkfn) { |
758 | LocationCheckers.push_back(checkfn); |
759 | } |
760 | |
761 | void CheckerManager::_registerForBind(CheckBindFunc checkfn) { |
762 | BindCheckers.push_back(checkfn); |
763 | } |
764 | |
765 | void CheckerManager::_registerForEndAnalysis(CheckEndAnalysisFunc checkfn) { |
766 | EndAnalysisCheckers.push_back(checkfn); |
767 | } |
768 | |
769 | void CheckerManager::_registerForBeginFunction(CheckBeginFunctionFunc checkfn) { |
770 | BeginFunctionCheckers.push_back(checkfn); |
771 | } |
772 | |
773 | void CheckerManager::_registerForEndFunction(CheckEndFunctionFunc checkfn) { |
774 | EndFunctionCheckers.push_back(checkfn); |
775 | } |
776 | |
777 | void CheckerManager::_registerForBranchCondition( |
778 | CheckBranchConditionFunc checkfn) { |
779 | BranchConditionCheckers.push_back(checkfn); |
780 | } |
781 | |
782 | void CheckerManager::_registerForNewAllocator(CheckNewAllocatorFunc checkfn) { |
783 | NewAllocatorCheckers.push_back(checkfn); |
784 | } |
785 | |
786 | void CheckerManager::_registerForLiveSymbols(CheckLiveSymbolsFunc checkfn) { |
787 | LiveSymbolsCheckers.push_back(checkfn); |
788 | } |
789 | |
790 | void CheckerManager::_registerForDeadSymbols(CheckDeadSymbolsFunc checkfn) { |
791 | DeadSymbolsCheckers.push_back(checkfn); |
792 | } |
793 | |
794 | void CheckerManager::_registerForRegionChanges(CheckRegionChangesFunc checkfn) { |
795 | RegionChangesCheckers.push_back(checkfn); |
796 | } |
797 | |
798 | void CheckerManager::_registerForPointerEscape(CheckPointerEscapeFunc checkfn){ |
799 | PointerEscapeCheckers.push_back(checkfn); |
800 | } |
801 | |
802 | void CheckerManager::_registerForConstPointerEscape( |
803 | CheckPointerEscapeFunc checkfn) { |
804 | PointerEscapeCheckers.push_back(checkfn); |
805 | } |
806 | |
807 | void CheckerManager::_registerForEvalAssume(EvalAssumeFunc checkfn) { |
808 | EvalAssumeCheckers.push_back(checkfn); |
809 | } |
810 | |
811 | void CheckerManager::_registerForEvalCall(EvalCallFunc checkfn) { |
812 | EvalCallCheckers.push_back(checkfn); |
813 | } |
814 | |
815 | void CheckerManager::_registerForEndOfTranslationUnit( |
816 | CheckEndOfTranslationUnit checkfn) { |
817 | EndOfTranslationUnitCheckers.push_back(checkfn); |
818 | } |
819 | |
820 | |
821 | |
822 | |
823 | |
824 | const CheckerManager::CachedStmtCheckers & |
825 | CheckerManager::getCachedStmtCheckersFor(const Stmt *S, bool isPreVisit) { |
826 | assert(S); |
827 | |
828 | unsigned Key = (S->getStmtClass() << 1) | unsigned(isPreVisit); |
829 | CachedStmtCheckersMapTy::iterator CCI = CachedStmtCheckersMap.find(Key); |
830 | if (CCI != CachedStmtCheckersMap.end()) |
831 | return CCI->second; |
832 | |
833 | |
834 | CachedStmtCheckers &Checkers = CachedStmtCheckersMap[Key]; |
835 | for (const auto &Info : StmtCheckers) |
836 | if (Info.IsPreVisit == isPreVisit && Info.IsForStmtFn(S)) |
837 | Checkers.push_back(Info.CheckFn); |
838 | return Checkers; |
839 | } |
840 | |
841 | CheckerManager::~CheckerManager() { |
842 | for (const auto CheckerDtor : CheckerDtors) |
843 | CheckerDtor(); |
844 | } |
845 | |