/Users/buildslave/jenkins/sharedspace/clang-stage2-coverage-R@2/llvm/tools/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
Line | Count | Source (jump to first uncovered line) |
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/Analysis/ProgramPoint.h" |
17 | | #include "clang/StaticAnalyzer/Core/Checker.h" |
18 | | #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" |
19 | | #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" |
20 | | |
21 | | using namespace clang; |
22 | | using namespace ento; |
23 | | |
24 | 7.52k | bool CheckerManager::hasPathSensitiveCheckers() const { |
25 | 7.52k | return !StmtCheckers.empty() || |
26 | 898 | !PreObjCMessageCheckers.empty() || |
27 | 898 | !PostObjCMessageCheckers.empty() || |
28 | 890 | !PreCallCheckers.empty() || |
29 | 800 | !PostCallCheckers.empty() || |
30 | 709 | !LocationCheckers.empty() || |
31 | 687 | !BindCheckers.empty() || |
32 | 687 | !EndAnalysisCheckers.empty() || |
33 | 667 | !EndFunctionCheckers.empty() || |
34 | 665 | !BranchConditionCheckers.empty() || |
35 | 665 | !LiveSymbolsCheckers.empty() || |
36 | 665 | !DeadSymbolsCheckers.empty() || |
37 | 654 | !RegionChangesCheckers.empty() || |
38 | 654 | !EvalAssumeCheckers.empty() || |
39 | 654 | !EvalCallCheckers.empty(); |
40 | 7.52k | } |
41 | | |
42 | 567 | void CheckerManager::finishedCheckerRegistration() { |
43 | | #ifndef NDEBUG |
44 | | // Make sure that for every event that has listeners, there is at least |
45 | | // one dispatcher registered for it. |
46 | | for (llvm::DenseMap<EventTag, EventInfo>::iterator |
47 | | I = Events.begin(), E = Events.end(); I != E; ++I) |
48 | | assert(I->second.HasDispatcher && "No dispatcher registered for an event"); |
49 | | #endif |
50 | | } |
51 | | |
52 | | //===----------------------------------------------------------------------===// |
53 | | // Functions for running checkers for AST traversing.. |
54 | | //===----------------------------------------------------------------------===// |
55 | | |
56 | | void CheckerManager::runCheckersOnASTDecl(const Decl *D, AnalysisManager& mgr, |
57 | 40.6k | BugReporter &BR) { |
58 | 40.6k | assert(D); |
59 | 40.6k | |
60 | 40.6k | unsigned DeclKind = D->getKind(); |
61 | 40.6k | CachedDeclCheckers *checkers = nullptr; |
62 | 40.6k | CachedDeclCheckersMapTy::iterator CCI = CachedDeclCheckersMap.find(DeclKind); |
63 | 40.6k | if (CCI != CachedDeclCheckersMap.end()40.6k ) { |
64 | 36.5k | checkers = &(CCI->second); |
65 | 40.6k | } else { |
66 | 4.11k | // Find the checkers that should run for this Decl and cache them. |
67 | 4.11k | checkers = &CachedDeclCheckersMap[DeclKind]; |
68 | 4.85k | for (unsigned i = 0, e = DeclCheckers.size(); i != e4.85k ; ++i739 ) { |
69 | 739 | DeclCheckerInfo &info = DeclCheckers[i]; |
70 | 739 | if (info.IsForDeclFn(D)) |
71 | 53 | checkers->push_back(info.CheckFn); |
72 | 739 | } |
73 | 4.11k | } |
74 | 40.6k | |
75 | 40.6k | assert(checkers); |
76 | 40.6k | for (CachedDeclCheckers::iterator |
77 | 41.0k | I = checkers->begin(), E = checkers->end(); I != E41.0k ; ++I359 ) |
78 | 359 | (*I)(D, mgr, BR); |
79 | 40.6k | } |
80 | | |
81 | | void CheckerManager::runCheckersOnASTBody(const Decl *D, AnalysisManager& mgr, |
82 | 8.48k | BugReporter &BR) { |
83 | 8.48k | assert(D && D->hasBody()); |
84 | 8.48k | |
85 | 13.8k | for (unsigned i = 0, e = BodyCheckers.size(); i != e13.8k ; ++i5.34k ) |
86 | 5.34k | BodyCheckers[i](D, mgr, BR); |
87 | 8.48k | } |
88 | | |
89 | | //===----------------------------------------------------------------------===// |
90 | | // Functions for running checkers for path-sensitive checking. |
91 | | //===----------------------------------------------------------------------===// |
92 | | |
93 | | template <typename CHECK_CTX> |
94 | | static void expandGraphWithCheckers(CHECK_CTX checkCtx, |
95 | | ExplodedNodeSet &Dst, |
96 | 1.22M | const ExplodedNodeSet &Src) { |
97 | 1.22M | const NodeBuilderContext &BldrCtx = checkCtx.Eng.getBuilderContext(); |
98 | 1.22M | if (Src.empty()) |
99 | 13.0k | return; |
100 | 1.20M | |
101 | 1.20M | typename CHECK_CTX::CheckersTy::const_iterator |
102 | 1.20M | I = checkCtx.checkers_begin(), E = checkCtx.checkers_end(); |
103 | 1.20M | if (I == E1.20M ) { |
104 | 305k | Dst.insert(Src); |
105 | 305k | return; |
106 | 305k | } |
107 | 902k | |
108 | 902k | ExplodedNodeSet Tmp1, Tmp2; |
109 | 902k | const ExplodedNodeSet *PrevSet = &Src; |
110 | 902k | |
111 | 2.43M | for (; I != E2.43M ; ++I1.52M ) { |
112 | 1.52M | ExplodedNodeSet *CurrSet = nullptr; |
113 | 1.52M | if (I+1 == E) |
114 | 902k | CurrSet = &Dst; |
115 | 627k | else { |
116 | 627k | CurrSet = (PrevSet == &Tmp1) ? &Tmp2105k : &Tmp1521k ; |
117 | 627k | CurrSet->clear(); |
118 | 627k | } |
119 | 1.52M | |
120 | 1.52M | NodeBuilder B(*PrevSet, *CurrSet, BldrCtx); |
121 | 1.52M | for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end(); |
122 | 3.06M | NI != NE3.06M ; ++NI1.53M ) { |
123 | 1.53M | checkCtx.runChecker(*I, B, *NI); |
124 | 1.53M | } |
125 | 1.52M | |
126 | 1.52M | // If all the produced transitions are sinks, stop. |
127 | 1.52M | if (CurrSet->empty()) |
128 | 1.78k | return; |
129 | 1.52M | |
130 | 1.52M | // Update which NodeSet is the current one. |
131 | 1.52M | PrevSet = CurrSet; |
132 | 1.52M | } |
133 | 1.22M | } CheckerManager.cpp:void expandGraphWithCheckers<(anonymous namespace)::CheckStmtContext>((anonymous namespace)::CheckStmtContext, clang::ento::ExplodedNodeSet&, clang::ento::ExplodedNodeSet const&) Line | Count | Source | 96 | 833k | const ExplodedNodeSet &Src) { | 97 | 833k | const NodeBuilderContext &BldrCtx = checkCtx.Eng.getBuilderContext(); | 98 | 833k | if (Src.empty()) | 99 | 6.41k | return; | 100 | 826k | | 101 | 826k | typename CHECK_CTX::CheckersTy::const_iterator | 102 | 826k | I = checkCtx.checkers_begin(), E = checkCtx.checkers_end(); | 103 | 826k | if (I == E826k ) { | 104 | 285k | Dst.insert(Src); | 105 | 285k | return; | 106 | 285k | } | 107 | 541k | | 108 | 541k | ExplodedNodeSet Tmp1, Tmp2; | 109 | 541k | const ExplodedNodeSet *PrevSet = &Src; | 110 | 541k | | 111 | 1.32M | for (; I != E1.32M ; ++I781k ) { | 112 | 781k | ExplodedNodeSet *CurrSet = nullptr; | 113 | 781k | if (I+1 == E) | 114 | 541k | CurrSet = &Dst; | 115 | 240k | else { | 116 | 240k | CurrSet = (PrevSet == &Tmp1) ? &Tmp218.7k : &Tmp1221k ; | 117 | 240k | CurrSet->clear(); | 118 | 240k | } | 119 | 781k | | 120 | 781k | NodeBuilder B(*PrevSet, *CurrSet, BldrCtx); | 121 | 781k | for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end(); | 122 | 1.56M | NI != NE1.56M ; ++NI781k ) { | 123 | 781k | checkCtx.runChecker(*I, B, *NI); | 124 | 781k | } | 125 | 781k | | 126 | 781k | // If all the produced transitions are sinks, stop. | 127 | 781k | if (CurrSet->empty()) | 128 | 550 | return; | 129 | 781k | | 130 | 781k | // Update which NodeSet is the current one. | 131 | 781k | PrevSet = CurrSet; | 132 | 781k | } | 133 | 833k | } |
CheckerManager.cpp:void expandGraphWithCheckers<(anonymous namespace)::CheckObjCMessageContext>((anonymous namespace)::CheckObjCMessageContext, clang::ento::ExplodedNodeSet&, clang::ento::ExplodedNodeSet const&) Line | Count | Source | 96 | 7.62k | const ExplodedNodeSet &Src) { | 97 | 7.62k | const NodeBuilderContext &BldrCtx = checkCtx.Eng.getBuilderContext(); | 98 | 7.62k | if (Src.empty()) | 99 | 568 | return; | 100 | 7.05k | | 101 | 7.05k | typename CHECK_CTX::CheckersTy::const_iterator | 102 | 7.05k | I = checkCtx.checkers_begin(), E = checkCtx.checkers_end(); | 103 | 7.05k | if (I == E7.05k ) { | 104 | 110 | Dst.insert(Src); | 105 | 110 | return; | 106 | 110 | } | 107 | 6.94k | | 108 | 6.94k | ExplodedNodeSet Tmp1, Tmp2; | 109 | 6.94k | const ExplodedNodeSet *PrevSet = &Src; | 110 | 6.94k | | 111 | 22.3k | for (; I != E22.3k ; ++I15.4k ) { | 112 | 15.4k | ExplodedNodeSet *CurrSet = nullptr; | 113 | 15.4k | if (I+1 == E) | 114 | 6.93k | CurrSet = &Dst; | 115 | 8.54k | else { | 116 | 8.54k | CurrSet = (PrevSet == &Tmp1) ? &Tmp22.52k : &Tmp16.01k ; | 117 | 8.54k | CurrSet->clear(); | 118 | 8.54k | } | 119 | 15.4k | | 120 | 15.4k | NodeBuilder B(*PrevSet, *CurrSet, BldrCtx); | 121 | 15.4k | for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end(); | 122 | 30.9k | NI != NE30.9k ; ++NI15.4k ) { | 123 | 15.4k | checkCtx.runChecker(*I, B, *NI); | 124 | 15.4k | } | 125 | 15.4k | | 126 | 15.4k | // If all the produced transitions are sinks, stop. | 127 | 15.4k | if (CurrSet->empty()) | 128 | 74 | return; | 129 | 15.4k | | 130 | 15.4k | // Update which NodeSet is the current one. | 131 | 15.4k | PrevSet = CurrSet; | 132 | 15.4k | } | 133 | 7.62k | } |
CheckerManager.cpp:void expandGraphWithCheckers<(anonymous namespace)::CheckCallContext>((anonymous namespace)::CheckCallContext, clang::ento::ExplodedNodeSet&, clang::ento::ExplodedNodeSet const&) Line | Count | Source | 96 | 110k | const ExplodedNodeSet &Src) { | 97 | 110k | const NodeBuilderContext &BldrCtx = checkCtx.Eng.getBuilderContext(); | 98 | 110k | if (Src.empty()) | 99 | 6.07k | return; | 100 | 104k | | 101 | 104k | typename CHECK_CTX::CheckersTy::const_iterator | 102 | 104k | I = checkCtx.checkers_begin(), E = checkCtx.checkers_end(); | 103 | 104k | if (I == E104k ) { | 104 | 2.84k | Dst.insert(Src); | 105 | 2.84k | return; | 106 | 2.84k | } | 107 | 101k | | 108 | 101k | ExplodedNodeSet Tmp1, Tmp2; | 109 | 101k | const ExplodedNodeSet *PrevSet = &Src; | 110 | 101k | | 111 | 369k | for (; I != E369k ; ++I268k ) { | 112 | 268k | ExplodedNodeSet *CurrSet = nullptr; | 113 | 268k | if (I+1 == E) | 114 | 101k | CurrSet = &Dst; | 115 | 167k | else { | 116 | 167k | CurrSet = (PrevSet == &Tmp1) ? &Tmp252.1k : &Tmp1115k ; | 117 | 167k | CurrSet->clear(); | 118 | 167k | } | 119 | 268k | | 120 | 268k | NodeBuilder B(*PrevSet, *CurrSet, BldrCtx); | 121 | 268k | for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end(); | 122 | 538k | NI != NE538k ; ++NI269k ) { | 123 | 269k | checkCtx.runChecker(*I, B, *NI); | 124 | 269k | } | 125 | 268k | | 126 | 268k | // If all the produced transitions are sinks, stop. | 127 | 268k | if (CurrSet->empty()) | 128 | 400 | return; | 129 | 268k | | 130 | 268k | // Update which NodeSet is the current one. | 131 | 268k | PrevSet = CurrSet; | 132 | 268k | } | 133 | 110k | } |
CheckerManager.cpp:void expandGraphWithCheckers<(anonymous namespace)::CheckLocationContext>((anonymous namespace)::CheckLocationContext, clang::ento::ExplodedNodeSet&, clang::ento::ExplodedNodeSet const&) Line | Count | Source | 96 | 122k | const ExplodedNodeSet &Src) { | 97 | 122k | const NodeBuilderContext &BldrCtx = checkCtx.Eng.getBuilderContext(); | 98 | 122k | if (Src.empty()) | 99 | 0 | return; | 100 | 122k | | 101 | 122k | typename CHECK_CTX::CheckersTy::const_iterator | 102 | 122k | I = checkCtx.checkers_begin(), E = checkCtx.checkers_end(); | 103 | 122k | if (I == E122k ) { | 104 | 3.47k | Dst.insert(Src); | 105 | 3.47k | return; | 106 | 3.47k | } | 107 | 118k | | 108 | 118k | ExplodedNodeSet Tmp1, Tmp2; | 109 | 118k | const ExplodedNodeSet *PrevSet = &Src; | 110 | 118k | | 111 | 288k | for (; I != E288k ; ++I169k ) { | 112 | 170k | ExplodedNodeSet *CurrSet = nullptr; | 113 | 170k | if (I+1 == E) | 114 | 118k | CurrSet = &Dst; | 115 | 51.4k | else { | 116 | 51.4k | CurrSet = (PrevSet == &Tmp1) ? &Tmp2694 : &Tmp150.7k ; | 117 | 51.4k | CurrSet->clear(); | 118 | 51.4k | } | 119 | 170k | | 120 | 170k | NodeBuilder B(*PrevSet, *CurrSet, BldrCtx); | 121 | 170k | for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end(); | 122 | 340k | NI != NE340k ; ++NI170k ) { | 123 | 170k | checkCtx.runChecker(*I, B, *NI); | 124 | 170k | } | 125 | 170k | | 126 | 170k | // If all the produced transitions are sinks, stop. | 127 | 170k | if (CurrSet->empty()) | 128 | 650 | return; | 129 | 169k | | 130 | 169k | // Update which NodeSet is the current one. | 131 | 169k | PrevSet = CurrSet; | 132 | 169k | } | 133 | 122k | } |
CheckerManager.cpp:void expandGraphWithCheckers<(anonymous namespace)::CheckBindContext>((anonymous namespace)::CheckBindContext, clang::ento::ExplodedNodeSet&, clang::ento::ExplodedNodeSet const&) Line | Count | Source | 96 | 48.3k | const ExplodedNodeSet &Src) { | 97 | 48.3k | const NodeBuilderContext &BldrCtx = checkCtx.Eng.getBuilderContext(); | 98 | 48.3k | if (Src.empty()) | 99 | 0 | return; | 100 | 48.3k | | 101 | 48.3k | typename CHECK_CTX::CheckersTy::const_iterator | 102 | 48.3k | I = checkCtx.checkers_begin(), E = checkCtx.checkers_end(); | 103 | 48.3k | if (I == E48.3k ) { | 104 | 1.99k | Dst.insert(Src); | 105 | 1.99k | return; | 106 | 1.99k | } | 107 | 46.4k | | 108 | 46.4k | ExplodedNodeSet Tmp1, Tmp2; | 109 | 46.4k | const ExplodedNodeSet *PrevSet = &Src; | 110 | 46.4k | | 111 | 143k | for (; I != E143k ; ++I96.7k ) { | 112 | 96.8k | ExplodedNodeSet *CurrSet = nullptr; | 113 | 96.8k | if (I+1 == E) | 114 | 46.3k | CurrSet = &Dst; | 115 | 50.4k | else { | 116 | 50.4k | CurrSet = (PrevSet == &Tmp1) ? &Tmp23.68k : &Tmp146.7k ; | 117 | 50.4k | CurrSet->clear(); | 118 | 50.4k | } | 119 | 96.8k | | 120 | 96.8k | NodeBuilder B(*PrevSet, *CurrSet, BldrCtx); | 121 | 96.8k | for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end(); | 122 | 193k | NI != NE193k ; ++NI96.8k ) { | 123 | 96.8k | checkCtx.runChecker(*I, B, *NI); | 124 | 96.8k | } | 125 | 96.8k | | 126 | 96.8k | // If all the produced transitions are sinks, stop. | 127 | 96.8k | if (CurrSet->empty()) | 128 | 41 | return; | 129 | 96.7k | | 130 | 96.7k | // Update which NodeSet is the current one. | 131 | 96.7k | PrevSet = CurrSet; | 132 | 96.7k | } | 133 | 48.3k | } |
CheckerManager.cpp:void expandGraphWithCheckers<(anonymous namespace)::CheckBeginFunctionContext>((anonymous namespace)::CheckBeginFunctionContext, clang::ento::ExplodedNodeSet&, clang::ento::ExplodedNodeSet const&) Line | Count | Source | 96 | 11.8k | const ExplodedNodeSet &Src) { | 97 | 11.8k | const NodeBuilderContext &BldrCtx = checkCtx.Eng.getBuilderContext(); | 98 | 11.8k | if (Src.empty()) | 99 | 0 | return; | 100 | 11.8k | | 101 | 11.8k | typename CHECK_CTX::CheckersTy::const_iterator | 102 | 11.8k | I = checkCtx.checkers_begin(), E = checkCtx.checkers_end(); | 103 | 11.8k | if (I == E11.8k ) { | 104 | 9.74k | Dst.insert(Src); | 105 | 9.74k | return; | 106 | 9.74k | } | 107 | 2.13k | | 108 | 2.13k | ExplodedNodeSet Tmp1, Tmp2; | 109 | 2.13k | const ExplodedNodeSet *PrevSet = &Src; | 110 | 2.13k | | 111 | 4.58k | for (; I != E4.58k ; ++I2.45k ) { | 112 | 2.45k | ExplodedNodeSet *CurrSet = nullptr; | 113 | 2.45k | if (I+1 == E) | 114 | 2.13k | CurrSet = &Dst; | 115 | 318 | else { | 116 | 318 | CurrSet = (PrevSet == &Tmp1) ? &Tmp21 : &Tmp1317 ; | 117 | 318 | CurrSet->clear(); | 118 | 318 | } | 119 | 2.45k | | 120 | 2.45k | NodeBuilder B(*PrevSet, *CurrSet, BldrCtx); | 121 | 2.45k | for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end(); | 122 | 4.90k | NI != NE4.90k ; ++NI2.45k ) { | 123 | 2.45k | checkCtx.runChecker(*I, B, *NI); | 124 | 2.45k | } | 125 | 2.45k | | 126 | 2.45k | // If all the produced transitions are sinks, stop. | 127 | 2.45k | if (CurrSet->empty()) | 128 | 0 | return; | 129 | 2.45k | | 130 | 2.45k | // Update which NodeSet is the current one. | 131 | 2.45k | PrevSet = CurrSet; | 132 | 2.45k | } | 133 | 11.8k | } |
CheckerManager.cpp:void expandGraphWithCheckers<(anonymous namespace)::CheckBranchConditionContext>((anonymous namespace)::CheckBranchConditionContext, clang::ento::ExplodedNodeSet&, clang::ento::ExplodedNodeSet const&) Line | Count | Source | 96 | 25.6k | const ExplodedNodeSet &Src) { | 97 | 25.6k | const NodeBuilderContext &BldrCtx = checkCtx.Eng.getBuilderContext(); | 98 | 25.6k | if (Src.empty()) | 99 | 0 | return; | 100 | 25.6k | | 101 | 25.6k | typename CHECK_CTX::CheckersTy::const_iterator | 102 | 25.6k | I = checkCtx.checkers_begin(), E = checkCtx.checkers_end(); | 103 | 25.6k | if (I == E25.6k ) { | 104 | 623 | Dst.insert(Src); | 105 | 623 | return; | 106 | 623 | } | 107 | 24.9k | | 108 | 24.9k | ExplodedNodeSet Tmp1, Tmp2; | 109 | 24.9k | const ExplodedNodeSet *PrevSet = &Src; | 110 | 24.9k | | 111 | 51.1k | for (; I != E51.1k ; ++I26.1k ) { | 112 | 26.1k | ExplodedNodeSet *CurrSet = nullptr; | 113 | 26.1k | if (I+1 == E) | 114 | 24.9k | CurrSet = &Dst; | 115 | 1.18k | else { | 116 | 1.18k | CurrSet = (PrevSet == &Tmp1) ? &Tmp20 : &Tmp11.18k ; | 117 | 1.18k | CurrSet->clear(); | 118 | 1.18k | } | 119 | 26.1k | | 120 | 26.1k | NodeBuilder B(*PrevSet, *CurrSet, BldrCtx); | 121 | 26.1k | for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end(); | 122 | 52.3k | NI != NE52.3k ; ++NI26.1k ) { | 123 | 26.1k | checkCtx.runChecker(*I, B, *NI); | 124 | 26.1k | } | 125 | 26.1k | | 126 | 26.1k | // If all the produced transitions are sinks, stop. | 127 | 26.1k | if (CurrSet->empty()) | 128 | 50 | return; | 129 | 26.1k | | 130 | 26.1k | // Update which NodeSet is the current one. | 131 | 26.1k | PrevSet = CurrSet; | 132 | 26.1k | } | 133 | 25.6k | } |
CheckerManager.cpp:void expandGraphWithCheckers<(anonymous namespace)::CheckDeadSymbolsContext>((anonymous namespace)::CheckDeadSymbolsContext, clang::ento::ExplodedNodeSet&, clang::ento::ExplodedNodeSet const&) Line | Count | Source | 96 | 61.7k | const ExplodedNodeSet &Src) { | 97 | 61.7k | const NodeBuilderContext &BldrCtx = checkCtx.Eng.getBuilderContext(); | 98 | 61.7k | if (Src.empty()) | 99 | 0 | return; | 100 | 61.7k | | 101 | 61.7k | typename CHECK_CTX::CheckersTy::const_iterator | 102 | 61.7k | I = checkCtx.checkers_begin(), E = checkCtx.checkers_end(); | 103 | 61.7k | if (I == E61.7k ) { | 104 | 864 | Dst.insert(Src); | 105 | 864 | return; | 106 | 864 | } | 107 | 60.8k | | 108 | 60.8k | ExplodedNodeSet Tmp1, Tmp2; | 109 | 60.8k | const ExplodedNodeSet *PrevSet = &Src; | 110 | 60.8k | | 111 | 228k | for (; I != E228k ; ++I168k ) { | 112 | 168k | ExplodedNodeSet *CurrSet = nullptr; | 113 | 168k | if (I+1 == E) | 114 | 60.8k | CurrSet = &Dst; | 115 | 107k | else { | 116 | 107k | CurrSet = (PrevSet == &Tmp1) ? &Tmp227.8k : &Tmp179.4k ; | 117 | 107k | CurrSet->clear(); | 118 | 107k | } | 119 | 168k | | 120 | 168k | NodeBuilder B(*PrevSet, *CurrSet, BldrCtx); | 121 | 168k | for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end(); | 122 | 336k | NI != NE336k ; ++NI168k ) { | 123 | 168k | checkCtx.runChecker(*I, B, *NI); | 124 | 168k | } | 125 | 168k | | 126 | 168k | // If all the produced transitions are sinks, stop. | 127 | 168k | if (CurrSet->empty()) | 128 | 17 | return; | 129 | 168k | | 130 | 168k | // Update which NodeSet is the current one. | 131 | 168k | PrevSet = CurrSet; | 132 | 168k | } | 133 | 61.7k | } |
|
134 | | |
135 | | namespace { |
136 | | struct CheckStmtContext { |
137 | | typedef SmallVectorImpl<CheckerManager::CheckStmtFunc> CheckersTy; |
138 | | bool IsPreVisit; |
139 | | const CheckersTy &Checkers; |
140 | | const Stmt *S; |
141 | | ExprEngine &Eng; |
142 | | bool WasInlined; |
143 | | |
144 | 826k | CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } |
145 | 826k | CheckersTy::const_iterator checkers_end() { return Checkers.end(); } |
146 | | |
147 | | CheckStmtContext(bool isPreVisit, const CheckersTy &checkers, |
148 | | const Stmt *s, ExprEngine &eng, bool wasInlined = false) |
149 | | : IsPreVisit(isPreVisit), Checkers(checkers), S(s), Eng(eng), |
150 | 833k | WasInlined(wasInlined) {} |
151 | | |
152 | | void runChecker(CheckerManager::CheckStmtFunc checkFn, |
153 | 781k | NodeBuilder &Bldr, ExplodedNode *Pred) { |
154 | 781k | // FIXME: Remove respondsToCallback from CheckerContext; |
155 | 347k | ProgramPoint::Kind K = IsPreVisit ? ProgramPoint::PreStmtKind : |
156 | 434k | ProgramPoint::PostStmtKind; |
157 | 781k | const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K, |
158 | 781k | Pred->getLocationContext(), checkFn.Checker); |
159 | 781k | CheckerContext C(Bldr, Eng, Pred, L, WasInlined); |
160 | 781k | checkFn(S, C); |
161 | 781k | } |
162 | | }; |
163 | | } |
164 | | |
165 | | /// \brief Run checkers for visiting Stmts. |
166 | | void CheckerManager::runCheckersForStmt(bool isPreVisit, |
167 | | ExplodedNodeSet &Dst, |
168 | | const ExplodedNodeSet &Src, |
169 | | const Stmt *S, |
170 | | ExprEngine &Eng, |
171 | 833k | bool WasInlined) { |
172 | 833k | CheckStmtContext C(isPreVisit, getCachedStmtCheckersFor(S, isPreVisit), |
173 | 833k | S, Eng, WasInlined); |
174 | 833k | expandGraphWithCheckers(C, Dst, Src); |
175 | 833k | } |
176 | | |
177 | | namespace { |
178 | | struct CheckObjCMessageContext { |
179 | | typedef std::vector<CheckerManager::CheckObjCMessageFunc> CheckersTy; |
180 | | |
181 | | ObjCMessageVisitKind Kind; |
182 | | bool WasInlined; |
183 | | const CheckersTy &Checkers; |
184 | | const ObjCMethodCall &Msg; |
185 | | ExprEngine &Eng; |
186 | | |
187 | 7.05k | CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } |
188 | 7.05k | CheckersTy::const_iterator checkers_end() { return Checkers.end(); } |
189 | | |
190 | | CheckObjCMessageContext(ObjCMessageVisitKind visitKind, |
191 | | const CheckersTy &checkers, |
192 | | const ObjCMethodCall &msg, ExprEngine &eng, |
193 | | bool wasInlined) |
194 | | : Kind(visitKind), WasInlined(wasInlined), Checkers(checkers), |
195 | 7.62k | Msg(msg), Eng(eng) { } |
196 | | |
197 | | void runChecker(CheckerManager::CheckObjCMessageFunc checkFn, |
198 | 15.4k | NodeBuilder &Bldr, ExplodedNode *Pred) { |
199 | 15.4k | |
200 | 15.4k | bool IsPreVisit; |
201 | 15.4k | |
202 | 15.4k | switch (Kind) { |
203 | 8.23k | case ObjCMessageVisitKind::Pre: |
204 | 8.23k | IsPreVisit = true; |
205 | 8.23k | break; |
206 | 7.25k | case ObjCMessageVisitKind::MessageNil: |
207 | 7.25k | case ObjCMessageVisitKind::Post: |
208 | 7.25k | IsPreVisit = false; |
209 | 7.25k | break; |
210 | 15.4k | } |
211 | 15.4k | |
212 | 15.4k | const ProgramPoint &L = Msg.getProgramPoint(IsPreVisit,checkFn.Checker); |
213 | 15.4k | CheckerContext C(Bldr, Eng, Pred, L, WasInlined); |
214 | 15.4k | |
215 | 15.4k | checkFn(*Msg.cloneWithState<ObjCMethodCall>(Pred->getState()), C); |
216 | 15.4k | } |
217 | | }; |
218 | | } |
219 | | |
220 | | /// \brief Run checkers for visiting obj-c messages. |
221 | | void CheckerManager::runCheckersForObjCMessage(ObjCMessageVisitKind visitKind, |
222 | | ExplodedNodeSet &Dst, |
223 | | const ExplodedNodeSet &Src, |
224 | | const ObjCMethodCall &msg, |
225 | | ExprEngine &Eng, |
226 | 7.62k | bool WasInlined) { |
227 | 7.62k | auto &checkers = getObjCMessageCheckers(visitKind); |
228 | 7.62k | CheckObjCMessageContext C(visitKind, checkers, msg, Eng, WasInlined); |
229 | 7.62k | expandGraphWithCheckers(C, Dst, Src); |
230 | 7.62k | } |
231 | | |
232 | | const std::vector<CheckerManager::CheckObjCMessageFunc> & |
233 | 7.62k | CheckerManager::getObjCMessageCheckers(ObjCMessageVisitKind Kind) { |
234 | 7.62k | switch (Kind) { |
235 | 3.52k | case ObjCMessageVisitKind::Pre: |
236 | 3.52k | return PreObjCMessageCheckers; |
237 | 0 | break; |
238 | 4.00k | case ObjCMessageVisitKind::Post: |
239 | 4.00k | return PostObjCMessageCheckers; |
240 | 88 | case ObjCMessageVisitKind::MessageNil: |
241 | 88 | return ObjCMessageNilCheckers; |
242 | 0 | } |
243 | 0 | llvm_unreachable0 ("Unknown Kind"); |
244 | 0 | } |
245 | | namespace { |
246 | | // FIXME: This has all the same signatures as CheckObjCMessageContext. |
247 | | // Is there a way we can merge the two? |
248 | | struct CheckCallContext { |
249 | | typedef std::vector<CheckerManager::CheckCallFunc> CheckersTy; |
250 | | bool IsPreVisit, WasInlined; |
251 | | const CheckersTy &Checkers; |
252 | | const CallEvent &Call; |
253 | | ExprEngine &Eng; |
254 | | |
255 | 104k | CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } |
256 | 104k | CheckersTy::const_iterator checkers_end() { return Checkers.end(); } |
257 | | |
258 | | CheckCallContext(bool isPreVisit, const CheckersTy &checkers, |
259 | | const CallEvent &call, ExprEngine &eng, |
260 | | bool wasInlined) |
261 | | : IsPreVisit(isPreVisit), WasInlined(wasInlined), Checkers(checkers), |
262 | 110k | Call(call), Eng(eng) { } |
263 | | |
264 | | void runChecker(CheckerManager::CheckCallFunc checkFn, |
265 | 269k | NodeBuilder &Bldr, ExplodedNode *Pred) { |
266 | 269k | const ProgramPoint &L = Call.getProgramPoint(IsPreVisit,checkFn.Checker); |
267 | 269k | CheckerContext C(Bldr, Eng, Pred, L, WasInlined); |
268 | 269k | |
269 | 269k | checkFn(*Call.cloneWithState(Pred->getState()), C); |
270 | 269k | } |
271 | | }; |
272 | | } |
273 | | |
274 | | /// \brief Run checkers for visiting an abstract call event. |
275 | | void CheckerManager::runCheckersForCallEvent(bool isPreVisit, |
276 | | ExplodedNodeSet &Dst, |
277 | | const ExplodedNodeSet &Src, |
278 | | const CallEvent &Call, |
279 | | ExprEngine &Eng, |
280 | 110k | bool WasInlined) { |
281 | 110k | CheckCallContext C(isPreVisit, |
282 | 52.2k | isPreVisit ? PreCallCheckers |
283 | 58.0k | : PostCallCheckers, |
284 | 110k | Call, Eng, WasInlined); |
285 | 110k | expandGraphWithCheckers(C, Dst, Src); |
286 | 110k | } |
287 | | |
288 | | namespace { |
289 | | struct CheckLocationContext { |
290 | | typedef std::vector<CheckerManager::CheckLocationFunc> CheckersTy; |
291 | | const CheckersTy &Checkers; |
292 | | SVal Loc; |
293 | | bool IsLoad; |
294 | | const Stmt *NodeEx; /* Will become a CFGStmt */ |
295 | | const Stmt *BoundEx; |
296 | | ExprEngine &Eng; |
297 | | |
298 | 122k | CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } |
299 | 122k | CheckersTy::const_iterator checkers_end() { return Checkers.end(); } |
300 | | |
301 | | CheckLocationContext(const CheckersTy &checkers, |
302 | | SVal loc, bool isLoad, const Stmt *NodeEx, |
303 | | const Stmt *BoundEx, |
304 | | ExprEngine &eng) |
305 | | : Checkers(checkers), Loc(loc), IsLoad(isLoad), NodeEx(NodeEx), |
306 | 122k | BoundEx(BoundEx), Eng(eng) {} |
307 | | |
308 | | void runChecker(CheckerManager::CheckLocationFunc checkFn, |
309 | 170k | NodeBuilder &Bldr, ExplodedNode *Pred) { |
310 | 134k | ProgramPoint::Kind K = IsLoad ? ProgramPoint::PreLoadKind : |
311 | 35.3k | ProgramPoint::PreStoreKind; |
312 | 170k | const ProgramPoint &L = |
313 | 170k | ProgramPoint::getProgramPoint(NodeEx, K, |
314 | 170k | Pred->getLocationContext(), |
315 | 170k | checkFn.Checker); |
316 | 170k | CheckerContext C(Bldr, Eng, Pred, L); |
317 | 170k | checkFn(Loc, IsLoad, BoundEx, C); |
318 | 170k | } |
319 | | }; |
320 | | } |
321 | | |
322 | | /// \brief Run checkers for load/store of a location. |
323 | | |
324 | | void CheckerManager::runCheckersForLocation(ExplodedNodeSet &Dst, |
325 | | const ExplodedNodeSet &Src, |
326 | | SVal location, bool isLoad, |
327 | | const Stmt *NodeEx, |
328 | | const Stmt *BoundEx, |
329 | 122k | ExprEngine &Eng) { |
330 | 122k | CheckLocationContext C(LocationCheckers, location, isLoad, NodeEx, |
331 | 122k | BoundEx, Eng); |
332 | 122k | expandGraphWithCheckers(C, Dst, Src); |
333 | 122k | } |
334 | | |
335 | | namespace { |
336 | | struct CheckBindContext { |
337 | | typedef std::vector<CheckerManager::CheckBindFunc> CheckersTy; |
338 | | const CheckersTy &Checkers; |
339 | | SVal Loc; |
340 | | SVal Val; |
341 | | const Stmt *S; |
342 | | ExprEngine &Eng; |
343 | | const ProgramPoint &PP; |
344 | | |
345 | 48.3k | CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } |
346 | 48.3k | CheckersTy::const_iterator checkers_end() { return Checkers.end(); } |
347 | | |
348 | | CheckBindContext(const CheckersTy &checkers, |
349 | | SVal loc, SVal val, const Stmt *s, ExprEngine &eng, |
350 | | const ProgramPoint &pp) |
351 | 48.3k | : Checkers(checkers), Loc(loc), Val(val), S(s), Eng(eng), PP(pp) {} |
352 | | |
353 | | void runChecker(CheckerManager::CheckBindFunc checkFn, |
354 | 96.8k | NodeBuilder &Bldr, ExplodedNode *Pred) { |
355 | 96.8k | const ProgramPoint &L = PP.withTag(checkFn.Checker); |
356 | 96.8k | CheckerContext C(Bldr, Eng, Pred, L); |
357 | 96.8k | |
358 | 96.8k | checkFn(Loc, Val, S, C); |
359 | 96.8k | } |
360 | | }; |
361 | | } |
362 | | |
363 | | /// \brief Run checkers for binding of a value to a location. |
364 | | void CheckerManager::runCheckersForBind(ExplodedNodeSet &Dst, |
365 | | const ExplodedNodeSet &Src, |
366 | | SVal location, SVal val, |
367 | | const Stmt *S, ExprEngine &Eng, |
368 | 48.3k | const ProgramPoint &PP) { |
369 | 48.3k | CheckBindContext C(BindCheckers, location, val, S, Eng, PP); |
370 | 48.3k | expandGraphWithCheckers(C, Dst, Src); |
371 | 48.3k | } |
372 | | |
373 | | void CheckerManager::runCheckersForEndAnalysis(ExplodedGraph &G, |
374 | | BugReporter &BR, |
375 | 6.87k | ExprEngine &Eng) { |
376 | 10.9k | for (unsigned i = 0, e = EndAnalysisCheckers.size(); i != e10.9k ; ++i4.03k ) |
377 | 4.03k | EndAnalysisCheckers[i](G, BR, Eng); |
378 | 6.87k | } |
379 | | |
380 | | namespace { |
381 | | struct CheckBeginFunctionContext { |
382 | | typedef std::vector<CheckerManager::CheckBeginFunctionFunc> CheckersTy; |
383 | | const CheckersTy &Checkers; |
384 | | ExprEngine &Eng; |
385 | | const ProgramPoint &PP; |
386 | | |
387 | 11.8k | CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } |
388 | 11.8k | CheckersTy::const_iterator checkers_end() { return Checkers.end(); } |
389 | | |
390 | | CheckBeginFunctionContext(const CheckersTy &Checkers, ExprEngine &Eng, |
391 | | const ProgramPoint &PP) |
392 | 11.8k | : Checkers(Checkers), Eng(Eng), PP(PP) {} |
393 | | |
394 | | void runChecker(CheckerManager::CheckBeginFunctionFunc checkFn, |
395 | 2.45k | NodeBuilder &Bldr, ExplodedNode *Pred) { |
396 | 2.45k | const ProgramPoint &L = PP.withTag(checkFn.Checker); |
397 | 2.45k | CheckerContext C(Bldr, Eng, Pred, L); |
398 | 2.45k | |
399 | 2.45k | checkFn(C); |
400 | 2.45k | } |
401 | | }; |
402 | | } |
403 | | |
404 | | void CheckerManager::runCheckersForBeginFunction(ExplodedNodeSet &Dst, |
405 | | const BlockEdge &L, |
406 | | ExplodedNode *Pred, |
407 | 11.8k | ExprEngine &Eng) { |
408 | 11.8k | ExplodedNodeSet Src; |
409 | 11.8k | Src.insert(Pred); |
410 | 11.8k | CheckBeginFunctionContext C(BeginFunctionCheckers, Eng, L); |
411 | 11.8k | expandGraphWithCheckers(C, Dst, Src); |
412 | 11.8k | } |
413 | | |
414 | | /// \brief Run checkers for end of path. |
415 | | // Note, We do not chain the checker output (like in expandGraphWithCheckers) |
416 | | // for this callback since end of path nodes are expected to be final. |
417 | | void CheckerManager::runCheckersForEndFunction(NodeBuilderContext &BC, |
418 | | ExplodedNodeSet &Dst, |
419 | | ExplodedNode *Pred, |
420 | 13.1k | ExprEngine &Eng) { |
421 | 13.1k | |
422 | 13.1k | // We define the builder outside of the loop bacause if at least one checkers |
423 | 13.1k | // creates a sucsessor for Pred, we do not need to generate an |
424 | 13.1k | // autotransition for it. |
425 | 13.1k | NodeBuilder Bldr(Pred, Dst, BC); |
426 | 28.8k | for (unsigned i = 0, e = EndFunctionCheckers.size(); i != e28.8k ; ++i15.6k ) { |
427 | 15.6k | CheckEndFunctionFunc checkFn = EndFunctionCheckers[i]; |
428 | 15.6k | |
429 | 15.6k | const ProgramPoint &L = BlockEntrance(BC.Block, |
430 | 15.6k | Pred->getLocationContext(), |
431 | 15.6k | checkFn.Checker); |
432 | 15.6k | CheckerContext C(Bldr, Eng, Pred, L); |
433 | 15.6k | checkFn(C); |
434 | 15.6k | } |
435 | 13.1k | } |
436 | | |
437 | | namespace { |
438 | | struct CheckBranchConditionContext { |
439 | | typedef std::vector<CheckerManager::CheckBranchConditionFunc> CheckersTy; |
440 | | const CheckersTy &Checkers; |
441 | | const Stmt *Condition; |
442 | | ExprEngine &Eng; |
443 | | |
444 | 25.6k | CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } |
445 | 25.6k | CheckersTy::const_iterator checkers_end() { return Checkers.end(); } |
446 | | |
447 | | CheckBranchConditionContext(const CheckersTy &checkers, |
448 | | const Stmt *Cond, ExprEngine &eng) |
449 | 25.6k | : Checkers(checkers), Condition(Cond), Eng(eng) {} |
450 | | |
451 | | void runChecker(CheckerManager::CheckBranchConditionFunc checkFn, |
452 | 26.1k | NodeBuilder &Bldr, ExplodedNode *Pred) { |
453 | 26.1k | ProgramPoint L = PostCondition(Condition, Pred->getLocationContext(), |
454 | 26.1k | checkFn.Checker); |
455 | 26.1k | CheckerContext C(Bldr, Eng, Pred, L); |
456 | 26.1k | checkFn(Condition, C); |
457 | 26.1k | } |
458 | | }; |
459 | | } |
460 | | |
461 | | /// \brief Run checkers for branch condition. |
462 | | void CheckerManager::runCheckersForBranchCondition(const Stmt *Condition, |
463 | | ExplodedNodeSet &Dst, |
464 | | ExplodedNode *Pred, |
465 | 25.6k | ExprEngine &Eng) { |
466 | 25.6k | ExplodedNodeSet Src; |
467 | 25.6k | Src.insert(Pred); |
468 | 25.6k | CheckBranchConditionContext C(BranchConditionCheckers, Condition, Eng); |
469 | 25.6k | expandGraphWithCheckers(C, Dst, Src); |
470 | 25.6k | } |
471 | | |
472 | | /// \brief Run checkers for live symbols. |
473 | | void CheckerManager::runCheckersForLiveSymbols(ProgramStateRef state, |
474 | 179k | SymbolReaper &SymReaper) { |
475 | 244k | for (unsigned i = 0, e = LiveSymbolsCheckers.size(); i != e244k ; ++i64.5k ) |
476 | 64.5k | LiveSymbolsCheckers[i](state, SymReaper); |
477 | 179k | } |
478 | | |
479 | | namespace { |
480 | | struct CheckDeadSymbolsContext { |
481 | | typedef std::vector<CheckerManager::CheckDeadSymbolsFunc> CheckersTy; |
482 | | const CheckersTy &Checkers; |
483 | | SymbolReaper &SR; |
484 | | const Stmt *S; |
485 | | ExprEngine &Eng; |
486 | | ProgramPoint::Kind ProgarmPointKind; |
487 | | |
488 | 61.7k | CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } |
489 | 61.7k | CheckersTy::const_iterator checkers_end() { return Checkers.end(); } |
490 | | |
491 | | CheckDeadSymbolsContext(const CheckersTy &checkers, SymbolReaper &sr, |
492 | | const Stmt *s, ExprEngine &eng, |
493 | | ProgramPoint::Kind K) |
494 | 61.7k | : Checkers(checkers), SR(sr), S(s), Eng(eng), ProgarmPointKind(K) { } |
495 | | |
496 | | void runChecker(CheckerManager::CheckDeadSymbolsFunc checkFn, |
497 | 168k | NodeBuilder &Bldr, ExplodedNode *Pred) { |
498 | 168k | const ProgramPoint &L = ProgramPoint::getProgramPoint(S, ProgarmPointKind, |
499 | 168k | Pred->getLocationContext(), checkFn.Checker); |
500 | 168k | CheckerContext C(Bldr, Eng, Pred, L); |
501 | 168k | |
502 | 168k | // Note, do not pass the statement to the checkers without letting them |
503 | 168k | // differentiate if we ran remove dead bindings before or after the |
504 | 168k | // statement. |
505 | 168k | checkFn(SR, C); |
506 | 168k | } |
507 | | }; |
508 | | } |
509 | | |
510 | | /// \brief Run checkers for dead symbols. |
511 | | void CheckerManager::runCheckersForDeadSymbols(ExplodedNodeSet &Dst, |
512 | | const ExplodedNodeSet &Src, |
513 | | SymbolReaper &SymReaper, |
514 | | const Stmt *S, |
515 | | ExprEngine &Eng, |
516 | 61.7k | ProgramPoint::Kind K) { |
517 | 61.7k | CheckDeadSymbolsContext C(DeadSymbolsCheckers, SymReaper, S, Eng, K); |
518 | 61.7k | expandGraphWithCheckers(C, Dst, Src); |
519 | 61.7k | } |
520 | | |
521 | | /// \brief Run checkers for region changes. |
522 | | ProgramStateRef |
523 | | CheckerManager::runCheckersForRegionChanges(ProgramStateRef state, |
524 | | const InvalidatedSymbols *invalidated, |
525 | | ArrayRef<const MemRegion *> ExplicitRegions, |
526 | | ArrayRef<const MemRegion *> Regions, |
527 | | const LocationContext *LCtx, |
528 | 99.9k | const CallEvent *Call) { |
529 | 147k | for (unsigned i = 0, e = RegionChangesCheckers.size(); i != e147k ; ++i47.3k ) { |
530 | 47.3k | // If any checker declares the state infeasible (or if it starts that way), |
531 | 47.3k | // bail out. |
532 | 47.3k | if (!state) |
533 | 0 | return nullptr; |
534 | 47.3k | state = RegionChangesCheckers[i](state, invalidated, |
535 | 47.3k | ExplicitRegions, Regions, |
536 | 47.3k | LCtx, Call); |
537 | 47.3k | } |
538 | 99.9k | return state; |
539 | 99.9k | } |
540 | | |
541 | | /// \brief Run checkers to process symbol escape event. |
542 | | ProgramStateRef |
543 | | CheckerManager::runCheckersForPointerEscape(ProgramStateRef State, |
544 | | const InvalidatedSymbols &Escaped, |
545 | | const CallEvent *Call, |
546 | | PointerEscapeKind Kind, |
547 | 28.0k | RegionAndSymbolInvalidationTraits *ETraits) { |
548 | 28.0k | assert((Call != nullptr || |
549 | 28.0k | (Kind != PSK_DirectEscapeOnCall && |
550 | 28.0k | Kind != PSK_IndirectEscapeOnCall)) && |
551 | 28.0k | "Call must not be NULL when escaping on call"); |
552 | 49.2k | for (unsigned i = 0, e = PointerEscapeCheckers.size(); i != e49.2k ; ++i21.1k ) { |
553 | 21.1k | // If any checker declares the state infeasible (or if it starts that |
554 | 21.1k | // way), bail out. |
555 | 21.1k | if (!State) |
556 | 0 | return nullptr; |
557 | 21.1k | State = PointerEscapeCheckers[i](State, Escaped, Call, Kind, ETraits); |
558 | 21.1k | } |
559 | 28.0k | return State; |
560 | 28.0k | } |
561 | | |
562 | | /// \brief Run checkers for handling assumptions on symbolic values. |
563 | | ProgramStateRef |
564 | | CheckerManager::runCheckersForEvalAssume(ProgramStateRef state, |
565 | 402k | SVal Cond, bool Assumption) { |
566 | 509k | for (unsigned i = 0, e = EvalAssumeCheckers.size(); i != e509k ; ++i106k ) { |
567 | 173k | // If any checker declares the state infeasible (or if it starts that way), |
568 | 173k | // bail out. |
569 | 173k | if (!state) |
570 | 66.8k | return nullptr; |
571 | 106k | state = EvalAssumeCheckers[i](state, Cond, Assumption); |
572 | 106k | } |
573 | 335k | return state; |
574 | 402k | } |
575 | | |
576 | | /// \brief Run checkers for evaluating a call. |
577 | | /// Only one checker will evaluate the call. |
578 | | void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst, |
579 | | const ExplodedNodeSet &Src, |
580 | | const CallEvent &Call, |
581 | 30.9k | ExprEngine &Eng) { |
582 | 30.9k | const CallExpr *CE = cast<CallExpr>(Call.getOriginExpr()); |
583 | 30.9k | for (ExplodedNodeSet::iterator |
584 | 61.7k | NI = Src.begin(), NE = Src.end(); NI != NE61.7k ; ++NI30.7k ) { |
585 | 30.7k | ExplodedNode *Pred = *NI; |
586 | 30.7k | bool anyEvaluated = false; |
587 | 30.7k | |
588 | 30.7k | ExplodedNodeSet checkDst; |
589 | 30.7k | NodeBuilder B(Pred, checkDst, Eng.getBuilderContext()); |
590 | 30.7k | |
591 | 30.7k | // Check if any of the EvalCall callbacks can evaluate the call. |
592 | 30.7k | for (std::vector<EvalCallFunc>::iterator |
593 | 30.7k | EI = EvalCallCheckers.begin(), EE = EvalCallCheckers.end(); |
594 | 73.9k | EI != EE73.9k ; ++EI43.1k ) { |
595 | 49.0k | ProgramPoint::Kind K = ProgramPoint::PostStmtKind; |
596 | 49.0k | const ProgramPoint &L = ProgramPoint::getProgramPoint(CE, K, |
597 | 49.0k | Pred->getLocationContext(), EI->Checker); |
598 | 49.0k | bool evaluated = false; |
599 | 49.0k | { // CheckerContext generates transitions(populates checkDest) on |
600 | 49.0k | // destruction, so introduce the scope to make sure it gets properly |
601 | 49.0k | // populated. |
602 | 49.0k | CheckerContext C(B, Eng, Pred, L); |
603 | 49.0k | evaluated = (*EI)(CE, C); |
604 | 49.0k | } |
605 | 49.0k | assert(!(evaluated && anyEvaluated) |
606 | 49.0k | && "There are more than one checkers evaluating the call"); |
607 | 49.0k | if (evaluated49.0k ) { |
608 | 5.92k | anyEvaluated = true; |
609 | 5.92k | Dst.insert(checkDst); |
610 | 5.92k | #ifdef NDEBUG |
611 | 5.92k | break; // on release don't check that no other checker also evals. |
612 | 5.92k | #endif |
613 | 5.92k | } |
614 | 49.0k | } |
615 | 30.7k | |
616 | 30.7k | // If none of the checkers evaluated the call, ask ExprEngine to handle it. |
617 | 30.7k | if (!anyEvaluated30.7k ) { |
618 | 24.8k | NodeBuilder B(Pred, Dst, Eng.getBuilderContext()); |
619 | 24.8k | Eng.defaultEvalCall(B, Pred, Call); |
620 | 24.8k | } |
621 | 30.7k | } |
622 | 30.9k | } |
623 | | |
624 | | /// \brief Run checkers for the entire Translation Unit. |
625 | | void CheckerManager::runCheckersOnEndOfTranslationUnit( |
626 | | const TranslationUnitDecl *TU, |
627 | | AnalysisManager &mgr, |
628 | 555 | BugReporter &BR) { |
629 | 584 | for (unsigned i = 0, e = EndOfTranslationUnitCheckers.size(); i != e584 ; ++i29 ) |
630 | 29 | EndOfTranslationUnitCheckers[i](TU, mgr, BR); |
631 | 555 | } |
632 | | |
633 | | void CheckerManager::runCheckersForPrintState(raw_ostream &Out, |
634 | | ProgramStateRef State, |
635 | 1 | const char *NL, const char *Sep) { |
636 | 1 | for (llvm::DenseMap<CheckerTag, CheckerRef>::iterator |
637 | 2 | I = CheckerTags.begin(), E = CheckerTags.end(); I != E2 ; ++I1 ) |
638 | 1 | I->second->printState(Out, State, NL, Sep); |
639 | 1 | } |
640 | | |
641 | | //===----------------------------------------------------------------------===// |
642 | | // Internal registration functions for AST traversing. |
643 | | //===----------------------------------------------------------------------===// |
644 | | |
645 | | void CheckerManager::_registerForDecl(CheckDeclFunc checkfn, |
646 | 101 | HandlesDeclFunc isForDeclFn) { |
647 | 101 | DeclCheckerInfo info = { checkfn, isForDeclFn }; |
648 | 101 | DeclCheckers.push_back(info); |
649 | 101 | } |
650 | | |
651 | 358 | void CheckerManager::_registerForBody(CheckDeclFunc checkfn) { |
652 | 358 | BodyCheckers.push_back(checkfn); |
653 | 358 | } |
654 | | |
655 | | //===----------------------------------------------------------------------===// |
656 | | // Internal registration functions for path-sensitive checking. |
657 | | //===----------------------------------------------------------------------===// |
658 | | |
659 | | void CheckerManager::_registerForPreStmt(CheckStmtFunc checkfn, |
660 | 4.04k | HandlesStmtFunc isForStmtFn) { |
661 | 4.04k | StmtCheckerInfo info = { checkfn, isForStmtFn, /*IsPreVisit*/true }; |
662 | 4.04k | StmtCheckers.push_back(info); |
663 | 4.04k | } |
664 | | void CheckerManager::_registerForPostStmt(CheckStmtFunc checkfn, |
665 | 2.75k | HandlesStmtFunc isForStmtFn) { |
666 | 2.75k | StmtCheckerInfo info = { checkfn, isForStmtFn, /*IsPreVisit*/false }; |
667 | 2.75k | StmtCheckers.push_back(info); |
668 | 2.75k | } |
669 | | |
670 | 920 | void CheckerManager::_registerForPreObjCMessage(CheckObjCMessageFunc checkfn) { |
671 | 920 | PreObjCMessageCheckers.push_back(checkfn); |
672 | 920 | } |
673 | | |
674 | 415 | void CheckerManager::_registerForObjCMessageNil(CheckObjCMessageFunc checkfn) { |
675 | 415 | ObjCMessageNilCheckers.push_back(checkfn); |
676 | 415 | } |
677 | | |
678 | 1.01k | void CheckerManager::_registerForPostObjCMessage(CheckObjCMessageFunc checkfn) { |
679 | 1.01k | PostObjCMessageCheckers.push_back(checkfn); |
680 | 1.01k | } |
681 | | |
682 | 1.43k | void CheckerManager::_registerForPreCall(CheckCallFunc checkfn) { |
683 | 1.43k | PreCallCheckers.push_back(checkfn); |
684 | 1.43k | } |
685 | 984 | void CheckerManager::_registerForPostCall(CheckCallFunc checkfn) { |
686 | 984 | PostCallCheckers.push_back(checkfn); |
687 | 984 | } |
688 | | |
689 | 568 | void CheckerManager::_registerForLocation(CheckLocationFunc checkfn) { |
690 | 568 | LocationCheckers.push_back(checkfn); |
691 | 568 | } |
692 | | |
693 | 1.01k | void CheckerManager::_registerForBind(CheckBindFunc checkfn) { |
694 | 1.01k | BindCheckers.push_back(checkfn); |
695 | 1.01k | } |
696 | | |
697 | 203 | void CheckerManager::_registerForEndAnalysis(CheckEndAnalysisFunc checkfn) { |
698 | 203 | EndAnalysisCheckers.push_back(checkfn); |
699 | 203 | } |
700 | | |
701 | 91 | void CheckerManager::_registerForBeginFunction(CheckBeginFunctionFunc checkfn) { |
702 | 91 | BeginFunctionCheckers.push_back(checkfn); |
703 | 91 | } |
704 | | |
705 | 568 | void CheckerManager::_registerForEndFunction(CheckEndFunctionFunc checkfn) { |
706 | 568 | EndFunctionCheckers.push_back(checkfn); |
707 | 568 | } |
708 | | |
709 | | void CheckerManager::_registerForBranchCondition( |
710 | 487 | CheckBranchConditionFunc checkfn) { |
711 | 487 | BranchConditionCheckers.push_back(checkfn); |
712 | 487 | } |
713 | | |
714 | 106 | void CheckerManager::_registerForLiveSymbols(CheckLiveSymbolsFunc checkfn) { |
715 | 106 | LiveSymbolsCheckers.push_back(checkfn); |
716 | 106 | } |
717 | | |
718 | 937 | void CheckerManager::_registerForDeadSymbols(CheckDeadSymbolsFunc checkfn) { |
719 | 937 | DeadSymbolsCheckers.push_back(checkfn); |
720 | 937 | } |
721 | | |
722 | 170 | void CheckerManager::_registerForRegionChanges(CheckRegionChangesFunc checkfn) { |
723 | 170 | RegionChangesCheckers.push_back(checkfn); |
724 | 170 | } |
725 | | |
726 | 228 | void CheckerManager::_registerForPointerEscape(CheckPointerEscapeFunc checkfn){ |
727 | 228 | PointerEscapeCheckers.push_back(checkfn); |
728 | 228 | } |
729 | | |
730 | | void CheckerManager::_registerForConstPointerEscape( |
731 | 0 | CheckPointerEscapeFunc checkfn) { |
732 | 0 | PointerEscapeCheckers.push_back(checkfn); |
733 | 0 | } |
734 | | |
735 | 183 | void CheckerManager::_registerForEvalAssume(EvalAssumeFunc checkfn) { |
736 | 183 | EvalAssumeCheckers.push_back(checkfn); |
737 | 183 | } |
738 | | |
739 | 754 | void CheckerManager::_registerForEvalCall(EvalCallFunc checkfn) { |
740 | 754 | EvalCallCheckers.push_back(checkfn); |
741 | 754 | } |
742 | | |
743 | | void CheckerManager::_registerForEndOfTranslationUnit( |
744 | 29 | CheckEndOfTranslationUnit checkfn) { |
745 | 29 | EndOfTranslationUnitCheckers.push_back(checkfn); |
746 | 29 | } |
747 | | |
748 | | //===----------------------------------------------------------------------===// |
749 | | // Implementation details. |
750 | | //===----------------------------------------------------------------------===// |
751 | | |
752 | | const CheckerManager::CachedStmtCheckers & |
753 | 833k | CheckerManager::getCachedStmtCheckersFor(const Stmt *S, bool isPreVisit) { |
754 | 833k | assert(S); |
755 | 833k | |
756 | 833k | unsigned Key = (S->getStmtClass() << 1) | unsigned(isPreVisit); |
757 | 833k | CachedStmtCheckersMapTy::iterator CCI = CachedStmtCheckersMap.find(Key); |
758 | 833k | if (CCI != CachedStmtCheckersMap.end()) |
759 | 825k | return CCI->second; |
760 | 7.95k | |
761 | 7.95k | // Find the checkers that should run for this Stmt and cache them. |
762 | 7.95k | CachedStmtCheckers &Checkers = CachedStmtCheckersMap[Key]; |
763 | 121k | for (unsigned i = 0, e = StmtCheckers.size(); i != e121k ; ++i113k ) { |
764 | 113k | StmtCheckerInfo &Info = StmtCheckers[i]; |
765 | 113k | if (Info.IsPreVisit == isPreVisit && 113k Info.IsForStmtFn(S)57.0k ) |
766 | 4.54k | Checkers.push_back(Info.CheckFn); |
767 | 113k | } |
768 | 833k | return Checkers; |
769 | 833k | } |
770 | | |
771 | 567 | CheckerManager::~CheckerManager() { |
772 | 8.58k | for (unsigned i = 0, e = CheckerDtors.size(); i != e8.58k ; ++i8.02k ) |
773 | 8.02k | CheckerDtors[i](); |
774 | 567 | } |