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