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