clang: lib/StaticAnalyzer/Core/BugReporter.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
13
47#include "llvm/ADT/ArrayRef.h"
48#include "llvm/ADT/DenseMap.h"
49#include "llvm/ADT/DenseSet.h"
50#include "llvm/ADT/FoldingSet.h"
51#include "llvm/ADT/STLExtras.h"
52#include "llvm/ADT/SmallPtrSet.h"
53#include "llvm/ADT/StringExtras.h"
54#include "llvm/ADT/StringRef.h"
55#include "llvm/Support/Compiler.h"
56#include "llvm/Support/ErrorHandling.h"
57#include "llvm/Support/TimeProfiler.h"
58#include "llvm/Support/raw_ostream.h"
59#include
60#include
61#include
62#include
63#include
64#include
65#include
66#include
67#include
68#include
69#include
70
71using namespace clang;
72using namespace ento;
73using namespace llvm;
74
75#define DEBUG_TYPE "BugReporter"
76
78 "The maximum number of bug reports in the same equivalence class");
80 "The maximum number of bug reports in the same equivalence class "
81 "where at least one report is valid (not suppressed)");
82
83STAT_COUNTER(NumTimesReportPassesZ3, "Number of reports passed Z3");
84STAT_COUNTER(NumTimesReportRefuted, "Number of reports refuted by Z3");
86 "Number of times a report equivalence class was aborted by the Z3 "
87 "oracle heuristic");
89 "Number of times all reports of an equivalence class was refuted");
90
92
93void BugReporterContext::anchor() {}
94
95
96
97
98
99namespace {
100
101
102using CallWithEntry =
103 std::pair<PathDiagnosticCallPiece *, const ExplodedNode *>;
104using CallWithEntryStack = SmallVector<CallWithEntry, 6>;
105
106
107using VisitorsDiagnosticsTy =
108 llvm::DenseMap<const ExplodedNode *, std::vector>;
109
110
111
112using LocationContextMap =
113 llvm::DenseMap<const PathPieces *, const LocationContext *>;
114
115
116
117
118class PathDiagnosticConstruct {
119
120 const PathDiagnosticConsumer *Consumer;
121
122
123 const ExplodedNode *CurrentNode;
124
125
126
127 LocationContextMap LCM;
128 const SourceManager &SM;
129
130public:
131
132
133
134 CallWithEntryStack CallStack;
135
136
137
138 std::unique_ptr PD;
139
140public:
141 PathDiagnosticConstruct(const PathDiagnosticConsumer *PDC,
142 const ExplodedNode *ErrorNode,
143 const PathSensitiveBugReport *R,
144 const Decl *AnalysisEntryPoint);
145
146
147
148 const LocationContext *getCurrLocationContext() const {
149 assert(CurrentNode && "Already reached the root!");
151 }
152
153
154
155
156 const LocationContext *getLocationContextForActivePath() const {
157 return LCM.find(&PD->getActivePath())->getSecond();
158 }
159
160 const ExplodedNode *getCurrentNode() const { return CurrentNode; }
161
162
163
164 bool ascendToPrevNode() {
166 return static_cast<bool>(CurrentNode);
167 }
168
169 const ParentMap &getParentMap() const {
170 return getCurrLocationContext()->getParentMap();
171 }
172
173 const SourceManager &getSourceManager() const { return SM; }
174
175 const Stmt *getParent(const Stmt *S) const {
176 return getParentMap().getParent(S);
177 }
178
179 void updateLocCtxMap(const PathPieces *Path, const LocationContext *LC) {
180 assert(Path && LC);
181 LCM[Path] = LC;
182 }
183
184 const LocationContext *getLocationContextFor(const PathPieces *Path) const {
185 assert(LCM.count(Path) &&
186 "Failed to find the context associated with these pieces!");
187 return LCM.find(Path)->getSecond();
188 }
189
190 bool isInLocCtxMap(const PathPieces *Path) const { return LCM.count(Path); }
191
192 PathPieces &getActivePath() { return PD->getActivePath(); }
193 PathPieces &getMutablePieces() { return PD->getMutablePieces(); }
194
195 bool shouldAddPathEdges() const { return Consumer->shouldAddPathEdges(); }
196 bool shouldAddControlNotes() const {
198 }
199 bool shouldGenerateDiagnostics() const {
201 }
202 bool supportsLogicalOpControlFlow() const {
204 }
205};
206
207
208
209
210
212
213 std::unique_ptr BugPath;
214
215
216
217
218 const PathSensitiveBugReport *R;
219
220
221 const ExplodedNode *const ErrorNode;
222
223
224 std::unique_ptr VisitorsDiagnostics;
225
226public:
227
228
229
230 static std::optional
231 findValidReport(ArrayRef<PathSensitiveBugReport *> &bugReports,
232 PathSensitiveBugReporter &Reporter);
233
234 PathDiagnosticBuilder(
235 BugReporterContext BRC, std::unique_ptr BugPath,
236 PathSensitiveBugReport *r, const ExplodedNode *ErrorNode,
237 std::unique_ptr VisitorsDiagnostics);
238
239
240
241
242
243
244
245
246
247
248
249 std::unique_ptr
250 generate(const PathDiagnosticConsumer *PDC) const;
251
252private:
254 const CallWithEntryStack &CallStack) const;
255 void generatePathDiagnosticsForNode(PathDiagnosticConstruct &C,
256 PathDiagnosticLocation &PrevLoc) const;
257
258 void generateMinimalDiagForBlockEdge(PathDiagnosticConstruct &C,
259 BlockEdge BE) const;
260
262 generateDiagForGotoOP(const PathDiagnosticConstruct &C, const Stmt *S,
263 PathDiagnosticLocation &Start) const;
264
266 generateDiagForSwitchOP(const PathDiagnosticConstruct &C, const CFGBlock *Dst,
267 PathDiagnosticLocation &Start) const;
268
270 generateDiagForBinaryOP(const PathDiagnosticConstruct &C, const Stmt *T,
271 const CFGBlock *Src, const CFGBlock *DstC) const;
272
273 PathDiagnosticLocation
274 ExecutionContinues(const PathDiagnosticConstruct &C) const;
275
276 PathDiagnosticLocation
277 ExecutionContinues(llvm::raw_string_ostream &os,
278 const PathDiagnosticConstruct &C) const;
279
280 const PathSensitiveBugReport *getBugReport() const { return R; }
281};
282
284 if (!llvm::timeTraceProfilerEnabled())
285 return "";
286 const auto &BugReports = EQ.getReports();
287 if (BugReports.empty())
288 return "Empty Equivalence Class";
289 const BugReport *R = BugReports.front().get();
291 return ("Flushing EQC " + BT.getDescription()).str();
292}
293
295 const SourceManager &SM) {
296
297 assert(llvm::timeTraceProfilerEnabled());
298
299 const auto &BugReports = EQ.getReports();
300 if (BugReports.empty())
301 return {};
302 const BugReport *R = BugReports.front().get();
305 std::string File = SM.getFilename(Loc).str();
306 return {BT.getCheckerName().str(), std::move(File),
307 static_cast<int>(Loc.getLineNumber())};
308}
309
310}
311
312
313
314
315
317
319 if (!N)
321
324
325
327 const auto *CE = dyn_cast_or_null(CallSite);
328 if (!CE)
329 return {};
330
331
332 for (auto [Idx, ArgExpr] : llvm::enumerate(CE->arguments())) {
334
335
337 if (AS == Sym) {
339 }
340
341
343
344 if (ArgExpr->getType()->isVoidPointerType())
345 continue;
346 SVal PSV = N->getState()->getSVal(Reg->getRegion());
348 if (AS == Sym) {
350 }
351 }
352 }
353
354
357 if (RetSym == Sym) {
359 }
360
362}
363
365 unsigned ArgIndex) {
366
367 ++ArgIndex;
368
369 return (llvm::Twine(Msg) + " via " + std::to_string(ArgIndex) +
370 llvm::getOrdinalSuffix(ArgIndex) + " parameter").str();
371}
372
373
374
375
376
380
381
382
383
386
388 return nullptr;
389
390 if (X->getTag() == tagPreferred && Y->getTag() == tagLesser)
392
393 if (Y->getTag() == tagPreferred && X->getTag() == tagLesser)
395
396 return nullptr;
397}
398
399
400
401
402
403
405 unsigned N = path.size();
406 if (N < 2)
407 return;
408
409
410
411
412 for (unsigned i = 0; i < N; ++i) {
413 auto piece = std::move(path.front());
414 path.pop_front();
415
416 switch (piece->getKind()) {
419 break;
422 break;
424 if (i == N-1)
425 break;
426
427 if (auto *nextEvent =
428 dyn_cast(path.front().get())) {
430
431
432
433 if (auto *pieceToKeep =
435 piece = std::move(pieceToKeep == event ? piece : path.front());
436 path.pop_front();
437 ++i;
438 }
439 }
440 break;
441 }
445 break;
446 }
447 path.push_back(std::move(piece));
448 }
449}
450
451
452
453
457 bool IsInteresting = false) {
458 bool containsSomethingInteresting = IsInteresting;
459 const unsigned N = pieces.size();
460
461 for (unsigned i = 0 ; i < N ; ++i) {
462
463
464 auto piece = std::move(pieces.front());
465 pieces.pop_front();
466
467 switch (piece->getKind()) {
470
472 C, call.path, R,
473 R->isInteresting(C.getLocationContextFor(&call.path))))
474 continue;
475
476 containsSomethingInteresting = true;
477 break;
478 }
482 continue;
483 containsSomethingInteresting = true;
484 break;
485 }
488
489
490
491 containsSomethingInteresting |= !event.isPrunable();
492 break;
493 }
497 break;
498 }
499
500 pieces.push_back(std::move(piece));
501 }
502
503 return containsSomethingInteresting;
504}
505
506
508 for (unsigned int i = 0; i < Path.size(); ++i) {
509 auto Piece = std::move(Path.front());
510 Path.pop_front();
512 Path.push_back(std::move(Piece));
513 }
514}
515
516
517
522
523
524
525static void
528 for (const auto &I : Pieces) {
529 auto *Call = dyn_cast(I.get());
530
532 continue;
533
534 if (LastCallLocation) {
536 if (CallerIsImplicit || ->callEnter.asLocation().isValid())
537 Call->callEnter = *LastCallLocation;
538 if (CallerIsImplicit || ->callReturn.asLocation().isValid())
539 Call->callReturn = *LastCallLocation;
540 }
541
542
543
545 if (Call->callEnterWithin.asLocation().isValid() &&
547 ThisCallLocation = &Call->callEnterWithin;
548 else
549 ThisCallLocation = &Call->callEnter;
550
551 assert(ThisCallLocation && "Outermost call has an invalid location");
553 }
554}
555
556
557
558
560 for (PathPieces::iterator I = Pieces.begin(), E = Pieces.end(); I != E;) {
561 if (auto *C = dyn_cast(I->get()))
563
564 if (auto *M = dyn_cast(I->get()))
566
567 if (auto *CF = dyn_cast(I->get())) {
568 const Stmt *Start = CF->getStartLocation().asStmt();
569 const Stmt *End = CF->getEndLocation().asStmt();
570 if (isa_and_nonnull(Start)) {
571 I = Pieces.erase(I);
572 continue;
573 } else if (isa_and_nonnull(End)) {
574 PathPieces::iterator Next = std::next(I);
575 if (Next != E) {
576 if (auto *NextCF =
577 dyn_cast(Next->get())) {
578 NextCF->setStartLocation(CF->getStartLocation());
579 }
580 }
581 I = Pieces.erase(I);
582 continue;
583 }
584 }
585
586 I++;
587 }
588}
589
590
591
592
594 for (PathPieces::iterator I = Pieces.begin(), E = Pieces.end(); I != E;) {
595 if (auto *C = dyn_cast(I->get()))
597
598 if (auto *M = dyn_cast(I->get()))
600
601 if (!(*I)->getLocation().isValid() ||
602 !(*I)->getLocation().asLocation().isValid()) {
603 I = Pieces.erase(I);
604 continue;
605 }
606 I++;
607 }
608}
609
611 const PathDiagnosticConstruct &C) const {
612 if (const Stmt *S = C.getCurrentNode()->getNextStmtForDiagnostics())
614 C.getCurrLocationContext());
615
617 getSourceManager());
618}
619
621 llvm::raw_string_ostream &os, const PathDiagnosticConstruct &C) const {
622
623 if (os.str().empty())
624 os << ' ';
625
627
628 if (Loc.asStmt())
629 os << "Execution continues on line "
630 << getSourceManager().getExpansionLineNumber(Loc.asLocation())
631 << '.';
632 else {
633 os << "Execution jumps to the end of the ";
634 const Decl *D = C.getCurrLocationContext()->getDecl();
636 os << "method";
638 os << "function";
639 else {
641 os << "anonymous block";
642 }
643 os << '.';
644 }
645
646 return Loc;
647}
648
652
654 if (!Parent)
655 return nullptr;
656
658 case Stmt::ForStmtClass:
659 case Stmt::DoStmtClass:
660 case Stmt::WhileStmtClass:
661 case Stmt::ObjCForCollectionStmtClass:
662 case Stmt::CXXForRangeStmtClass:
663 return Parent;
664 default:
665 break;
666 }
667
668 return nullptr;
669}
670
673 bool allowNestedContexts = false) {
674 if (!S)
675 return {};
676
678
680 switch (Parent->getStmtClass()) {
681 case Stmt::BinaryOperatorClass: {
683 if (B->isLogicalOp())
685 break;
686 }
687 case Stmt::CompoundStmtClass:
688 case Stmt::StmtExprClass:
690 case Stmt::ChooseExprClass:
691
692
693 if (allowNestedContexts || cast(Parent)->getCond() == S)
695 else
697 case Stmt::BinaryConditionalOperatorClass:
698 case Stmt::ConditionalOperatorClass:
699
700
701 if (allowNestedContexts ||
704 else
706 case Stmt::CXXForRangeStmtClass:
709 break;
710 case Stmt::DoStmtClass:
712 case Stmt::ForStmtClass:
715 break;
716 case Stmt::IfStmtClass:
719 break;
720 case Stmt::ObjCForCollectionStmtClass:
723 break;
724 case Stmt::WhileStmtClass:
727 break;
728 default:
729 break;
730 }
731
732 S = Parent;
733 }
734
735 assert(S && "Cannot have null Stmt for PathDiagnosticLocation");
736
738}
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754void PathDiagnosticBuilder::updateStackPiecesWithMessage(
756 if (R->hasCallStackHint(P))
757 for (const auto &I : CallStack) {
760 std::string stackMsg = R->getCallStackMessage(P, N);
761
762
763
764
767 }
768}
769
771 const SourceManager& SM);
772
774 const PathDiagnosticConstruct &C, const CFGBlock *Dst,
776
777 const SourceManager &SM = getSourceManager();
778
779 std::string sbuf;
780 llvm::raw_string_ostream os(sbuf);
782
783 if (const Stmt *S = Dst->getLabel()) {
785
787 default:
788 os << "No cases match in the switch statement. "
789 "Control jumps to line "
791 break;
792 case Stmt::DefaultStmtClass:
793 os << "Control jumps to the 'default' case at line "
795 break;
796
797 case Stmt::CaseStmtClass: {
798 os << "Control jumps to 'case ";
800 const Expr *LHS = Case->getLHS()->IgnoreParenImpCasts();
801
802
803 bool GetRawInt = true;
804
805 if (const auto *DR = dyn_cast(LHS)) {
806
807
808 const auto *D = dyn_cast(DR->getDecl());
809
810 if (D) {
811 GetRawInt = false;
812 os << *D;
813 }
814 }
815
816 if (GetRawInt)
818
820 break;
821 }
822 }
823 } else {
824 os << "'Default' branch taken. ";
825 End = ExecutionContinues(os, C);
826 }
827 return std::make_shared(Start, End, sbuf);
828}
829
831 const PathDiagnosticConstruct &C, const Stmt *S,
833 std::string sbuf;
834 llvm::raw_string_ostream os(sbuf);
838 return std::make_shared(Start, End, sbuf);
839}
840
842 const PathDiagnosticConstruct &C, const Stmt *T, const CFGBlock *Src,
843 const CFGBlock *Dst) const {
844
845 const SourceManager &SM = getSourceManager();
846
848 std::string sbuf;
849 llvm::raw_string_ostream os(sbuf);
850 os << "Left side of '";
852
853 if (B->getOpcode() == BO_LAnd) {
854 os << "&&"
855 << "' is ";
856
857 if (*(Src->succ_begin() + 1) == Dst) {
858 os << "false";
860 Start =
862 } else {
863 os << "true";
864 Start =
866 End = ExecutionContinues(C);
867 }
868 } else {
869 assert(B->getOpcode() == BO_LOr);
870 os << "||"
871 << "' is ";
872
873 if (*(Src->succ_begin() + 1) == Dst) {
874 os << "false";
875 Start =
877 End = ExecutionContinues(C);
878 } else {
879 os << "true";
881 Start =
883 }
884 }
885 return std::make_shared(Start, End, sbuf);
886}
887
888void PathDiagnosticBuilder::generateMinimalDiagForBlockEdge(
889 PathDiagnosticConstruct &C, BlockEdge BE) const {
890 const SourceManager &SM = getSourceManager();
891 const LocationContext *LC = C.getCurrLocationContext();
892 const CFGBlock *Src = BE.getSrc();
893 const CFGBlock *Dst = BE.getDst();
895 if ()
896 return;
897
899 switch (T->getStmtClass()) {
900 default:
901 break;
902
903 case Stmt::GotoStmtClass:
904 case Stmt::IndirectGotoStmtClass: {
905 if (const Stmt *S = C.getCurrentNode()->getNextStmtForDiagnostics())
906 C.getActivePath().push_front(generateDiagForGotoOP(C, S, Start));
907 break;
908 }
909
910 case Stmt::SwitchStmtClass: {
911 C.getActivePath().push_front(generateDiagForSwitchOP(C, Dst, Start));
912 break;
913 }
914
915 case Stmt::BreakStmtClass:
916 case Stmt::ContinueStmtClass: {
917 std::string sbuf;
918 llvm::raw_string_ostream os(sbuf);
920 C.getActivePath().push_front(
921 std::make_shared(Start, End, sbuf));
922 break;
923 }
924
925
926 case Stmt::BinaryConditionalOperatorClass:
927 case Stmt::ConditionalOperatorClass: {
928 std::string sbuf;
929 llvm::raw_string_ostream os(sbuf);
930 os << "'?' condition is ";
931
933 os << "false";
934 else
935 os << "true";
936
938
939 if (const Stmt *S = End.asStmt())
941
942 C.getActivePath().push_front(
943 std::make_shared(Start, End, sbuf));
944 break;
945 }
946
947
948 case Stmt::BinaryOperatorClass: {
949 if (.supportsLogicalOpControlFlow())
950 break;
951
952 C.getActivePath().push_front(generateDiagForBinaryOP(C, T, Src, Dst));
953 break;
954 }
955
956 case Stmt::DoStmtClass:
958 std::string sbuf;
959 llvm::raw_string_ostream os(sbuf);
960
961 os << "Loop condition is true. ";
963
964 if (const Stmt *S = End.asStmt())
966
967 C.getActivePath().push_front(
968 std::make_shared(Start, End, sbuf));
969 } else {
971
972 if (const Stmt *S = End.asStmt())
974
975 C.getActivePath().push_front(
976 std::make_shared(
977 Start, End, "Loop condition is false. Exiting loop"));
978 }
979 break;
980
981 case Stmt::WhileStmtClass:
982 case Stmt::ForStmtClass:
983 if (*(Src->succ_begin() + 1) == Dst) {
984 std::string sbuf;
985 llvm::raw_string_ostream os(sbuf);
986
987 os << "Loop condition is false. ";
989 if (const Stmt *S = End.asStmt())
991
992 C.getActivePath().push_front(
993 std::make_shared(Start, End, sbuf));
994 } else {
996 if (const Stmt *S = End.asStmt())
998
999 C.getActivePath().push_front(
1000 std::make_shared(
1001 Start, End, "Loop condition is true. Entering loop body"));
1002 }
1003
1004 break;
1005
1006 case Stmt::IfStmtClass: {
1008
1009 if (const Stmt *S = End.asStmt())
1011
1012 if (*(Src->succ_begin() + 1) == Dst)
1013 C.getActivePath().push_front(
1014 std::make_shared(
1015 Start, End, "Taking false branch"));
1016 else
1017 C.getActivePath().push_front(
1018 std::make_shared(
1019 Start, End, "Taking true branch"));
1020
1021 break;
1022 }
1023 }
1024}
1025
1026
1027
1028
1029
1032 case Stmt::ForStmtClass:
1033 case Stmt::WhileStmtClass:
1034 case Stmt::ObjCForCollectionStmtClass:
1035 case Stmt::CXXForRangeStmtClass:
1036 return true;
1037 default:
1038
1039 return false;
1040 }
1041}
1042
1048
1050 const Stmt *SubS) {
1051 while (SubS) {
1052 if (SubS == S)
1053 return true;
1055 }
1056 return false;
1057}
1058
1061 while (N) {
1063 if (SP) {
1064 const Stmt *S = SP->getStmt();
1066 return S;
1067 }
1069 }
1070 return nullptr;
1071}
1072
1074 const Stmt *LoopBody = nullptr;
1076 case Stmt::CXXForRangeStmtClass: {
1079 return true;
1081 return true;
1082 LoopBody = FR->getBody();
1083 break;
1084 }
1085 case Stmt::ForStmtClass: {
1088 return true;
1089 LoopBody = FS->getBody();
1090 break;
1091 }
1092 case Stmt::ObjCForCollectionStmtClass: {
1094 LoopBody = FC->getBody();
1095 break;
1096 }
1097 case Stmt::WhileStmtClass:
1099 break;
1100 default:
1101 return false;
1102 }
1104}
1105
1106
1111 return;
1112
1115 return;
1116
1118 PrevLoc = NewLoc;
1119 return;
1120 }
1121
1122
1123
1125 return;
1126
1127 path.push_front(
1128 std::make_shared(NewLoc, PrevLoc));
1129 PrevLoc = NewLoc;
1130}
1131
1132
1133
1136 if (const auto *FS = dyn_cast_or_null(S))
1137 return FS->getElement();
1138 return S;
1139}
1140
1142constexpr llvm::StringLiteral StrLoopBodyZero = "Loop body executed 0 times";
1144 "Loop body skipped when range is empty";
1146 "Loop body skipped when collection is empty";
1147
1148static std::unique_ptr
1150
1151void PathDiagnosticBuilder::generatePathDiagnosticsForNode(
1153 ProgramPoint P = C.getCurrentNode()->getLocation();
1155
1156
1157
1158
1159
1161
1162 if (C.shouldAddPathEdges()) {
1163
1166
1167
1168
1169
1170
1171
1175 }
1176
1177
1178 bool VisitedEntireCall = C.PD->isWithinCall();
1179 C.PD->popActivePath();
1180
1182 if (VisitedEntireCall) {
1184 } else {
1185
1186
1187 const Decl *Caller = CE->getLocationContext()->getDecl();
1189 assert(C.getActivePath().size() == 1 &&
1190 C.getActivePath().front().get() == Call);
1191
1192
1193
1194 assert(C.isInLocCtxMap(&C.getActivePath()) &&
1195 "When we ascend to a previously unvisited call, the active path's "
1196 "address shouldn't change, but rather should be compacted into "
1197 "a single CallEvent!");
1198 C.updateLocCtxMap(&C.getActivePath(), C.getCurrLocationContext());
1199
1200
1201 assert(.isInLocCtxMap(&Call->path) &&
1202 "When we ascend to a previously unvisited call, this must be the "
1203 "first time we encounter the caller context!");
1204 C.updateLocCtxMap(&Call->path, CE->getCalleeContext());
1205 }
1207
1208
1209 PrevLoc = Call->getLocation();
1210
1211 if (.CallStack.empty()) {
1212 assert(C.CallStack.back().first == Call);
1213 C.CallStack.pop_back();
1214 }
1215 return;
1216 }
1217
1218 assert(C.getCurrLocationContext() == C.getLocationContextForActivePath() &&
1219 "The current position in the bug path is out of sync with the "
1220 "location context associated with the active path!");
1221
1222
1223 if (std::optional CE = P.getAs()) {
1224
1225
1226
1228
1229 assert(.isInLocCtxMap(&Call->path) &&
1230 "We just entered a call, this must've been the first time we "
1231 "encounter its context!");
1232 C.updateLocCtxMap(&Call->path, CE->getCalleeContext());
1233
1234 if (C.shouldAddPathEdges()) {
1235
1238 }
1239
1240 auto *P = Call.get();
1241 C.getActivePath().push_front(std::move(Call));
1242
1243
1244 C.PD->pushActivePath(&P->path);
1245 C.CallStack.push_back(CallWithEntry(P, C.getCurrentNode()));
1246 return;
1247 }
1248
1249 if (auto PS = P.getAs()) {
1250 if (.shouldAddPathEdges())
1251 return;
1252
1253
1254
1255
1260 }
1261
1262 } else if (auto BE = P.getAs()) {
1263
1264 if (C.shouldAddControlNotes()) {
1265 generateMinimalDiagForBlockEdge(C, *BE);
1266 }
1267
1268 if (.shouldAddPathEdges()) {
1269 return;
1270 }
1271
1272
1275 const Stmt *Body = nullptr;
1276
1277 if (const auto *FS = dyn_cast(Loop))
1278 Body = FS->getBody();
1279 else if (const auto *WS = dyn_cast(Loop))
1280 Body = WS->getBody();
1281 else if (const auto *OFS = dyn_cast(Loop)) {
1282 Body = OFS->getBody();
1283 } else if (const auto *FRS = dyn_cast(Loop)) {
1284 Body = FRS->getBody();
1285 }
1286
1287
1288 auto p = std::make_shared(
1289 L, "Looping back to the head of the loop");
1290 p->setPrunable(true);
1291
1292 addEdgeToPath(C.getActivePath(), PrevLoc, p->getLocation());
1293
1294 if (.shouldAddControlNotes()) {
1295 C.getActivePath().push_front(std::move(p));
1296 }
1297
1298 if (const auto *CS = dyn_cast_or_null(Body)) {
1301 }
1302 }
1303
1304 const CFGBlock *BSrc = BE->getSrc();
1305 const ParentMap &PM = C.getParentMap();
1306
1308
1309
1314
1315 StringRef str;
1316
1318 if (!IsInLoopBody) {
1323 } else {
1325 }
1326 }
1327 } else {
1329 }
1330
1331 if (!str.empty()) {
1333 C.getCurrLocationContext());
1334 auto PE = std::make_shared(L, str);
1335 PE->setPrunable(true);
1336 addEdgeToPath(C.getActivePath(), PrevLoc, PE->getLocation());
1337
1338
1339 if (.shouldAddControlNotes()) {
1340 C.getActivePath().push_front(std::move(PE));
1341 }
1342 }
1346 }
1347 }
1348 }
1349}
1350
1351static std::unique_ptr
1353 const Decl *AnalysisEntryPoint) {
1355 return std::make_unique(
1359 AnalysisEntryPoint, std::make_unique());
1360}
1361
1362static std::unique_ptr
1365 const Decl *AnalysisEntryPoint) {
1367 return std::make_unique(
1372}
1373
1375 if (!S)
1376 return nullptr;
1377
1378 while (true) {
1380
1381 if (!S)
1382 break;
1383
1385 continue;
1386
1387 break;
1388 }
1389
1390 return S;
1391}
1392
1395 case Stmt::BinaryOperatorClass: {
1397 if (!BO->isLogicalOp())
1398 return false;
1399 return BO->getLHS() == Cond || BO->getRHS() == Cond;
1400 }
1401 case Stmt::IfStmtClass:
1403 case Stmt::ForStmtClass:
1405 case Stmt::WhileStmtClass:
1407 case Stmt::DoStmtClass:
1409 case Stmt::ChooseExprClass:
1411 case Stmt::IndirectGotoStmtClass:
1413 case Stmt::SwitchStmtClass:
1415 case Stmt::BinaryConditionalOperatorClass:
1417 case Stmt::ConditionalOperatorClass: {
1419 return CO->getCond() == Cond ||
1420 CO->getLHS() == Cond ||
1421 CO->getRHS() == Cond;
1422 }
1423 case Stmt::ObjCForCollectionStmtClass:
1425 case Stmt::CXXForRangeStmtClass: {
1427 return FRS->getCond() == Cond || FRS->getRangeInit() == Cond;
1428 }
1429 default:
1430 return false;
1431 }
1432}
1433
1435 if (const auto *FS = dyn_cast(FL))
1436 return FS->getInc() == S || FS->getInit() == S;
1437 if (const auto *FRS = dyn_cast(FL))
1438 return FRS->getInc() == S || FRS->getRangeStmt() == S ||
1439 FRS->getLoopVarStmt() || FRS->getRangeInit() == S;
1440 return false;
1441}
1442
1444
1445
1446
1447
1448
1449
1452 PathPieces::iterator Prev = pieces.end();
1453 for (PathPieces::iterator I = pieces.begin(), E = Prev; I != E;
1454 Prev = I, ++I) {
1455 auto *Piece = dyn_cast(I->get());
1456
1457 if (!Piece)
1458 continue;
1459
1462
1464 const Stmt *InnerStmt = nullptr;
1465 while (NextSrcContext.isValid() && NextSrcContext.asStmt() != InnerStmt) {
1466 SrcContexts.push_back(NextSrcContext);
1467 InnerStmt = NextSrcContext.asStmt();
1469 true);
1470 }
1471
1472
1473
1474
1475 while (true) {
1476 const Stmt *Dst = Piece->getEndLocation().getStmtOrNull();
1477
1478
1479
1482 if (!DstContext.isValid() || DstContext.asStmt() == Dst)
1483 break;
1484
1485
1486 if (llvm::is_contained(SrcContexts, DstContext))
1487 break;
1488
1489
1490 Piece->setStartLocation(DstContext);
1491
1492
1493
1494 if (Prev != E) {
1495 auto *PrevPiece = dyn_cast(Prev->get());
1496
1497 if (PrevPiece) {
1498 if (const Stmt *PrevSrc =
1499 PrevPiece->getStartLocation().getStmtOrNull()) {
1501 if (PrevSrcParent ==
1503 PrevPiece->setEndLocation(DstContext);
1504 break;
1505 }
1506 }
1507 }
1508 }
1509
1510
1511
1512
1513 auto P =
1514 std::make_shared(SrcLoc, DstContext);
1515 Piece = P.get();
1516 I = pieces.insert(I, std::move(P));
1517 }
1518 }
1519}
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1532 for (PathPieces::iterator I = pieces.begin(), E = pieces.end(); I != E; ++I) {
1533 const auto *PieceI = dyn_cast(I->get());
1534
1535 if (!PieceI)
1536 continue;
1537
1538 const Stmt *s1Start = PieceI->getStartLocation().getStmtOrNull();
1539 const Stmt *s1End = PieceI->getEndLocation().getStmtOrNull();
1540
1541 if (!s1Start || !s1End)
1542 continue;
1543
1544 PathPieces::iterator NextI = I; ++NextI;
1545 if (NextI == E)
1546 break;
1547
1549
1550 while (true) {
1551 if (NextI == E)
1552 break;
1553
1554 const auto *EV = dyn_cast(NextI->get());
1555 if (EV) {
1556 StringRef S = EV->getString();
1559 ++NextI;
1560 continue;
1561 }
1562 break;
1563 }
1564
1565 PieceNextI = dyn_cast(NextI->get());
1566 break;
1567 }
1568
1569 if (!PieceNextI)
1570 continue;
1571
1574
1575 if (!s2Start || !s2End || s1End != s2Start)
1576 continue;
1577
1578
1579
1582 continue;
1583
1584
1586 continue;
1587
1588
1589
1591 I = pieces.erase(I);
1592 }
1593}
1594
1595
1596
1597
1598
1599
1600
1604 SM.getExpansionRange(Range.getEnd()).getEnd());
1605
1607 if (FID != SM.getFileID(ExpansionRange.getEnd()))
1608 return std::nullopt;
1609
1610 std::optional Buffer = SM.getBufferOrNone(FID);
1611 if (!Buffer)
1612 return std::nullopt;
1613
1614 unsigned BeginOffset = SM.getFileOffset(ExpansionRange.getBegin());
1615 unsigned EndOffset = SM.getFileOffset(ExpansionRange.getEnd());
1616 StringRef Snippet = Buffer->getBuffer().slice(BeginOffset, EndOffset);
1617
1618
1619
1620
1621
1622 if (Snippet.find_first_of("\r\n") != StringRef::npos)
1623 return std::nullopt;
1624
1625
1626 return Snippet.size();
1627}
1628
1629
1631 const Stmt *S) {
1633}
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1652 for (PathPieces::iterator I = Path.begin(), E = Path.end(); I != E; ) {
1653
1654 const auto *PieceI = dyn_cast(I->get());
1655
1656 if (!PieceI) {
1657 ++I;
1658 continue;
1659 }
1660
1661 const Stmt *s1Start = PieceI->getStartLocation().getStmtOrNull();
1662 const Stmt *s1End = PieceI->getEndLocation().getStmtOrNull();
1663
1664 PathPieces::iterator NextI = I; ++NextI;
1665 if (NextI == E)
1666 break;
1667
1668 const auto *PieceNextI =
1669 dyn_cast(NextI->get());
1670
1671 if (!PieceNextI) {
1673 ++NextI;
1674 if (NextI == E)
1675 break;
1676 PieceNextI = dyn_cast(NextI->get());
1677 }
1678
1679 if (!PieceNextI) {
1680 ++I;
1681 continue;
1682 }
1683 }
1684
1685 const Stmt *s2Start = PieceNextI->getStartLocation().getStmtOrNull();
1686 const Stmt *s2End = PieceNextI->getEndLocation().getStmtOrNull();
1687
1688 if (s1Start && s2Start && s1Start == s2End && s2Start == s1End) {
1689 const size_t MAX_SHORT_LINE_LENGTH = 80;
1691 if (s1Length && *s1Length <= MAX_SHORT_LINE_LENGTH) {
1693 if (s2Length && *s2Length <= MAX_SHORT_LINE_LENGTH) {
1694 Path.erase(I);
1695 I = Path.erase(NextI);
1696 continue;
1697 }
1698 }
1699 }
1700
1701 ++I;
1702 }
1703}
1704
1705
1707 while (X) {
1708 if (X == Y)
1709 return true;
1711 }
1712 return false;
1713}
1714
1715
1718 bool erased = false;
1719
1720 for (PathPieces::iterator I = path.begin(), E = path.end(); I != E;
1721 erased ? I : ++I) {
1722 erased = false;
1723
1724 const auto *PieceI = dyn_cast(I->get());
1725
1726 if (!PieceI)
1727 continue;
1728
1729 const Stmt *start = PieceI->getStartLocation().getStmtOrNull();
1730 const Stmt *end = PieceI->getEndLocation().getStmtOrNull();
1731
1732 if (!start || !end)
1733 continue;
1734
1736 if (!endParent)
1737 continue;
1738
1740 continue;
1741
1744
1745 if (.isWrittenInSameFile(FirstLoc, SecondLoc))
1746 continue;
1747 if (SM.isBeforeInTranslationUnit(SecondLoc, FirstLoc))
1748 std::swap(SecondLoc, FirstLoc);
1749
1750 SourceRange EdgeRange(FirstLoc, SecondLoc);
1752
1753
1754 if (!ByteWidth)
1755 continue;
1756
1757 const size_t MAX_PUNY_EDGE_LENGTH = 2;
1758 if (*ByteWidth <= MAX_PUNY_EDGE_LENGTH) {
1759
1760
1761
1762 I = path.erase(I);
1763 erased = true;
1764 continue;
1765 }
1766 }
1767}
1768
1770 for (PathPieces::iterator I = path.begin(), E = path.end(); I != E; ++I) {
1771 const auto *PieceI = dyn_cast(I->get());
1772
1773 if (!PieceI)
1774 continue;
1775
1776 PathPieces::iterator NextI = I; ++NextI;
1777 if (NextI == E)
1778 return;
1779
1780 const auto *PieceNextI = dyn_cast(NextI->get());
1781
1782 if (!PieceNextI)
1783 continue;
1784
1785
1786 if (PieceI->getString() == PieceNextI->getString()) {
1787 path.erase(NextI);
1788 }
1789 }
1790}
1791
1794 bool hasChanges = false;
1796 assert(LC);
1799
1800 for (PathPieces::iterator I = path.begin(), E = path.end(); I != E; ) {
1801
1802 if (auto *CallI = dyn_cast(I->get())) {
1803
1804
1805 if (!OCS.count(CallI)) {
1807 }
1808 OCS.insert(CallI);
1809 }
1810 ++I;
1811 continue;
1812 }
1813
1814
1815 auto *PieceI = dyn_cast(I->get());
1816
1817 if (!PieceI) {
1818 ++I;
1819 continue;
1820 }
1821
1822 const Stmt *s1Start = PieceI->getStartLocation().getStmtOrNull();
1823 const Stmt *s1End = PieceI->getEndLocation().getStmtOrNull();
1826
1827 PathPieces::iterator NextI = I; ++NextI;
1828 if (NextI == E)
1829 break;
1830
1831 const auto *PieceNextI = dyn_cast(NextI->get());
1832
1833 if (!PieceNextI) {
1834 ++I;
1835 continue;
1836 }
1837
1838 const Stmt *s2Start = PieceNextI->getStartLocation().getStmtOrNull();
1839 const Stmt *s2End = PieceNextI->getEndLocation().getStmtOrNull();
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857 if (level1 && level1 == level2 && level1 == level3 && level1 == level4) {
1858 PieceI->setEndLocation(PieceNextI->getEndLocation());
1859 path.erase(NextI);
1860 hasChanges = true;
1861 continue;
1862 }
1863
1864
1865
1866
1867
1868
1869
1870
1871 if (s1End && s1End == s2Start && level2) {
1872 bool removeEdge = false;
1873
1874
1875
1877 removeEdge = true;
1878
1879
1880
1882
1883
1885 removeEdge = true;
1886 }
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898 else if (s1Start && s2End &&
1901 removeEdge = true;
1902 }
1903
1904
1905
1906
1907
1908
1909
1910
1911 else if (s1Start && s2End &&
1913 SourceRange EdgeRange(PieceI->getEndLocation().asLocation(),
1914 PieceI->getStartLocation().asLocation());
1916 removeEdge = true;
1917 }
1918 }
1919
1920 if (removeEdge) {
1921 PieceI->setEndLocation(PieceNextI->getEndLocation());
1922 path.erase(NextI);
1923 hasChanges = true;
1924 continue;
1925 }
1926 }
1927
1928
1929
1930
1931
1932
1933
1934
1935 if (s1End == s2Start) {
1936 const auto *FS = dyn_cast_or_null(level3);
1937 if (FS && FS->getCollection()->IgnoreParens() == s2Start &&
1938 s2End == FS->getElement()) {
1939 PieceI->setEndLocation(PieceNextI->getEndLocation());
1940 path.erase(NextI);
1941 hasChanges = true;
1942 continue;
1943 }
1944 }
1945
1946
1947 ++I;
1948 }
1949
1950 if (!hasChanges) {
1951
1952
1954
1956
1957
1959
1961
1963 }
1964
1965 return hasChanges;
1966}
1967
1968
1969
1970
1971
1972
1973
1976 const auto *FirstEdge =
1977 dyn_cast(Path.front().get());
1978 if (!FirstEdge)
1979 return;
1980
1981 const Decl *D = C.getLocationContextFor(&Path)->getDecl();
1984 if (FirstEdge->getStartLocation() != EntryLoc)
1985 return;
1986
1987 Path.pop_front();
1988}
1989
1990
1992
1995
1996 for (const auto &P : path) {
1997 FullSourceLoc Loc = P->getLocation().asLocation().getExpansionLoc();
1999 unsigned LineNo = Loc.getLineNumber();
2001 ExecutedLines[FID].insert(LineNo);
2002 }
2003}
2004
2005PathDiagnosticConstruct::PathDiagnosticConstruct(
2008 : Consumer(PDC), CurrentNode(ErrorNode),
2009 SM(CurrentNode->getCodeDecl().getASTContext().getSourceManager()),
2011 AnalysisEntryPoint)) {
2013}
2014
2015PathDiagnosticBuilder::PathDiagnosticBuilder(
2018 std::unique_ptr VisitorsDiagnostics)
2020 ErrorNode(ErrorNode),
2021 VisitorsDiagnostics(std::move(VisitorsDiagnostics)) {}
2022
2023std::unique_ptr
2025 const Decl *EntryPoint = getBugReporter().getAnalysisEntryPoint();
2026 PathDiagnosticConstruct Construct(PDC, ErrorNode, R, EntryPoint);
2027
2028 const SourceManager &SM = getSourceManager();
2029 const AnalyzerOptions &Opts = getAnalyzerOptions();
2030
2033
2034
2035 auto EndNotes = VisitorsDiagnostics->find(ErrorNode);
2037 if (EndNotes != VisitorsDiagnostics->end()) {
2038 assert(!EndNotes->second.empty());
2039 LastPiece = EndNotes->second[0];
2040 } else {
2042 *getBugReport());
2043 }
2044 Construct.PD->setEndOfPath(LastPiece);
2045
2046 PathDiagnosticLocation PrevLoc = Construct.PD->getLocation();
2047
2048
2049 while (Construct.ascendToPrevNode()) {
2050 generatePathDiagnosticsForNode(Construct, PrevLoc);
2051
2052 auto VisitorNotes = VisitorsDiagnostics->find(Construct.getCurrentNode());
2053 if (VisitorNotes == VisitorsDiagnostics->end())
2054 continue;
2055
2056
2057
2058 std::setllvm::FoldingSetNodeID DeduplicationSet;
2059
2060
2062 llvm::FoldingSetNodeID ID;
2063 Note->Profile(ID);
2064 if (!DeduplicationSet.insert(ID).second)
2065 continue;
2066
2068 addEdgeToPath(Construct.getActivePath(), PrevLoc, Note->getLocation());
2069 updateStackPiecesWithMessage(Note, Construct.CallStack);
2070 Construct.getActivePath().push_front(Note);
2071 }
2072 }
2073
2075
2076
2077 const StackFrameContext *CalleeLC =
2078 Construct.getLocationContextForActivePath()->getStackFrame();
2080 addEdgeToPath(Construct.getActivePath(), PrevLoc,
2082 }
2083
2084
2085
2086 if (!Construct.PD->path.empty()) {
2088 bool stillHasNotes =
2090 assert(stillHasNotes);
2091 (void)stillHasNotes;
2092 }
2093
2094
2095 if (!Opts.ShouldAddPopUpNotes)
2097
2098
2101
2103
2104
2105
2106
2108 while (optimizeEdges(Construct, Construct.getMutablePieces(), OCS)) {
2109 }
2110
2111
2112
2114 }
2115
2116
2117
2118
2121 }
2122
2123 if (Opts.ShouldDisplayMacroExpansions)
2125
2126 return std::move(Construct.PD);
2127}
2128
2129
2130
2131
2132
2133void BugType::anchor() {}
2134
2135
2136
2137
2138
2139LLVM_ATTRIBUTE_USED static bool
2141 for (const std::pair<StringRef, StringRef> &Pair : Registry.Dependencies) {
2142 if (Pair.second == CheckerName)
2143 return true;
2144 }
2145 return false;
2146}
2147
2149 StringRef CheckerName) {
2151 if (Checker.FullName == CheckerName)
2152 return Checker.IsHidden;
2153 }
2154 llvm_unreachable(
2155 "Checker name not found in CheckerRegistry -- did you retrieve it "
2156 "correctly from CheckerManager::getCurrentCheckerName?");
2157}
2158
2160 const BugType &bt, StringRef shortDesc, StringRef desc,
2162 const Decl *DeclToUnique)
2166 assert(ErrorNode && "The error node must be non-null!");
2168 ->getAnalysisManager()
2169 .getCheckerManager()
2170 ->getCheckerRegistryData(),
2172 "Some checkers depend on this one! We don't allow dependency "
2173 "checkers to emit warnings, because checkers should depend on "
2174 "*modeling*, not *diagnostics*.");
2175
2178 ->getAnalysisManager()
2179 .getCheckerManager()
2180 ->getCheckerRegistryData(),
2182 "Hidden checkers musn't emit diagnostics as they are by definition "
2183 "non-user facing!");
2184}
2185
2187 std::unique_ptr visitor) {
2188 if (!visitor)
2189 return;
2190
2191 llvm::FoldingSetNodeID ID;
2192 visitor->Profile(ID);
2193
2194 void *InsertPos = nullptr;
2195 if (CallbacksSet.FindNodeOrInsertPos(ID, InsertPos)) {
2196 return;
2197 }
2198
2199 Callbacks.push_back(std::move(visitor));
2200}
2201
2205
2208 if (!N)
2209 return nullptr;
2210
2213}
2214
2216 hash.AddInteger(static_cast<int>(getKind()));
2217 hash.AddPointer(&BT);
2219 assert(Location.isValid());
2220 Location.Profile(hash);
2221
2223 if (!range.isValid())
2224 continue;
2225 hash.Add(range.getBegin());
2226 hash.Add(range.getEnd());
2227 }
2228}
2229
2231 hash.AddInteger(static_cast<int>(getKind()));
2232 hash.AddPointer(&BT);
2237 } else {
2238
2239
2240
2241
2242 hash.AddPointer(ErrorNode->getCurrentOrPreviousStmtForDiagnostics());
2243 }
2244
2246 if (!range.isValid())
2247 continue;
2248 hash.Add(range.getBegin());
2249 hash.Add(range.getEnd());
2250 }
2251}
2252
2253template
2255 llvm::DenseMap<T, bugreporter::TrackingKind> &InterestingnessMap, T Val,
2257 auto Result = InterestingnessMap.insert({Val, TKind});
2258
2259 if (Result.second)
2260 return;
2261
2262
2263
2264
2265
2266
2267
2268 switch (TKind) {
2271 return;
2273 return;
2274 }
2275
2276 llvm_unreachable(
2277 "BugReport::markInteresting currently can only handle 2 different "
2278 "tracking kinds! Please define what tracking kind should this entitiy"
2279 "have, if it was already marked as interesting with a different kind!");
2280}
2281
2284 if (!sym)
2285 return;
2286
2288
2289
2290
2291 if (const auto *meta = dyn_cast(sym))
2293}
2294
2296 if (!sym)
2297 return;
2299
2300
2301
2302
2303 if (const auto *meta = dyn_cast(sym))
2305}
2306
2309 if (!R)
2310 return;
2311
2314
2315 if (const auto *SR = dyn_cast(R))
2317}
2318
2320 if (!R)
2321 return;
2322
2325
2326 if (const auto *SR = dyn_cast(R))
2328}
2329
2335
2337 if (!LC)
2338 return;
2340}
2341
2342std::optionalbugreporter::TrackingKind
2346 if (!RKind)
2347 return SKind;
2348 if (!SKind)
2349 return RKind;
2350
2351
2352
2353 switch(*RKind) {
2355 return RKind;
2357 return SKind;
2358 }
2359
2360 llvm_unreachable(
2361 "BugReport::getInterestingnessKind currently can only handle 2 different "
2362 "tracking kinds! Please define what tracking kind should we return here "
2363 "when the kind of getAsRegion() and getAsSymbol() is different!");
2364 return std::nullopt;
2365}
2366
2367std::optionalbugreporter::TrackingKind
2369 if (!sym)
2370 return std::nullopt;
2371
2372
2375 return std::nullopt;
2376 return It->getSecond();
2377}
2378
2379std::optionalbugreporter::TrackingKind
2381 if (!R)
2382 return std::nullopt;
2383
2387 return It->getSecond();
2388
2389 if (const auto *SR = dyn_cast(R))
2391 return std::nullopt;
2392}
2393
2397
2401
2405
2407 if (!LC)
2408 return false;
2410}
2411
2414 return nullptr;
2415
2417 const Stmt *S = nullptr;
2418
2419 if (std::optional BE = ProgP.getAs<BlockEntrance>()) {
2421 if (BE->getBlock() == &Exit)
2422 S = ErrorNode->getPreviousStmtForDiagnostics();
2423 }
2424 if (!S)
2425 S = ErrorNode->getStmtForDiagnostics();
2426
2427 return S;
2428}
2429
2432
2433
2434 if (Ranges.empty() && isa_and_nonnull(getStmt()))
2436
2438}
2439
2448
2449static const Stmt *
2452
2453
2455 return S;
2456
2457
2458 }
2460}
2461
2464 assert(ErrorNode && "Cannot create a location with a null node.");
2465 const Stmt *S = ErrorNode->getStmtForDiagnostics();
2469 ErrorNode->getState()->getStateManager().getContext().getSourceManager();
2470
2471 if (!S) {
2472
2476 if (const ReturnStmt *RS = FE->getStmt())
2478
2480 }
2481 if (!S)
2482 S = ErrorNode->getNextStmtForDiagnostics();
2483 }
2484
2485 if (S) {
2486
2487
2488
2489 if (const auto *AS = dyn_cast(S))
2490 S = AS->getSubStmt();
2491
2492
2493 if (const auto *ME = dyn_cast(S))
2495
2496
2497 if (const auto *B = dyn_cast(S))
2499
2502
2505
2508 }
2509
2511 SM);
2512}
2513
2514
2515
2516
2517
2519 return Eng.getGraph();
2520}
2521
2523 return Eng.getStateManager();
2524}
2525
2527 : D(D), UserSuppressions(D.getASTContext()) {}
2528
2530
2531 assert(StrBugTypes.empty() &&
2532 "Destroying BugReporter before diagnostics are emitted!");
2533
2534
2535 for (const auto I : EQClassesVector)
2536 delete I;
2537}
2538
2540
2541
2542 for (const auto EQ : EQClassesVector)
2543 FlushReport(*EQ);
2544
2545
2546
2547
2548
2549 StrBugTypes.clear();
2550}
2551
2552
2553
2554
2555
2556namespace {
2557
2558
2559
2560class BugPathInfo {
2561public:
2562 std::unique_ptr BugPath;
2565};
2566
2567
2568
2569class BugPathGetter {
2570 std::unique_ptr TrimmedGraph;
2571
2572 using PriorityMapTy = llvm::DenseMap<const ExplodedNode *, unsigned>;
2573
2574
2575 PriorityMapTy PriorityMap;
2576
2577
2578
2579 using ReportNewNodePair =
2580 std::pair<PathSensitiveBugReport *, const ExplodedNode *>;
2582
2583 BugPathInfo CurrentBugPath;
2584
2585
2586 template
2587 class PriorityCompare {
2588 const PriorityMapTy &PriorityMap;
2589
2590 public:
2591 PriorityCompare(const PriorityMapTy &M) : PriorityMap(M) {}
2592
2594 PriorityMapTy::const_iterator LI = PriorityMap.find(LHS);
2595 PriorityMapTy::const_iterator RI = PriorityMap.find(RHS);
2596 PriorityMapTy::const_iterator E = PriorityMap.end();
2597
2598 if (LI == E)
2599 return Descending;
2600 if (RI == E)
2601 return !Descending;
2602
2603 return Descending ? LI->second > RI->second
2604 : LI->second < RI->second;
2605 }
2606
2607 bool operator()(const ReportNewNodePair &LHS,
2608 const ReportNewNodePair &RHS) const {
2609 return (*this)(LHS.second, RHS.second);
2610 }
2611 };
2612
2613public:
2614 BugPathGetter(const ExplodedGraph *OriginalGraph,
2615 ArrayRef<PathSensitiveBugReport *> &bugReports);
2616
2617 BugPathInfo *getNextBugPath();
2618};
2619
2620}
2621
2622BugPathGetter::BugPathGetter(const ExplodedGraph *OriginalGraph,
2623 ArrayRef<PathSensitiveBugReport *> &bugReports) {
2624 SmallVector<const ExplodedNode *, 32> Nodes;
2625 for (const auto I : bugReports) {
2626 assert(I->isValid() &&
2627 "We only allow BugReporterVisitors and BugReporter itself to "
2628 "invalidate reports!");
2629 Nodes.emplace_back(I->getErrorNode());
2630 }
2631
2632
2633
2635 TrimmedGraph = OriginalGraph->trim(Nodes, &ForwardMap);
2636
2637
2638
2639
2640 llvm::SmallPtrSet<const ExplodedNode *, 32> RemainingNodes;
2641
2643 const ExplodedNode *NewNode = ForwardMap.lookup(Report->getErrorNode());
2644 assert(NewNode &&
2645 "Failed to construct a trimmed graph that contains this error "
2646 "node!");
2647 ReportNodes.emplace_back(Report, NewNode);
2648 RemainingNodes.insert(NewNode);
2649 }
2650
2651 assert(!RemainingNodes.empty() && "No error node found in the trimmed graph");
2652
2653
2654 std::queue<const ExplodedNode *> WS;
2655
2656 WS.push(TrimmedGraph->getRoot());
2657 unsigned Priority = 0;
2658
2659 while (!WS.empty()) {
2661 WS.pop();
2662
2663 PriorityMapTy::iterator PriorityEntry;
2664 bool IsNew;
2665 std::tie(PriorityEntry, IsNew) = PriorityMap.insert({Node, Priority});
2666 ++Priority;
2667
2668 if (!IsNew) {
2669 assert(PriorityEntry->second <= Priority);
2670 continue;
2671 }
2672
2673 if (RemainingNodes.erase(Node))
2674 if (RemainingNodes.empty())
2675 break;
2676
2678 WS.push(Succ);
2679 }
2680
2681
2682 llvm::sort(ReportNodes, PriorityCompare(PriorityMap));
2683}
2684
2685BugPathInfo *BugPathGetter::getNextBugPath() {
2686 if (ReportNodes.empty())
2687 return nullptr;
2688
2690 std::tie(CurrentBugPath.Report, OrigN) = ReportNodes.pop_back_val();
2691 assert(PriorityMap.contains(OrigN) && "error node not accessible from root");
2692
2693
2694
2695 auto GNew = std::make_unique();
2696
2697
2698
2700 while (true) {
2701
2702
2703 ExplodedNode *NewN = GNew->createUncachedNode(
2706
2707
2708 if (Succ)
2710 else
2711 CurrentBugPath.ErrorNode = NewN;
2712
2713 Succ = NewN;
2714
2715
2717 assert(OrigN == TrimmedGraph->getRoot() &&
2718 "There should be only one root!");
2719 GNew->designateAsRoot(NewN);
2720 break;
2721 }
2722
2723
2724
2726 PriorityCompare(PriorityMap));
2727 }
2728
2729 CurrentBugPath.BugPath = std::move(GNew);
2730
2731 return &CurrentBugPath;
2732}
2733
2734
2735
2738 using MacroStackTy = std::vector<
2739 std::pair<std::shared_ptr, SourceLocation>>;
2740
2741 using PiecesTy = std::vector;
2742
2743 MacroStackTy MacroStack;
2744 PiecesTy Pieces;
2745
2746 for (PathPieces::const_iterator I = path.begin(), E = path.end();
2747 I != E; ++I) {
2748 const auto &piece = *I;
2749
2750
2751 if (auto *call = dyn_cast(&*piece)) {
2753 }
2754
2755
2756 const FullSourceLoc Loc = piece->getLocation().asLocation();
2757
2758
2759
2761 SM.getExpansionLoc(Loc) :
2763
2764 if (Loc.isFileID()) {
2765 MacroStack.clear();
2766 Pieces.push_back(piece);
2767 continue;
2768 }
2769
2770 assert(Loc.isMacroID());
2771
2772
2773 if (!MacroStack.empty() && InstantiationLoc == MacroStack.back().second) {
2774 MacroStack.back().first->subPieces.push_back(piece);
2775 continue;
2776 }
2777
2778
2779
2780 std::shared_ptr MacroGroup;
2781
2783 SM.getExpansionLoc(Loc) :
2785
2786
2787 while (!MacroStack.empty()) {
2788 if (InstantiationLoc == MacroStack.back().second) {
2789 MacroGroup = MacroStack.back().first;
2790 break;
2791 }
2792
2793 if (ParentInstantiationLoc == MacroStack.back().second) {
2794 MacroGroup = MacroStack.back().first;
2795 break;
2796 }
2797
2798 MacroStack.pop_back();
2799 }
2800
2801 if (!MacroGroup || ParentInstantiationLoc == MacroStack.back().second) {
2802
2803 auto NewGroup = std::make_shared(
2805
2806 if (MacroGroup)
2807 MacroGroup->subPieces.push_back(NewGroup);
2808 else {
2809 assert(InstantiationLoc.isFileID());
2810 Pieces.push_back(NewGroup);
2811 }
2812
2813 MacroGroup = NewGroup;
2814 MacroStack.push_back(std::make_pair(MacroGroup, InstantiationLoc));
2815 }
2816
2817
2818 MacroGroup->subPieces.push_back(piece);
2819 }
2820
2821
2822 path.clear();
2823
2824 llvm::append_range(path, Pieces);
2825}
2826
2827
2828
2829
2830static std::unique_ptr
2834 std::unique_ptr Notes =
2835 std::make_unique();
2837
2838
2839
2841 while (NextNode) {
2842
2843
2844
2845
2846
2847
2848 for (std::unique_ptr &Visitor : R->visitors())
2849 visitors.push_back(std::move(Visitor));
2850
2852
2854 if (!Pred) {
2856 for (auto &V : visitors) {
2857 V->finalizeVisitor(BRC, ErrorNode, *R);
2858
2859 if (auto Piece = V->getEndPath(BRC, ErrorNode, *R)) {
2860 assert(!LastPiece &&
2861 "There can only be one final piece in a diagnostic.");
2863 "The final piece must contain a message!");
2864 LastPiece = std::move(Piece);
2865 (*Notes)[ErrorNode].push_back(LastPiece);
2866 }
2867 }
2868 break;
2869 }
2870
2871 for (auto &V : visitors) {
2872 auto P = V->VisitNode(NextNode, BRC, *R);
2873 if (P)
2874 (*Notes)[NextNode].push_back(std::move(P));
2875 }
2876
2878 break;
2879
2880 NextNode = Pred;
2881 }
2882
2883 return Notes;
2884}
2885
2886std::optional PathDiagnosticBuilder::findValidReport(
2887 ArrayRef<PathSensitiveBugReport *> &bugReports,
2890
2891 BugPathGetter BugGraph(&Reporter.getGraph(), bugReports);
2892
2893 while (BugPathInfo *BugPath = BugGraph.getNextBugPath()) {
2894
2896 assert(R && "No original report found for sliced graph.");
2897 assert(R->isValid() && "Report selected by trimmed graph marked invalid.");
2898 const ExplodedNode *ErrorNode = BugPath->ErrorNode;
2899
2900
2901
2903
2904
2908
2910
2911
2912 std::unique_ptr visitorNotes =
2914
2917 llvm::TimeTraceScope TCS{"Crosscheck with Z3"};
2918
2919
2924
2925
2926
2928 switch (Z3Oracle.interpretQueryResult(CrosscheckResult)) {
2930 ++NumTimesReportRefuted;
2931 R->markInvalid("Infeasible constraints", nullptr);
2932 continue;
2934 ++NumTimesReportEQClassAborted;
2935 return {};
2937 ++NumTimesReportPassesZ3;
2938 break;
2939 }
2940 }
2941
2943 return PathDiagnosticBuilder(std::move(BRC), std::move(BugPath->BugPath),
2944 BugPath->Report, BugPath->ErrorNode,
2945 std::move(visitorNotes));
2946 }
2947 }
2948
2949 ++NumTimesReportEQClassWasExhausted;
2950 return {};
2951}
2952
2953std::unique_ptr
2955 ArrayRef<std::unique_ptr> consumers,
2957 assert(!bugReports.empty());
2958
2959 auto Out = std::make_unique();
2960
2961 std::optional PDB =
2962 PathDiagnosticBuilder::findValidReport(bugReports, *this);
2963
2964 if (PDB) {
2965 for (const auto &PC : consumers) {
2966 if (std::unique_ptr PD = PDB->generate(PC.get())) {
2967 (*Out)[PC.get()] = std::move(PD);
2968 }
2969 }
2970 }
2971
2972 return Out;
2973}
2974
2976 bool ValidSourceLoc = R->getLocation().isValid();
2977 assert(ValidSourceLoc);
2978
2979
2980 if (!ValidSourceLoc)
2981 return;
2982
2983
2984 if (UserSuppressions.isSuppressed(*R))
2985 return;
2986
2987
2988 llvm::FoldingSetNodeID ID;
2989 R->Profile(ID);
2990
2991
2992 void *InsertPos;
2994
2995 if (!EQ) {
2997 EQClasses.InsertNode(EQ, InsertPos);
2998 EQClassesVector.push_back(EQ);
2999 } else
3000 EQ->AddReport(std::move(R));
3001}
3002
3004 if (auto PR = dyn_cast(R.get()))
3005 if (const ExplodedNode *E = PR->getErrorNode()) {
3006
3007
3008 assert((E->isSink() || E->getLocation().getTag()) &&
3009 "Error node must either be a sink or have a tag");
3010
3012 E->getLocationContext()->getAnalysisDeclContext();
3013
3014
3015
3016
3019 return;
3020 }
3021
3023}
3024
3025
3026
3027
3028
3029namespace {
3030
3031struct FRIEC_WLItem {
3034
3036 : N(n), I(N->succ_begin()), E(N->succ_end()) {}
3037};
3038
3039}
3040
3041BugReport *PathSensitiveBugReporter::findReportInEquivalenceClass(
3043
3044
3045
3046 assert(EQ.getReports().size() > 0);
3047 const BugType& BT = EQ.getReports()[0]->getBugType();
3049 BugReport *R = EQ.getReports()[0].get();
3050 for (auto &J : EQ.getReports()) {
3051 if (auto *PR = dyn_cast(J.get())) {
3052 R = PR;
3053 bugReports.push_back(PR);
3054 }
3055 }
3056 return R;
3057 }
3058
3059
3060
3061
3062
3063
3064
3065 BugReport *exampleReport = nullptr;
3066
3067 for (const auto &I: EQ.getReports()) {
3068 auto *R = dyn_cast(I.get());
3069 if (!R)
3070 continue;
3071
3072 const ExplodedNode *errorNode = R->getErrorNode();
3073 if (errorNode->isSink()) {
3074 llvm_unreachable(
3075 "BugType::isSuppressSink() should not be 'true' for sink end nodes");
3076 }
3077
3079 bugReports.push_back(R);
3080 if (!exampleReport)
3081 exampleReport = R;
3082 continue;
3083 }
3084
3085
3086
3087
3088
3089 if (const CFGBlock *ErrorB = errorNode->getCFGBlock())
3090 if (ErrorB->isInevitablySinking())
3091 continue;
3092
3093
3094
3095 using WLItem = FRIEC_WLItem;
3096 using DFSWorkList = SmallVector<WLItem, 10>;
3097
3098 llvm::DenseMap<const ExplodedNode *, unsigned> Visited;
3099
3100 DFSWorkList WL;
3101 WL.push_back(errorNode);
3102 Visited[errorNode] = 1;
3103
3104 while (!WL.empty()) {
3105 WLItem &WI = WL.back();
3106 assert(!WI.N->succ_empty());
3107
3108 for (; WI.I != WI.E; ++WI.I) {
3109 const ExplodedNode *Succ = *WI.I;
3110
3112
3113 if (!Succ->isSink()) {
3114 bugReports.push_back(R);
3115 if (!exampleReport)
3116 exampleReport = R;
3117 WL.clear();
3118 break;
3119 }
3120
3121 continue;
3122 }
3123
3124
3125 unsigned &mark = Visited[Succ];
3126 if (!mark) {
3127 mark = 1;
3128 WL.push_back(Succ);
3129 break;
3130 }
3131 }
3132
3133
3134
3135 if (!WL.empty() && &WL.back() == &WI)
3136 WL.pop_back();
3137 }
3138 }
3139
3140
3141
3142 return exampleReport;
3143}
3144
3146 llvm::TimeTraceScope TCS{timeTraceName(EQ), [&]() {
3148 }};
3149 SmallVector<BugReport*, 10> bugReports;
3150 BugReport *report = findReportInEquivalenceClass(EQ, bugReports);
3151 if (!report)
3152 return;
3153
3154
3155 for (const std::string &CheckerOrPackage :
3158 return;
3159 }
3160
3162 std::unique_ptr Diagnostics =
3164
3165 for (auto &P : *Diagnostics) {
3166 PathDiagnosticConsumer *Consumer = P.first;
3167 std::unique_ptr &PD = P.second;
3168
3169
3170
3171 if (PD->path.empty()) {
3172 PathDiagnosticLocation L = report->getLocation();
3173 auto piece = std::make_unique(
3175 for (SourceRange Range : report->getRanges())
3176 piece->addRange(Range);
3177 PD->setEndOfPath(std::move(piece));
3178 }
3179
3180 PathPieces &Pieces = PD->getMutablePieces();
3182
3183
3184 for (const auto &I : llvm::reverse(report->getNotes())) {
3185 PathDiagnosticNotePiece *Piece = I.get();
3186 auto ConvertedPiece = std::make_shared(
3188 for (const auto &R: Piece->getRanges())
3189 ConvertedPiece->addRange(R);
3190
3191 Pieces.push_front(std::move(ConvertedPiece));
3192 }
3193 } else {
3194 for (const auto &I : llvm::reverse(report->getNotes()))
3195 Pieces.push_front(I);
3196 }
3197
3198 for (const auto &I : report->getFixits())
3199 Pieces.back()->addFixit(I);
3200
3202
3203
3207 Pieces.push_front(std::make_shared(
3209 "[debug] analyzing from " +
3211 }
3213 }
3214}
3215
3216
3217
3222 const Stmt* Body = Signature->getBody();
3223 if (const auto FD = dyn_cast(Signature)) {
3224 SignatureSourceRange = FD->getSourceRange();
3225 } else if (const auto OD = dyn_cast(Signature)) {
3226 SignatureSourceRange = OD->getSourceRange();
3227 } else {
3228 return;
3229 }
3232 : SignatureSourceRange.getEnd();
3234 return;
3235 unsigned StartLine = SM.getExpansionLineNumber(Start);
3236 unsigned EndLine = SM.getExpansionLineNumber(End);
3237
3238 FileID FID = SM.getFileID(SM.getExpansionLoc(Start));
3239 for (unsigned Line = StartLine; Line <= EndLine; Line++)
3240 ExecutedLines[FID].insert(Line);
3241}
3242
3248 return;
3250 FileID FID = SM.getFileID(ExpansionLoc);
3251 unsigned LineNo = SM.getExpansionLineNumber(ExpansionLoc);
3252 ExecutedLines[FID].insert(LineNo);
3253}
3254
3255
3256
3257static std::unique_ptr
3259 auto ExecutedLines = std::make_unique();
3260
3261 while (N) {
3263
3267
3268 const Decl* D = CE->getCalleeContext()->getDecl();
3272
3273
3275
3276
3277
3278
3279 if (const auto *RS = dyn_cast_or_null(P)) {
3282 }
3283
3284 if (isa_and_nonnull<SwitchCase, LabelStmt>(P))
3286 }
3287
3289 }
3290 return ExecutedLines;
3291}
3292
3293std::unique_ptr
3296 ArrayRef<std::unique_ptr> consumers,
3299 auto Out = std::make_unique();
3300 for (const auto &Consumer : consumers)
3301 (*Out)[Consumer.get()] =
3303 return Out;
3304}
3305
3310
3311
3313 return nullptr;
3314
3316 "The call piece should not be in a header file.");
3317
3318
3320 return CP;
3321
3323 if (Path.empty())
3324 return nullptr;
3325
3326
3327
3328 if (auto *CPInner = dyn_cast(Path.back().get()))
3330
3331
3332 return nullptr;
3333}
3334
3336 if (PD.path.empty())
3337 return;
3338
3340 assert(LastP);
3342
3343
3344
3345 if (auto *CP = dyn_cast(LastP)) {
3347 if (CP) {
3348
3350
3351
3352 const auto *ND = dyn_cast(CP->getCallee());
3353 if (ND) {
3355 llvm::raw_svector_ostream os(buf);
3356 os << " (within a call to '" << ND->getDeclName() << "')";
3358 }
3359
3360
3363
3364 return;
3365 }
3366 }
3367}
3368
3369std::unique_ptr
3370PathSensitiveBugReporter::generateDiagnosticForConsumerMap(
3372 ArrayRef<std::unique_ptr> consumers,
3373 ArrayRef<BugReport *> bugReports) {
3376 consumers, bugReports);
3377
3378
3379
3380
3381
3382 assert(!bugReports.empty());
3383 MaxBugClassSize.updateMax(bugReports.size());
3384
3385
3386 ArrayRef<PathSensitiveBugReport *> convertedArrayOfReports(
3387 reinterpret_cast<PathSensitiveBugReport *const *>(&*bugReports.begin()),
3388 reinterpret_cast<PathSensitiveBugReport *const *>(&*bugReports.end()));
3390 consumers, convertedArrayOfReports);
3391
3392 if (Out->empty())
3393 return Out;
3394
3395 MaxValidBugClassSize.updateMax(bugReports.size());
3396
3397
3398
3400 for (auto const &P : *Out)
3401 if (Opts.ShouldReportIssuesInMainSourceFile && !Opts.AnalyzeAll)
3403
3404 return Out;
3405}
3406
3409 StringRef Name, StringRef Category,
3414 Ranges, Fixits);
3415}
3416
3419 StringRef name, StringRef category,
3423
3424 BugType *BT = getBugTypeForName(CheckName, name, category);
3425 auto R = std::make_unique(*BT, str, Loc);
3426 R->setDeclWithIssue(DeclWithIssue);
3427 for (const auto &SR : Ranges)
3429 for (const auto &FH : Fixits)
3432}
3433
3435 StringRef name, StringRef category) {
3437 llvm::raw_svector_ostream(fullDesc)
3438 << CheckName << ":" << name << ":" << category;
3439 std::unique_ptr &BT = StrBugTypes[fullDesc];
3440 if (!BT)
3441 BT = std::make_unique(CheckName, name, category);
3442 return BT.get();
3443}
This file defines AnalysisDeclContext, a class that manages the analysis context data for context sen...
static void dropFunctionEntryEdge(const PathDiagnosticConstruct &C, PathPieces &Path)
Drop the very first edge in a path, which should be a function entry edge.
Definition BugReporter.cpp:1974
constexpr llvm::StringLiteral StrLoopRangeEmpty
Definition BugReporter.cpp:1143
static PathDiagnosticLocation getEnclosingStmtLocation(const Stmt *S, const LocationContext *LC, bool allowNestedContexts=false)
Definition BugReporter.cpp:672
static std::unique_ptr< FilesToLineNumsMap > findExecutedLines(const SourceManager &SM, const ExplodedNode *N)
Definition BugReporter.cpp:3258
static bool isConditionForTerminator(const Stmt *S, const Stmt *Cond)
Definition BugReporter.cpp:1393
static void updateExecutedLinesWithDiagnosticPieces(PathDiagnostic &PD)
Populate executes lines with lines containing at least one diagnostics.
Definition BugReporter.cpp:1991
static void removeRedundantMsgs(PathPieces &path)
An optimization pass over PathPieces that removes redundant diagnostics generated by both ConditionBR...
Definition BugReporter.cpp:404
constexpr llvm::StringLiteral StrLoopCollectionEmpty
Definition BugReporter.cpp:1145
static void adjustCallLocations(PathPieces &Pieces, PathDiagnosticLocation *LastCallLocation=nullptr)
Recursively scan through a path and make sure that all call pieces have valid locations.
Definition BugReporter.cpp:526
static void removeIdenticalEvents(PathPieces &path)
Definition BugReporter.cpp:1769
static const Stmt * getTerminatorCondition(const CFGBlock *B)
A customized wrapper for CFGBlock::getTerminatorCondition() which returns the element for ObjCForColl...
Definition BugReporter.cpp:1134
static std::unique_ptr< VisitorsDiagnosticsTy > generateVisitorsDiagnostics(PathSensitiveBugReport *R, const ExplodedNode *ErrorNode, BugReporterContext &BRC)
Generate notes from all visitors.
Definition BugReporter.cpp:2831
static bool removeUnneededCalls(const PathDiagnosticConstruct &C, PathPieces &pieces, const PathSensitiveBugReport *R, bool IsInteresting=false)
Recursively scan through a path and prune out calls and macros pieces that aren't needed.
Definition BugReporter.cpp:454
static const Stmt * findReasonableStmtCloseToFunctionExit(const ExplodedNode *N)
Definition BugReporter.cpp:2450
static void populateExecutedLinesWithStmt(const Stmt *S, const SourceManager &SM, FilesToLineNumsMap &ExecutedLines)
Definition BugReporter.cpp:3243
static bool isJumpToFalseBranch(const BlockEdge *BE)
Definition BugReporter.cpp:1043
static std::optional< size_t > getLengthOnSingleLine(const SourceManager &SM, SourceRange Range)
Returns the number of bytes in the given (character-based) SourceRange.
Definition BugReporter.cpp:1601
static bool isContainedByStmt(const ParentMap &PM, const Stmt *S, const Stmt *SubS)
Definition BugReporter.cpp:1049
constexpr llvm::StringLiteral StrEnteringLoop
Definition BugReporter.cpp:1141
static void addEdgeToPath(PathPieces &path, PathDiagnosticLocation &PrevLoc, PathDiagnosticLocation NewLoc)
Adds a sanitized control-flow diagnostic edge to a path.
Definition BugReporter.cpp:1107
static bool isIncrementOrInitInForLoop(const Stmt *S, const Stmt *FL)
Definition BugReporter.cpp:1434
static std::unique_ptr< PathDiagnostic > generateEmptyDiagnosticForReport(const PathSensitiveBugReport *R, const SourceManager &SM, const Decl *AnalysisEntryPoint)
Definition BugReporter.cpp:1363
static void removeContextCycles(PathPieces &Path, const SourceManager &SM)
Eliminate two-edge cycles created by addContextEdges().
Definition BugReporter.cpp:1651
static bool lexicalContains(const ParentMap &PM, const Stmt *X, const Stmt *Y)
Return true if X is contained by Y.
Definition BugReporter.cpp:1706
static std::unique_ptr< PathDiagnostic > generateDiagnosticForBasicReport(const BasicBugReport *R, const Decl *AnalysisEntryPoint)
Definition BugReporter.cpp:1352
static void removePopUpNotes(PathPieces &Path)
Same logic as above to remove extra pieces.
Definition BugReporter.cpp:507
static void insertToInterestingnessMap(llvm::DenseMap< T, bugreporter::TrackingKind > &InterestingnessMap, T Val, bugreporter::TrackingKind TKind)
Definition BugReporter.cpp:2254
constexpr llvm::StringLiteral StrLoopBodyZero
Definition BugReporter.cpp:1142
static const Stmt * getEnclosingParent(const Stmt *S, const ParentMap &PM)
Definition BugReporter.cpp:649
static void removePunyEdges(PathPieces &path, const SourceManager &SM, const ParentMap &PM)
Definition BugReporter.cpp:1716
static const Stmt * getStmtParent(const Stmt *S, const ParentMap &PM)
Definition BugReporter.cpp:1374
static bool exitingDestructor(const ExplodedNode *N)
Definition BugReporter.cpp:2440
static void CompactMacroExpandedPieces(PathPieces &path, const SourceManager &SM)
CompactMacroExpandedPieces - This function postprocesses a PathDiagnostic object and collapses PathDi...
Definition BugReporter.cpp:2736
static void simplifySimpleBranches(PathPieces &pieces)
Move edges from a branch condition to a branch target when the condition is simple.
Definition BugReporter.cpp:1531
static void populateExecutedLinesWithFunctionSignature(const Decl *Signature, const SourceManager &SM, FilesToLineNumsMap &ExecutedLines)
Insert all lines participating in the function signature Signature into ExecutedLines.
Definition BugReporter.cpp:3218
static void resetDiagnosticLocationToMainFile(PathDiagnostic &PD)
Definition BugReporter.cpp:3335
static bool optimizeEdges(const PathDiagnosticConstruct &C, PathPieces &path, OptimizedCallsSet &OCS)
Definition BugReporter.cpp:1792
static bool hasImplicitBody(const Decl *D)
Returns true if the given decl has been implicitly given a body, either by the analyzer or by the com...
Definition BugReporter.cpp:518
static PathDiagnosticCallPiece * getFirstStackedCallToHeaderFile(PathDiagnosticCallPiece *CP, const SourceManager &SMgr)
Definition BugReporter.cpp:3307
llvm::DenseSet< const PathDiagnosticCallPiece * > OptimizedCallsSet
Definition BugReporter.cpp:1443
static void addContextEdges(PathPieces &pieces, const LocationContext *LC)
Adds synthetic edges from top-level statements to their subexpressions.
Definition BugReporter.cpp:1450
static LLVM_ATTRIBUTE_USED bool isDependency(const CheckerRegistryData &Registry, StringRef CheckerName)
Definition BugReporter.cpp:2140
static PathDiagnosticEventPiece * eventsDescribeSameCondition(PathDiagnosticEventPiece *X, PathDiagnosticEventPiece *Y)
Definition BugReporter.cpp:378
static bool isInLoopBody(const ParentMap &PM, const Stmt *S, const Stmt *Term)
Definition BugReporter.cpp:1073
static void removeEdgesToDefaultInitializers(PathPieces &Pieces)
Remove edges in and out of C++ default initializer expressions.
Definition BugReporter.cpp:559
static const Stmt * getStmtBeforeCond(const ParentMap &PM, const Stmt *Term, const ExplodedNode *N)
Definition BugReporter.cpp:1059
static void removePiecesWithInvalidLocations(PathPieces &Pieces)
Remove all pieces with invalid locations as these cannot be serialized.
Definition BugReporter.cpp:593
static LLVM_ATTRIBUTE_USED bool isHidden(const CheckerRegistryData &Registry, StringRef CheckerName)
Definition BugReporter.cpp:2148
static llvm::TimeTraceMetadata timeTraceMetadata(const ExplodedNode *Pred, const ProgramPoint &Loc)
#define STAT_COUNTER(VARNAME, DESC)
#define STAT_MAX(VARNAME, DESC)
Defines the clang::Expr interface and subclasses for C++ expressions.
bool isLoop(const FormatStyle &Style) const
FormatToken * Next
The next token in the unwrapped line.
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
Defines the clang::SourceLocation class and associated facilities.
Defines the SourceManager interface.
Defines the Objective-C statement AST node classes.
SourceManager & getSourceManager()
AnalysisDeclContext contains the context data for the function, method or block under analysis.
static std::string getFunctionName(const Decl *D)
bool isBodyAutosynthesized() const
bool isBodyAutosynthesizedFromModelFile() const
const CFGBlock * getSrc() const
const CFGBlock * getDst() const
Represents a single basic block in a source-level CFG.
succ_iterator succ_begin()
Stmt * getTerminatorStmt()
const Stmt * getLoopTarget() const
const Stmt * getTerminatorCondition(bool StripParens=true) const
unsigned succ_size() const
CXXForRangeStmt - This represents C++0x [stmt.ranged]'s ranged for statement, represented as 'for (ra...
Represents a point when we begin processing an inlined call.
Represents a point when we finish the call exit sequence (for inlined call).
const StackFrameContext * getCalleeContext() const
Decl - This represents one declaration (or definition), e.g.
ASTContext & getASTContext() const LLVM_READONLY
bool isImplicit() const
isImplicit - Indicates whether the declaration was implicitly generated by the implementation.
virtual Stmt * getBody() const
getBody - If this Decl represents a declaration for a body of code, such as a function or method defi...
virtual bool hasBody() const
Returns true if this Decl represents a declaration for a body of code, such as a function or method d...
SourceLocation getLocation() const
This represents one expression.
llvm::APSInt EvaluateKnownConstInt(const ASTContext &Ctx) const
EvaluateKnownConstInt - Call EvaluateAsRValue and return the folded integer.
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
ForStmt - This represents a 'for (init;cond;inc)' stmt.
A SourceLocation and its associated SourceManager.
unsigned getExpansionLineNumber(bool *Invalid=nullptr) const
IfStmt - This represents an if/then/else.
It wraps the AnalysisDeclContext to represent both the call stack with the help of StackFrameContext ...
const Decl * getDecl() const
const ParentMap & getParentMap() const
const StackFrameContext * getStackFrame() const
Represents Objective-C's collection statement.
bool isConsumedExpr(Expr *E) const
Stmt * getParent(Stmt *) const
Stmt * getParentIgnoreParens(Stmt *) const
Represents a point after we ran remove dead bindings AFTER processing the given statement.
Represents a program point just before an implicit call event.
T castAs() const
Convert to the specified ProgramPoint type, asserting that this ProgramPoint is of the desired type.
std::optional< T > getAs() const
Convert to the specified ProgramPoint type, returning std::nullopt if this ProgramPoint is not of the...
const LocationContext * getLocationContext() const
ReturnStmt - This represents a return, optionally of an expression: return; return 4;.
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
This class handles loading and caching of source files into memory.
A trivial tuple used to represent a source range.
SourceLocation getEnd() const
SourceLocation getBegin() const
It represents a stack frame of the call stack (based on CallEvent).
const Stmt * getCallSite() const
Stmt - This represents one statement.
StmtClass getStmtClass() const
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
SourceLocation getBeginLoc() const LLVM_READONLY
WhileStmt - This represents a 'while' stmt.
static bool isInCodeFile(SourceLocation SL, const SourceManager &SM)
const Decl * getDeclWithIssue() const override
The smallest declaration that contains the bug location.
PathDiagnosticLocation getUniqueingLocation() const override
Get the location on which the report should be uniqued.
void Profile(llvm::FoldingSetNodeID &hash) const override
Reports are uniqued to ensure that we do not emit multiple diagnostics for each bug.
Definition BugReporter.cpp:2215
const Decl * getUniqueingDecl() const override
Get the declaration that corresponds to (usually contains) the uniqueing location.
This class provides an interface through which checkers can create individual bug reports.
llvm::ArrayRef< FixItHint > getFixits() const
void addRange(SourceRange R)
Add a range to a bug report.
SmallVector< SourceRange, 4 > Ranges
virtual PathDiagnosticLocation getLocation() const =0
The primary location of the bug report that points at the undesirable behavior in the code.
ArrayRef< std::shared_ptr< PathDiagnosticNotePiece > > getNotes()
BugReport(Kind kind, const BugType &bt, StringRef desc)
void addFixItHint(const FixItHint &F)
Add a fix-it hint to the bug report.
StringRef getDescription() const
A verbose warning message that is appropriate for displaying next to the source code that introduces ...
const BugType & getBugType() const
StringRef getShortDescription(bool UseFallback=true) const
A short general warning message that is appropriate for displaying in the list of all reported bugs.
virtual ArrayRef< SourceRange > getRanges() const
Get the SourceRanges associated with the report.
static PathDiagnosticPieceRef getDefaultEndPath(const BugReporterContext &BRC, const ExplodedNode *N, const PathSensitiveBugReport &BR)
Generates the default final diagnostic piece.
virtual ~BugReporterVisitor()
void FlushReports()
Generate and flush diagnostics for all bug reports.
Definition BugReporter.cpp:2539
BugReporter(BugReporterData &d)
Definition BugReporter.cpp:2526
const SourceManager & getSourceManager()
const Decl * getAnalysisEntryPoint() const
Get the top-level entry point for the issue to be reported.
ArrayRef< std::unique_ptr< PathDiagnosticConsumer > > getPathDiagnosticConsumers()
virtual ~BugReporter()
Definition BugReporter.cpp:2529
void EmitBasicReport(const Decl *DeclWithIssue, const CheckerFrontend *Checker, StringRef BugName, StringRef BugCategory, StringRef BugStr, PathDiagnosticLocation Loc, ArrayRef< SourceRange > Ranges={}, ArrayRef< FixItHint > Fixits={})
Definition BugReporter.cpp:3407
virtual std::unique_ptr< DiagnosticForConsumerMapTy > generateDiagnosticForConsumerMap(BugReport *exampleReport, ArrayRef< std::unique_ptr< PathDiagnosticConsumer > > consumers, ArrayRef< BugReport * > bugReports)
Generate the diagnostics for the given bug report.
Definition BugReporter.cpp:3294
const AnalyzerOptions & getAnalyzerOptions()
virtual void emitReport(std::unique_ptr< BugReport > R)
Add the given report to the set of reports tracked by BugReporter.
Definition BugReporter.cpp:2975
bool isSuppressOnSink() const
isSuppressOnSink - Returns true if bug reports associated with this bug type should be suppressed if ...
StringRef getCategory() const
StringRef getDescription() const
StringRef getCheckerName() const
A CheckerFrontend instance is what the user recognizes as "one checker": it has a public canonical na...
CheckerNameRef getName() const
This wrapper is used to ensure that only StringRefs originating from the CheckerRegistry are used as ...
Simple checker classes that implement one frontend (i.e.
Visitor that tries to report interesting diagnostics from conditions.
static bool isPieceMessageGeneric(const PathDiagnosticPiece *Piece)
static const char * getTag()
Return the tag associated with this visitor.
bool isValid() const =delete
std::unique_ptr< ExplodedGraph > trim(ArrayRef< const NodeTy * > Nodes, InterExplodedGraphMap *ForwardMap=nullptr, InterExplodedGraphMap *InverseMap=nullptr) const
Creates a trimmed version of the graph that only contains paths leading to the given nodes.
const CFGBlock * getCFGBlock() const
const ProgramStateRef & getState() const
pred_iterator pred_begin()
const Stmt * getStmtForDiagnostics() const
If the node's program point corresponds to a statement, retrieve that statement.
const Stmt * getPreviousStmtForDiagnostics() const
Find the statement that was executed immediately before this node.
ProgramPoint getLocation() const
getLocation - Returns the edge associated with the given node.
void addPredecessor(ExplodedNode *V, ExplodedGraph &G)
addPredeccessor - Adds a predecessor to the current node, and in tandem add this node as a successor ...
const Stmt * getNextStmtForDiagnostics() const
Find the next statement that was executed on this node's execution path.
const ParentMap & getParentMap() const
SVal getSVal(const Stmt *S) const
Get the value of an arbitrary expression at this node.
const LocationContext * getLocationContext() const
std::optional< T > getLocationAs() const &
ExplodedNode * getFirstPred()
const ExplodedNode *const * const_succ_iterator
Suppress reports that might lead to known false positives.
MemRegion - The root abstract class for all memory regions.
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * getBaseRegion() const
Prints path notes when a message is sent to a nil receiver.
PathDiagnosticLocation getLocation() const override
void setCallee(const CallEnter &CE, const SourceManager &SM)
PathDiagnosticLocation callEnter
void setCallStackMessage(StringRef st)
bool hasCallStackMessage()
const Decl * getCallee() const
static std::shared_ptr< PathDiagnosticCallPiece > construct(const CallExitEnd &CE, const SourceManager &SM)
const Decl * getCaller() const
PathDiagnosticLocation callEnterWithin
virtual bool supportsLogicalOpControlFlow() const
bool shouldAddPathEdges() const
void HandlePathDiagnostic(std::unique_ptr< PathDiagnostic > D)
bool shouldAddControlNotes() const
bool shouldGenerateDiagnostics() const
PathDiagnosticLocation getStartLocation() const
void setStartLocation(const PathDiagnosticLocation &L)
PathDiagnosticLocation getEndLocation() const
static PathDiagnosticLocation createMemberLoc(const MemberExpr *ME, const SourceManager &SM)
For member expressions, return the location of the '.
const Stmt * asStmt() const
void Profile(llvm::FoldingSetNodeID &ID) const
const SourceManager & getManager() const
static PathDiagnosticLocation createOperatorLoc(const BinaryOperator *BO, const SourceManager &SM)
Create the location for the operator of the binary expression.
static PathDiagnosticLocation createEndBrace(const CompoundStmt *CS, const SourceManager &SM)
Create a location for the end of the compound statement.
static SourceLocation getValidSourceLocation(const Stmt *S, LocationOrAnalysisDeclContext LAC, bool UseEndOfStatement=false)
Construct a source location that corresponds to either the beginning or the end of the given statemen...
static PathDiagnosticLocation createEnd(const Stmt *S, const SourceManager &SM, const LocationOrAnalysisDeclContext LAC)
Create a location for the end of the statement.
static PathDiagnosticLocation createBegin(const Decl *D, const SourceManager &SM)
Create a location for the beginning of the declaration.
FullSourceLoc asLocation() const
static PathDiagnosticLocation createDeclEnd(const LocationContext *LC, const SourceManager &SM)
Constructs a location for the end of the enclosing declaration body.
const Stmt * getStmtOrNull() const
static PathDiagnosticLocation createSingleLocation(const PathDiagnosticLocation &PDL)
Convert the given location into a single kind location.
ArrayRef< SourceRange > getRanges() const
Return the SourceRanges associated with this PathDiagnosticPiece.
virtual PathDiagnosticLocation getLocation() const =0
void setAsLastInMainSourceFile()
const void * getTag() const
Return the opaque tag (if any) on the PathDiagnosticPiece.
StringRef getString() const
PathDiagnosticLocation getLocation() const override
PathDiagnostic - PathDiagnostic objects represent a single path-sensitive diagnostic.
void setDeclWithIssue(const Decl *D)
void appendToDesc(StringRef S)
void setLocation(PathDiagnosticLocation NewLoc)
const FilesToLineNumsMap & getExecutedLines() const
PathPieces flatten(bool ShouldFlattenMacros) const
void markInteresting(SymbolRef sym, bugreporter::TrackingKind TKind=bugreporter::TrackingKind::Thorough)
Marks a symbol as interesting.
Definition BugReporter.cpp:2282
SmallVector< std::unique_ptr< BugReporterVisitor >, 8 > VisitorList
PathDiagnosticLocation getUniqueingLocation() const override
Get the location on which the report should be uniqued.
VisitorList Callbacks
A set of custom visitors which generate "event" diagnostics at interesting points in the path.
const Stmt * getStmt() const
Definition BugReporter.cpp:2412
PathDiagnosticLocation getLocation() const override
The primary location of the bug report that points at the undesirable behavior in the code.
Definition BugReporter.cpp:2463
const Decl * getDeclWithIssue() const override
The smallest declaration that contains the bug location.
Definition BugReporter.cpp:2206
bool shouldPrunePath() const
Indicates whether or not any path pruning should take place when generating a PathDiagnostic from thi...
PathDiagnosticLocation UniqueingLocation
Reports with different uniqueing locations are considered to be different for the purposes of dedupli...
ArrayRef< SourceRange > getRanges() const override
Get the SourceRanges associated with the report.
Definition BugReporter.cpp:2431
llvm::DenseMap< SymbolRef, bugreporter::TrackingKind > InterestingSymbols
Profile to identify equivalent bug reports for error report coalescing.
const Decl * getUniqueingDecl() const override
Get the declaration containing the uniqueing location.
const ExplodedNode * getErrorNode() const
PathSensitiveBugReport(const BugType &bt, StringRef desc, const ExplodedNode *errorNode)
const ExplodedNode * ErrorNode
The ExplodedGraph node against which the report was thrown.
void markInvalid(const void *Tag, const void *Data)
Marks the current report as invalid, meaning that it is probably a false positive and should not be r...
void Profile(llvm::FoldingSetNodeID &hash) const override
Profile to identify equivalent bug reports for error report coalescing.
Definition BugReporter.cpp:2230
void clearVisitors()
Remove all visitors attached to this bug report.
Definition BugReporter.cpp:2202
void addVisitor(std::unique_ptr< BugReporterVisitor > visitor)
Add custom or predefined bug report visitors to this report.
Definition BugReporter.cpp:2186
bool isValid() const
Returns whether or not this report should be considered valid.
std::optional< bugreporter::TrackingKind > getInterestingnessKind(SymbolRef sym) const
Definition BugReporter.cpp:2368
void markNotInteresting(SymbolRef sym)
Definition BugReporter.cpp:2295
llvm::DenseMap< const MemRegion *, bugreporter::TrackingKind > InterestingRegions
A (stack of) set of regions that are registered with this report as being "interesting",...
bool isInteresting(SymbolRef sym) const
Definition BugReporter.cpp:2398
const SourceRange ErrorNodeRange
The range that corresponds to ErrorNode's program point.
llvm::FoldingSet< BugReporterVisitor > CallbacksSet
Used for ensuring the visitors are only added once.
llvm::SmallPtrSet< const LocationContext *, 2 > InterestingLocationContexts
A set of location contexts that correspoind to call sites which should be considered "interesting".
const Decl * UniqueingDecl
GRBugReporter is used for generating path-sensitive reports.
const ExplodedGraph & getGraph() const
getGraph - Get the exploded graph created by the analysis engine for the analyzed method or function.
Definition BugReporter.cpp:2518
void emitReport(std::unique_ptr< BugReport > R) override
Add the given report to the set of reports tracked by BugReporter.
Definition BugReporter.cpp:3003
std::unique_ptr< DiagnosticForConsumerMapTy > generatePathDiagnostics(ArrayRef< std::unique_ptr< PathDiagnosticConsumer > > consumers, ArrayRef< PathSensitiveBugReport * > &bugReports)
bugReports A set of bug reports within a single equivalence class
Definition BugReporter.cpp:2954
ProgramStateManager & getStateManager() const
getStateManager - Return the state manager used by the analysis engine.
Definition BugReporter.cpp:2522
A Range represents the closed range [from, to].
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
std::optional< T > getAs() const
Convert to the specified SVal type, returning std::nullopt if this SVal is not of the desired type.
SymbolRef getAsLocSymbol(bool IncludeBaseRegions=false) const
If this SVal is a location and wraps a symbol, return that SymbolRef.
std::string getMessage(const ExplodedNode *N) override
Search the call expression for the symbol Sym and dispatch the 'getMessageForX()' methods to construc...
Definition BugReporter.cpp:318
virtual std::string getMessageForSymbolNotFound()
virtual std::string getMessageForReturn(const CallExpr *CallExpr)
virtual std::string getMessageForArg(const Expr *ArgE, unsigned ArgIndex)
Produces the message of the following form: 'Msg via Nth parameter'.
Definition BugReporter.cpp:364
virtual ~StackHintGenerator()=0
The visitor detects NoteTags and displays the event notes they contain.
static const char * getTag()
Return the tag associated with this visitor.
The oracle will decide if a report should be accepted or rejected based on the results of the Z3 solv...
The bug visitor will walk all the nodes in a path and collect all the constraints.
TrackingKind
Specifies the type of tracking for an expression.
@ Thorough
Default tracking kind – specifies that as much information should be gathered about the tracked expre...
@ Condition
Specifies that a more moderate tracking should be used for the expression value.
llvm::DenseMap< const ExplodedNode *, const ExplodedNode * > InterExplodedGraphMap
const SymExpr * SymbolRef
@ CF
Indicates that the tracked object is a CF object.
std::shared_ptr< PathDiagnosticPiece > PathDiagnosticPieceRef
std::map< FileID, std::set< unsigned > > FilesToLineNumsMap
File IDs mapped to sets of line numbers.
bool EQ(InterpState &S, CodePtr OpPC)
std::variant< struct RequiresDecl, struct HeaderDecl, struct UmbrellaDirDecl, struct ModuleDecl, struct ExcludeDecl, struct ExportDecl, struct ExportAsDecl, struct ExternModuleDecl, struct UseDecl, struct LinkDecl, struct ConfigMacrosDecl, struct ConflictDecl > Decl
All declarations that can appear in a module declaration.
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
const FunctionProtoType * T
U cast(CodeGen::Address addr)
Diagnostic wrappers for TextAPI types for error reporting.