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::finishedCheckerRegistration() {
53 // Make sure that for every event that has listeners, there is at least
54 // one dispatcher registered for it.
55 for (const auto &Event
: Events
)
56 assert(Event
.second
.HasDispatcher
&&
57 "No dispatcher registered for an event");
61 void CheckerManager::reportInvalidCheckerOptionValue(
62 const CheckerBase
*C
, StringRef OptionName
,
63 StringRef ExpectedValueDesc
) const {
65 getDiagnostics().Report(diag::err_analyzer_checker_option_invalid_input
)
66 << (llvm::Twine() + C
->getTagDescription() + ":" + OptionName
).str()
70 //===----------------------------------------------------------------------===//
71 // Functions for running checkers for AST traversing..
72 //===----------------------------------------------------------------------===//
74 void CheckerManager::runCheckersOnASTDecl(const Decl
*D
, AnalysisManager
& mgr
,
78 unsigned DeclKind
= D
->getKind();
79 CachedDeclCheckers
*checkers
= nullptr;
80 CachedDeclCheckersMapTy::iterator CCI
= CachedDeclCheckersMap
.find(DeclKind
);
81 if (CCI
!= CachedDeclCheckersMap
.end()) {
82 checkers
= &(CCI
->second
);
84 // Find the checkers that should run for this Decl and cache them.
85 checkers
= &CachedDeclCheckersMap
[DeclKind
];
86 for (const auto &info
: DeclCheckers
)
87 if (info
.IsForDeclFn(D
))
88 checkers
->push_back(info
.CheckFn
);
92 for (const auto &checker
: *checkers
)
96 void CheckerManager::runCheckersOnASTBody(const Decl
*D
, AnalysisManager
& mgr
,
98 assert(D
&& D
->hasBody());
100 for (const auto &BodyChecker
: BodyCheckers
)
101 BodyChecker(D
, mgr
, BR
);
104 //===----------------------------------------------------------------------===//
105 // Functions for running checkers for path-sensitive checking.
106 //===----------------------------------------------------------------------===//
108 template <typename CHECK_CTX
>
109 static void expandGraphWithCheckers(CHECK_CTX checkCtx
,
110 ExplodedNodeSet
&Dst
,
111 const ExplodedNodeSet
&Src
) {
112 const NodeBuilderContext
&BldrCtx
= checkCtx
.Eng
.getBuilderContext();
116 typename
CHECK_CTX::CheckersTy::const_iterator
117 I
= checkCtx
.checkers_begin(), E
= checkCtx
.checkers_end();
123 ExplodedNodeSet Tmp1
, Tmp2
;
124 const ExplodedNodeSet
*PrevSet
= &Src
;
126 for (; I
!= E
; ++I
) {
127 ExplodedNodeSet
*CurrSet
= nullptr;
131 CurrSet
= (PrevSet
== &Tmp1
) ? &Tmp2
: &Tmp1
;
135 NodeBuilder
B(*PrevSet
, *CurrSet
, BldrCtx
);
136 for (const auto &NI
: *PrevSet
)
137 checkCtx
.runChecker(*I
, B
, NI
);
139 // If all the produced transitions are sinks, stop.
140 if (CurrSet
->empty())
143 // Update which NodeSet is the current one.
150 struct CheckStmtContext
{
151 using CheckersTy
= SmallVectorImpl
<CheckerManager::CheckStmtFunc
>;
154 const CheckersTy
&Checkers
;
159 CheckStmtContext(bool isPreVisit
, const CheckersTy
&checkers
,
160 const Stmt
*s
, ExprEngine
&eng
, bool wasInlined
= false)
161 : IsPreVisit(isPreVisit
), Checkers(checkers
), S(s
), Eng(eng
),
162 WasInlined(wasInlined
) {}
164 CheckersTy::const_iterator
checkers_begin() { return Checkers
.begin(); }
165 CheckersTy::const_iterator
checkers_end() { return Checkers
.end(); }
167 void runChecker(CheckerManager::CheckStmtFunc checkFn
,
168 NodeBuilder
&Bldr
, ExplodedNode
*Pred
) {
169 // FIXME: Remove respondsToCallback from CheckerContext;
170 ProgramPoint::Kind K
= IsPreVisit
? ProgramPoint::PreStmtKind
:
171 ProgramPoint::PostStmtKind
;
172 const ProgramPoint
&L
= ProgramPoint::getProgramPoint(S
, K
,
173 Pred
->getLocationContext(), checkFn
.Checker
);
174 CheckerContext
C(Bldr
, Eng
, Pred
, L
, WasInlined
);
181 /// Run checkers for visiting Stmts.
182 void CheckerManager::runCheckersForStmt(bool isPreVisit
,
183 ExplodedNodeSet
&Dst
,
184 const ExplodedNodeSet
&Src
,
188 CheckStmtContext
C(isPreVisit
, getCachedStmtCheckersFor(S
, isPreVisit
),
190 expandGraphWithCheckers(C
, Dst
, Src
);
195 struct CheckObjCMessageContext
{
196 using CheckersTy
= std::vector
<CheckerManager::CheckObjCMessageFunc
>;
198 ObjCMessageVisitKind Kind
;
200 const CheckersTy
&Checkers
;
201 const ObjCMethodCall
&Msg
;
204 CheckObjCMessageContext(ObjCMessageVisitKind visitKind
,
205 const CheckersTy
&checkers
,
206 const ObjCMethodCall
&msg
, ExprEngine
&eng
,
208 : Kind(visitKind
), WasInlined(wasInlined
), Checkers(checkers
), Msg(msg
),
211 CheckersTy::const_iterator
checkers_begin() { return Checkers
.begin(); }
212 CheckersTy::const_iterator
checkers_end() { return Checkers
.end(); }
214 void runChecker(CheckerManager::CheckObjCMessageFunc checkFn
,
215 NodeBuilder
&Bldr
, ExplodedNode
*Pred
) {
219 case ObjCMessageVisitKind::Pre
:
222 case ObjCMessageVisitKind::MessageNil
:
223 case ObjCMessageVisitKind::Post
:
228 const ProgramPoint
&L
= Msg
.getProgramPoint(IsPreVisit
,checkFn
.Checker
);
229 CheckerContext
C(Bldr
, Eng
, Pred
, L
, WasInlined
);
231 checkFn(*Msg
.cloneWithState
<ObjCMethodCall
>(Pred
->getState()), C
);
237 /// Run checkers for visiting obj-c messages.
238 void CheckerManager::runCheckersForObjCMessage(ObjCMessageVisitKind visitKind
,
239 ExplodedNodeSet
&Dst
,
240 const ExplodedNodeSet
&Src
,
241 const ObjCMethodCall
&msg
,
244 const auto &checkers
= getObjCMessageCheckers(visitKind
);
245 CheckObjCMessageContext
C(visitKind
, checkers
, msg
, Eng
, WasInlined
);
246 expandGraphWithCheckers(C
, Dst
, Src
);
249 const std::vector
<CheckerManager::CheckObjCMessageFunc
> &
250 CheckerManager::getObjCMessageCheckers(ObjCMessageVisitKind Kind
) const {
252 case ObjCMessageVisitKind::Pre
:
253 return PreObjCMessageCheckers
;
255 case ObjCMessageVisitKind::Post
:
256 return PostObjCMessageCheckers
;
257 case ObjCMessageVisitKind::MessageNil
:
258 return ObjCMessageNilCheckers
;
260 llvm_unreachable("Unknown Kind");
265 // FIXME: This has all the same signatures as CheckObjCMessageContext.
266 // Is there a way we can merge the two?
267 struct CheckCallContext
{
268 using CheckersTy
= std::vector
<CheckerManager::CheckCallFunc
>;
270 bool IsPreVisit
, WasInlined
;
271 const CheckersTy
&Checkers
;
272 const CallEvent
&Call
;
275 CheckCallContext(bool isPreVisit
, const CheckersTy
&checkers
,
276 const CallEvent
&call
, ExprEngine
&eng
,
278 : IsPreVisit(isPreVisit
), WasInlined(wasInlined
), Checkers(checkers
),
279 Call(call
), Eng(eng
) {}
281 CheckersTy::const_iterator
checkers_begin() { return Checkers
.begin(); }
282 CheckersTy::const_iterator
checkers_end() { return Checkers
.end(); }
284 void runChecker(CheckerManager::CheckCallFunc checkFn
,
285 NodeBuilder
&Bldr
, ExplodedNode
*Pred
) {
286 const ProgramPoint
&L
= Call
.getProgramPoint(IsPreVisit
,checkFn
.Checker
);
287 CheckerContext
C(Bldr
, Eng
, Pred
, L
, WasInlined
);
289 checkFn(*Call
.cloneWithState(Pred
->getState()), C
);
295 /// Run checkers for visiting an abstract call event.
296 void CheckerManager::runCheckersForCallEvent(bool isPreVisit
,
297 ExplodedNodeSet
&Dst
,
298 const ExplodedNodeSet
&Src
,
299 const CallEvent
&Call
,
302 CheckCallContext
C(isPreVisit
,
303 isPreVisit
? PreCallCheckers
305 Call
, Eng
, WasInlined
);
306 expandGraphWithCheckers(C
, Dst
, Src
);
311 struct CheckLocationContext
{
312 using CheckersTy
= std::vector
<CheckerManager::CheckLocationFunc
>;
314 const CheckersTy
&Checkers
;
317 const Stmt
*NodeEx
; /* Will become a CFGStmt */
321 CheckLocationContext(const CheckersTy
&checkers
,
322 SVal loc
, bool isLoad
, const Stmt
*NodeEx
,
325 : Checkers(checkers
), Loc(loc
), IsLoad(isLoad
), NodeEx(NodeEx
),
326 BoundEx(BoundEx
), Eng(eng
) {}
328 CheckersTy::const_iterator
checkers_begin() { return Checkers
.begin(); }
329 CheckersTy::const_iterator
checkers_end() { return Checkers
.end(); }
331 void runChecker(CheckerManager::CheckLocationFunc checkFn
,
332 NodeBuilder
&Bldr
, ExplodedNode
*Pred
) {
333 ProgramPoint::Kind K
= IsLoad
? ProgramPoint::PreLoadKind
:
334 ProgramPoint::PreStoreKind
;
335 const ProgramPoint
&L
=
336 ProgramPoint::getProgramPoint(NodeEx
, K
,
337 Pred
->getLocationContext(),
339 CheckerContext
C(Bldr
, Eng
, Pred
, L
);
340 checkFn(Loc
, IsLoad
, BoundEx
, C
);
346 /// Run checkers for load/store of a location.
348 void CheckerManager::runCheckersForLocation(ExplodedNodeSet
&Dst
,
349 const ExplodedNodeSet
&Src
,
350 SVal location
, bool isLoad
,
354 CheckLocationContext
C(LocationCheckers
, location
, isLoad
, NodeEx
,
356 expandGraphWithCheckers(C
, Dst
, Src
);
361 struct CheckBindContext
{
362 using CheckersTy
= std::vector
<CheckerManager::CheckBindFunc
>;
364 const CheckersTy
&Checkers
;
369 const ProgramPoint
&PP
;
371 CheckBindContext(const CheckersTy
&checkers
,
372 SVal loc
, SVal val
, const Stmt
*s
, ExprEngine
&eng
,
373 const ProgramPoint
&pp
)
374 : Checkers(checkers
), Loc(loc
), Val(val
), S(s
), Eng(eng
), PP(pp
) {}
376 CheckersTy::const_iterator
checkers_begin() { return Checkers
.begin(); }
377 CheckersTy::const_iterator
checkers_end() { return Checkers
.end(); }
379 void runChecker(CheckerManager::CheckBindFunc checkFn
,
380 NodeBuilder
&Bldr
, ExplodedNode
*Pred
) {
381 const ProgramPoint
&L
= PP
.withTag(checkFn
.Checker
);
382 CheckerContext
C(Bldr
, Eng
, Pred
, L
);
384 checkFn(Loc
, Val
, S
, C
);
390 /// Run checkers for binding of a value to a location.
391 void CheckerManager::runCheckersForBind(ExplodedNodeSet
&Dst
,
392 const ExplodedNodeSet
&Src
,
393 SVal location
, SVal val
,
394 const Stmt
*S
, ExprEngine
&Eng
,
395 const ProgramPoint
&PP
) {
396 CheckBindContext
C(BindCheckers
, location
, val
, S
, Eng
, PP
);
397 expandGraphWithCheckers(C
, Dst
, Src
);
400 void CheckerManager::runCheckersForEndAnalysis(ExplodedGraph
&G
,
403 for (const auto &EndAnalysisChecker
: EndAnalysisCheckers
)
404 EndAnalysisChecker(G
, BR
, Eng
);
409 struct CheckBeginFunctionContext
{
410 using CheckersTy
= std::vector
<CheckerManager::CheckBeginFunctionFunc
>;
412 const CheckersTy
&Checkers
;
414 const ProgramPoint
&PP
;
416 CheckBeginFunctionContext(const CheckersTy
&Checkers
, ExprEngine
&Eng
,
417 const ProgramPoint
&PP
)
418 : Checkers(Checkers
), Eng(Eng
), PP(PP
) {}
420 CheckersTy::const_iterator
checkers_begin() { return Checkers
.begin(); }
421 CheckersTy::const_iterator
checkers_end() { return Checkers
.end(); }
423 void runChecker(CheckerManager::CheckBeginFunctionFunc checkFn
,
424 NodeBuilder
&Bldr
, ExplodedNode
*Pred
) {
425 const ProgramPoint
&L
= PP
.withTag(checkFn
.Checker
);
426 CheckerContext
C(Bldr
, Eng
, Pred
, L
);
434 void CheckerManager::runCheckersForBeginFunction(ExplodedNodeSet
&Dst
,
440 CheckBeginFunctionContext
C(BeginFunctionCheckers
, Eng
, L
);
441 expandGraphWithCheckers(C
, Dst
, Src
);
444 /// Run checkers for end of path.
445 // Note, We do not chain the checker output (like in expandGraphWithCheckers)
446 // for this callback since end of path nodes are expected to be final.
447 void CheckerManager::runCheckersForEndFunction(NodeBuilderContext
&BC
,
448 ExplodedNodeSet
&Dst
,
451 const ReturnStmt
*RS
) {
452 // We define the builder outside of the loop because if at least one checker
453 // creates a successor for Pred, we do not need to generate an
454 // autotransition for it.
455 NodeBuilder
Bldr(Pred
, Dst
, BC
);
456 for (const auto &checkFn
: EndFunctionCheckers
) {
457 const ProgramPoint
&L
=
458 FunctionExitPoint(RS
, Pred
->getLocationContext(), checkFn
.Checker
);
459 CheckerContext
C(Bldr
, Eng
, Pred
, L
);
466 struct CheckBranchConditionContext
{
467 using CheckersTy
= std::vector
<CheckerManager::CheckBranchConditionFunc
>;
469 const CheckersTy
&Checkers
;
470 const Stmt
*Condition
;
473 CheckBranchConditionContext(const CheckersTy
&checkers
,
474 const Stmt
*Cond
, ExprEngine
&eng
)
475 : Checkers(checkers
), Condition(Cond
), Eng(eng
) {}
477 CheckersTy::const_iterator
checkers_begin() { return Checkers
.begin(); }
478 CheckersTy::const_iterator
checkers_end() { return Checkers
.end(); }
480 void runChecker(CheckerManager::CheckBranchConditionFunc checkFn
,
481 NodeBuilder
&Bldr
, ExplodedNode
*Pred
) {
482 ProgramPoint L
= PostCondition(Condition
, Pred
->getLocationContext(),
484 CheckerContext
C(Bldr
, Eng
, Pred
, L
);
485 checkFn(Condition
, C
);
491 /// Run checkers for branch condition.
492 void CheckerManager::runCheckersForBranchCondition(const Stmt
*Condition
,
493 ExplodedNodeSet
&Dst
,
498 CheckBranchConditionContext
C(BranchConditionCheckers
, Condition
, Eng
);
499 expandGraphWithCheckers(C
, Dst
, Src
);
504 struct CheckNewAllocatorContext
{
505 using CheckersTy
= std::vector
<CheckerManager::CheckNewAllocatorFunc
>;
507 const CheckersTy
&Checkers
;
508 const CXXAllocatorCall
&Call
;
512 CheckNewAllocatorContext(const CheckersTy
&Checkers
,
513 const CXXAllocatorCall
&Call
, bool WasInlined
,
515 : Checkers(Checkers
), Call(Call
), WasInlined(WasInlined
), Eng(Eng
) {}
517 CheckersTy::const_iterator
checkers_begin() { return Checkers
.begin(); }
518 CheckersTy::const_iterator
checkers_end() { return Checkers
.end(); }
520 void runChecker(CheckerManager::CheckNewAllocatorFunc checkFn
,
521 NodeBuilder
&Bldr
, ExplodedNode
*Pred
) {
523 PostAllocatorCall(Call
.getOriginExpr(), Pred
->getLocationContext());
524 CheckerContext
C(Bldr
, Eng
, Pred
, L
, WasInlined
);
525 checkFn(cast
<CXXAllocatorCall
>(*Call
.cloneWithState(Pred
->getState())),
532 void CheckerManager::runCheckersForNewAllocator(const CXXAllocatorCall
&Call
,
533 ExplodedNodeSet
&Dst
,
539 CheckNewAllocatorContext
C(NewAllocatorCheckers
, Call
, WasInlined
, Eng
);
540 expandGraphWithCheckers(C
, Dst
, Src
);
543 /// Run checkers for live symbols.
544 void CheckerManager::runCheckersForLiveSymbols(ProgramStateRef state
,
545 SymbolReaper
&SymReaper
) {
546 for (const auto &LiveSymbolsChecker
: LiveSymbolsCheckers
)
547 LiveSymbolsChecker(state
, SymReaper
);
552 struct CheckDeadSymbolsContext
{
553 using CheckersTy
= std::vector
<CheckerManager::CheckDeadSymbolsFunc
>;
555 const CheckersTy
&Checkers
;
559 ProgramPoint::Kind ProgarmPointKind
;
561 CheckDeadSymbolsContext(const CheckersTy
&checkers
, SymbolReaper
&sr
,
562 const Stmt
*s
, ExprEngine
&eng
,
563 ProgramPoint::Kind K
)
564 : Checkers(checkers
), SR(sr
), S(s
), Eng(eng
), ProgarmPointKind(K
) {}
566 CheckersTy::const_iterator
checkers_begin() { return Checkers
.begin(); }
567 CheckersTy::const_iterator
checkers_end() { return Checkers
.end(); }
569 void runChecker(CheckerManager::CheckDeadSymbolsFunc checkFn
,
570 NodeBuilder
&Bldr
, ExplodedNode
*Pred
) {
571 const ProgramPoint
&L
= ProgramPoint::getProgramPoint(S
, ProgarmPointKind
,
572 Pred
->getLocationContext(), checkFn
.Checker
);
573 CheckerContext
C(Bldr
, Eng
, Pred
, L
);
575 // Note, do not pass the statement to the checkers without letting them
576 // differentiate if we ran remove dead bindings before or after the
584 /// Run checkers for dead symbols.
585 void CheckerManager::runCheckersForDeadSymbols(ExplodedNodeSet
&Dst
,
586 const ExplodedNodeSet
&Src
,
587 SymbolReaper
&SymReaper
,
590 ProgramPoint::Kind K
) {
591 CheckDeadSymbolsContext
C(DeadSymbolsCheckers
, SymReaper
, S
, Eng
, K
);
592 expandGraphWithCheckers(C
, Dst
, Src
);
595 /// Run checkers for region changes.
597 CheckerManager::runCheckersForRegionChanges(ProgramStateRef state
,
598 const InvalidatedSymbols
*invalidated
,
599 ArrayRef
<const MemRegion
*> ExplicitRegions
,
600 ArrayRef
<const MemRegion
*> Regions
,
601 const LocationContext
*LCtx
,
602 const CallEvent
*Call
) {
603 for (const auto &RegionChangesChecker
: RegionChangesCheckers
) {
604 // If any checker declares the state infeasible (or if it starts that way),
608 state
= RegionChangesChecker(state
, invalidated
, ExplicitRegions
, Regions
,
614 /// Run checkers to process symbol escape event.
616 CheckerManager::runCheckersForPointerEscape(ProgramStateRef State
,
617 const InvalidatedSymbols
&Escaped
,
618 const CallEvent
*Call
,
619 PointerEscapeKind Kind
,
620 RegionAndSymbolInvalidationTraits
*ETraits
) {
621 assert((Call
!= nullptr ||
622 (Kind
!= PSK_DirectEscapeOnCall
&&
623 Kind
!= PSK_IndirectEscapeOnCall
)) &&
624 "Call must not be NULL when escaping on call");
625 for (const auto &PointerEscapeChecker
: PointerEscapeCheckers
) {
626 // If any checker declares the state infeasible (or if it starts that
630 State
= PointerEscapeChecker(State
, Escaped
, Call
, Kind
, ETraits
);
635 /// Run checkers for handling assumptions on symbolic values.
637 CheckerManager::runCheckersForEvalAssume(ProgramStateRef state
,
638 SVal Cond
, bool Assumption
) {
639 for (const auto &EvalAssumeChecker
: EvalAssumeCheckers
) {
640 // If any checker declares the state infeasible (or if it starts that way),
644 state
= EvalAssumeChecker(state
, Cond
, Assumption
);
649 /// Run checkers for evaluating a call.
650 /// Only one checker will evaluate the call.
651 void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet
&Dst
,
652 const ExplodedNodeSet
&Src
,
653 const CallEvent
&Call
,
655 const EvalCallOptions
&CallOpts
) {
656 for (auto *const Pred
: Src
) {
657 std::optional
<CheckerNameRef
> evaluatorChecker
;
659 ExplodedNodeSet checkDst
;
660 NodeBuilder
B(Pred
, checkDst
, Eng
.getBuilderContext());
662 // Check if any of the EvalCall callbacks can evaluate the call.
663 for (const auto &EvalCallChecker
: EvalCallCheckers
) {
664 // TODO: Support the situation when the call doesn't correspond
666 ProgramPoint L
= ProgramPoint::getProgramPoint(
667 Call
.getOriginExpr(), ProgramPoint::PostStmtKind
,
668 Pred
->getLocationContext(), EvalCallChecker
.Checker
);
669 bool evaluated
= false;
670 { // CheckerContext generates transitions(populates checkDest) on
671 // destruction, so introduce the scope to make sure it gets properly
673 CheckerContext
C(B
, Eng
, Pred
, L
);
674 evaluated
= EvalCallChecker(Call
, C
);
677 if (evaluated
&& evaluatorChecker
) {
678 const auto toString
= [](const CallEvent
&Call
) -> std::string
{
680 llvm::raw_string_ostream
OS(Buf
);
685 std::string AssertionMessage
= llvm::formatv(
686 "The '{0}' call has been already evaluated by the {1} checker, "
687 "while the {2} checker also tried to evaluate the same call. At "
688 "most one checker supposed to evaluate a call.",
689 toString(Call
), evaluatorChecker
->getName(),
690 EvalCallChecker
.Checker
->getCheckerName());
691 llvm_unreachable(AssertionMessage
.c_str());
695 evaluatorChecker
= EvalCallChecker
.Checker
->getCheckerName();
696 Dst
.insert(checkDst
);
698 break; // on release don't check that no other checker also evals.
703 // If none of the checkers evaluated the call, ask ExprEngine to handle it.
704 if (!evaluatorChecker
) {
705 NodeBuilder
B(Pred
, Dst
, Eng
.getBuilderContext());
706 Eng
.defaultEvalCall(B
, Pred
, Call
, CallOpts
);
711 /// Run checkers for the entire Translation Unit.
712 void CheckerManager::runCheckersOnEndOfTranslationUnit(
713 const TranslationUnitDecl
*TU
,
714 AnalysisManager
&mgr
,
716 for (const auto &EndOfTranslationUnitChecker
: EndOfTranslationUnitCheckers
)
717 EndOfTranslationUnitChecker(TU
, mgr
, BR
);
720 void CheckerManager::runCheckersForPrintStateJson(raw_ostream
&Out
,
721 ProgramStateRef State
,
725 Indent(Out
, Space
, IsDot
) << "\"checker_messages\": ";
727 // Create a temporary stream to see whether we have any message.
728 SmallString
<1024> TempBuf
;
729 llvm::raw_svector_ostream
TempOut(TempBuf
);
730 unsigned int InnerSpace
= Space
+ 2;
732 // Create the new-line in JSON with enough space.
733 SmallString
<128> NewLine
;
734 llvm::raw_svector_ostream
NLOut(NewLine
);
735 NLOut
<< "\", " << NL
; // Inject the ending and a new line
736 Indent(NLOut
, InnerSpace
, IsDot
) << "\""; // then begin the next message.
739 bool HasMessage
= false;
741 // Store the last CheckerTag.
742 const void *LastCT
= nullptr;
743 for (const auto &CT
: CheckerTags
) {
744 // See whether the current checker has a message.
745 CT
.second
->printState(TempOut
, State
, /*NL=*/NewLine
.c_str(), /*Sep=*/"");
759 for (const auto &CT
: CheckerTags
) {
760 // See whether the current checker has a message.
761 CT
.second
->printState(TempOut
, State
, /*NL=*/NewLine
.c_str(), /*Sep=*/"");
766 Indent(Out
, Space
, IsDot
)
767 << "{ \"checker\": \"" << CT
.second
->getCheckerName().getName()
768 << "\", \"messages\": [" << NL
;
769 Indent(Out
, InnerSpace
, IsDot
)
770 << '\"' << TempBuf
.str().trim() << '\"' << NL
;
771 Indent(Out
, Space
, IsDot
) << "]}";
780 // It is the last element of the 'program_state' so do not add a comma.
782 Indent(Out
, --Space
, IsDot
) << "]";
789 //===----------------------------------------------------------------------===//
790 // Internal registration functions for AST traversing.
791 //===----------------------------------------------------------------------===//
793 void CheckerManager::_registerForDecl(CheckDeclFunc checkfn
,
794 HandlesDeclFunc isForDeclFn
) {
795 DeclCheckerInfo info
= { checkfn
, isForDeclFn
};
796 DeclCheckers
.push_back(info
);
799 void CheckerManager::_registerForBody(CheckDeclFunc checkfn
) {
800 BodyCheckers
.push_back(checkfn
);
803 //===----------------------------------------------------------------------===//
804 // Internal registration functions for path-sensitive checking.
805 //===----------------------------------------------------------------------===//
807 void CheckerManager::_registerForPreStmt(CheckStmtFunc checkfn
,
808 HandlesStmtFunc isForStmtFn
) {
809 StmtCheckerInfo info
= { checkfn
, isForStmtFn
, /*IsPreVisit*/true };
810 StmtCheckers
.push_back(info
);
813 void CheckerManager::_registerForPostStmt(CheckStmtFunc checkfn
,
814 HandlesStmtFunc isForStmtFn
) {
815 StmtCheckerInfo info
= { checkfn
, isForStmtFn
, /*IsPreVisit*/false };
816 StmtCheckers
.push_back(info
);
819 void CheckerManager::_registerForPreObjCMessage(CheckObjCMessageFunc checkfn
) {
820 PreObjCMessageCheckers
.push_back(checkfn
);
823 void CheckerManager::_registerForObjCMessageNil(CheckObjCMessageFunc checkfn
) {
824 ObjCMessageNilCheckers
.push_back(checkfn
);
827 void CheckerManager::_registerForPostObjCMessage(CheckObjCMessageFunc checkfn
) {
828 PostObjCMessageCheckers
.push_back(checkfn
);
831 void CheckerManager::_registerForPreCall(CheckCallFunc checkfn
) {
832 PreCallCheckers
.push_back(checkfn
);
834 void CheckerManager::_registerForPostCall(CheckCallFunc checkfn
) {
835 PostCallCheckers
.push_back(checkfn
);
838 void CheckerManager::_registerForLocation(CheckLocationFunc checkfn
) {
839 LocationCheckers
.push_back(checkfn
);
842 void CheckerManager::_registerForBind(CheckBindFunc checkfn
) {
843 BindCheckers
.push_back(checkfn
);
846 void CheckerManager::_registerForEndAnalysis(CheckEndAnalysisFunc checkfn
) {
847 EndAnalysisCheckers
.push_back(checkfn
);
850 void CheckerManager::_registerForBeginFunction(CheckBeginFunctionFunc checkfn
) {
851 BeginFunctionCheckers
.push_back(checkfn
);
854 void CheckerManager::_registerForEndFunction(CheckEndFunctionFunc checkfn
) {
855 EndFunctionCheckers
.push_back(checkfn
);
858 void CheckerManager::_registerForBranchCondition(
859 CheckBranchConditionFunc checkfn
) {
860 BranchConditionCheckers
.push_back(checkfn
);
863 void CheckerManager::_registerForNewAllocator(CheckNewAllocatorFunc checkfn
) {
864 NewAllocatorCheckers
.push_back(checkfn
);
867 void CheckerManager::_registerForLiveSymbols(CheckLiveSymbolsFunc checkfn
) {
868 LiveSymbolsCheckers
.push_back(checkfn
);
871 void CheckerManager::_registerForDeadSymbols(CheckDeadSymbolsFunc checkfn
) {
872 DeadSymbolsCheckers
.push_back(checkfn
);
875 void CheckerManager::_registerForRegionChanges(CheckRegionChangesFunc checkfn
) {
876 RegionChangesCheckers
.push_back(checkfn
);
879 void CheckerManager::_registerForPointerEscape(CheckPointerEscapeFunc checkfn
){
880 PointerEscapeCheckers
.push_back(checkfn
);
883 void CheckerManager::_registerForConstPointerEscape(
884 CheckPointerEscapeFunc checkfn
) {
885 PointerEscapeCheckers
.push_back(checkfn
);
888 void CheckerManager::_registerForEvalAssume(EvalAssumeFunc checkfn
) {
889 EvalAssumeCheckers
.push_back(checkfn
);
892 void CheckerManager::_registerForEvalCall(EvalCallFunc checkfn
) {
893 EvalCallCheckers
.push_back(checkfn
);
896 void CheckerManager::_registerForEndOfTranslationUnit(
897 CheckEndOfTranslationUnit checkfn
) {
898 EndOfTranslationUnitCheckers
.push_back(checkfn
);
901 //===----------------------------------------------------------------------===//
902 // Implementation details.
903 //===----------------------------------------------------------------------===//
905 const CheckerManager::CachedStmtCheckers
&
906 CheckerManager::getCachedStmtCheckersFor(const Stmt
*S
, bool isPreVisit
) {
909 unsigned Key
= (S
->getStmtClass() << 1) | unsigned(isPreVisit
);
910 CachedStmtCheckersMapTy::iterator CCI
= CachedStmtCheckersMap
.find(Key
);
911 if (CCI
!= CachedStmtCheckersMap
.end())
914 // Find the checkers that should run for this Stmt and cache them.
915 CachedStmtCheckers
&Checkers
= CachedStmtCheckersMap
[Key
];
916 for (const auto &Info
: StmtCheckers
)
917 if (Info
.IsPreVisit
== isPreVisit
&& Info
.IsForStmtFn(S
))
918 Checkers
.push_back(Info
.CheckFn
);