xref: /openbsd-src/gnu/llvm/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp (revision 12c855180aad702bbcca06e0398d774beeafb155)
1e5dd7070Spatrick //===- CheckerManager.cpp - Static Analyzer Checker Manager ---------------===//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick //
9e5dd7070Spatrick // Defines the Static Analyzer Checker Manager.
10e5dd7070Spatrick //
11e5dd7070Spatrick //===----------------------------------------------------------------------===//
12e5dd7070Spatrick 
13e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/CheckerManager.h"
14e5dd7070Spatrick #include "clang/AST/DeclBase.h"
15e5dd7070Spatrick #include "clang/AST/Stmt.h"
16e5dd7070Spatrick #include "clang/Analysis/ProgramPoint.h"
17e5dd7070Spatrick #include "clang/Basic/JsonSupport.h"
18e5dd7070Spatrick #include "clang/Basic/LLVM.h"
19e5dd7070Spatrick #include "clang/Driver/DriverDiagnostic.h"
20e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/Checker.h"
21e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
22e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
23e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h"
24e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
25e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
26e5dd7070Spatrick #include "llvm/ADT/SmallVector.h"
27e5dd7070Spatrick #include "llvm/Support/Casting.h"
28e5dd7070Spatrick #include "llvm/Support/ErrorHandling.h"
29*12c85518Srobert #include "llvm/Support/FormatVariadic.h"
30e5dd7070Spatrick #include <cassert>
31*12c85518Srobert #include <optional>
32e5dd7070Spatrick #include <vector>
33e5dd7070Spatrick 
34e5dd7070Spatrick using namespace clang;
35e5dd7070Spatrick using namespace ento;
36e5dd7070Spatrick 
hasPathSensitiveCheckers() const37e5dd7070Spatrick bool CheckerManager::hasPathSensitiveCheckers() const {
38a9ac8606Spatrick   const auto IfAnyAreNonEmpty = [](const auto &... Callbacks) -> bool {
39*12c85518Srobert     return (!Callbacks.empty() || ...);
40a9ac8606Spatrick   };
41a9ac8606Spatrick   return IfAnyAreNonEmpty(
42a9ac8606Spatrick       StmtCheckers, PreObjCMessageCheckers, ObjCMessageNilCheckers,
43a9ac8606Spatrick       PostObjCMessageCheckers, PreCallCheckers, PostCallCheckers,
44a9ac8606Spatrick       LocationCheckers, BindCheckers, EndAnalysisCheckers,
45a9ac8606Spatrick       BeginFunctionCheckers, EndFunctionCheckers, BranchConditionCheckers,
46a9ac8606Spatrick       NewAllocatorCheckers, LiveSymbolsCheckers, DeadSymbolsCheckers,
47a9ac8606Spatrick       RegionChangesCheckers, PointerEscapeCheckers, EvalAssumeCheckers,
48a9ac8606Spatrick       EvalCallCheckers, EndOfTranslationUnitCheckers);
49e5dd7070Spatrick }
50e5dd7070Spatrick 
finishedCheckerRegistration()51e5dd7070Spatrick void CheckerManager::finishedCheckerRegistration() {
52e5dd7070Spatrick #ifndef NDEBUG
53e5dd7070Spatrick   // Make sure that for every event that has listeners, there is at least
54e5dd7070Spatrick   // one dispatcher registered for it.
55e5dd7070Spatrick   for (const auto &Event : Events)
56e5dd7070Spatrick     assert(Event.second.HasDispatcher &&
57e5dd7070Spatrick            "No dispatcher registered for an event");
58e5dd7070Spatrick #endif
59e5dd7070Spatrick }
60e5dd7070Spatrick 
reportInvalidCheckerOptionValue(const CheckerBase * C,StringRef OptionName,StringRef ExpectedValueDesc) const61e5dd7070Spatrick void CheckerManager::reportInvalidCheckerOptionValue(
62ec727ea7Spatrick     const CheckerBase *C, StringRef OptionName,
63ec727ea7Spatrick     StringRef ExpectedValueDesc) const {
64e5dd7070Spatrick 
65ec727ea7Spatrick   getDiagnostics().Report(diag::err_analyzer_checker_option_invalid_input)
66e5dd7070Spatrick       << (llvm::Twine() + C->getTagDescription() + ":" + OptionName).str()
67e5dd7070Spatrick       << ExpectedValueDesc;
68e5dd7070Spatrick }
69e5dd7070Spatrick 
70e5dd7070Spatrick //===----------------------------------------------------------------------===//
71e5dd7070Spatrick // Functions for running checkers for AST traversing..
72e5dd7070Spatrick //===----------------------------------------------------------------------===//
73e5dd7070Spatrick 
runCheckersOnASTDecl(const Decl * D,AnalysisManager & mgr,BugReporter & BR)74e5dd7070Spatrick void CheckerManager::runCheckersOnASTDecl(const Decl *D, AnalysisManager& mgr,
75e5dd7070Spatrick                                           BugReporter &BR) {
76e5dd7070Spatrick   assert(D);
77e5dd7070Spatrick 
78e5dd7070Spatrick   unsigned DeclKind = D->getKind();
79e5dd7070Spatrick   CachedDeclCheckers *checkers = nullptr;
80e5dd7070Spatrick   CachedDeclCheckersMapTy::iterator CCI = CachedDeclCheckersMap.find(DeclKind);
81e5dd7070Spatrick   if (CCI != CachedDeclCheckersMap.end()) {
82e5dd7070Spatrick     checkers = &(CCI->second);
83e5dd7070Spatrick   } else {
84e5dd7070Spatrick     // Find the checkers that should run for this Decl and cache them.
85e5dd7070Spatrick     checkers = &CachedDeclCheckersMap[DeclKind];
86e5dd7070Spatrick     for (const auto &info : DeclCheckers)
87e5dd7070Spatrick       if (info.IsForDeclFn(D))
88e5dd7070Spatrick         checkers->push_back(info.CheckFn);
89e5dd7070Spatrick   }
90e5dd7070Spatrick 
91e5dd7070Spatrick   assert(checkers);
92e5dd7070Spatrick   for (const auto &checker : *checkers)
93e5dd7070Spatrick     checker(D, mgr, BR);
94e5dd7070Spatrick }
95e5dd7070Spatrick 
runCheckersOnASTBody(const Decl * D,AnalysisManager & mgr,BugReporter & BR)96e5dd7070Spatrick void CheckerManager::runCheckersOnASTBody(const Decl *D, AnalysisManager& mgr,
97e5dd7070Spatrick                                           BugReporter &BR) {
98e5dd7070Spatrick   assert(D && D->hasBody());
99e5dd7070Spatrick 
100e5dd7070Spatrick   for (const auto &BodyChecker : BodyCheckers)
101e5dd7070Spatrick     BodyChecker(D, mgr, BR);
102e5dd7070Spatrick }
103e5dd7070Spatrick 
104e5dd7070Spatrick //===----------------------------------------------------------------------===//
105e5dd7070Spatrick // Functions for running checkers for path-sensitive checking.
106e5dd7070Spatrick //===----------------------------------------------------------------------===//
107e5dd7070Spatrick 
108e5dd7070Spatrick template <typename CHECK_CTX>
expandGraphWithCheckers(CHECK_CTX checkCtx,ExplodedNodeSet & Dst,const ExplodedNodeSet & Src)109e5dd7070Spatrick static void expandGraphWithCheckers(CHECK_CTX checkCtx,
110e5dd7070Spatrick                                     ExplodedNodeSet &Dst,
111e5dd7070Spatrick                                     const ExplodedNodeSet &Src) {
112e5dd7070Spatrick   const NodeBuilderContext &BldrCtx = checkCtx.Eng.getBuilderContext();
113e5dd7070Spatrick   if (Src.empty())
114e5dd7070Spatrick     return;
115e5dd7070Spatrick 
116e5dd7070Spatrick   typename CHECK_CTX::CheckersTy::const_iterator
117e5dd7070Spatrick       I = checkCtx.checkers_begin(), E = checkCtx.checkers_end();
118e5dd7070Spatrick   if (I == E) {
119e5dd7070Spatrick     Dst.insert(Src);
120e5dd7070Spatrick     return;
121e5dd7070Spatrick   }
122e5dd7070Spatrick 
123e5dd7070Spatrick   ExplodedNodeSet Tmp1, Tmp2;
124e5dd7070Spatrick   const ExplodedNodeSet *PrevSet = &Src;
125e5dd7070Spatrick 
126e5dd7070Spatrick   for (; I != E; ++I) {
127e5dd7070Spatrick     ExplodedNodeSet *CurrSet = nullptr;
128e5dd7070Spatrick     if (I+1 == E)
129e5dd7070Spatrick       CurrSet = &Dst;
130e5dd7070Spatrick     else {
131e5dd7070Spatrick       CurrSet = (PrevSet == &Tmp1) ? &Tmp2 : &Tmp1;
132e5dd7070Spatrick       CurrSet->clear();
133e5dd7070Spatrick     }
134e5dd7070Spatrick 
135e5dd7070Spatrick     NodeBuilder B(*PrevSet, *CurrSet, BldrCtx);
136e5dd7070Spatrick     for (const auto &NI : *PrevSet)
137e5dd7070Spatrick       checkCtx.runChecker(*I, B, NI);
138e5dd7070Spatrick 
139e5dd7070Spatrick     // If all the produced transitions are sinks, stop.
140e5dd7070Spatrick     if (CurrSet->empty())
141e5dd7070Spatrick       return;
142e5dd7070Spatrick 
143e5dd7070Spatrick     // Update which NodeSet is the current one.
144e5dd7070Spatrick     PrevSet = CurrSet;
145e5dd7070Spatrick   }
146e5dd7070Spatrick }
147e5dd7070Spatrick 
148e5dd7070Spatrick namespace {
149e5dd7070Spatrick 
150e5dd7070Spatrick   struct CheckStmtContext {
151e5dd7070Spatrick     using CheckersTy = SmallVectorImpl<CheckerManager::CheckStmtFunc>;
152e5dd7070Spatrick 
153e5dd7070Spatrick     bool IsPreVisit;
154e5dd7070Spatrick     const CheckersTy &Checkers;
155e5dd7070Spatrick     const Stmt *S;
156e5dd7070Spatrick     ExprEngine &Eng;
157e5dd7070Spatrick     bool WasInlined;
158e5dd7070Spatrick 
CheckStmtContext__anon9a9a7b160211::CheckStmtContext159e5dd7070Spatrick     CheckStmtContext(bool isPreVisit, const CheckersTy &checkers,
160e5dd7070Spatrick                      const Stmt *s, ExprEngine &eng, bool wasInlined = false)
161e5dd7070Spatrick         : IsPreVisit(isPreVisit), Checkers(checkers), S(s), Eng(eng),
162e5dd7070Spatrick           WasInlined(wasInlined) {}
163e5dd7070Spatrick 
checkers_begin__anon9a9a7b160211::CheckStmtContext164e5dd7070Spatrick     CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
checkers_end__anon9a9a7b160211::CheckStmtContext165e5dd7070Spatrick     CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
166e5dd7070Spatrick 
runChecker__anon9a9a7b160211::CheckStmtContext167e5dd7070Spatrick     void runChecker(CheckerManager::CheckStmtFunc checkFn,
168e5dd7070Spatrick                     NodeBuilder &Bldr, ExplodedNode *Pred) {
169e5dd7070Spatrick       // FIXME: Remove respondsToCallback from CheckerContext;
170e5dd7070Spatrick       ProgramPoint::Kind K =  IsPreVisit ? ProgramPoint::PreStmtKind :
171e5dd7070Spatrick                                            ProgramPoint::PostStmtKind;
172e5dd7070Spatrick       const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K,
173e5dd7070Spatrick                                 Pred->getLocationContext(), checkFn.Checker);
174e5dd7070Spatrick       CheckerContext C(Bldr, Eng, Pred, L, WasInlined);
175e5dd7070Spatrick       checkFn(S, C);
176e5dd7070Spatrick     }
177e5dd7070Spatrick   };
178e5dd7070Spatrick 
179e5dd7070Spatrick } // namespace
180e5dd7070Spatrick 
181e5dd7070Spatrick /// Run checkers for visiting Stmts.
runCheckersForStmt(bool isPreVisit,ExplodedNodeSet & Dst,const ExplodedNodeSet & Src,const Stmt * S,ExprEngine & Eng,bool WasInlined)182e5dd7070Spatrick void CheckerManager::runCheckersForStmt(bool isPreVisit,
183e5dd7070Spatrick                                         ExplodedNodeSet &Dst,
184e5dd7070Spatrick                                         const ExplodedNodeSet &Src,
185e5dd7070Spatrick                                         const Stmt *S,
186e5dd7070Spatrick                                         ExprEngine &Eng,
187e5dd7070Spatrick                                         bool WasInlined) {
188e5dd7070Spatrick   CheckStmtContext C(isPreVisit, getCachedStmtCheckersFor(S, isPreVisit),
189e5dd7070Spatrick                      S, Eng, WasInlined);
190e5dd7070Spatrick   expandGraphWithCheckers(C, Dst, Src);
191e5dd7070Spatrick }
192e5dd7070Spatrick 
193e5dd7070Spatrick namespace {
194e5dd7070Spatrick 
195e5dd7070Spatrick   struct CheckObjCMessageContext {
196e5dd7070Spatrick     using CheckersTy = std::vector<CheckerManager::CheckObjCMessageFunc>;
197e5dd7070Spatrick 
198e5dd7070Spatrick     ObjCMessageVisitKind Kind;
199e5dd7070Spatrick     bool WasInlined;
200e5dd7070Spatrick     const CheckersTy &Checkers;
201e5dd7070Spatrick     const ObjCMethodCall &Msg;
202e5dd7070Spatrick     ExprEngine &Eng;
203e5dd7070Spatrick 
CheckObjCMessageContext__anon9a9a7b160311::CheckObjCMessageContext204e5dd7070Spatrick     CheckObjCMessageContext(ObjCMessageVisitKind visitKind,
205e5dd7070Spatrick                             const CheckersTy &checkers,
206e5dd7070Spatrick                             const ObjCMethodCall &msg, ExprEngine &eng,
207e5dd7070Spatrick                             bool wasInlined)
208e5dd7070Spatrick         : Kind(visitKind), WasInlined(wasInlined), Checkers(checkers), Msg(msg),
209e5dd7070Spatrick           Eng(eng) {}
210e5dd7070Spatrick 
checkers_begin__anon9a9a7b160311::CheckObjCMessageContext211e5dd7070Spatrick     CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
checkers_end__anon9a9a7b160311::CheckObjCMessageContext212e5dd7070Spatrick     CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
213e5dd7070Spatrick 
runChecker__anon9a9a7b160311::CheckObjCMessageContext214e5dd7070Spatrick     void runChecker(CheckerManager::CheckObjCMessageFunc checkFn,
215e5dd7070Spatrick                     NodeBuilder &Bldr, ExplodedNode *Pred) {
216e5dd7070Spatrick       bool IsPreVisit;
217e5dd7070Spatrick 
218e5dd7070Spatrick       switch (Kind) {
219e5dd7070Spatrick         case ObjCMessageVisitKind::Pre:
220e5dd7070Spatrick           IsPreVisit = true;
221e5dd7070Spatrick           break;
222e5dd7070Spatrick         case ObjCMessageVisitKind::MessageNil:
223e5dd7070Spatrick         case ObjCMessageVisitKind::Post:
224e5dd7070Spatrick           IsPreVisit = false;
225e5dd7070Spatrick           break;
226e5dd7070Spatrick       }
227e5dd7070Spatrick 
228e5dd7070Spatrick       const ProgramPoint &L = Msg.getProgramPoint(IsPreVisit,checkFn.Checker);
229e5dd7070Spatrick       CheckerContext C(Bldr, Eng, Pred, L, WasInlined);
230e5dd7070Spatrick 
231e5dd7070Spatrick       checkFn(*Msg.cloneWithState<ObjCMethodCall>(Pred->getState()), C);
232e5dd7070Spatrick     }
233e5dd7070Spatrick   };
234e5dd7070Spatrick 
235e5dd7070Spatrick } // namespace
236e5dd7070Spatrick 
237e5dd7070Spatrick /// Run checkers for visiting obj-c messages.
runCheckersForObjCMessage(ObjCMessageVisitKind visitKind,ExplodedNodeSet & Dst,const ExplodedNodeSet & Src,const ObjCMethodCall & msg,ExprEngine & Eng,bool WasInlined)238e5dd7070Spatrick void CheckerManager::runCheckersForObjCMessage(ObjCMessageVisitKind visitKind,
239e5dd7070Spatrick                                                ExplodedNodeSet &Dst,
240e5dd7070Spatrick                                                const ExplodedNodeSet &Src,
241e5dd7070Spatrick                                                const ObjCMethodCall &msg,
242e5dd7070Spatrick                                                ExprEngine &Eng,
243e5dd7070Spatrick                                                bool WasInlined) {
244ec727ea7Spatrick   const auto &checkers = getObjCMessageCheckers(visitKind);
245e5dd7070Spatrick   CheckObjCMessageContext C(visitKind, checkers, msg, Eng, WasInlined);
246e5dd7070Spatrick   expandGraphWithCheckers(C, Dst, Src);
247e5dd7070Spatrick }
248e5dd7070Spatrick 
249e5dd7070Spatrick const std::vector<CheckerManager::CheckObjCMessageFunc> &
getObjCMessageCheckers(ObjCMessageVisitKind Kind) const250ec727ea7Spatrick CheckerManager::getObjCMessageCheckers(ObjCMessageVisitKind Kind) const {
251e5dd7070Spatrick   switch (Kind) {
252e5dd7070Spatrick   case ObjCMessageVisitKind::Pre:
253e5dd7070Spatrick     return PreObjCMessageCheckers;
254e5dd7070Spatrick     break;
255e5dd7070Spatrick   case ObjCMessageVisitKind::Post:
256e5dd7070Spatrick     return PostObjCMessageCheckers;
257e5dd7070Spatrick   case ObjCMessageVisitKind::MessageNil:
258e5dd7070Spatrick     return ObjCMessageNilCheckers;
259e5dd7070Spatrick   }
260e5dd7070Spatrick   llvm_unreachable("Unknown Kind");
261e5dd7070Spatrick }
262e5dd7070Spatrick 
263e5dd7070Spatrick namespace {
264e5dd7070Spatrick 
265e5dd7070Spatrick   // FIXME: This has all the same signatures as CheckObjCMessageContext.
266e5dd7070Spatrick   // Is there a way we can merge the two?
267e5dd7070Spatrick   struct CheckCallContext {
268e5dd7070Spatrick     using CheckersTy = std::vector<CheckerManager::CheckCallFunc>;
269e5dd7070Spatrick 
270e5dd7070Spatrick     bool IsPreVisit, WasInlined;
271e5dd7070Spatrick     const CheckersTy &Checkers;
272e5dd7070Spatrick     const CallEvent &Call;
273e5dd7070Spatrick     ExprEngine &Eng;
274e5dd7070Spatrick 
CheckCallContext__anon9a9a7b160411::CheckCallContext275e5dd7070Spatrick     CheckCallContext(bool isPreVisit, const CheckersTy &checkers,
276e5dd7070Spatrick                      const CallEvent &call, ExprEngine &eng,
277e5dd7070Spatrick                      bool wasInlined)
278e5dd7070Spatrick         : IsPreVisit(isPreVisit), WasInlined(wasInlined), Checkers(checkers),
279e5dd7070Spatrick           Call(call), Eng(eng) {}
280e5dd7070Spatrick 
checkers_begin__anon9a9a7b160411::CheckCallContext281e5dd7070Spatrick     CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
checkers_end__anon9a9a7b160411::CheckCallContext282e5dd7070Spatrick     CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
283e5dd7070Spatrick 
runChecker__anon9a9a7b160411::CheckCallContext284e5dd7070Spatrick     void runChecker(CheckerManager::CheckCallFunc checkFn,
285e5dd7070Spatrick                     NodeBuilder &Bldr, ExplodedNode *Pred) {
286e5dd7070Spatrick       const ProgramPoint &L = Call.getProgramPoint(IsPreVisit,checkFn.Checker);
287e5dd7070Spatrick       CheckerContext C(Bldr, Eng, Pred, L, WasInlined);
288e5dd7070Spatrick 
289e5dd7070Spatrick       checkFn(*Call.cloneWithState(Pred->getState()), C);
290e5dd7070Spatrick     }
291e5dd7070Spatrick   };
292e5dd7070Spatrick 
293e5dd7070Spatrick } // namespace
294e5dd7070Spatrick 
295e5dd7070Spatrick /// Run checkers for visiting an abstract call event.
runCheckersForCallEvent(bool isPreVisit,ExplodedNodeSet & Dst,const ExplodedNodeSet & Src,const CallEvent & Call,ExprEngine & Eng,bool WasInlined)296e5dd7070Spatrick void CheckerManager::runCheckersForCallEvent(bool isPreVisit,
297e5dd7070Spatrick                                              ExplodedNodeSet &Dst,
298e5dd7070Spatrick                                              const ExplodedNodeSet &Src,
299e5dd7070Spatrick                                              const CallEvent &Call,
300e5dd7070Spatrick                                              ExprEngine &Eng,
301e5dd7070Spatrick                                              bool WasInlined) {
302e5dd7070Spatrick   CheckCallContext C(isPreVisit,
303e5dd7070Spatrick                      isPreVisit ? PreCallCheckers
304e5dd7070Spatrick                                 : PostCallCheckers,
305e5dd7070Spatrick                      Call, Eng, WasInlined);
306e5dd7070Spatrick   expandGraphWithCheckers(C, Dst, Src);
307e5dd7070Spatrick }
308e5dd7070Spatrick 
309e5dd7070Spatrick namespace {
310e5dd7070Spatrick 
311e5dd7070Spatrick   struct CheckLocationContext {
312e5dd7070Spatrick     using CheckersTy = std::vector<CheckerManager::CheckLocationFunc>;
313e5dd7070Spatrick 
314e5dd7070Spatrick     const CheckersTy &Checkers;
315e5dd7070Spatrick     SVal Loc;
316e5dd7070Spatrick     bool IsLoad;
317e5dd7070Spatrick     const Stmt *NodeEx; /* Will become a CFGStmt */
318e5dd7070Spatrick     const Stmt *BoundEx;
319e5dd7070Spatrick     ExprEngine &Eng;
320e5dd7070Spatrick 
CheckLocationContext__anon9a9a7b160511::CheckLocationContext321e5dd7070Spatrick     CheckLocationContext(const CheckersTy &checkers,
322e5dd7070Spatrick                          SVal loc, bool isLoad, const Stmt *NodeEx,
323e5dd7070Spatrick                          const Stmt *BoundEx,
324e5dd7070Spatrick                          ExprEngine &eng)
325e5dd7070Spatrick         : Checkers(checkers), Loc(loc), IsLoad(isLoad), NodeEx(NodeEx),
326e5dd7070Spatrick           BoundEx(BoundEx), Eng(eng) {}
327e5dd7070Spatrick 
checkers_begin__anon9a9a7b160511::CheckLocationContext328e5dd7070Spatrick     CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
checkers_end__anon9a9a7b160511::CheckLocationContext329e5dd7070Spatrick     CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
330e5dd7070Spatrick 
runChecker__anon9a9a7b160511::CheckLocationContext331e5dd7070Spatrick     void runChecker(CheckerManager::CheckLocationFunc checkFn,
332e5dd7070Spatrick                     NodeBuilder &Bldr, ExplodedNode *Pred) {
333e5dd7070Spatrick       ProgramPoint::Kind K =  IsLoad ? ProgramPoint::PreLoadKind :
334e5dd7070Spatrick                                        ProgramPoint::PreStoreKind;
335e5dd7070Spatrick       const ProgramPoint &L =
336e5dd7070Spatrick         ProgramPoint::getProgramPoint(NodeEx, K,
337e5dd7070Spatrick                                       Pred->getLocationContext(),
338e5dd7070Spatrick                                       checkFn.Checker);
339e5dd7070Spatrick       CheckerContext C(Bldr, Eng, Pred, L);
340e5dd7070Spatrick       checkFn(Loc, IsLoad, BoundEx, C);
341e5dd7070Spatrick     }
342e5dd7070Spatrick   };
343e5dd7070Spatrick 
344e5dd7070Spatrick } // namespace
345e5dd7070Spatrick 
346e5dd7070Spatrick /// Run checkers for load/store of a location.
347e5dd7070Spatrick 
runCheckersForLocation(ExplodedNodeSet & Dst,const ExplodedNodeSet & Src,SVal location,bool isLoad,const Stmt * NodeEx,const Stmt * BoundEx,ExprEngine & Eng)348e5dd7070Spatrick void CheckerManager::runCheckersForLocation(ExplodedNodeSet &Dst,
349e5dd7070Spatrick                                             const ExplodedNodeSet &Src,
350e5dd7070Spatrick                                             SVal location, bool isLoad,
351e5dd7070Spatrick                                             const Stmt *NodeEx,
352e5dd7070Spatrick                                             const Stmt *BoundEx,
353e5dd7070Spatrick                                             ExprEngine &Eng) {
354e5dd7070Spatrick   CheckLocationContext C(LocationCheckers, location, isLoad, NodeEx,
355e5dd7070Spatrick                          BoundEx, Eng);
356e5dd7070Spatrick   expandGraphWithCheckers(C, Dst, Src);
357e5dd7070Spatrick }
358e5dd7070Spatrick 
359e5dd7070Spatrick namespace {
360e5dd7070Spatrick 
361e5dd7070Spatrick   struct CheckBindContext {
362e5dd7070Spatrick     using CheckersTy = std::vector<CheckerManager::CheckBindFunc>;
363e5dd7070Spatrick 
364e5dd7070Spatrick     const CheckersTy &Checkers;
365e5dd7070Spatrick     SVal Loc;
366e5dd7070Spatrick     SVal Val;
367e5dd7070Spatrick     const Stmt *S;
368e5dd7070Spatrick     ExprEngine &Eng;
369e5dd7070Spatrick     const ProgramPoint &PP;
370e5dd7070Spatrick 
CheckBindContext__anon9a9a7b160611::CheckBindContext371e5dd7070Spatrick     CheckBindContext(const CheckersTy &checkers,
372e5dd7070Spatrick                      SVal loc, SVal val, const Stmt *s, ExprEngine &eng,
373e5dd7070Spatrick                      const ProgramPoint &pp)
374e5dd7070Spatrick         : Checkers(checkers), Loc(loc), Val(val), S(s), Eng(eng), PP(pp) {}
375e5dd7070Spatrick 
checkers_begin__anon9a9a7b160611::CheckBindContext376e5dd7070Spatrick     CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
checkers_end__anon9a9a7b160611::CheckBindContext377e5dd7070Spatrick     CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
378e5dd7070Spatrick 
runChecker__anon9a9a7b160611::CheckBindContext379e5dd7070Spatrick     void runChecker(CheckerManager::CheckBindFunc checkFn,
380e5dd7070Spatrick                     NodeBuilder &Bldr, ExplodedNode *Pred) {
381e5dd7070Spatrick       const ProgramPoint &L = PP.withTag(checkFn.Checker);
382e5dd7070Spatrick       CheckerContext C(Bldr, Eng, Pred, L);
383e5dd7070Spatrick 
384e5dd7070Spatrick       checkFn(Loc, Val, S, C);
385e5dd7070Spatrick     }
386e5dd7070Spatrick   };
387e5dd7070Spatrick 
388e5dd7070Spatrick } // namespace
389e5dd7070Spatrick 
390e5dd7070Spatrick /// Run checkers for binding of a value to a location.
runCheckersForBind(ExplodedNodeSet & Dst,const ExplodedNodeSet & Src,SVal location,SVal val,const Stmt * S,ExprEngine & Eng,const ProgramPoint & PP)391e5dd7070Spatrick void CheckerManager::runCheckersForBind(ExplodedNodeSet &Dst,
392e5dd7070Spatrick                                         const ExplodedNodeSet &Src,
393e5dd7070Spatrick                                         SVal location, SVal val,
394e5dd7070Spatrick                                         const Stmt *S, ExprEngine &Eng,
395e5dd7070Spatrick                                         const ProgramPoint &PP) {
396e5dd7070Spatrick   CheckBindContext C(BindCheckers, location, val, S, Eng, PP);
397e5dd7070Spatrick   expandGraphWithCheckers(C, Dst, Src);
398e5dd7070Spatrick }
399e5dd7070Spatrick 
runCheckersForEndAnalysis(ExplodedGraph & G,BugReporter & BR,ExprEngine & Eng)400e5dd7070Spatrick void CheckerManager::runCheckersForEndAnalysis(ExplodedGraph &G,
401e5dd7070Spatrick                                                BugReporter &BR,
402e5dd7070Spatrick                                                ExprEngine &Eng) {
403e5dd7070Spatrick   for (const auto &EndAnalysisChecker : EndAnalysisCheckers)
404e5dd7070Spatrick     EndAnalysisChecker(G, BR, Eng);
405e5dd7070Spatrick }
406e5dd7070Spatrick 
407e5dd7070Spatrick namespace {
408e5dd7070Spatrick 
409e5dd7070Spatrick struct CheckBeginFunctionContext {
410e5dd7070Spatrick   using CheckersTy = std::vector<CheckerManager::CheckBeginFunctionFunc>;
411e5dd7070Spatrick 
412e5dd7070Spatrick   const CheckersTy &Checkers;
413e5dd7070Spatrick   ExprEngine &Eng;
414e5dd7070Spatrick   const ProgramPoint &PP;
415e5dd7070Spatrick 
CheckBeginFunctionContext__anon9a9a7b160711::CheckBeginFunctionContext416e5dd7070Spatrick   CheckBeginFunctionContext(const CheckersTy &Checkers, ExprEngine &Eng,
417e5dd7070Spatrick                             const ProgramPoint &PP)
418e5dd7070Spatrick       : Checkers(Checkers), Eng(Eng), PP(PP) {}
419e5dd7070Spatrick 
checkers_begin__anon9a9a7b160711::CheckBeginFunctionContext420e5dd7070Spatrick   CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
checkers_end__anon9a9a7b160711::CheckBeginFunctionContext421e5dd7070Spatrick   CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
422e5dd7070Spatrick 
runChecker__anon9a9a7b160711::CheckBeginFunctionContext423e5dd7070Spatrick   void runChecker(CheckerManager::CheckBeginFunctionFunc checkFn,
424e5dd7070Spatrick                   NodeBuilder &Bldr, ExplodedNode *Pred) {
425e5dd7070Spatrick     const ProgramPoint &L = PP.withTag(checkFn.Checker);
426e5dd7070Spatrick     CheckerContext C(Bldr, Eng, Pred, L);
427e5dd7070Spatrick 
428e5dd7070Spatrick     checkFn(C);
429e5dd7070Spatrick   }
430e5dd7070Spatrick };
431e5dd7070Spatrick 
432e5dd7070Spatrick } // namespace
433e5dd7070Spatrick 
runCheckersForBeginFunction(ExplodedNodeSet & Dst,const BlockEdge & L,ExplodedNode * Pred,ExprEngine & Eng)434e5dd7070Spatrick void CheckerManager::runCheckersForBeginFunction(ExplodedNodeSet &Dst,
435e5dd7070Spatrick                                                  const BlockEdge &L,
436e5dd7070Spatrick                                                  ExplodedNode *Pred,
437e5dd7070Spatrick                                                  ExprEngine &Eng) {
438e5dd7070Spatrick   ExplodedNodeSet Src;
439e5dd7070Spatrick   Src.insert(Pred);
440e5dd7070Spatrick   CheckBeginFunctionContext C(BeginFunctionCheckers, Eng, L);
441e5dd7070Spatrick   expandGraphWithCheckers(C, Dst, Src);
442e5dd7070Spatrick }
443e5dd7070Spatrick 
444e5dd7070Spatrick /// Run checkers for end of path.
445e5dd7070Spatrick // Note, We do not chain the checker output (like in expandGraphWithCheckers)
446e5dd7070Spatrick // for this callback since end of path nodes are expected to be final.
runCheckersForEndFunction(NodeBuilderContext & BC,ExplodedNodeSet & Dst,ExplodedNode * Pred,ExprEngine & Eng,const ReturnStmt * RS)447e5dd7070Spatrick void CheckerManager::runCheckersForEndFunction(NodeBuilderContext &BC,
448e5dd7070Spatrick                                                ExplodedNodeSet &Dst,
449e5dd7070Spatrick                                                ExplodedNode *Pred,
450e5dd7070Spatrick                                                ExprEngine &Eng,
451e5dd7070Spatrick                                                const ReturnStmt *RS) {
452e5dd7070Spatrick   // We define the builder outside of the loop because if at least one checker
453e5dd7070Spatrick   // creates a successor for Pred, we do not need to generate an
454e5dd7070Spatrick   // autotransition for it.
455e5dd7070Spatrick   NodeBuilder Bldr(Pred, Dst, BC);
456e5dd7070Spatrick   for (const auto &checkFn : EndFunctionCheckers) {
457e5dd7070Spatrick     const ProgramPoint &L =
458e5dd7070Spatrick         FunctionExitPoint(RS, Pred->getLocationContext(), checkFn.Checker);
459e5dd7070Spatrick     CheckerContext C(Bldr, Eng, Pred, L);
460e5dd7070Spatrick     checkFn(RS, C);
461e5dd7070Spatrick   }
462e5dd7070Spatrick }
463e5dd7070Spatrick 
464e5dd7070Spatrick namespace {
465e5dd7070Spatrick 
466e5dd7070Spatrick   struct CheckBranchConditionContext {
467e5dd7070Spatrick     using CheckersTy = std::vector<CheckerManager::CheckBranchConditionFunc>;
468e5dd7070Spatrick 
469e5dd7070Spatrick     const CheckersTy &Checkers;
470e5dd7070Spatrick     const Stmt *Condition;
471e5dd7070Spatrick     ExprEngine &Eng;
472e5dd7070Spatrick 
CheckBranchConditionContext__anon9a9a7b160811::CheckBranchConditionContext473e5dd7070Spatrick     CheckBranchConditionContext(const CheckersTy &checkers,
474e5dd7070Spatrick                                 const Stmt *Cond, ExprEngine &eng)
475e5dd7070Spatrick         : Checkers(checkers), Condition(Cond), Eng(eng) {}
476e5dd7070Spatrick 
checkers_begin__anon9a9a7b160811::CheckBranchConditionContext477e5dd7070Spatrick     CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
checkers_end__anon9a9a7b160811::CheckBranchConditionContext478e5dd7070Spatrick     CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
479e5dd7070Spatrick 
runChecker__anon9a9a7b160811::CheckBranchConditionContext480e5dd7070Spatrick     void runChecker(CheckerManager::CheckBranchConditionFunc checkFn,
481e5dd7070Spatrick                     NodeBuilder &Bldr, ExplodedNode *Pred) {
482e5dd7070Spatrick       ProgramPoint L = PostCondition(Condition, Pred->getLocationContext(),
483e5dd7070Spatrick                                      checkFn.Checker);
484e5dd7070Spatrick       CheckerContext C(Bldr, Eng, Pred, L);
485e5dd7070Spatrick       checkFn(Condition, C);
486e5dd7070Spatrick     }
487e5dd7070Spatrick   };
488e5dd7070Spatrick 
489e5dd7070Spatrick } // namespace
490e5dd7070Spatrick 
491e5dd7070Spatrick /// Run checkers for branch condition.
runCheckersForBranchCondition(const Stmt * Condition,ExplodedNodeSet & Dst,ExplodedNode * Pred,ExprEngine & Eng)492e5dd7070Spatrick void CheckerManager::runCheckersForBranchCondition(const Stmt *Condition,
493e5dd7070Spatrick                                                    ExplodedNodeSet &Dst,
494e5dd7070Spatrick                                                    ExplodedNode *Pred,
495e5dd7070Spatrick                                                    ExprEngine &Eng) {
496e5dd7070Spatrick   ExplodedNodeSet Src;
497e5dd7070Spatrick   Src.insert(Pred);
498e5dd7070Spatrick   CheckBranchConditionContext C(BranchConditionCheckers, Condition, Eng);
499e5dd7070Spatrick   expandGraphWithCheckers(C, Dst, Src);
500e5dd7070Spatrick }
501e5dd7070Spatrick 
502e5dd7070Spatrick namespace {
503e5dd7070Spatrick 
504e5dd7070Spatrick   struct CheckNewAllocatorContext {
505e5dd7070Spatrick     using CheckersTy = std::vector<CheckerManager::CheckNewAllocatorFunc>;
506e5dd7070Spatrick 
507e5dd7070Spatrick     const CheckersTy &Checkers;
508ec727ea7Spatrick     const CXXAllocatorCall &Call;
509e5dd7070Spatrick     bool WasInlined;
510e5dd7070Spatrick     ExprEngine &Eng;
511e5dd7070Spatrick 
CheckNewAllocatorContext__anon9a9a7b160911::CheckNewAllocatorContext512ec727ea7Spatrick     CheckNewAllocatorContext(const CheckersTy &Checkers,
513ec727ea7Spatrick                              const CXXAllocatorCall &Call, bool WasInlined,
514ec727ea7Spatrick                              ExprEngine &Eng)
515ec727ea7Spatrick         : Checkers(Checkers), Call(Call), WasInlined(WasInlined), Eng(Eng) {}
516e5dd7070Spatrick 
checkers_begin__anon9a9a7b160911::CheckNewAllocatorContext517e5dd7070Spatrick     CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
checkers_end__anon9a9a7b160911::CheckNewAllocatorContext518e5dd7070Spatrick     CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
519e5dd7070Spatrick 
runChecker__anon9a9a7b160911::CheckNewAllocatorContext520e5dd7070Spatrick     void runChecker(CheckerManager::CheckNewAllocatorFunc checkFn,
521e5dd7070Spatrick                     NodeBuilder &Bldr, ExplodedNode *Pred) {
522ec727ea7Spatrick       ProgramPoint L =
523ec727ea7Spatrick           PostAllocatorCall(Call.getOriginExpr(), Pred->getLocationContext());
524e5dd7070Spatrick       CheckerContext C(Bldr, Eng, Pred, L, WasInlined);
525ec727ea7Spatrick       checkFn(cast<CXXAllocatorCall>(*Call.cloneWithState(Pred->getState())),
526ec727ea7Spatrick               C);
527e5dd7070Spatrick     }
528e5dd7070Spatrick   };
529e5dd7070Spatrick 
530e5dd7070Spatrick } // namespace
531e5dd7070Spatrick 
runCheckersForNewAllocator(const CXXAllocatorCall & Call,ExplodedNodeSet & Dst,ExplodedNode * Pred,ExprEngine & Eng,bool WasInlined)532ec727ea7Spatrick void CheckerManager::runCheckersForNewAllocator(const CXXAllocatorCall &Call,
533ec727ea7Spatrick                                                 ExplodedNodeSet &Dst,
534ec727ea7Spatrick                                                 ExplodedNode *Pred,
535ec727ea7Spatrick                                                 ExprEngine &Eng,
536ec727ea7Spatrick                                                 bool WasInlined) {
537e5dd7070Spatrick   ExplodedNodeSet Src;
538e5dd7070Spatrick   Src.insert(Pred);
539ec727ea7Spatrick   CheckNewAllocatorContext C(NewAllocatorCheckers, Call, WasInlined, Eng);
540e5dd7070Spatrick   expandGraphWithCheckers(C, Dst, Src);
541e5dd7070Spatrick }
542e5dd7070Spatrick 
543e5dd7070Spatrick /// Run checkers for live symbols.
runCheckersForLiveSymbols(ProgramStateRef state,SymbolReaper & SymReaper)544e5dd7070Spatrick void CheckerManager::runCheckersForLiveSymbols(ProgramStateRef state,
545e5dd7070Spatrick                                                SymbolReaper &SymReaper) {
546e5dd7070Spatrick   for (const auto &LiveSymbolsChecker : LiveSymbolsCheckers)
547e5dd7070Spatrick     LiveSymbolsChecker(state, SymReaper);
548e5dd7070Spatrick }
549e5dd7070Spatrick 
550e5dd7070Spatrick namespace {
551e5dd7070Spatrick 
552e5dd7070Spatrick   struct CheckDeadSymbolsContext {
553e5dd7070Spatrick     using CheckersTy = std::vector<CheckerManager::CheckDeadSymbolsFunc>;
554e5dd7070Spatrick 
555e5dd7070Spatrick     const CheckersTy &Checkers;
556e5dd7070Spatrick     SymbolReaper &SR;
557e5dd7070Spatrick     const Stmt *S;
558e5dd7070Spatrick     ExprEngine &Eng;
559e5dd7070Spatrick     ProgramPoint::Kind ProgarmPointKind;
560e5dd7070Spatrick 
CheckDeadSymbolsContext__anon9a9a7b160a11::CheckDeadSymbolsContext561e5dd7070Spatrick     CheckDeadSymbolsContext(const CheckersTy &checkers, SymbolReaper &sr,
562e5dd7070Spatrick                             const Stmt *s, ExprEngine &eng,
563e5dd7070Spatrick                             ProgramPoint::Kind K)
564e5dd7070Spatrick         : Checkers(checkers), SR(sr), S(s), Eng(eng), ProgarmPointKind(K) {}
565e5dd7070Spatrick 
checkers_begin__anon9a9a7b160a11::CheckDeadSymbolsContext566e5dd7070Spatrick     CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
checkers_end__anon9a9a7b160a11::CheckDeadSymbolsContext567e5dd7070Spatrick     CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
568e5dd7070Spatrick 
runChecker__anon9a9a7b160a11::CheckDeadSymbolsContext569e5dd7070Spatrick     void runChecker(CheckerManager::CheckDeadSymbolsFunc checkFn,
570e5dd7070Spatrick                     NodeBuilder &Bldr, ExplodedNode *Pred) {
571e5dd7070Spatrick       const ProgramPoint &L = ProgramPoint::getProgramPoint(S, ProgarmPointKind,
572e5dd7070Spatrick                                 Pred->getLocationContext(), checkFn.Checker);
573e5dd7070Spatrick       CheckerContext C(Bldr, Eng, Pred, L);
574e5dd7070Spatrick 
575e5dd7070Spatrick       // Note, do not pass the statement to the checkers without letting them
576e5dd7070Spatrick       // differentiate if we ran remove dead bindings before or after the
577e5dd7070Spatrick       // statement.
578e5dd7070Spatrick       checkFn(SR, C);
579e5dd7070Spatrick     }
580e5dd7070Spatrick   };
581e5dd7070Spatrick 
582e5dd7070Spatrick } // namespace
583e5dd7070Spatrick 
584e5dd7070Spatrick /// Run checkers for dead symbols.
runCheckersForDeadSymbols(ExplodedNodeSet & Dst,const ExplodedNodeSet & Src,SymbolReaper & SymReaper,const Stmt * S,ExprEngine & Eng,ProgramPoint::Kind K)585e5dd7070Spatrick void CheckerManager::runCheckersForDeadSymbols(ExplodedNodeSet &Dst,
586e5dd7070Spatrick                                                const ExplodedNodeSet &Src,
587e5dd7070Spatrick                                                SymbolReaper &SymReaper,
588e5dd7070Spatrick                                                const Stmt *S,
589e5dd7070Spatrick                                                ExprEngine &Eng,
590e5dd7070Spatrick                                                ProgramPoint::Kind K) {
591e5dd7070Spatrick   CheckDeadSymbolsContext C(DeadSymbolsCheckers, SymReaper, S, Eng, K);
592e5dd7070Spatrick   expandGraphWithCheckers(C, Dst, Src);
593e5dd7070Spatrick }
594e5dd7070Spatrick 
595e5dd7070Spatrick /// Run checkers for region changes.
596e5dd7070Spatrick ProgramStateRef
runCheckersForRegionChanges(ProgramStateRef state,const InvalidatedSymbols * invalidated,ArrayRef<const MemRegion * > ExplicitRegions,ArrayRef<const MemRegion * > Regions,const LocationContext * LCtx,const CallEvent * Call)597e5dd7070Spatrick CheckerManager::runCheckersForRegionChanges(ProgramStateRef state,
598e5dd7070Spatrick                                             const InvalidatedSymbols *invalidated,
599e5dd7070Spatrick                                             ArrayRef<const MemRegion *> ExplicitRegions,
600e5dd7070Spatrick                                             ArrayRef<const MemRegion *> Regions,
601e5dd7070Spatrick                                             const LocationContext *LCtx,
602e5dd7070Spatrick                                             const CallEvent *Call) {
603e5dd7070Spatrick   for (const auto &RegionChangesChecker : RegionChangesCheckers) {
604e5dd7070Spatrick     // If any checker declares the state infeasible (or if it starts that way),
605e5dd7070Spatrick     // bail out.
606e5dd7070Spatrick     if (!state)
607e5dd7070Spatrick       return nullptr;
608e5dd7070Spatrick     state = RegionChangesChecker(state, invalidated, ExplicitRegions, Regions,
609e5dd7070Spatrick                                  LCtx, Call);
610e5dd7070Spatrick   }
611e5dd7070Spatrick   return state;
612e5dd7070Spatrick }
613e5dd7070Spatrick 
614e5dd7070Spatrick /// Run checkers to process symbol escape event.
615e5dd7070Spatrick ProgramStateRef
runCheckersForPointerEscape(ProgramStateRef State,const InvalidatedSymbols & Escaped,const CallEvent * Call,PointerEscapeKind Kind,RegionAndSymbolInvalidationTraits * ETraits)616e5dd7070Spatrick CheckerManager::runCheckersForPointerEscape(ProgramStateRef State,
617e5dd7070Spatrick                                    const InvalidatedSymbols &Escaped,
618e5dd7070Spatrick                                    const CallEvent *Call,
619e5dd7070Spatrick                                    PointerEscapeKind Kind,
620e5dd7070Spatrick                                    RegionAndSymbolInvalidationTraits *ETraits) {
621e5dd7070Spatrick   assert((Call != nullptr ||
622e5dd7070Spatrick           (Kind != PSK_DirectEscapeOnCall &&
623e5dd7070Spatrick            Kind != PSK_IndirectEscapeOnCall)) &&
624e5dd7070Spatrick          "Call must not be NULL when escaping on call");
625e5dd7070Spatrick   for (const auto &PointerEscapeChecker : PointerEscapeCheckers) {
626e5dd7070Spatrick     // If any checker declares the state infeasible (or if it starts that
627e5dd7070Spatrick     //  way), bail out.
628e5dd7070Spatrick     if (!State)
629e5dd7070Spatrick       return nullptr;
630e5dd7070Spatrick     State = PointerEscapeChecker(State, Escaped, Call, Kind, ETraits);
631e5dd7070Spatrick   }
632e5dd7070Spatrick   return State;
633e5dd7070Spatrick }
634e5dd7070Spatrick 
635e5dd7070Spatrick /// Run checkers for handling assumptions on symbolic values.
636e5dd7070Spatrick ProgramStateRef
runCheckersForEvalAssume(ProgramStateRef state,SVal Cond,bool Assumption)637e5dd7070Spatrick CheckerManager::runCheckersForEvalAssume(ProgramStateRef state,
638e5dd7070Spatrick                                          SVal Cond, bool Assumption) {
639e5dd7070Spatrick   for (const auto &EvalAssumeChecker : EvalAssumeCheckers) {
640e5dd7070Spatrick     // If any checker declares the state infeasible (or if it starts that way),
641e5dd7070Spatrick     // bail out.
642e5dd7070Spatrick     if (!state)
643e5dd7070Spatrick       return nullptr;
644e5dd7070Spatrick     state = EvalAssumeChecker(state, Cond, Assumption);
645e5dd7070Spatrick   }
646e5dd7070Spatrick   return state;
647e5dd7070Spatrick }
648e5dd7070Spatrick 
649e5dd7070Spatrick /// Run checkers for evaluating a call.
650e5dd7070Spatrick /// Only one checker will evaluate the call.
runCheckersForEvalCall(ExplodedNodeSet & Dst,const ExplodedNodeSet & Src,const CallEvent & Call,ExprEngine & Eng,const EvalCallOptions & CallOpts)651e5dd7070Spatrick void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst,
652e5dd7070Spatrick                                             const ExplodedNodeSet &Src,
653e5dd7070Spatrick                                             const CallEvent &Call,
654ec727ea7Spatrick                                             ExprEngine &Eng,
655ec727ea7Spatrick                                             const EvalCallOptions &CallOpts) {
656ec727ea7Spatrick   for (auto *const Pred : Src) {
657*12c85518Srobert     std::optional<CheckerNameRef> evaluatorChecker;
658e5dd7070Spatrick 
659e5dd7070Spatrick     ExplodedNodeSet checkDst;
660e5dd7070Spatrick     NodeBuilder B(Pred, checkDst, Eng.getBuilderContext());
661e5dd7070Spatrick 
662e5dd7070Spatrick     // Check if any of the EvalCall callbacks can evaluate the call.
663e5dd7070Spatrick     for (const auto &EvalCallChecker : EvalCallCheckers) {
664e5dd7070Spatrick       // TODO: Support the situation when the call doesn't correspond
665e5dd7070Spatrick       // to any Expr.
666e5dd7070Spatrick       ProgramPoint L = ProgramPoint::getProgramPoint(
667ec727ea7Spatrick           Call.getOriginExpr(), ProgramPoint::PostStmtKind,
668ec727ea7Spatrick           Pred->getLocationContext(), EvalCallChecker.Checker);
669e5dd7070Spatrick       bool evaluated = false;
670e5dd7070Spatrick       { // CheckerContext generates transitions(populates checkDest) on
671e5dd7070Spatrick         // destruction, so introduce the scope to make sure it gets properly
672e5dd7070Spatrick         // populated.
673e5dd7070Spatrick         CheckerContext C(B, Eng, Pred, L);
674e5dd7070Spatrick         evaluated = EvalCallChecker(Call, C);
675e5dd7070Spatrick       }
676*12c85518Srobert #ifndef NDEBUG
677*12c85518Srobert       if (evaluated && evaluatorChecker) {
678*12c85518Srobert         const auto toString = [](const CallEvent &Call) -> std::string {
679*12c85518Srobert           std::string Buf;
680*12c85518Srobert           llvm::raw_string_ostream OS(Buf);
681*12c85518Srobert           Call.dump(OS);
682*12c85518Srobert           OS.flush();
683*12c85518Srobert           return Buf;
684*12c85518Srobert         };
685*12c85518Srobert         std::string AssertionMessage = llvm::formatv(
686*12c85518Srobert             "The '{0}' call has been already evaluated by the {1} checker, "
687*12c85518Srobert             "while the {2} checker also tried to evaluate the same call. At "
688*12c85518Srobert             "most one checker supposed to evaluate a call.",
689*12c85518Srobert             toString(Call), evaluatorChecker->getName(),
690*12c85518Srobert             EvalCallChecker.Checker->getCheckerName());
691*12c85518Srobert         llvm_unreachable(AssertionMessage.c_str());
692*12c85518Srobert       }
693*12c85518Srobert #endif
694e5dd7070Spatrick       if (evaluated) {
695*12c85518Srobert         evaluatorChecker = EvalCallChecker.Checker->getCheckerName();
696e5dd7070Spatrick         Dst.insert(checkDst);
697e5dd7070Spatrick #ifdef NDEBUG
698e5dd7070Spatrick         break; // on release don't check that no other checker also evals.
699e5dd7070Spatrick #endif
700e5dd7070Spatrick       }
701e5dd7070Spatrick     }
702e5dd7070Spatrick 
703e5dd7070Spatrick     // If none of the checkers evaluated the call, ask ExprEngine to handle it.
704*12c85518Srobert     if (!evaluatorChecker) {
705e5dd7070Spatrick       NodeBuilder B(Pred, Dst, Eng.getBuilderContext());
706ec727ea7Spatrick       Eng.defaultEvalCall(B, Pred, Call, CallOpts);
707e5dd7070Spatrick     }
708e5dd7070Spatrick   }
709e5dd7070Spatrick }
710e5dd7070Spatrick 
711e5dd7070Spatrick /// Run checkers for the entire Translation Unit.
runCheckersOnEndOfTranslationUnit(const TranslationUnitDecl * TU,AnalysisManager & mgr,BugReporter & BR)712e5dd7070Spatrick void CheckerManager::runCheckersOnEndOfTranslationUnit(
713e5dd7070Spatrick                                                   const TranslationUnitDecl *TU,
714e5dd7070Spatrick                                                   AnalysisManager &mgr,
715e5dd7070Spatrick                                                   BugReporter &BR) {
716e5dd7070Spatrick   for (const auto &EndOfTranslationUnitChecker : EndOfTranslationUnitCheckers)
717e5dd7070Spatrick     EndOfTranslationUnitChecker(TU, mgr, BR);
718e5dd7070Spatrick }
719e5dd7070Spatrick 
runCheckersForPrintStateJson(raw_ostream & Out,ProgramStateRef State,const char * NL,unsigned int Space,bool IsDot) const720e5dd7070Spatrick void CheckerManager::runCheckersForPrintStateJson(raw_ostream &Out,
721e5dd7070Spatrick                                                   ProgramStateRef State,
722e5dd7070Spatrick                                                   const char *NL,
723e5dd7070Spatrick                                                   unsigned int Space,
724e5dd7070Spatrick                                                   bool IsDot) const {
725e5dd7070Spatrick   Indent(Out, Space, IsDot) << "\"checker_messages\": ";
726e5dd7070Spatrick 
727e5dd7070Spatrick   // Create a temporary stream to see whether we have any message.
728e5dd7070Spatrick   SmallString<1024> TempBuf;
729e5dd7070Spatrick   llvm::raw_svector_ostream TempOut(TempBuf);
730e5dd7070Spatrick   unsigned int InnerSpace = Space + 2;
731e5dd7070Spatrick 
732e5dd7070Spatrick   // Create the new-line in JSON with enough space.
733e5dd7070Spatrick   SmallString<128> NewLine;
734e5dd7070Spatrick   llvm::raw_svector_ostream NLOut(NewLine);
735e5dd7070Spatrick   NLOut << "\", " << NL;                     // Inject the ending and a new line
736e5dd7070Spatrick   Indent(NLOut, InnerSpace, IsDot) << "\"";  // then begin the next message.
737e5dd7070Spatrick 
738e5dd7070Spatrick   ++Space;
739e5dd7070Spatrick   bool HasMessage = false;
740e5dd7070Spatrick 
741e5dd7070Spatrick   // Store the last CheckerTag.
742e5dd7070Spatrick   const void *LastCT = nullptr;
743e5dd7070Spatrick   for (const auto &CT : CheckerTags) {
744e5dd7070Spatrick     // See whether the current checker has a message.
745e5dd7070Spatrick     CT.second->printState(TempOut, State, /*NL=*/NewLine.c_str(), /*Sep=*/"");
746e5dd7070Spatrick 
747e5dd7070Spatrick     if (TempBuf.empty())
748e5dd7070Spatrick       continue;
749e5dd7070Spatrick 
750e5dd7070Spatrick     if (!HasMessage) {
751e5dd7070Spatrick       Out << '[' << NL;
752e5dd7070Spatrick       HasMessage = true;
753e5dd7070Spatrick     }
754e5dd7070Spatrick 
755e5dd7070Spatrick     LastCT = &CT;
756e5dd7070Spatrick     TempBuf.clear();
757e5dd7070Spatrick   }
758e5dd7070Spatrick 
759e5dd7070Spatrick   for (const auto &CT : CheckerTags) {
760e5dd7070Spatrick     // See whether the current checker has a message.
761e5dd7070Spatrick     CT.second->printState(TempOut, State, /*NL=*/NewLine.c_str(), /*Sep=*/"");
762e5dd7070Spatrick 
763e5dd7070Spatrick     if (TempBuf.empty())
764e5dd7070Spatrick       continue;
765e5dd7070Spatrick 
766e5dd7070Spatrick     Indent(Out, Space, IsDot)
767e5dd7070Spatrick         << "{ \"checker\": \"" << CT.second->getCheckerName().getName()
768e5dd7070Spatrick         << "\", \"messages\": [" << NL;
769e5dd7070Spatrick     Indent(Out, InnerSpace, IsDot)
770e5dd7070Spatrick         << '\"' << TempBuf.str().trim() << '\"' << NL;
771e5dd7070Spatrick     Indent(Out, Space, IsDot) << "]}";
772e5dd7070Spatrick 
773e5dd7070Spatrick     if (&CT != LastCT)
774e5dd7070Spatrick       Out << ',';
775e5dd7070Spatrick     Out << NL;
776e5dd7070Spatrick 
777e5dd7070Spatrick     TempBuf.clear();
778e5dd7070Spatrick   }
779e5dd7070Spatrick 
780e5dd7070Spatrick   // It is the last element of the 'program_state' so do not add a comma.
781e5dd7070Spatrick   if (HasMessage)
782e5dd7070Spatrick     Indent(Out, --Space, IsDot) << "]";
783e5dd7070Spatrick   else
784e5dd7070Spatrick     Out << "null";
785e5dd7070Spatrick 
786e5dd7070Spatrick   Out << NL;
787e5dd7070Spatrick }
788e5dd7070Spatrick 
789e5dd7070Spatrick //===----------------------------------------------------------------------===//
790e5dd7070Spatrick // Internal registration functions for AST traversing.
791e5dd7070Spatrick //===----------------------------------------------------------------------===//
792e5dd7070Spatrick 
_registerForDecl(CheckDeclFunc checkfn,HandlesDeclFunc isForDeclFn)793e5dd7070Spatrick void CheckerManager::_registerForDecl(CheckDeclFunc checkfn,
794e5dd7070Spatrick                                       HandlesDeclFunc isForDeclFn) {
795e5dd7070Spatrick   DeclCheckerInfo info = { checkfn, isForDeclFn };
796e5dd7070Spatrick   DeclCheckers.push_back(info);
797e5dd7070Spatrick }
798e5dd7070Spatrick 
_registerForBody(CheckDeclFunc checkfn)799e5dd7070Spatrick void CheckerManager::_registerForBody(CheckDeclFunc checkfn) {
800e5dd7070Spatrick   BodyCheckers.push_back(checkfn);
801e5dd7070Spatrick }
802e5dd7070Spatrick 
803e5dd7070Spatrick //===----------------------------------------------------------------------===//
804e5dd7070Spatrick // Internal registration functions for path-sensitive checking.
805e5dd7070Spatrick //===----------------------------------------------------------------------===//
806e5dd7070Spatrick 
_registerForPreStmt(CheckStmtFunc checkfn,HandlesStmtFunc isForStmtFn)807e5dd7070Spatrick void CheckerManager::_registerForPreStmt(CheckStmtFunc checkfn,
808e5dd7070Spatrick                                          HandlesStmtFunc isForStmtFn) {
809e5dd7070Spatrick   StmtCheckerInfo info = { checkfn, isForStmtFn, /*IsPreVisit*/true };
810e5dd7070Spatrick   StmtCheckers.push_back(info);
811e5dd7070Spatrick }
812e5dd7070Spatrick 
_registerForPostStmt(CheckStmtFunc checkfn,HandlesStmtFunc isForStmtFn)813e5dd7070Spatrick void CheckerManager::_registerForPostStmt(CheckStmtFunc checkfn,
814e5dd7070Spatrick                                           HandlesStmtFunc isForStmtFn) {
815e5dd7070Spatrick   StmtCheckerInfo info = { checkfn, isForStmtFn, /*IsPreVisit*/false };
816e5dd7070Spatrick   StmtCheckers.push_back(info);
817e5dd7070Spatrick }
818e5dd7070Spatrick 
_registerForPreObjCMessage(CheckObjCMessageFunc checkfn)819e5dd7070Spatrick void CheckerManager::_registerForPreObjCMessage(CheckObjCMessageFunc checkfn) {
820e5dd7070Spatrick   PreObjCMessageCheckers.push_back(checkfn);
821e5dd7070Spatrick }
822e5dd7070Spatrick 
_registerForObjCMessageNil(CheckObjCMessageFunc checkfn)823e5dd7070Spatrick void CheckerManager::_registerForObjCMessageNil(CheckObjCMessageFunc checkfn) {
824e5dd7070Spatrick   ObjCMessageNilCheckers.push_back(checkfn);
825e5dd7070Spatrick }
826e5dd7070Spatrick 
_registerForPostObjCMessage(CheckObjCMessageFunc checkfn)827e5dd7070Spatrick void CheckerManager::_registerForPostObjCMessage(CheckObjCMessageFunc checkfn) {
828e5dd7070Spatrick   PostObjCMessageCheckers.push_back(checkfn);
829e5dd7070Spatrick }
830e5dd7070Spatrick 
_registerForPreCall(CheckCallFunc checkfn)831e5dd7070Spatrick void CheckerManager::_registerForPreCall(CheckCallFunc checkfn) {
832e5dd7070Spatrick   PreCallCheckers.push_back(checkfn);
833e5dd7070Spatrick }
_registerForPostCall(CheckCallFunc checkfn)834e5dd7070Spatrick void CheckerManager::_registerForPostCall(CheckCallFunc checkfn) {
835e5dd7070Spatrick   PostCallCheckers.push_back(checkfn);
836e5dd7070Spatrick }
837e5dd7070Spatrick 
_registerForLocation(CheckLocationFunc checkfn)838e5dd7070Spatrick void CheckerManager::_registerForLocation(CheckLocationFunc checkfn) {
839e5dd7070Spatrick   LocationCheckers.push_back(checkfn);
840e5dd7070Spatrick }
841e5dd7070Spatrick 
_registerForBind(CheckBindFunc checkfn)842e5dd7070Spatrick void CheckerManager::_registerForBind(CheckBindFunc checkfn) {
843e5dd7070Spatrick   BindCheckers.push_back(checkfn);
844e5dd7070Spatrick }
845e5dd7070Spatrick 
_registerForEndAnalysis(CheckEndAnalysisFunc checkfn)846e5dd7070Spatrick void CheckerManager::_registerForEndAnalysis(CheckEndAnalysisFunc checkfn) {
847e5dd7070Spatrick   EndAnalysisCheckers.push_back(checkfn);
848e5dd7070Spatrick }
849e5dd7070Spatrick 
_registerForBeginFunction(CheckBeginFunctionFunc checkfn)850e5dd7070Spatrick void CheckerManager::_registerForBeginFunction(CheckBeginFunctionFunc checkfn) {
851e5dd7070Spatrick   BeginFunctionCheckers.push_back(checkfn);
852e5dd7070Spatrick }
853e5dd7070Spatrick 
_registerForEndFunction(CheckEndFunctionFunc checkfn)854e5dd7070Spatrick void CheckerManager::_registerForEndFunction(CheckEndFunctionFunc checkfn) {
855e5dd7070Spatrick   EndFunctionCheckers.push_back(checkfn);
856e5dd7070Spatrick }
857e5dd7070Spatrick 
_registerForBranchCondition(CheckBranchConditionFunc checkfn)858e5dd7070Spatrick void CheckerManager::_registerForBranchCondition(
859e5dd7070Spatrick                                              CheckBranchConditionFunc checkfn) {
860e5dd7070Spatrick   BranchConditionCheckers.push_back(checkfn);
861e5dd7070Spatrick }
862e5dd7070Spatrick 
_registerForNewAllocator(CheckNewAllocatorFunc checkfn)863e5dd7070Spatrick void CheckerManager::_registerForNewAllocator(CheckNewAllocatorFunc checkfn) {
864e5dd7070Spatrick   NewAllocatorCheckers.push_back(checkfn);
865e5dd7070Spatrick }
866e5dd7070Spatrick 
_registerForLiveSymbols(CheckLiveSymbolsFunc checkfn)867e5dd7070Spatrick void CheckerManager::_registerForLiveSymbols(CheckLiveSymbolsFunc checkfn) {
868e5dd7070Spatrick   LiveSymbolsCheckers.push_back(checkfn);
869e5dd7070Spatrick }
870e5dd7070Spatrick 
_registerForDeadSymbols(CheckDeadSymbolsFunc checkfn)871e5dd7070Spatrick void CheckerManager::_registerForDeadSymbols(CheckDeadSymbolsFunc checkfn) {
872e5dd7070Spatrick   DeadSymbolsCheckers.push_back(checkfn);
873e5dd7070Spatrick }
874e5dd7070Spatrick 
_registerForRegionChanges(CheckRegionChangesFunc checkfn)875e5dd7070Spatrick void CheckerManager::_registerForRegionChanges(CheckRegionChangesFunc checkfn) {
876e5dd7070Spatrick   RegionChangesCheckers.push_back(checkfn);
877e5dd7070Spatrick }
878e5dd7070Spatrick 
_registerForPointerEscape(CheckPointerEscapeFunc checkfn)879e5dd7070Spatrick void CheckerManager::_registerForPointerEscape(CheckPointerEscapeFunc checkfn){
880e5dd7070Spatrick   PointerEscapeCheckers.push_back(checkfn);
881e5dd7070Spatrick }
882e5dd7070Spatrick 
_registerForConstPointerEscape(CheckPointerEscapeFunc checkfn)883e5dd7070Spatrick void CheckerManager::_registerForConstPointerEscape(
884e5dd7070Spatrick                                           CheckPointerEscapeFunc checkfn) {
885e5dd7070Spatrick   PointerEscapeCheckers.push_back(checkfn);
886e5dd7070Spatrick }
887e5dd7070Spatrick 
_registerForEvalAssume(EvalAssumeFunc checkfn)888e5dd7070Spatrick void CheckerManager::_registerForEvalAssume(EvalAssumeFunc checkfn) {
889e5dd7070Spatrick   EvalAssumeCheckers.push_back(checkfn);
890e5dd7070Spatrick }
891e5dd7070Spatrick 
_registerForEvalCall(EvalCallFunc checkfn)892e5dd7070Spatrick void CheckerManager::_registerForEvalCall(EvalCallFunc checkfn) {
893e5dd7070Spatrick   EvalCallCheckers.push_back(checkfn);
894e5dd7070Spatrick }
895e5dd7070Spatrick 
_registerForEndOfTranslationUnit(CheckEndOfTranslationUnit checkfn)896e5dd7070Spatrick void CheckerManager::_registerForEndOfTranslationUnit(
897e5dd7070Spatrick                                             CheckEndOfTranslationUnit checkfn) {
898e5dd7070Spatrick   EndOfTranslationUnitCheckers.push_back(checkfn);
899e5dd7070Spatrick }
900e5dd7070Spatrick 
901e5dd7070Spatrick //===----------------------------------------------------------------------===//
902e5dd7070Spatrick // Implementation details.
903e5dd7070Spatrick //===----------------------------------------------------------------------===//
904e5dd7070Spatrick 
905e5dd7070Spatrick const CheckerManager::CachedStmtCheckers &
getCachedStmtCheckersFor(const Stmt * S,bool isPreVisit)906e5dd7070Spatrick CheckerManager::getCachedStmtCheckersFor(const Stmt *S, bool isPreVisit) {
907e5dd7070Spatrick   assert(S);
908e5dd7070Spatrick 
909e5dd7070Spatrick   unsigned Key = (S->getStmtClass() << 1) | unsigned(isPreVisit);
910e5dd7070Spatrick   CachedStmtCheckersMapTy::iterator CCI = CachedStmtCheckersMap.find(Key);
911e5dd7070Spatrick   if (CCI != CachedStmtCheckersMap.end())
912e5dd7070Spatrick     return CCI->second;
913e5dd7070Spatrick 
914e5dd7070Spatrick   // Find the checkers that should run for this Stmt and cache them.
915e5dd7070Spatrick   CachedStmtCheckers &Checkers = CachedStmtCheckersMap[Key];
916e5dd7070Spatrick   for (const auto &Info : StmtCheckers)
917e5dd7070Spatrick     if (Info.IsPreVisit == isPreVisit && Info.IsForStmtFn(S))
918e5dd7070Spatrick       Checkers.push_back(Info.CheckFn);
919e5dd7070Spatrick   return Checkers;
920e5dd7070Spatrick }
921