1 //===- CheckerManager.cpp - Static Analyzer Checker Manager ---------------===//
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
7 //===----------------------------------------------------------------------===//
9 // Defines the Static Analyzer Checker Manager.
11 //===----------------------------------------------------------------------===//
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"
34 using namespace clang
;
37 bool CheckerManager::hasPathSensitiveCheckers() const {
38 const auto IfAnyAreNonEmpty
= [](const auto &... Callbacks
) -> bool {
39 return (!Callbacks
.empty() || ...);
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
);
51 void CheckerManager::reportInvalidCheckerOptionValue(
52 const CheckerBase
*C
, StringRef OptionName
,
53 StringRef ExpectedValueDesc
) const {
55 getDiagnostics().Report(diag::err_analyzer_checker_option_invalid_input
)
56 << (llvm::Twine() + C
->getTagDescription() + ":" + OptionName
).str()
60 //===----------------------------------------------------------------------===//
61 // Functions for running checkers for AST traversing..
62 //===----------------------------------------------------------------------===//
64 void CheckerManager::runCheckersOnASTDecl(const Decl
*D
, AnalysisManager
& mgr
,
68 unsigned DeclKind
= D
->getKind();
69 auto [CCI
, Inserted
] = CachedDeclCheckersMap
.try_emplace(DeclKind
);
70 CachedDeclCheckers
*checkers
= &(CCI
->second
);
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
);
79 for (const auto &checker
: *checkers
)
83 void CheckerManager::runCheckersOnASTBody(const Decl
*D
, AnalysisManager
& mgr
,
85 assert(D
&& D
->hasBody());
87 for (const auto &BodyChecker
: BodyCheckers
)
88 BodyChecker(D
, mgr
, BR
);
91 //===----------------------------------------------------------------------===//
92 // Functions for running checkers for path-sensitive checking.
93 //===----------------------------------------------------------------------===//
95 template <typename CHECK_CTX
>
96 static void expandGraphWithCheckers(CHECK_CTX checkCtx
,
98 const ExplodedNodeSet
&Src
) {
99 const NodeBuilderContext
&BldrCtx
= checkCtx
.Eng
.getBuilderContext();
103 typename
CHECK_CTX::CheckersTy::const_iterator
104 I
= checkCtx
.checkers_begin(), E
= checkCtx
.checkers_end();
110 ExplodedNodeSet Tmp1
, Tmp2
;
111 const ExplodedNodeSet
*PrevSet
= &Src
;
113 for (; I
!= E
; ++I
) {
114 ExplodedNodeSet
*CurrSet
= nullptr;
118 CurrSet
= (PrevSet
== &Tmp1
) ? &Tmp2
: &Tmp1
;
122 NodeBuilder
B(*PrevSet
, *CurrSet
, BldrCtx
);
123 for (const auto &NI
: *PrevSet
)
124 checkCtx
.runChecker(*I
, B
, NI
);
126 // If all the produced transitions are sinks, stop.
127 if (CurrSet
->empty())
130 // Update which NodeSet is the current one.
137 struct CheckStmtContext
{
138 using CheckersTy
= SmallVectorImpl
<CheckerManager::CheckStmtFunc
>;
141 const CheckersTy
&Checkers
;
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
) {}
151 CheckersTy::const_iterator
checkers_begin() { return Checkers
.begin(); }
152 CheckersTy::const_iterator
checkers_end() { return Checkers
.end(); }
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
);
168 /// Run checkers for visiting Stmts.
169 void CheckerManager::runCheckersForStmt(bool isPreVisit
,
170 ExplodedNodeSet
&Dst
,
171 const ExplodedNodeSet
&Src
,
175 CheckStmtContext
C(isPreVisit
, getCachedStmtCheckersFor(S
, isPreVisit
),
177 expandGraphWithCheckers(C
, Dst
, Src
);
182 struct CheckObjCMessageContext
{
183 using CheckersTy
= std::vector
<CheckerManager::CheckObjCMessageFunc
>;
185 ObjCMessageVisitKind Kind
;
187 const CheckersTy
&Checkers
;
188 const ObjCMethodCall
&Msg
;
191 CheckObjCMessageContext(ObjCMessageVisitKind visitKind
,
192 const CheckersTy
&checkers
,
193 const ObjCMethodCall
&msg
, ExprEngine
&eng
,
195 : Kind(visitKind
), WasInlined(wasInlined
), Checkers(checkers
), Msg(msg
),
198 CheckersTy::const_iterator
checkers_begin() { return Checkers
.begin(); }
199 CheckersTy::const_iterator
checkers_end() { return Checkers
.end(); }
201 void runChecker(CheckerManager::CheckObjCMessageFunc checkFn
,
202 NodeBuilder
&Bldr
, ExplodedNode
*Pred
) {
206 case ObjCMessageVisitKind::Pre
:
209 case ObjCMessageVisitKind::MessageNil
:
210 case ObjCMessageVisitKind::Post
:
215 const ProgramPoint
&L
= Msg
.getProgramPoint(IsPreVisit
,checkFn
.Checker
);
216 CheckerContext
C(Bldr
, Eng
, Pred
, L
, WasInlined
);
218 checkFn(*Msg
.cloneWithState
<ObjCMethodCall
>(Pred
->getState()), C
);
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
,
231 const auto &checkers
= getObjCMessageCheckers(visitKind
);
232 CheckObjCMessageContext
C(visitKind
, checkers
, msg
, Eng
, WasInlined
);
233 expandGraphWithCheckers(C
, Dst
, Src
);
236 const std::vector
<CheckerManager::CheckObjCMessageFunc
> &
237 CheckerManager::getObjCMessageCheckers(ObjCMessageVisitKind Kind
) const {
239 case ObjCMessageVisitKind::Pre
:
240 return PreObjCMessageCheckers
;
242 case ObjCMessageVisitKind::Post
:
243 return PostObjCMessageCheckers
;
244 case ObjCMessageVisitKind::MessageNil
:
245 return ObjCMessageNilCheckers
;
247 llvm_unreachable("Unknown Kind");
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
>;
257 bool IsPreVisit
, WasInlined
;
258 const CheckersTy
&Checkers
;
259 const CallEvent
&Call
;
262 CheckCallContext(bool isPreVisit
, const CheckersTy
&checkers
,
263 const CallEvent
&call
, ExprEngine
&eng
,
265 : IsPreVisit(isPreVisit
), WasInlined(wasInlined
), Checkers(checkers
),
266 Call(call
), Eng(eng
) {}
268 CheckersTy::const_iterator
checkers_begin() { return Checkers
.begin(); }
269 CheckersTy::const_iterator
checkers_end() { return Checkers
.end(); }
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
);
276 checkFn(*Call
.cloneWithState(Pred
->getState()), C
);
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
,
289 CheckCallContext
C(isPreVisit
,
290 isPreVisit
? PreCallCheckers
292 Call
, Eng
, WasInlined
);
293 expandGraphWithCheckers(C
, Dst
, Src
);
298 struct CheckLocationContext
{
299 using CheckersTy
= std::vector
<CheckerManager::CheckLocationFunc
>;
301 const CheckersTy
&Checkers
;
304 const Stmt
*NodeEx
; /* Will become a CFGStmt */
308 CheckLocationContext(const CheckersTy
&checkers
,
309 SVal loc
, bool isLoad
, const Stmt
*NodeEx
,
312 : Checkers(checkers
), Loc(loc
), IsLoad(isLoad
), NodeEx(NodeEx
),
313 BoundEx(BoundEx
), Eng(eng
) {}
315 CheckersTy::const_iterator
checkers_begin() { return Checkers
.begin(); }
316 CheckersTy::const_iterator
checkers_end() { return Checkers
.end(); }
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(),
326 CheckerContext
C(Bldr
, Eng
, Pred
, L
);
327 checkFn(Loc
, IsLoad
, BoundEx
, C
);
333 /// Run checkers for load/store of a location.
335 void CheckerManager::runCheckersForLocation(ExplodedNodeSet
&Dst
,
336 const ExplodedNodeSet
&Src
,
337 SVal location
, bool isLoad
,
341 CheckLocationContext
C(LocationCheckers
, location
, isLoad
, NodeEx
,
343 expandGraphWithCheckers(C
, Dst
, Src
);
348 struct CheckBindContext
{
349 using CheckersTy
= std::vector
<CheckerManager::CheckBindFunc
>;
351 const CheckersTy
&Checkers
;
356 const ProgramPoint
&PP
;
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
) {}
363 CheckersTy::const_iterator
checkers_begin() { return Checkers
.begin(); }
364 CheckersTy::const_iterator
checkers_end() { return Checkers
.end(); }
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
);
371 checkFn(Loc
, Val
, S
, C
);
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
);
387 void CheckerManager::runCheckersForEndAnalysis(ExplodedGraph
&G
,
390 for (const auto &EndAnalysisChecker
: EndAnalysisCheckers
)
391 EndAnalysisChecker(G
, BR
, Eng
);
396 struct CheckBeginFunctionContext
{
397 using CheckersTy
= std::vector
<CheckerManager::CheckBeginFunctionFunc
>;
399 const CheckersTy
&Checkers
;
401 const ProgramPoint
&PP
;
403 CheckBeginFunctionContext(const CheckersTy
&Checkers
, ExprEngine
&Eng
,
404 const ProgramPoint
&PP
)
405 : Checkers(Checkers
), Eng(Eng
), PP(PP
) {}
407 CheckersTy::const_iterator
checkers_begin() { return Checkers
.begin(); }
408 CheckersTy::const_iterator
checkers_end() { return Checkers
.end(); }
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
);
421 void CheckerManager::runCheckersForBeginFunction(ExplodedNodeSet
&Dst
,
427 CheckBeginFunctionContext
C(BeginFunctionCheckers
, Eng
, L
);
428 expandGraphWithCheckers(C
, Dst
, Src
);
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
,
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
);
453 struct CheckBranchConditionContext
{
454 using CheckersTy
= std::vector
<CheckerManager::CheckBranchConditionFunc
>;
456 const CheckersTy
&Checkers
;
457 const Stmt
*Condition
;
460 CheckBranchConditionContext(const CheckersTy
&checkers
,
461 const Stmt
*Cond
, ExprEngine
&eng
)
462 : Checkers(checkers
), Condition(Cond
), Eng(eng
) {}
464 CheckersTy::const_iterator
checkers_begin() { return Checkers
.begin(); }
465 CheckersTy::const_iterator
checkers_end() { return Checkers
.end(); }
467 void runChecker(CheckerManager::CheckBranchConditionFunc checkFn
,
468 NodeBuilder
&Bldr
, ExplodedNode
*Pred
) {
469 ProgramPoint L
= PostCondition(Condition
, Pred
->getLocationContext(),
471 CheckerContext
C(Bldr
, Eng
, Pred
, L
);
472 checkFn(Condition
, C
);
478 /// Run checkers for branch condition.
479 void CheckerManager::runCheckersForBranchCondition(const Stmt
*Condition
,
480 ExplodedNodeSet
&Dst
,
485 CheckBranchConditionContext
C(BranchConditionCheckers
, Condition
, Eng
);
486 expandGraphWithCheckers(C
, Dst
, Src
);
491 struct CheckNewAllocatorContext
{
492 using CheckersTy
= std::vector
<CheckerManager::CheckNewAllocatorFunc
>;
494 const CheckersTy
&Checkers
;
495 const CXXAllocatorCall
&Call
;
499 CheckNewAllocatorContext(const CheckersTy
&Checkers
,
500 const CXXAllocatorCall
&Call
, bool WasInlined
,
502 : Checkers(Checkers
), Call(Call
), WasInlined(WasInlined
), Eng(Eng
) {}
504 CheckersTy::const_iterator
checkers_begin() { return Checkers
.begin(); }
505 CheckersTy::const_iterator
checkers_end() { return Checkers
.end(); }
507 void runChecker(CheckerManager::CheckNewAllocatorFunc checkFn
,
508 NodeBuilder
&Bldr
, ExplodedNode
*Pred
) {
510 PostAllocatorCall(Call
.getOriginExpr(), Pred
->getLocationContext());
511 CheckerContext
C(Bldr
, Eng
, Pred
, L
, WasInlined
);
512 checkFn(cast
<CXXAllocatorCall
>(*Call
.cloneWithState(Pred
->getState())),
519 void CheckerManager::runCheckersForNewAllocator(const CXXAllocatorCall
&Call
,
520 ExplodedNodeSet
&Dst
,
526 CheckNewAllocatorContext
C(NewAllocatorCheckers
, Call
, WasInlined
, Eng
);
527 expandGraphWithCheckers(C
, Dst
, Src
);
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
);
539 struct CheckDeadSymbolsContext
{
540 using CheckersTy
= std::vector
<CheckerManager::CheckDeadSymbolsFunc
>;
542 const CheckersTy
&Checkers
;
546 ProgramPoint::Kind ProgarmPointKind
;
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
) {}
553 CheckersTy::const_iterator
checkers_begin() { return Checkers
.begin(); }
554 CheckersTy::const_iterator
checkers_end() { return Checkers
.end(); }
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
);
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
571 /// Run checkers for dead symbols.
572 void CheckerManager::runCheckersForDeadSymbols(ExplodedNodeSet
&Dst
,
573 const ExplodedNodeSet
&Src
,
574 SymbolReaper
&SymReaper
,
577 ProgramPoint::Kind K
) {
578 CheckDeadSymbolsContext
C(DeadSymbolsCheckers
, SymReaper
, S
, Eng
, K
);
579 expandGraphWithCheckers(C
, Dst
, Src
);
582 /// Run checkers for region changes.
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),
595 state
= RegionChangesChecker(state
, invalidated
, ExplicitRegions
, Regions
,
601 /// Run checkers to process symbol escape event.
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
617 State
= PointerEscapeChecker(State
, Escaped
, Call
, Kind
, ETraits
);
622 /// Run checkers for handling assumptions on symbolic values.
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),
631 state
= EvalAssumeChecker(state
, Cond
, Assumption
);
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
,
642 const EvalCallOptions
&CallOpts
) {
643 for (auto *const Pred
: Src
) {
644 std::optional
<CheckerNameRef
> evaluatorChecker
;
646 ExplodedNodeSet checkDst
;
647 NodeBuilder
B(Pred
, checkDst
, Eng
.getBuilderContext());
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
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
660 CheckerContext
C(B
, Eng
, Pred
, L
);
661 evaluated
= EvalCallChecker(Call
, C
);
664 if (evaluated
&& evaluatorChecker
) {
665 const auto toString
= [](const CallEvent
&Call
) -> std::string
{
667 llvm::raw_string_ostream
OS(Buf
);
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());
681 evaluatorChecker
= EvalCallChecker
.Checker
->getCheckerName();
682 Dst
.insert(checkDst
);
684 break; // on release don't check that no other checker also evals.
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
);
697 /// Run checkers for the entire Translation Unit.
698 void CheckerManager::runCheckersOnEndOfTranslationUnit(
699 const TranslationUnitDecl
*TU
,
700 AnalysisManager
&mgr
,
702 for (const auto &EndOfTranslationUnitChecker
: EndOfTranslationUnitCheckers
)
703 EndOfTranslationUnitChecker(TU
, mgr
, BR
);
706 void CheckerManager::runCheckersForPrintStateJson(raw_ostream
&Out
,
707 ProgramStateRef State
,
711 Indent(Out
, Space
, IsDot
) << "\"checker_messages\": ";
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;
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.
725 bool HasMessage
= false;
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=*/"");
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=*/"");
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
) << "]}";
766 // It is the last element of the 'program_state' so do not add a comma.
768 Indent(Out
, --Space
, IsDot
) << "]";
775 //===----------------------------------------------------------------------===//
776 // Internal registration functions for AST traversing.
777 //===----------------------------------------------------------------------===//
779 void CheckerManager::_registerForDecl(CheckDeclFunc checkfn
,
780 HandlesDeclFunc isForDeclFn
) {
781 DeclCheckerInfo info
= { checkfn
, isForDeclFn
};
782 DeclCheckers
.push_back(info
);
785 void CheckerManager::_registerForBody(CheckDeclFunc checkfn
) {
786 BodyCheckers
.push_back(checkfn
);
789 //===----------------------------------------------------------------------===//
790 // Internal registration functions for path-sensitive checking.
791 //===----------------------------------------------------------------------===//
793 void CheckerManager::_registerForPreStmt(CheckStmtFunc checkfn
,
794 HandlesStmtFunc isForStmtFn
) {
795 StmtCheckerInfo info
= { checkfn
, isForStmtFn
, /*IsPreVisit*/true };
796 StmtCheckers
.push_back(info
);
799 void CheckerManager::_registerForPostStmt(CheckStmtFunc checkfn
,
800 HandlesStmtFunc isForStmtFn
) {
801 StmtCheckerInfo info
= { checkfn
, isForStmtFn
, /*IsPreVisit*/false };
802 StmtCheckers
.push_back(info
);
805 void CheckerManager::_registerForPreObjCMessage(CheckObjCMessageFunc checkfn
) {
806 PreObjCMessageCheckers
.push_back(checkfn
);
809 void CheckerManager::_registerForObjCMessageNil(CheckObjCMessageFunc checkfn
) {
810 ObjCMessageNilCheckers
.push_back(checkfn
);
813 void CheckerManager::_registerForPostObjCMessage(CheckObjCMessageFunc checkfn
) {
814 PostObjCMessageCheckers
.push_back(checkfn
);
817 void CheckerManager::_registerForPreCall(CheckCallFunc checkfn
) {
818 PreCallCheckers
.push_back(checkfn
);
820 void CheckerManager::_registerForPostCall(CheckCallFunc checkfn
) {
821 PostCallCheckers
.push_back(checkfn
);
824 void CheckerManager::_registerForLocation(CheckLocationFunc checkfn
) {
825 LocationCheckers
.push_back(checkfn
);
828 void CheckerManager::_registerForBind(CheckBindFunc checkfn
) {
829 BindCheckers
.push_back(checkfn
);
832 void CheckerManager::_registerForEndAnalysis(CheckEndAnalysisFunc checkfn
) {
833 EndAnalysisCheckers
.push_back(checkfn
);
836 void CheckerManager::_registerForBeginFunction(CheckBeginFunctionFunc checkfn
) {
837 BeginFunctionCheckers
.push_back(checkfn
);
840 void CheckerManager::_registerForEndFunction(CheckEndFunctionFunc checkfn
) {
841 EndFunctionCheckers
.push_back(checkfn
);
844 void CheckerManager::_registerForBranchCondition(
845 CheckBranchConditionFunc checkfn
) {
846 BranchConditionCheckers
.push_back(checkfn
);
849 void CheckerManager::_registerForNewAllocator(CheckNewAllocatorFunc checkfn
) {
850 NewAllocatorCheckers
.push_back(checkfn
);
853 void CheckerManager::_registerForLiveSymbols(CheckLiveSymbolsFunc checkfn
) {
854 LiveSymbolsCheckers
.push_back(checkfn
);
857 void CheckerManager::_registerForDeadSymbols(CheckDeadSymbolsFunc checkfn
) {
858 DeadSymbolsCheckers
.push_back(checkfn
);
861 void CheckerManager::_registerForRegionChanges(CheckRegionChangesFunc checkfn
) {
862 RegionChangesCheckers
.push_back(checkfn
);
865 void CheckerManager::_registerForPointerEscape(CheckPointerEscapeFunc checkfn
){
866 PointerEscapeCheckers
.push_back(checkfn
);
869 void CheckerManager::_registerForConstPointerEscape(
870 CheckPointerEscapeFunc checkfn
) {
871 PointerEscapeCheckers
.push_back(checkfn
);
874 void CheckerManager::_registerForEvalAssume(EvalAssumeFunc checkfn
) {
875 EvalAssumeCheckers
.push_back(checkfn
);
878 void CheckerManager::_registerForEvalCall(EvalCallFunc checkfn
) {
879 EvalCallCheckers
.push_back(checkfn
);
882 void CheckerManager::_registerForEndOfTranslationUnit(
883 CheckEndOfTranslationUnit checkfn
) {
884 EndOfTranslationUnitCheckers
.push_back(checkfn
);
887 //===----------------------------------------------------------------------===//
888 // Implementation details.
889 //===----------------------------------------------------------------------===//
891 const CheckerManager::CachedStmtCheckers
&
892 CheckerManager::getCachedStmtCheckersFor(const Stmt
*S
, bool isPreVisit
) {
895 unsigned Key
= (S
->getStmtClass() << 1) | unsigned(isPreVisit
);
896 auto [CCI
, Inserted
] = CachedStmtCheckersMap
.try_emplace(Key
);
897 CachedStmtCheckers
&Checkers
= CCI
->second
;
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
);