clang 22.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 ExplodedNodeSet &Dst,
510 ExplodedNode *Pred,
511 ExprEngine &Eng,
512 const ReturnStmt *RS) {
513 // We define the builder outside of the loop because if at least one checker
514 // creates a successor for Pred, we do not need to generate an
515 // autotransition for it.
516 NodeBuilder Bldr(Pred, Dst, BC);
517 for (const auto &checkFn : EndFunctionCheckers) {
518 const ProgramPoint &L =
519 FunctionExitPoint(RS, Pred->getLocationContext(), checkFn.Checker);
520 CheckerContext C(Bldr, Eng, Pred, L);
521 llvm::TimeTraceScope TimeScope(checkerScopeName("End", checkFn.Checker));
522 checkFn(RS, C);
523 }
524}
525
526namespace {
527
528 struct CheckBranchConditionContext {
529 using CheckersTy = std::vector<CheckerManager::CheckBranchConditionFunc>;
530
531 const CheckersTy &Checkers;
532 const Stmt *Condition;
533 ExprEngine &Eng;
534
535 CheckBranchConditionContext(const CheckersTy &checkers,
536 const Stmt *Cond, ExprEngine &eng)
537 : Checkers(checkers), Condition(Cond), Eng(eng) {}
538
539 CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
540 CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
541
542 void runChecker(CheckerManager::CheckBranchConditionFunc checkFn,
543 NodeBuilder &Bldr, ExplodedNode *Pred) {
544 llvm::TimeTraceScope TimeScope(
545 checkerScopeName("BranchCond", checkFn.Checker));
546 ProgramPoint L = PostCondition(Condition, Pred->getLocationContext(),
547 checkFn.Checker);
548 CheckerContext C(Bldr, Eng, Pred, L);
549 checkFn(Condition, C);
550 }
551 };
552
553} // namespace
554
555/// Run checkers for branch condition.
557 ExplodedNodeSet &Dst,
558 ExplodedNode *Pred,
559 ExprEngine &Eng) {
560 ExplodedNodeSet Src;
561 Src.insert(Pred);
562 CheckBranchConditionContext C(BranchConditionCheckers, Condition, Eng);
563 llvm::TimeTraceScope TimeScope(
564 "CheckerManager::runCheckersForBranchCondition");
565 expandGraphWithCheckers(C, Dst, Src);
566}
567
568namespace {
569
570 struct CheckNewAllocatorContext {
571 using CheckersTy = std::vector<CheckerManager::CheckNewAllocatorFunc>;
572
573 const CheckersTy &Checkers;
574 const CXXAllocatorCall &Call;
575 bool WasInlined;
576 ExprEngine &Eng;
577
578 CheckNewAllocatorContext(const CheckersTy &Checkers,
579 const CXXAllocatorCall &Call, bool WasInlined,
580 ExprEngine &Eng)
581 : Checkers(Checkers), Call(Call), WasInlined(WasInlined), Eng(Eng) {}
582
583 CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
584 CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
585
586 void runChecker(CheckerManager::CheckNewAllocatorFunc checkFn,
587 NodeBuilder &Bldr, ExplodedNode *Pred) {
588 llvm::TimeTraceScope TimeScope(
589 checkerScopeName("Allocator", checkFn.Checker));
590 ProgramPoint L = PostAllocatorCall(
591 Call.getOriginExpr(), Pred->getLocationContext(), checkFn.Checker);
592 CheckerContext C(Bldr, Eng, Pred, L, WasInlined);
593 checkFn(cast<CXXAllocatorCall>(*Call.cloneWithState(Pred->getState())),
594 C);
595 }
596 };
597
598} // namespace
599
601 ExplodedNodeSet &Dst,
602 ExplodedNode *Pred,
603 ExprEngine &Eng,
604 bool WasInlined) {
605 ExplodedNodeSet Src;
606 Src.insert(Pred);
607 CheckNewAllocatorContext C(NewAllocatorCheckers, Call, WasInlined, Eng);
608 llvm::TimeTraceScope TimeScope("CheckerManager::runCheckersForNewAllocator");
609 expandGraphWithCheckers(C, Dst, Src);
610}
611
612/// Run checkers for live symbols.
614 SymbolReaper &SymReaper) {
615 for (const auto &LiveSymbolsChecker : LiveSymbolsCheckers)
616 LiveSymbolsChecker(state, SymReaper);
617}
618
619namespace {
620
621 struct CheckDeadSymbolsContext {
622 using CheckersTy = std::vector<CheckerManager::CheckDeadSymbolsFunc>;
623
624 const CheckersTy &Checkers;
625 SymbolReaper &SR;
626 const Stmt *S;
627 ExprEngine &Eng;
628 ProgramPoint::Kind ProgarmPointKind;
629
630 CheckDeadSymbolsContext(const CheckersTy &checkers, SymbolReaper &sr,
631 const Stmt *s, ExprEngine &eng,
633 : Checkers(checkers), SR(sr), S(s), Eng(eng), ProgarmPointKind(K) {}
634
635 CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
636 CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
637
638 void runChecker(CheckerManager::CheckDeadSymbolsFunc checkFn,
639 NodeBuilder &Bldr, ExplodedNode *Pred) {
640 llvm::TimeTraceScope TimeScope(
641 checkerScopeName("DeadSymbols", checkFn.Checker));
642 const ProgramPoint &L = ProgramPoint::getProgramPoint(S, ProgarmPointKind,
643 Pred->getLocationContext(), checkFn.Checker);
644 CheckerContext C(Bldr, Eng, Pred, L);
645
646 // Note, do not pass the statement to the checkers without letting them
647 // differentiate if we ran remove dead bindings before or after the
648 // statement.
649 checkFn(SR, C);
650 }
651 };
652
653} // namespace
654
655/// Run checkers for dead symbols.
657 const ExplodedNodeSet &Src,
658 SymbolReaper &SymReaper,
659 const Stmt *S,
660 ExprEngine &Eng,
662 CheckDeadSymbolsContext C(DeadSymbolsCheckers, SymReaper, S, Eng, K);
663 llvm::TimeTraceScope TimeScope("CheckerManager::runCheckersForDeadSymbols");
664 expandGraphWithCheckers(C, Dst, Src);
665}
666
667/// Run checkers for region changes.
670 const InvalidatedSymbols *invalidated,
671 ArrayRef<const MemRegion *> ExplicitRegions,
673 const LocationContext *LCtx,
674 const CallEvent *Call) {
675 for (const auto &RegionChangesChecker : RegionChangesCheckers) {
676 // If any checker declares the state infeasible (or if it starts that way),
677 // bail out.
678 if (!state)
679 return nullptr;
680 state = RegionChangesChecker(state, invalidated, ExplicitRegions, Regions,
681 LCtx, Call);
682 }
683 return state;
684}
685
686/// Run checkers to process symbol escape event.
689 const InvalidatedSymbols &Escaped,
690 const CallEvent *Call,
693 assert((Call != nullptr ||
694 (Kind != PSK_DirectEscapeOnCall &&
695 Kind != PSK_IndirectEscapeOnCall)) &&
696 "Call must not be NULL when escaping on call");
697 for (const auto &PointerEscapeChecker : PointerEscapeCheckers) {
698 // If any checker declares the state infeasible (or if it starts that
699 // way), bail out.
700 if (!State)
701 return nullptr;
702 State = PointerEscapeChecker(State, Escaped, Call, Kind, ETraits);
703 }
704 return State;
705}
706
707/// Run checkers for handling assumptions on symbolic values.
710 SVal Cond, bool Assumption) {
711 for (const auto &EvalAssumeChecker : EvalAssumeCheckers) {
712 // If any checker declares the state infeasible (or if it starts that way),
713 // bail out.
714 if (!state)
715 return nullptr;
716 state = EvalAssumeChecker(state, Cond, Assumption);
717 }
718 return state;
719}
720
721/// Run checkers for evaluating a call.
722/// Only one checker will evaluate the call.
724 const ExplodedNodeSet &Src,
725 const CallEvent &Call,
726 ExprEngine &Eng,
727 const EvalCallOptions &CallOpts) {
728 for (auto *const Pred : Src) {
729 std::optional<StringRef> evaluatorChecker;
730
731 ExplodedNodeSet checkDst;
732 NodeBuilder B(Pred, checkDst, Eng.getBuilderContext());
733
734 // Check if any of the EvalCall callbacks can evaluate the call.
735 for (const auto &EvalCallChecker : EvalCallCheckers) {
736 // TODO: Support the situation when the call doesn't correspond
737 // to any Expr.
739 Call.getOriginExpr(), ProgramPoint::PostStmtKind,
740 Pred->getLocationContext(), EvalCallChecker.Checker);
741 bool evaluated = false;
742 { // CheckerContext generates transitions(populates checkDest) on
743 // destruction, so introduce the scope to make sure it gets properly
744 // populated.
745 CheckerContext C(B, Eng, Pred, L);
746 evaluated = EvalCallChecker(Call, C);
747 }
748#ifndef NDEBUG
749 if (evaluated && evaluatorChecker) {
750 const auto toString = [](const CallEvent &Call) -> std::string {
751 std::string Buf;
752 llvm::raw_string_ostream OS(Buf);
753 Call.dump(OS);
754 return Buf;
755 };
756 std::string AssertionMessage = llvm::formatv(
757 "The '{0}' call has been already evaluated by the {1} checker, "
758 "while the {2} checker also tried to evaluate the same call. At "
759 "most one checker supposed to evaluate a call.",
760 toString(Call), evaluatorChecker,
761 EvalCallChecker.Checker->getDebugTag());
762 llvm_unreachable(AssertionMessage.c_str());
763 }
764#endif
765 if (evaluated) {
766 evaluatorChecker = EvalCallChecker.Checker->getDebugTag();
767 Dst.insert(checkDst);
768#ifdef NDEBUG
769 break; // on release don't check that no other checker also evals.
770#endif
771 }
772 }
773
774 // If none of the checkers evaluated the call, ask ExprEngine to handle it.
775 if (!evaluatorChecker) {
776 NodeBuilder B(Pred, Dst, Eng.getBuilderContext());
777 Eng.defaultEvalCall(B, Pred, Call, CallOpts);
778 }
779 }
780}
781
782/// Run checkers for the entire Translation Unit.
784 const TranslationUnitDecl *TU,
785 AnalysisManager &mgr,
786 BugReporter &BR) {
787 for (const auto &EndOfTranslationUnitChecker : EndOfTranslationUnitCheckers)
788 EndOfTranslationUnitChecker(TU, mgr, BR);
789}
790
792 ProgramStateRef State,
793 const char *NL,
794 unsigned int Space,
795 bool IsDot) const {
796 Indent(Out, Space, IsDot) << "\"checker_messages\": ";
797
798 // Create a temporary stream to see whether we have any message.
799 SmallString<1024> TempBuf;
800 llvm::raw_svector_ostream TempOut(TempBuf);
801 unsigned int InnerSpace = Space + 2;
802
803 // Create the new-line in JSON with enough space.
804 SmallString<128> NewLine;
805 llvm::raw_svector_ostream NLOut(NewLine);
806 NLOut << "\", " << NL; // Inject the ending and a new line
807 Indent(NLOut, InnerSpace, IsDot) << "\""; // then begin the next message.
808
809 ++Space;
810 bool HasMessage = false;
811
812 // Store the last CheckerTag.
813 const void *LastCT = nullptr;
814 for (const auto &CT : CheckerTags) {
815 // See whether the current checker has a message.
816 CT.second->printState(TempOut, State, /*NL=*/NewLine.c_str(), /*Sep=*/"");
817
818 if (TempBuf.empty())
819 continue;
820
821 if (!HasMessage) {
822 Out << '[' << NL;
823 HasMessage = true;
824 }
825
826 LastCT = &CT;
827 TempBuf.clear();
828 }
829
830 for (const auto &CT : CheckerTags) {
831 // See whether the current checker has a message.
832 CT.second->printState(TempOut, State, /*NL=*/NewLine.c_str(), /*Sep=*/"");
833
834 if (TempBuf.empty())
835 continue;
836
837 Indent(Out, Space, IsDot) << "{ \"checker\": \"" << CT.second->getDebugTag()
838 << "\", \"messages\": [" << NL;
839 Indent(Out, InnerSpace, IsDot)
840 << '\"' << TempBuf.str().trim() << '\"' << NL;
841 Indent(Out, Space, IsDot) << "]}";
842
843 if (&CT != LastCT)
844 Out << ',';
845 Out << NL;
846
847 TempBuf.clear();
848 }
849
850 // It is the last element of the 'program_state' so do not add a comma.
851 if (HasMessage)
852 Indent(Out, --Space, IsDot) << "]";
853 else
854 Out << "null";
855
856 Out << NL;
857}
858
859//===----------------------------------------------------------------------===//
860// Internal registration functions for AST traversing.
861//===----------------------------------------------------------------------===//
862
864 HandlesDeclFunc isForDeclFn) {
865 DeclCheckerInfo info = { checkfn, isForDeclFn };
866 DeclCheckers.push_back(info);
867}
868
870 BodyCheckers.push_back(checkfn);
871}
872
873//===----------------------------------------------------------------------===//
874// Internal registration functions for path-sensitive checking.
875//===----------------------------------------------------------------------===//
876
878 HandlesStmtFunc isForStmtFn) {
879 StmtCheckerInfo info = { checkfn, isForStmtFn, /*IsPreVisit*/true };
880 StmtCheckers.push_back(info);
881}
882
884 HandlesStmtFunc isForStmtFn) {
885 StmtCheckerInfo info = { checkfn, isForStmtFn, /*IsPreVisit*/false };
886 StmtCheckers.push_back(info);
887}
888
890 PreObjCMessageCheckers.push_back(checkfn);
891}
892
894 ObjCMessageNilCheckers.push_back(checkfn);
895}
896
898 PostObjCMessageCheckers.push_back(checkfn);
899}
900
902 PreCallCheckers.push_back(checkfn);
903}
905 PostCallCheckers.push_back(checkfn);
906}
907
909 LocationCheckers.push_back(checkfn);
910}
911
913 BindCheckers.push_back(checkfn);
914}
915
917 BlockEntranceCheckers.push_back(checkfn);
918}
919
921 EndAnalysisCheckers.push_back(checkfn);
922}
923
925 BeginFunctionCheckers.push_back(checkfn);
926}
927
929 EndFunctionCheckers.push_back(checkfn);
930}
931
933 CheckBranchConditionFunc checkfn) {
934 BranchConditionCheckers.push_back(checkfn);
935}
936
938 NewAllocatorCheckers.push_back(checkfn);
939}
940
942 LiveSymbolsCheckers.push_back(checkfn);
943}
944
946 DeadSymbolsCheckers.push_back(checkfn);
947}
948
950 RegionChangesCheckers.push_back(checkfn);
951}
952
954 PointerEscapeCheckers.push_back(checkfn);
955}
956
958 CheckPointerEscapeFunc checkfn) {
959 PointerEscapeCheckers.push_back(checkfn);
960}
961
963 EvalAssumeCheckers.push_back(checkfn);
964}
965
967 EvalCallCheckers.push_back(checkfn);
968}
969
972 EndOfTranslationUnitCheckers.push_back(checkfn);
973}
974
975//===----------------------------------------------------------------------===//
976// Implementation details.
977//===----------------------------------------------------------------------===//
978
979const CheckerManager::CachedStmtCheckers &
980CheckerManager::getCachedStmtCheckersFor(const Stmt *S, bool isPreVisit) {
981 assert(S);
982
983 unsigned Key = (S->getStmtClass() << 1) | unsigned(isPreVisit);
984 auto [CCI, Inserted] = CachedStmtCheckersMap.try_emplace(Key);
985 CachedStmtCheckers &Checkers = CCI->second;
986 if (Inserted) {
987 // Find the checkers that should run for this Stmt and cache them.
988 for (const auto &Info : StmtCheckers)
989 if (Info.IsPreVisit == isPreVisit && Info.IsForStmtFn(S))
990 Checkers.push_back(Info.CheckFn);
991 }
992 return Checkers;
993}
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:3160
Stmt - This represents one statement.
Definition Stmt.h:85
StmtClass getStmtClass() const
Definition Stmt.h:1472
The top declaration context.
Definition Decl.h:104
BugReporter is a utility class for generating PathDiagnostics for analysis.
Represents the memory allocation call in a C++ new-expression.
Definition CallEvent.h:1119
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:1480
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
void runCheckersForEndFunction(NodeBuilderContext &BC, ExplodedNodeSet &Dst, ExplodedNode *Pred, ExprEngine &Eng, const ReturnStmt *RS)
Run checkers on end of function.
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 _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 obj-c messages.
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
void insert(const ExplodedNodeSet &S)
const ProgramStateRef & getState() const
const LocationContext * getLocationContext() const
void defaultEvalCall(NodeBuilder &B, ExplodedNode *Pred, const CallEvent &Call, const EvalCallOptions &CallOpts={})
Default implementation of call evaluation.
const NodeBuilderContext & getBuilderContext()
Definition ExprEngine.h:220
This is the simplest builder which generates nodes in the ExplodedGraph.
Definition CoreEngine.h:240
Represents any expression that calls an Objective-C method.
Definition CallEvent.h:1250
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.
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:97