clang 23.0.0git
CheckerManager.cpp
Go to the documentation of this file.
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
14#include "clang/AST/DeclBase.h"
15#include "clang/AST/Stmt.h"
18#include "clang/Basic/LLVM.h"
26#include "llvm/ADT/SmallVector.h"
27#include "llvm/Support/ErrorHandling.h"
28#include "llvm/Support/FormatVariadic.h"
29#include "llvm/Support/TimeProfiler.h"
30#include <cassert>
31#include <optional>
32#include <vector>
33
34using namespace clang;
35using namespace ento;
36
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, BlockEntranceCheckers,
45 EndAnalysisCheckers, BeginFunctionCheckers, EndFunctionCheckers,
46 BranchConditionCheckers, NewAllocatorCheckers, LiveSymbolsCheckers,
47 DeadSymbolsCheckers, RegionChangesCheckers, PointerEscapeCheckers,
48 EvalAssumeCheckers, EvalCallCheckers, EndOfTranslationUnitCheckers);
49}
50
52 const CheckerFrontend *Checker, StringRef OptionName,
53 StringRef ExpectedValueDesc) const {
54
55 getDiagnostics().Report(diag::err_analyzer_checker_option_invalid_input)
56 << (llvm::Twine(Checker->getName()) + ":" + OptionName).str()
57 << ExpectedValueDesc;
58}
59
60//===----------------------------------------------------------------------===//
61// Functions for running checkers for AST traversing..
62//===----------------------------------------------------------------------===//
63
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
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
95template <typename CHECK_CTX>
96static 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
135namespace {
136
137std::string checkerScopeName(StringRef Name, const CheckerBackend *Checker) {
138 if (!llvm::timeTraceProfilerEnabled())
139 return "";
140 StringRef CheckerTag = Checker ? Checker->getDebugTag() : "<unknown>";
141 return (Name + ":" + CheckerTag).str();
142}
143
144 struct CheckStmtContext {
145 using CheckersTy = SmallVectorImpl<CheckerManager::CheckStmtFunc>;
146
147 bool IsPreVisit;
148 const CheckersTy &Checkers;
149 const Stmt *S;
150 ExprEngine &Eng;
151 bool WasInlined;
152
153 CheckStmtContext(bool isPreVisit, const CheckersTy &checkers,
154 const Stmt *s, ExprEngine &eng, bool wasInlined = false)
155 : IsPreVisit(isPreVisit), Checkers(checkers), S(s), Eng(eng),
156 WasInlined(wasInlined) {}
157
158 CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
159 CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
160
161 void runChecker(CheckerManager::CheckStmtFunc checkFn,
162 NodeBuilder &Bldr, ExplodedNode *Pred) {
163 llvm::TimeTraceScope TimeScope(checkerScopeName("Stmt", checkFn.Checker));
164 // FIXME: Remove respondsToCallback from CheckerContext;
168 Pred->getLocationContext(), checkFn.Checker);
169 CheckerContext C(Bldr, Eng, Pred, L, WasInlined);
170 checkFn(S, C);
171 }
172 };
173
174} // namespace
175
176/// Run checkers for visiting Stmts.
178 ExplodedNodeSet &Dst,
179 const ExplodedNodeSet &Src,
180 const Stmt *S,
181 ExprEngine &Eng,
182 bool WasInlined) {
183 CheckStmtContext C(isPreVisit, getCachedStmtCheckersFor(S, isPreVisit),
184 S, Eng, WasInlined);
185 llvm::TimeTraceScope TimeScope(
186 isPreVisit ? "CheckerManager::runCheckersForStmt (Pre)"
187 : "CheckerManager::runCheckersForStmt (Post)");
188 expandGraphWithCheckers(C, Dst, Src);
189}
190
191namespace {
192
193 struct CheckObjCMessageContext {
194 using CheckersTy = std::vector<CheckerManager::CheckObjCMessageFunc>;
195
197 bool WasInlined;
198 const CheckersTy &Checkers;
199 const ObjCMethodCall &Msg;
200 ExprEngine &Eng;
201
202 CheckObjCMessageContext(ObjCMessageVisitKind visitKind,
203 const CheckersTy &checkers,
204 const ObjCMethodCall &msg, ExprEngine &eng,
205 bool wasInlined)
206 : Kind(visitKind), WasInlined(wasInlined), Checkers(checkers), Msg(msg),
207 Eng(eng) {}
208
209 CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
210 CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
211
212 void runChecker(CheckerManager::CheckObjCMessageFunc checkFn,
213 NodeBuilder &Bldr, ExplodedNode *Pred) {
214 llvm::TimeTraceScope TimeScope(
215 checkerScopeName("ObjCMsg", checkFn.Checker));
216 bool IsPreVisit;
217
218 switch (Kind) {
219 case ObjCMessageVisitKind::Pre:
220 IsPreVisit = true;
221 break;
222 case ObjCMessageVisitKind::MessageNil:
223 case ObjCMessageVisitKind::Post:
224 IsPreVisit = false;
225 break;
226 }
227
228 const ProgramPoint &L = Msg.getProgramPoint(IsPreVisit,checkFn.Checker);
229 CheckerContext C(Bldr, Eng, Pred, L, WasInlined);
230
231 checkFn(*Msg.cloneWithState<ObjCMethodCall>(Pred->getState()), C);
232 }
233 };
234
235} // namespace
236
237/// Run checkers for visiting obj-c messages.
239 ExplodedNodeSet &Dst,
240 const ExplodedNodeSet &Src,
241 const ObjCMethodCall &msg,
242 ExprEngine &Eng,
243 bool WasInlined) {
244 const auto &checkers = getObjCMessageCheckers(visitKind);
245 CheckObjCMessageContext C(visitKind, checkers, msg, Eng, WasInlined);
246 llvm::TimeTraceScope TimeScope("CheckerManager::runCheckersForObjCMessage");
247 expandGraphWithCheckers(C, Dst, Src);
248}
249
250const std::vector<CheckerManager::CheckObjCMessageFunc> &
251CheckerManager::getObjCMessageCheckers(ObjCMessageVisitKind Kind) const {
252 switch (Kind) {
254 return PreObjCMessageCheckers;
255 break;
257 return PostObjCMessageCheckers;
259 return ObjCMessageNilCheckers;
260 }
261 llvm_unreachable("Unknown Kind");
262}
263
264namespace {
265
266 // FIXME: This has all the same signatures as CheckObjCMessageContext.
267 // Is there a way we can merge the two?
268 struct CheckCallContext {
269 using CheckersTy = std::vector<CheckerManager::CheckCallFunc>;
270
271 bool IsPreVisit, WasInlined;
272 const CheckersTy &Checkers;
273 const CallEvent &Call;
274 ExprEngine &Eng;
275
276 CheckCallContext(bool isPreVisit, const CheckersTy &checkers,
277 const CallEvent &call, ExprEngine &eng,
278 bool wasInlined)
279 : IsPreVisit(isPreVisit), WasInlined(wasInlined), Checkers(checkers),
280 Call(call), Eng(eng) {}
281
282 CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
283 CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
284
285 void runChecker(CheckerManager::CheckCallFunc checkFn,
286 NodeBuilder &Bldr, ExplodedNode *Pred) {
287 llvm::TimeTraceScope TimeScope(checkerScopeName("Call", checkFn.Checker));
288 const ProgramPoint &L = Call.getProgramPoint(IsPreVisit,checkFn.Checker);
289 CheckerContext C(Bldr, Eng, Pred, L, WasInlined);
290
291 checkFn(*Call.cloneWithState(Pred->getState()), C);
292 }
293 };
294
295} // namespace
296
297/// Run checkers for visiting an abstract call event.
299 ExplodedNodeSet &Dst,
300 const ExplodedNodeSet &Src,
301 const CallEvent &Call,
302 ExprEngine &Eng,
303 bool WasInlined) {
304 CheckCallContext C(isPreVisit,
305 isPreVisit ? PreCallCheckers
306 : PostCallCheckers,
307 Call, Eng, WasInlined);
308 llvm::TimeTraceScope TimeScope(
309 isPreVisit ? "CheckerManager::runCheckersForCallEvent (Pre)"
310 : "CheckerManager::runCheckersForCallEvent (Post)");
311 expandGraphWithCheckers(C, Dst, Src);
312}
313
314namespace {
315
316 struct CheckLocationContext {
317 using CheckersTy = std::vector<CheckerManager::CheckLocationFunc>;
318
319 const CheckersTy &Checkers;
320 SVal Loc;
321 bool IsLoad;
322 const Stmt *NodeEx; /* Will become a CFGStmt */
323 const Stmt *BoundEx;
324 ExprEngine &Eng;
325
326 CheckLocationContext(const CheckersTy &checkers,
327 SVal loc, bool isLoad, const Stmt *NodeEx,
328 const Stmt *BoundEx,
329 ExprEngine &eng)
330 : Checkers(checkers), Loc(loc), IsLoad(isLoad), NodeEx(NodeEx),
331 BoundEx(BoundEx), Eng(eng) {}
332
333 CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
334 CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
335
336 void runChecker(CheckerManager::CheckLocationFunc checkFn,
337 NodeBuilder &Bldr, ExplodedNode *Pred) {
338 llvm::TimeTraceScope TimeScope(checkerScopeName("Loc", checkFn.Checker));
341 const ProgramPoint &L =
343 Pred->getLocationContext(),
344 checkFn.Checker);
345 CheckerContext C(Bldr, Eng, Pred, L);
346 checkFn(Loc, IsLoad, BoundEx, C);
347 }
348 };
349
350} // namespace
351
352/// Run checkers for load/store of a location.
353
355 const ExplodedNodeSet &Src,
356 SVal location, bool isLoad,
357 const Stmt *NodeEx,
358 const Stmt *BoundEx,
359 ExprEngine &Eng) {
360 CheckLocationContext C(LocationCheckers, location, isLoad, NodeEx,
361 BoundEx, Eng);
362 llvm::TimeTraceScope TimeScope(
363 isLoad ? "CheckerManager::runCheckersForLocation (Load)"
364 : "CheckerManager::runCheckersForLocation (Store)");
365 expandGraphWithCheckers(C, Dst, Src);
366}
367
368namespace {
369
370 struct CheckBindContext {
371 using CheckersTy = std::vector<CheckerManager::CheckBindFunc>;
372
373 const CheckersTy &Checkers;
374 SVal Loc;
375 SVal Val;
376 const Stmt *S;
377 ExprEngine &Eng;
378 const ProgramPoint &PP;
379 bool AtDeclInit;
380
381 CheckBindContext(const CheckersTy &checkers, SVal loc, SVal val,
382 const Stmt *s, bool AtDeclInit, ExprEngine &eng,
383 const ProgramPoint &pp)
384 : Checkers(checkers), Loc(loc), Val(val), S(s), Eng(eng), PP(pp),
385 AtDeclInit(AtDeclInit) {}
386
387 CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
388 CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
389
390 void runChecker(CheckerManager::CheckBindFunc checkFn,
391 NodeBuilder &Bldr, ExplodedNode *Pred) {
392 llvm::TimeTraceScope TimeScope(checkerScopeName("Bind", checkFn.Checker));
393 const ProgramPoint &L = PP.withTag(checkFn.Checker);
394 CheckerContext C(Bldr, Eng, Pred, L);
395
396 checkFn(Loc, Val, S, AtDeclInit, C);
397 }
398 };
399
400 llvm::TimeTraceMetadata getTimeTraceBindMetadata(SVal Val) {
401 assert(llvm::timeTraceProfilerEnabled());
402 std::string Name;
403 llvm::raw_string_ostream OS(Name);
404 Val.dumpToStream(OS);
405 return llvm::TimeTraceMetadata{OS.str(), ""};
406 }
407
408} // namespace
409
410/// Run checkers for binding of a value to a location.
412 const ExplodedNodeSet &Src,
413 SVal location, SVal val, const Stmt *S,
414 bool AtDeclInit, ExprEngine &Eng,
415 const ProgramPoint &PP) {
416 CheckBindContext C(BindCheckers, location, val, S, AtDeclInit, Eng, PP);
417 llvm::TimeTraceScope TimeScope{
418 "CheckerManager::runCheckersForBind",
419 [&val]() { return getTimeTraceBindMetadata(val); }};
420 expandGraphWithCheckers(C, Dst, Src);
421}
422
423namespace {
424struct CheckBlockEntranceContext {
425 using CheckBlockEntranceFunc = CheckerManager::CheckBlockEntranceFunc;
426 using CheckersTy = std::vector<CheckBlockEntranceFunc>;
427
428 const CheckersTy &Checkers;
429 const BlockEntrance &Entrance;
430 ExprEngine &Eng;
431
432 CheckBlockEntranceContext(const CheckersTy &Checkers,
433 const BlockEntrance &Entrance, ExprEngine &Eng)
434 : Checkers(Checkers), Entrance(Entrance), Eng(Eng) {}
435
436 auto checkers_begin() const { return Checkers.begin(); }
437 auto checkers_end() const { return Checkers.end(); }
438
439 void runChecker(CheckBlockEntranceFunc CheckFn, NodeBuilder &Bldr,
440 ExplodedNode *Pred) {
441 llvm::TimeTraceScope TimeScope(
442 checkerScopeName("BlockEntrance", CheckFn.Checker));
443 CheckerContext C(Bldr, Eng, Pred, Entrance.withTag(CheckFn.Checker));
444 CheckFn(Entrance, C);
445 }
446};
447
448} // namespace
449
451 const ExplodedNodeSet &Src,
452 const BlockEntrance &Entrance,
453 ExprEngine &Eng) const {
454 CheckBlockEntranceContext C(BlockEntranceCheckers, Entrance, Eng);
455 llvm::TimeTraceScope TimeScope{"CheckerManager::runCheckersForBlockEntrance"};
456 expandGraphWithCheckers(C, Dst, Src);
457}
458
460 BugReporter &BR,
461 ExprEngine &Eng) {
462 for (const auto &EndAnalysisChecker : EndAnalysisCheckers)
463 EndAnalysisChecker(G, BR, Eng);
464}
465
466namespace {
467
468struct CheckBeginFunctionContext {
469 using CheckersTy = std::vector<CheckerManager::CheckBeginFunctionFunc>;
470
471 const CheckersTy &Checkers;
472 ExprEngine &Eng;
473 const ProgramPoint &PP;
474
475 CheckBeginFunctionContext(const CheckersTy &Checkers, ExprEngine &Eng,
476 const ProgramPoint &PP)
477 : Checkers(Checkers), Eng(Eng), PP(PP) {}
478
479 CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
480 CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
481
482 void runChecker(CheckerManager::CheckBeginFunctionFunc checkFn,
483 NodeBuilder &Bldr, ExplodedNode *Pred) {
484 llvm::TimeTraceScope TimeScope(checkerScopeName("Begin", checkFn.Checker));
485 const ProgramPoint &L = PP.withTag(checkFn.Checker);
486 CheckerContext C(Bldr, Eng, Pred, L);
487
488 checkFn(C);
489 }
490};
491
492} // namespace
493
495 const BlockEdge &L,
496 ExplodedNode *Pred,
497 ExprEngine &Eng) {
498 ExplodedNodeSet Src;
499 Src.insert(Pred);
500 CheckBeginFunctionContext C(BeginFunctionCheckers, Eng, L);
501 llvm::TimeTraceScope TimeScope("CheckerManager::runCheckersForBeginFunction");
502 expandGraphWithCheckers(C, Dst, Src);
503}
504
505/// Run checkers for end of path.
506// Note, We do not chain the checker output (like in expandGraphWithCheckers)
507// for this callback since end of path nodes are expected to be final.
509 ExplodedNode *Pred,
510 ExprEngine &Eng,
511 const ReturnStmt *RS) {
512 // We define the builder outside of the loop because if at least one checker
513 // creates a successor for Pred, we do not need to generate an
514 // autotransition for it.
515 NodeBuilder Bldr(Pred, Dst, Eng.getBuilderContext());
516 for (const auto &checkFn : EndFunctionCheckers) {
517 const ProgramPoint &L =
518 FunctionExitPoint(RS, Pred->getLocationContext(), checkFn.Checker);
519 CheckerContext C(Bldr, Eng, Pred, L);
520 llvm::TimeTraceScope TimeScope(checkerScopeName("End", checkFn.Checker));
521 checkFn(RS, C);
522 }
523}
524
525namespace {
526
527 struct CheckBranchConditionContext {
528 using CheckersTy = std::vector<CheckerManager::CheckBranchConditionFunc>;
529
530 const CheckersTy &Checkers;
531 const Stmt *Condition;
532 ExprEngine &Eng;
533
534 CheckBranchConditionContext(const CheckersTy &checkers,
535 const Stmt *Cond, ExprEngine &eng)
536 : Checkers(checkers), Condition(Cond), Eng(eng) {}
537
538 CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
539 CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
540
541 void runChecker(CheckerManager::CheckBranchConditionFunc checkFn,
542 NodeBuilder &Bldr, ExplodedNode *Pred) {
543 llvm::TimeTraceScope TimeScope(
544 checkerScopeName("BranchCond", checkFn.Checker));
545 ProgramPoint L = PostCondition(Condition, Pred->getLocationContext(),
546 checkFn.Checker);
547 CheckerContext C(Bldr, Eng, Pred, L);
548 checkFn(Condition, C);
549 }
550 };
551
552} // namespace
553
554/// Run checkers for branch condition.
556 ExplodedNodeSet &Dst,
557 ExplodedNode *Pred,
558 ExprEngine &Eng) {
559 ExplodedNodeSet Src;
560 Src.insert(Pred);
561 CheckBranchConditionContext C(BranchConditionCheckers, Condition, Eng);
562 llvm::TimeTraceScope TimeScope(
563 "CheckerManager::runCheckersForBranchCondition");
564 expandGraphWithCheckers(C, Dst, Src);
565}
566
567namespace {
568
569 struct CheckNewAllocatorContext {
570 using CheckersTy = std::vector<CheckerManager::CheckNewAllocatorFunc>;
571
572 const CheckersTy &Checkers;
573 const CXXAllocatorCall &Call;
574 bool WasInlined;
575 ExprEngine &Eng;
576
577 CheckNewAllocatorContext(const CheckersTy &Checkers,
578 const CXXAllocatorCall &Call, bool WasInlined,
579 ExprEngine &Eng)
580 : Checkers(Checkers), Call(Call), WasInlined(WasInlined), Eng(Eng) {}
581
582 CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
583 CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
584
585 void runChecker(CheckerManager::CheckNewAllocatorFunc checkFn,
586 NodeBuilder &Bldr, ExplodedNode *Pred) {
587 llvm::TimeTraceScope TimeScope(
588 checkerScopeName("Allocator", checkFn.Checker));
589 ProgramPoint L = PostAllocatorCall(
590 Call.getOriginExpr(), Pred->getLocationContext(), checkFn.Checker);
591 CheckerContext C(Bldr, Eng, Pred, L, WasInlined);
592 checkFn(cast<CXXAllocatorCall>(*Call.cloneWithState(Pred->getState())),
593 C);
594 }
595 };
596
597} // namespace
598
600 ExplodedNodeSet &Dst,
601 ExplodedNode *Pred,
602 ExprEngine &Eng,
603 bool WasInlined) {
604 ExplodedNodeSet Src;
605 Src.insert(Pred);
606 CheckNewAllocatorContext C(NewAllocatorCheckers, Call, WasInlined, Eng);
607 llvm::TimeTraceScope TimeScope("CheckerManager::runCheckersForNewAllocator");
608 expandGraphWithCheckers(C, Dst, Src);
609}
610
611/// Run checkers for live symbols.
613 SymbolReaper &SymReaper) {
614 for (const auto &LiveSymbolsChecker : LiveSymbolsCheckers)
615 LiveSymbolsChecker(state, SymReaper);
616}
617
618namespace {
619
620 struct CheckDeadSymbolsContext {
621 using CheckersTy = std::vector<CheckerManager::CheckDeadSymbolsFunc>;
622
623 const CheckersTy &Checkers;
624 SymbolReaper &SR;
625 const Stmt *S;
626 ExprEngine &Eng;
627 ProgramPoint::Kind ProgarmPointKind;
628
629 CheckDeadSymbolsContext(const CheckersTy &checkers, SymbolReaper &sr,
630 const Stmt *s, ExprEngine &eng,
632 : Checkers(checkers), SR(sr), S(s), Eng(eng), ProgarmPointKind(K) {}
633
634 CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
635 CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
636
637 void runChecker(CheckerManager::CheckDeadSymbolsFunc checkFn,
638 NodeBuilder &Bldr, ExplodedNode *Pred) {
639 llvm::TimeTraceScope TimeScope(
640 checkerScopeName("DeadSymbols", checkFn.Checker));
641 const ProgramPoint &L = ProgramPoint::getProgramPoint(S, ProgarmPointKind,
642 Pred->getLocationContext(), checkFn.Checker);
643 CheckerContext C(Bldr, Eng, Pred, L);
644
645 // Note, do not pass the statement to the checkers without letting them
646 // differentiate if we ran remove dead bindings before or after the
647 // statement.
648 checkFn(SR, C);
649 }
650 };
651
652} // namespace
653
654/// Run checkers for dead symbols.
656 const ExplodedNodeSet &Src,
657 SymbolReaper &SymReaper,
658 const Stmt *S,
659 ExprEngine &Eng,
661 CheckDeadSymbolsContext C(DeadSymbolsCheckers, SymReaper, S, Eng, K);
662 llvm::TimeTraceScope TimeScope("CheckerManager::runCheckersForDeadSymbols");
663 expandGraphWithCheckers(C, Dst, Src);
664}
665
666/// Run checkers for region changes.
669 const InvalidatedSymbols *invalidated,
670 ArrayRef<const MemRegion *> ExplicitRegions,
672 const LocationContext *LCtx,
673 const CallEvent *Call) {
674 for (const auto &RegionChangesChecker : RegionChangesCheckers) {
675 // If any checker declares the state infeasible (or if it starts that way),
676 // bail out.
677 if (!state)
678 return nullptr;
679 state = RegionChangesChecker(state, invalidated, ExplicitRegions, Regions,
680 LCtx, Call);
681 }
682 return state;
683}
684
685/// Run checkers to process symbol escape event.
688 const InvalidatedSymbols &Escaped,
689 const CallEvent *Call,
692 assert((Call != nullptr ||
693 (Kind != PSK_DirectEscapeOnCall &&
694 Kind != PSK_IndirectEscapeOnCall)) &&
695 "Call must not be NULL when escaping on call");
696 for (const auto &PointerEscapeChecker : PointerEscapeCheckers) {
697 // If any checker declares the state infeasible (or if it starts that
698 // way), bail out.
699 if (!State)
700 return nullptr;
701 State = PointerEscapeChecker(State, Escaped, Call, Kind, ETraits);
702 }
703 return State;
704}
705
706/// Run checkers for handling assumptions on symbolic values.
709 SVal Cond, bool Assumption) {
710 for (const auto &EvalAssumeChecker : EvalAssumeCheckers) {
711 // If any checker declares the state infeasible (or if it starts that way),
712 // bail out.
713 if (!state)
714 return nullptr;
715 state = EvalAssumeChecker(state, Cond, Assumption);
716 }
717 return state;
718}
719
720/// Run checkers for evaluating a call.
721/// Only one checker will evaluate the call.
723 const ExplodedNodeSet &Src,
724 const CallEvent &Call,
725 ExprEngine &Eng,
726 const EvalCallOptions &CallOpts) {
727 for (auto *const Pred : Src) {
728 std::optional<StringRef> evaluatorChecker;
729
730 ExplodedNodeSet checkDst;
731 NodeBuilder B(Pred, checkDst, Eng.getBuilderContext());
732
733 ProgramStateRef State = Pred->getState();
734 CallEventRef<> UpdatedCall = Call.cloneWithState(State);
735
736 // Check if any of the EvalCall callbacks can evaluate the call.
737 for (const auto &EvalCallChecker : EvalCallCheckers) {
738 // TODO: Support the situation when the call doesn't correspond
739 // to any Expr.
741 UpdatedCall->getOriginExpr(), ProgramPoint::PostStmtKind,
742 Pred->getLocationContext(), EvalCallChecker.Checker);
743 bool evaluated = false;
744 { // CheckerContext generates transitions (populates checkDest) on
745 // destruction, so introduce the scope to make sure it gets properly
746 // populated.
747 CheckerContext C(B, Eng, Pred, L);
748 evaluated = EvalCallChecker(*UpdatedCall, C);
749 }
750#ifndef NDEBUG
751 if (evaluated && evaluatorChecker) {
752 const auto toString = [](const CallEvent &Call) -> std::string {
753 std::string Buf;
754 llvm::raw_string_ostream OS(Buf);
755 Call.dump(OS);
756 return Buf;
757 };
758 std::string AssertionMessage = llvm::formatv(
759 "The '{0}' call has been already evaluated by the {1} checker, "
760 "while the {2} checker also tried to evaluate the same call. At "
761 "most one checker supposed to evaluate a call.",
762 toString(Call), evaluatorChecker,
763 EvalCallChecker.Checker->getDebugTag());
764 llvm_unreachable(AssertionMessage.c_str());
765 }
766#endif
767 if (evaluated) {
768 evaluatorChecker = EvalCallChecker.Checker->getDebugTag();
769 Dst.insert(checkDst);
770#ifdef NDEBUG
771 break; // on release don't check that no other checker also evals.
772#endif
773 }
774 }
775
776 // If none of the checkers evaluated the call, ask ExprEngine to handle it.
777 if (!evaluatorChecker) {
778 NodeBuilder B(Pred, Dst, Eng.getBuilderContext());
779 Eng.defaultEvalCall(B, Pred, *UpdatedCall, CallOpts);
780 }
781 }
782}
783
784/// Run checkers for the entire Translation Unit.
786 const TranslationUnitDecl *TU,
787 AnalysisManager &mgr,
788 BugReporter &BR) {
789 for (const auto &EndOfTranslationUnitChecker : EndOfTranslationUnitCheckers)
790 EndOfTranslationUnitChecker(TU, mgr, BR);
791}
792
794 ProgramStateRef State,
795 const char *NL,
796 unsigned int Space,
797 bool IsDot) const {
798 Indent(Out, Space, IsDot) << "\"checker_messages\": ";
799
800 // Create a temporary stream to see whether we have any message.
801 SmallString<1024> TempBuf;
802 llvm::raw_svector_ostream TempOut(TempBuf);
803 unsigned int InnerSpace = Space + 2;
804
805 // Create the new-line in JSON with enough space.
806 SmallString<128> NewLine;
807 llvm::raw_svector_ostream NLOut(NewLine);
808 NLOut << "\", " << NL; // Inject the ending and a new line
809 Indent(NLOut, InnerSpace, IsDot) << "\""; // then begin the next message.
810
811 ++Space;
812 bool HasMessage = false;
813
814 // Store the last CheckerTag.
815 const void *LastCT = nullptr;
816 for (const auto &CT : CheckerTags) {
817 // See whether the current checker has a message.
818 CT.second->printState(TempOut, State, /*NL=*/NewLine.c_str(), /*Sep=*/"");
819
820 if (TempBuf.empty())
821 continue;
822
823 if (!HasMessage) {
824 Out << '[' << NL;
825 HasMessage = true;
826 }
827
828 LastCT = &CT;
829 TempBuf.clear();
830 }
831
832 for (const auto &CT : CheckerTags) {
833 // See whether the current checker has a message.
834 CT.second->printState(TempOut, State, /*NL=*/NewLine.c_str(), /*Sep=*/"");
835
836 if (TempBuf.empty())
837 continue;
838
839 Indent(Out, Space, IsDot) << "{ \"checker\": \"" << CT.second->getDebugTag()
840 << "\", \"messages\": [" << NL;
841 Indent(Out, InnerSpace, IsDot)
842 << '\"' << TempBuf.str().trim() << '\"' << NL;
843 Indent(Out, Space, IsDot) << "]}";
844
845 if (&CT != LastCT)
846 Out << ',';
847 Out << NL;
848
849 TempBuf.clear();
850 }
851
852 // It is the last element of the 'program_state' so do not add a comma.
853 if (HasMessage)
854 Indent(Out, --Space, IsDot) << "]";
855 else
856 Out << "null";
857
858 Out << NL;
859}
860
861//===----------------------------------------------------------------------===//
862// Internal registration functions for AST traversing.
863//===----------------------------------------------------------------------===//
864
866 HandlesDeclFunc isForDeclFn) {
867 DeclCheckerInfo info = { checkfn, isForDeclFn };
868 DeclCheckers.push_back(info);
869}
870
872 BodyCheckers.push_back(checkfn);
873}
874
875//===----------------------------------------------------------------------===//
876// Internal registration functions for path-sensitive checking.
877//===----------------------------------------------------------------------===//
878
880 HandlesStmtFunc isForStmtFn) {
881 StmtCheckerInfo info = { checkfn, isForStmtFn, /*IsPreVisit*/true };
882 StmtCheckers.push_back(info);
883}
884
886 HandlesStmtFunc isForStmtFn) {
887 StmtCheckerInfo info = { checkfn, isForStmtFn, /*IsPreVisit*/false };
888 StmtCheckers.push_back(info);
889}
890
892 PreObjCMessageCheckers.push_back(checkfn);
893}
894
896 ObjCMessageNilCheckers.push_back(checkfn);
897}
898
900 PostObjCMessageCheckers.push_back(checkfn);
901}
902
904 PreCallCheckers.push_back(checkfn);
905}
907 PostCallCheckers.push_back(checkfn);
908}
909
911 LocationCheckers.push_back(checkfn);
912}
913
915 BindCheckers.push_back(checkfn);
916}
917
919 BlockEntranceCheckers.push_back(checkfn);
920}
921
923 EndAnalysisCheckers.push_back(checkfn);
924}
925
927 BeginFunctionCheckers.push_back(checkfn);
928}
929
931 EndFunctionCheckers.push_back(checkfn);
932}
933
935 CheckBranchConditionFunc checkfn) {
936 BranchConditionCheckers.push_back(checkfn);
937}
938
940 NewAllocatorCheckers.push_back(checkfn);
941}
942
944 LiveSymbolsCheckers.push_back(checkfn);
945}
946
948 DeadSymbolsCheckers.push_back(checkfn);
949}
950
952 RegionChangesCheckers.push_back(checkfn);
953}
954
956 PointerEscapeCheckers.push_back(checkfn);
957}
958
960 CheckPointerEscapeFunc checkfn) {
961 PointerEscapeCheckers.push_back(checkfn);
962}
963
965 EvalAssumeCheckers.push_back(checkfn);
966}
967
969 EvalCallCheckers.push_back(checkfn);
970}
971
974 EndOfTranslationUnitCheckers.push_back(checkfn);
975}
976
977//===----------------------------------------------------------------------===//
978// Implementation details.
979//===----------------------------------------------------------------------===//
980
981const CheckerManager::CachedStmtCheckers &
982CheckerManager::getCachedStmtCheckersFor(const Stmt *S, bool isPreVisit) {
983 assert(S);
984
985 unsigned Key = (S->getStmtClass() << 1) | unsigned(isPreVisit);
986 auto [CCI, Inserted] = CachedStmtCheckersMap.try_emplace(Key);
987 CachedStmtCheckers &Checkers = CCI->second;
988 if (Inserted) {
989 // Find the checkers that should run for this Stmt and cache them.
990 for (const auto &Info : StmtCheckers)
991 if (Info.IsPreVisit == isPreVisit && Info.IsForStmtFn(S))
992 Checkers.push_back(Info.CheckFn);
993 }
994 return Checkers;
995}
static void expandGraphWithCheckers(CHECK_CTX checkCtx, ExplodedNodeSet &Dst, const ExplodedNodeSet &Src)
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
static std::string toString(const clang::SanitizerSet &Sanitizers)
Produce a string containing comma-separated names of sanitizers in Sanitizers set.
__device__ __2f16 float __ockl_bool s
Decl - This represents one declaration (or definition), e.g.
Definition DeclBase.h:86
virtual bool hasBody() const
Returns true if this Decl represents a declaration for a body of code, such as a function or method d...
Definition DeclBase.h:1093
Kind getKind() const
Definition DeclBase.h:442
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
It wraps the AnalysisDeclContext to represent both the call stack with the help of StackFrameContext ...
static ProgramPoint getProgramPoint(const Stmt *S, ProgramPoint::Kind K, const LocationContext *LC, const ProgramPointTag *tag)
ProgramPoint withTag(const ProgramPointTag *tag) const
Create a new ProgramPoint object that is the same as the original except for using the specified tag ...
ReturnStmt - This represents a return, optionally of an expression: return; return 4;.
Definition Stmt.h:3161
Stmt - This represents one statement.
Definition Stmt.h:86
StmtClass getStmtClass() const
Definition Stmt.h:1494
The top declaration context.
Definition Decl.h:105
BugReporter is a utility class for generating PathDiagnostics for analysis.
Represents the memory allocation call in a C++ new-expression.
Definition CallEvent.h:1130
Represents an abstract call to a function or method along a particular path.
Definition CallEvent.h:153
CallEventRef< T > cloneWithState(ProgramStateRef NewState) const
Returns a copy of this CallEvent, but using the given state.
Definition CallEvent.h:1491
ProgramPoint getProgramPoint(bool IsPreVisit=false, const ProgramPointTag *Tag=nullptr) const
Returns an appropriate ProgramPoint for this call.
CheckerBackend is an abstract base class that serves as the common ancestor of all the Checker<....
Definition Checker.h:532
StringRef getDebugTag() const override
Attached to nodes created by this checker class when the ExplodedGraph is dumped for debugging.
Definition Checker.cpp:20
A CheckerFrontend instance is what the user recognizes as "one checker": it has a public canonical na...
Definition Checker.h:514
CheckerNameRef getName() const
Definition Checker.h:524
void _registerForLiveSymbols(CheckLiveSymbolsFunc checkfn)
void _registerForEndOfTranslationUnit(CheckEndOfTranslationUnit checkfn)
CheckerFn< ProgramStateRef(ProgramStateRef, const InvalidatedSymbols *symbols, ArrayRef< const MemRegion * > ExplicitRegions, ArrayRef< const MemRegion * > Regions, const LocationContext *LCtx, const CallEvent *Call)> CheckRegionChangesFunc
void _registerForBeginFunction(CheckBeginFunctionFunc checkfn)
void _registerForNewAllocator(CheckNewAllocatorFunc checkfn)
CheckerFn< void(const Decl *, AnalysisManager &, BugReporter &)> CheckDeclFunc
void _registerForPreCall(CheckCallFunc checkfn)
CheckerFn< ProgramStateRef(ProgramStateRef, SVal cond, bool assumption)> EvalAssumeFunc
void _registerForObjCMessageNil(CheckObjCMessageFunc checkfn)
CheckerFn< ProgramStateRef(ProgramStateRef, const InvalidatedSymbols &Escaped, const CallEvent *Call, PointerEscapeKind Kind, RegionAndSymbolInvalidationTraits *ITraits)> CheckPointerEscapeFunc
bool(*)(const Decl *D) HandlesDeclFunc
void runCheckersForObjCMessage(ObjCMessageVisitKind visitKind, ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, const ObjCMethodCall &msg, ExprEngine &Eng, bool wasInlined=false)
Run checkers for visiting obj-c messages.
void runCheckersOnASTDecl(const Decl *D, AnalysisManager &mgr, BugReporter &BR)
Run checkers handling Decls.
void _registerForDecl(CheckDeclFunc checkfn, HandlesDeclFunc isForDeclFn)
CheckerFn< void(const ReturnStmt *, CheckerContext &)> CheckEndFunctionFunc
CheckerFn< void(const Stmt *, CheckerContext &)> CheckBranchConditionFunc
void _registerForPreObjCMessage(CheckObjCMessageFunc checkfn)
void runCheckersOnEndOfTranslationUnit(const TranslationUnitDecl *TU, AnalysisManager &mgr, BugReporter &BR)
Run checkers for the entire Translation Unit.
CheckerFn< bool(const CallEvent &, CheckerContext &)> EvalCallFunc
CheckerFn< void(CheckerContext &)> CheckBeginFunctionFunc
CheckerFn< void(ExplodedGraph &, BugReporter &, ExprEngine &)> CheckEndAnalysisFunc
void _registerForEvalAssume(EvalAssumeFunc checkfn)
void _registerForEndAnalysis(CheckEndAnalysisFunc checkfn)
void _registerForBody(CheckDeclFunc checkfn)
DiagnosticsEngine & getDiagnostics() const
void runCheckersForLocation(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, SVal location, bool isLoad, const Stmt *NodeEx, const Stmt *BoundEx, ExprEngine &Eng)
Run checkers for load/store of a location.
CheckerFn< void(const Stmt *, CheckerContext &)> CheckStmtFunc
CheckerFn< void(SVal location, SVal val, const Stmt *S, bool AtDeclInit, CheckerContext &)> CheckBindFunc
void runCheckersForBind(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, SVal location, SVal val, const Stmt *S, bool AtDeclInit, ExprEngine &Eng, const ProgramPoint &PP)
Run checkers for binding of a value to a location.
void reportInvalidCheckerOptionValue(const CheckerFrontend *Checker, StringRef OptionName, StringRef ExpectedValueDesc) const
Emits an error through a DiagnosticsEngine about an invalid user supplied checker option value.
void runCheckersForEndAnalysis(ExplodedGraph &G, BugReporter &BR, ExprEngine &Eng)
Run checkers for end of analysis.
CheckerFn< void(const CXXAllocatorCall &Call, CheckerContext &)> CheckNewAllocatorFunc
void runCheckersForPrintStateJson(raw_ostream &Out, ProgramStateRef State, const char *NL="\n", unsigned int Space=0, bool IsDot=false) const
Run checkers for debug-printing a ProgramState.
void _registerForDeadSymbols(CheckDeadSymbolsFunc checkfn)
void runCheckersForDeadSymbols(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, SymbolReaper &SymReaper, const Stmt *S, ExprEngine &Eng, ProgramPoint::Kind K)
Run checkers for dead symbols.
ProgramStateRef runCheckersForRegionChanges(ProgramStateRef state, const InvalidatedSymbols *invalidated, ArrayRef< const MemRegion * > ExplicitRegions, ArrayRef< const MemRegion * > Regions, const LocationContext *LCtx, const CallEvent *Call)
Run checkers for region changes.
void _registerForPostObjCMessage(CheckObjCMessageFunc checkfn)
void _registerForRegionChanges(CheckRegionChangesFunc checkfn)
void runCheckersForEndFunction(ExplodedNodeSet &Dst, ExplodedNode *Pred, ExprEngine &Eng, const ReturnStmt *RS)
Run checkers on end of function.
void _registerForBind(CheckBindFunc checkfn)
void runCheckersForLiveSymbols(ProgramStateRef state, SymbolReaper &SymReaper)
Run checkers for live symbols.
void _registerForPointerEscape(CheckPointerEscapeFunc checkfn)
CheckerFn< void(const TranslationUnitDecl *, AnalysisManager &, BugReporter &)> CheckEndOfTranslationUnit
void _registerForPreStmt(CheckStmtFunc checkfn, HandlesStmtFunc isForStmtFn)
void runCheckersForEvalCall(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, const CallEvent &CE, ExprEngine &Eng, const EvalCallOptions &CallOpts)
Run checkers for evaluating a call.
void _registerForPostStmt(CheckStmtFunc checkfn, HandlesStmtFunc isForStmtFn)
void runCheckersForBeginFunction(ExplodedNodeSet &Dst, const BlockEdge &L, ExplodedNode *Pred, ExprEngine &Eng)
Run checkers on beginning of function.
void runCheckersForNewAllocator(const CXXAllocatorCall &Call, ExplodedNodeSet &Dst, ExplodedNode *Pred, ExprEngine &Eng, bool wasInlined=false)
Run checkers between C++ operator new and constructor calls.
CheckerFn< void(const CallEvent &, CheckerContext &)> CheckCallFunc
void _registerForBranchCondition(CheckBranchConditionFunc checkfn)
CheckerFn< void(SymbolReaper &, CheckerContext &)> CheckDeadSymbolsFunc
CheckerFn< void(SVal location, bool isLoad, const Stmt *S, CheckerContext &)> CheckLocationFunc
void runCheckersForBlockEntrance(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, const BlockEntrance &Entrance, ExprEngine &Eng) const
Run checkers after taking a control flow edge.
void runCheckersForStmt(bool isPreVisit, ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, const Stmt *S, ExprEngine &Eng, bool wasInlined=false)
Run checkers for visiting Stmts.
void _registerForEvalCall(EvalCallFunc checkfn)
void _registerForEndFunction(CheckEndFunctionFunc checkfn)
void _registerForBlockEntrance(CheckBlockEntranceFunc checkfn)
void runCheckersForBranchCondition(const Stmt *condition, ExplodedNodeSet &Dst, ExplodedNode *Pred, ExprEngine &Eng)
Run checkers for branch condition.
CheckerFn< void(const ObjCMethodCall &, CheckerContext &)> CheckObjCMessageFunc
void _registerForLocation(CheckLocationFunc checkfn)
ProgramStateRef runCheckersForPointerEscape(ProgramStateRef State, const InvalidatedSymbols &Escaped, const CallEvent *Call, PointerEscapeKind Kind, RegionAndSymbolInvalidationTraits *ITraits)
Run checkers when pointers escape.
void _registerForConstPointerEscape(CheckPointerEscapeFunc checkfn)
CheckerFn< void(const BlockEntrance &, CheckerContext &)> CheckBlockEntranceFunc
CheckerFn< void(ProgramStateRef, SymbolReaper &)> CheckLiveSymbolsFunc
void runCheckersForCallEvent(bool isPreVisit, ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, const CallEvent &Call, ExprEngine &Eng, bool wasInlined=false)
Run checkers for visiting function calls (including methods, constructors, destructors etc.
bool(*)(const Stmt *D) HandlesStmtFunc
void _registerForPostCall(CheckCallFunc checkfn)
void runCheckersOnASTBody(const Decl *D, AnalysisManager &mgr, BugReporter &BR)
Run checkers handling Decls containing a Stmt body.
ProgramStateRef runCheckersForEvalAssume(ProgramStateRef state, SVal Cond, bool Assumption)
Run checkers for handling assumptions on symbolic values.
Simple checker classes that implement one frontend (i.e.
Definition Checker.h:553
ExplodedNodeSet is a set of ExplodedNode * elements with the invariant that its elements cannot be nu...
void insert(ExplodedNode *N)
const ProgramStateRef & getState() const
const LocationContext * getLocationContext() const
const NodeBuilderContext & getBuilderContext() const
Definition ExprEngine.h:266
void defaultEvalCall(NodeBuilder &B, ExplodedNode *Pred, const CallEvent &Call, const EvalCallOptions &CallOpts={})
Default implementation of call evaluation.
This is the simplest builder which generates nodes in the ExplodedGraph.
Definition CoreEngine.h:245
Represents any expression that calls an Objective-C method.
Definition CallEvent.h:1261
Information about invalidation for a particular region/symbol.
Definition MemRegion.h:1657
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
Definition SVals.h:56
void dumpToStream(raw_ostream &OS) const
Definition SVals.cpp:293
A class responsible for cleaning up unused symbols.
PointerEscapeKind
Describes the different reasons a pointer escapes during analysis.
@ PSK_DirectEscapeOnCall
The pointer has been passed to a function call directly.
@ PSK_IndirectEscapeOnCall
The pointer has been passed to a function indirectly.
llvm::DenseSet< SymbolRef > InvalidatedSymbols
Definition Store.h:51
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
const Fact * ProgramPoint
A ProgramPoint identifies a location in the CFG by pointing to a specific Fact.
Definition Facts.h:89
The JSON file list parser is used to communicate input to InstallAPI.
Expr * Cond
};
raw_ostream & Indent(raw_ostream &Out, const unsigned int Space, bool IsDot)
Definition JsonSupport.h:21
U cast(CodeGen::Address addr)
Definition Address.h:327
Hints for figuring out of a call should be inlined during evalCall().
Definition ExprEngine.h:95