43 #include "llvm/ADT/ArrayRef.h" 44 #include "llvm/ADT/DenseMap.h" 45 #include "llvm/ADT/DenseSet.h" 46 #include "llvm/ADT/FoldingSet.h" 47 #include "llvm/ADT/None.h" 48 #include "llvm/ADT/Optional.h" 49 #include "llvm/ADT/STLExtras.h" 50 #include "llvm/ADT/SmallPtrSet.h" 51 #include "llvm/ADT/SmallString.h" 52 #include "llvm/ADT/SmallVector.h" 53 #include "llvm/ADT/Statistic.h" 54 #include "llvm/ADT/StringRef.h" 55 #include "llvm/ADT/iterator_range.h" 56 #include "llvm/Support/Casting.h" 57 #include "llvm/Support/Compiler.h" 58 #include "llvm/Support/ErrorHandling.h" 59 #include "llvm/Support/MemoryBuffer.h" 60 #include "llvm/Support/raw_ostream.h" 72 using namespace clang;
75 #define DEBUG_TYPE "BugReporter" 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)");
83 BugReporterVisitor::~BugReporterVisitor() =
default;
85 void BugReporterContext::anchor() {}
92 for (N = N->getFirstPred(); N; N = N->getFirstPred())
99 static inline const Stmt*
111 static PathDiagnosticEventPiece *
113 PathDiagnosticEventPiece *Y) {
118 const void *tagPreferred = ConditionBRVisitor::getTag();
119 const void *tagLesser = TrackConstraintBRVisitor::getTag();
121 if (X->getLocation() != Y->getLocation())
124 if (X->getTag() == tagPreferred && Y->getTag() == tagLesser)
125 return ConditionBRVisitor::isPieceMessageGeneric(X) ? Y :
X;
127 if (Y->getTag() == tagPreferred && X->getTag() == tagLesser)
128 return ConditionBRVisitor::isPieceMessageGeneric(Y) ?
X : Y;
139 unsigned N = path.size();
146 for (
unsigned i = 0;
i < N; ++
i) {
147 auto piece = std::move(path.front());
150 switch (piece->getKind()) {
161 if (
auto *nextEvent =
162 dyn_cast<PathDiagnosticEventPiece>(path.front().get())) {
163 auto *
event = cast<PathDiagnosticEventPiece>(piece.get());
167 if (
auto *pieceToKeep =
169 piece = std::move(pieceToKeep == event ? piece : path.front());
181 path.push_back(std::move(piece));
188 llvm::DenseMap<const PathPieces *, const LocationContext *>;
195 bool IsInteresting =
false) {
196 bool containsSomethingInteresting = IsInteresting;
197 const unsigned N = pieces.size();
199 for (
unsigned i = 0 ;
i < N ; ++
i) {
202 auto piece = std::move(pieces.front());
205 switch (piece->getKind()) {
207 auto &call = cast<PathDiagnosticCallPiece>(*piece);
209 assert(LCM.count(&call.path));
211 R->isInteresting(LCM[&call.path])))
214 containsSomethingInteresting =
true;
218 auto ¯o = cast<PathDiagnosticMacroPiece>(*piece);
221 containsSomethingInteresting =
true;
225 auto &
event = cast<PathDiagnosticEventPiece>(*piece);
229 containsSomethingInteresting |= !
event.isPrunable();
238 pieces.push_back(std::move(piece));
241 return containsSomethingInteresting;
246 for (
unsigned int i = 0;
i < Path.size(); ++
i) {
247 auto Piece = std::move(Path.front());
249 if (!isa<PathDiagnosticPopUpPiece>(*Piece))
250 Path.push_back(std::move(Piece));
265 PathDiagnosticLocation *LastCallLocation =
nullptr) {
266 for (
const auto &I : Pieces) {
267 auto *Call = dyn_cast<PathDiagnosticCallPiece>(I.get());
272 if (LastCallLocation) {
274 if (CallerIsImplicit || !Call->callEnter.asLocation().isValid())
275 Call->callEnter = *LastCallLocation;
276 if (CallerIsImplicit || !Call->callReturn.asLocation().isValid())
277 Call->callReturn = *LastCallLocation;
282 PathDiagnosticLocation *ThisCallLocation;
283 if (Call->callEnterWithin.asLocation().isValid() &&
285 ThisCallLocation = &Call->callEnterWithin;
287 ThisCallLocation = &Call->callEnter;
289 assert(ThisCallLocation &&
"Outermost call has an invalid location");
298 for (PathPieces::iterator I = Pieces.begin(), E = Pieces.end(); I != E;) {
299 if (
auto *C = dyn_cast<PathDiagnosticCallPiece>(I->get()))
302 if (
auto *M = dyn_cast<PathDiagnosticMacroPiece>(I->get()))
305 if (
auto *
CF = dyn_cast<PathDiagnosticControlFlowPiece>(I->get())) {
306 const Stmt *Start =
CF->getStartLocation().asStmt();
307 const Stmt *
End =
CF->getEndLocation().asStmt();
308 if (Start && isa<CXXDefaultInitExpr>(Start)) {
311 }
else if (End && isa<CXXDefaultInitExpr>(End)) {
312 PathPieces::iterator Next = std::next(I);
315 dyn_cast<PathDiagnosticControlFlowPiece>(Next->get())) {
316 NextCF->setStartLocation(
CF->getStartLocation());
332 for (PathPieces::iterator I = Pieces.begin(), E = Pieces.end(); I != E;) {
333 if (
auto *C = dyn_cast<PathDiagnosticCallPiece>(I->get()))
336 if (
auto *M = dyn_cast<PathDiagnosticMacroPiece>(I->get()))
339 if (!(*I)->getLocation().isValid() ||
340 !(*I)->getLocation().asLocation().isValid()) {
356 PathDiagnosticConsumer *PDC;
361 PathDiagnosticBuilder(GRBugReporter &br,
363 PathDiagnosticConsumer *pdc)
365 LC(r->getErrorNode()->getLocationContext()) {}
367 PathDiagnosticLocation ExecutionContinues(
const ExplodedNode *N);
369 PathDiagnosticLocation ExecutionContinues(llvm::raw_string_ostream &os,
370 const ExplodedNode *N);
372 BugReport *getBugReport() {
return R; }
374 Decl const &getCodeDecl() {
return R->getErrorNode()->getCodeDecl(); }
378 const Stmt *getParent(
const Stmt *S) {
379 return getParentMap().getParent(S);
388 bool supportsLogicalOpControlFlow()
const {
389 return PDC ? PDC->supportsLogicalOpControlFlow() :
true;
395 PathDiagnosticLocation
396 PathDiagnosticBuilder::ExecutionContinues(
const ExplodedNode *N) {
404 PathDiagnosticLocation
405 PathDiagnosticBuilder::ExecutionContinues(llvm::raw_string_ostream &os,
406 const ExplodedNode *N) {
408 if (os.str().empty())
411 const PathDiagnosticLocation &Loc = ExecutionContinues(N);
414 os <<
"Execution continues on line " 418 os <<
"Execution jumps to the end of the ";
419 const Decl *D = N->getLocationContext()->getDecl();
420 if (isa<ObjCMethodDecl>(D))
422 else if (isa<FunctionDecl>(D))
425 assert(isa<BlockDecl>(D));
426 os <<
"anonymous block";
443 case Stmt::ForStmtClass:
444 case Stmt::DoStmtClass:
445 case Stmt::WhileStmtClass:
446 case Stmt::ObjCForCollectionStmtClass:
447 case Stmt::CXXForRangeStmtClass:
456 static PathDiagnosticLocation
463 switch (
Parent->getStmtClass()) {
464 case Stmt::BinaryOperatorClass: {
465 const auto *B = cast<BinaryOperator>(
Parent);
466 if (B->isLogicalOp())
467 return PathDiagnosticLocation(allowNestedContexts ? B : S, SMgr, LC);
470 case Stmt::CompoundStmtClass:
471 case Stmt::StmtExprClass:
472 return PathDiagnosticLocation(S, SMgr, LC);
473 case Stmt::ChooseExprClass:
476 if (allowNestedContexts || cast<ChooseExpr>(
Parent)->getCond() == S)
477 return PathDiagnosticLocation(
Parent, SMgr, LC);
479 return PathDiagnosticLocation(S, SMgr, LC);
480 case Stmt::BinaryConditionalOperatorClass:
481 case Stmt::ConditionalOperatorClass:
484 if (allowNestedContexts ||
485 cast<AbstractConditionalOperator>(
Parent)->getCond() == S)
486 return PathDiagnosticLocation(
Parent, SMgr, LC);
488 return PathDiagnosticLocation(S, SMgr, LC);
489 case Stmt::CXXForRangeStmtClass:
490 if (cast<CXXForRangeStmt>(
Parent)->getBody() == S)
491 return PathDiagnosticLocation(S, SMgr, LC);
493 case Stmt::DoStmtClass:
494 return PathDiagnosticLocation(S, SMgr, LC);
495 case Stmt::ForStmtClass:
496 if (cast<ForStmt>(
Parent)->getBody() == S)
497 return PathDiagnosticLocation(S, SMgr, LC);
499 case Stmt::IfStmtClass:
500 if (cast<IfStmt>(
Parent)->getCond() != S)
501 return PathDiagnosticLocation(S, SMgr, LC);
503 case Stmt::ObjCForCollectionStmtClass:
504 if (cast<ObjCForCollectionStmt>(
Parent)->getBody() == S)
505 return PathDiagnosticLocation(S, SMgr, LC);
507 case Stmt::WhileStmtClass:
508 if (cast<WhileStmt>(
Parent)->getCond() != S)
509 return PathDiagnosticLocation(S, SMgr, LC);
518 assert(S &&
"Cannot have null Stmt for PathDiagnosticLocation");
520 return PathDiagnosticLocation(S, SMgr, LC);
523 PathDiagnosticLocation
525 assert(S &&
"Null Stmt passed to getEnclosingStmtLocation");
534 std::pair<PathDiagnosticCallPiece *, const ExplodedNode *>;
541 if (
auto *ep = dyn_cast<PathDiagnosticEventPiece>(&P)) {
542 if (ep->hasCallStackHint())
543 for (
const auto &I : CallStack) {
544 PathDiagnosticCallPiece *CP = I.first;
545 const ExplodedNode *N = I.second;
546 std::string stackMsg = ep->getCallStackMessage(N);
551 if (!CP->hasCallStackMessage())
552 CP->setCallStackMessage(stackMsg);
562 const ExplodedNode *N,
566 PathDiagnosticBuilder &PDB,
567 PathDiagnosticLocation &Start
571 llvm::raw_string_ostream os(sbuf);
572 PathDiagnosticLocation
End;
575 End = PathDiagnosticLocation(S, SM, LC);
579 os <<
"No cases match in the switch statement. " 580 "Control jumps to line " 581 << End.asLocation().getExpansionLineNumber();
583 case Stmt::DefaultStmtClass:
584 os <<
"Control jumps to the 'default' case at line " 585 << End.asLocation().getExpansionLineNumber();
588 case Stmt::CaseStmtClass: {
589 os <<
"Control jumps to 'case ";
590 const auto *Case = cast<CaseStmt>(S);
594 bool GetRawInt =
true;
596 if (
const auto *DR = dyn_cast<DeclRefExpr>(LHS)) {
608 os << LHS->EvaluateKnownConstInt(PDB.getASTContext());
610 os <<
":' at line " << End.asLocation().getExpansionLineNumber();
615 os <<
"'Default' branch taken. ";
616 End = PDB.ExecutionContinues(os, N);
618 return std::make_shared<PathDiagnosticControlFlowPiece>(Start,
End,
625 PathDiagnosticBuilder &PDB,
626 PathDiagnosticLocation &Start) {
628 llvm::raw_string_ostream os(sbuf);
629 const PathDiagnosticLocation &
End = PDB.getEnclosingStmtLocation(S);
630 os <<
"Control jumps to line " << End.asLocation().getExpansionLineNumber();
631 return std::make_shared<PathDiagnosticControlFlowPiece>(Start,
End, os.str());
636 const ExplodedNode *N,
641 PathDiagnosticBuilder &PDB,
643 const auto *B = cast<BinaryOperator>(T);
645 llvm::raw_string_ostream os(sbuf);
646 os <<
"Left side of '";
647 PathDiagnosticLocation Start,
End;
649 if (B->getOpcode() == BO_LAnd) {
655 End = PathDiagnosticLocation(B->getLHS(),
SM, LC);
660 Start = PathDiagnosticLocation(B->getLHS(),
SM, LC);
661 End = PDB.ExecutionContinues(N);
664 assert(B->getOpcode() == BO_LOr);
670 Start = PathDiagnosticLocation(B->getLHS(),
SM, LC);
671 End = PDB.ExecutionContinues(N);
674 End = PathDiagnosticLocation(B->getLHS(),
SM, LC);
679 return std::make_shared<PathDiagnosticControlFlowPiece>(Start,
End,
685 PathDiagnosticBuilder &PDB,
686 PathDiagnostic &PD) {
699 case Stmt::GotoStmtClass:
700 case Stmt::IndirectGotoStmtClass: {
706 case Stmt::SwitchStmtClass: {
707 PD.getActivePath().push_front(
712 case Stmt::BreakStmtClass:
713 case Stmt::ContinueStmtClass: {
715 llvm::raw_string_ostream os(sbuf);
716 PathDiagnosticLocation
End = PDB.ExecutionContinues(os, N);
717 PD.getActivePath().push_front(
718 std::make_shared<PathDiagnosticControlFlowPiece>(Start, End, os.str()));
723 case Stmt::BinaryConditionalOperatorClass:
724 case Stmt::ConditionalOperatorClass: {
726 llvm::raw_string_ostream os(sbuf);
727 os <<
"'?' condition is ";
734 PathDiagnosticLocation
End = PDB.ExecutionContinues(N);
736 if (
const Stmt *S = End.asStmt())
737 End = PDB.getEnclosingStmtLocation(S);
739 PD.getActivePath().push_front(
740 std::make_shared<PathDiagnosticControlFlowPiece>(Start, End, os.str()));
745 case Stmt::BinaryOperatorClass: {
746 if (!PDB.supportsLogicalOpControlFlow())
749 std::shared_ptr<PathDiagnosticControlFlowPiece>
Diag =
751 PD.getActivePath().push_front(Diag);
755 case Stmt::DoStmtClass:
758 llvm::raw_string_ostream os(sbuf);
760 os <<
"Loop condition is true. ";
761 PathDiagnosticLocation
End = PDB.ExecutionContinues(os, N);
763 if (
const Stmt *S = End.asStmt())
764 End = PDB.getEnclosingStmtLocation(S);
766 PD.getActivePath().push_front(
767 std::make_shared<PathDiagnosticControlFlowPiece>(Start, End,
770 PathDiagnosticLocation
End = PDB.ExecutionContinues(N);
772 if (
const Stmt *S = End.asStmt())
773 End = PDB.getEnclosingStmtLocation(S);
775 PD.getActivePath().push_front(
776 std::make_shared<PathDiagnosticControlFlowPiece>(
777 Start, End,
"Loop condition is false. Exiting loop"));
781 case Stmt::WhileStmtClass:
782 case Stmt::ForStmtClass:
785 llvm::raw_string_ostream os(sbuf);
787 os <<
"Loop condition is false. ";
788 PathDiagnosticLocation
End = PDB.ExecutionContinues(os, N);
789 if (
const Stmt *S = End.asStmt())
790 End = PDB.getEnclosingStmtLocation(S);
792 PD.getActivePath().push_front(
793 std::make_shared<PathDiagnosticControlFlowPiece>(Start, End,
796 PathDiagnosticLocation
End = PDB.ExecutionContinues(N);
797 if (
const Stmt *S = End.asStmt())
798 End = PDB.getEnclosingStmtLocation(S);
800 PD.getActivePath().push_front(
801 std::make_shared<PathDiagnosticControlFlowPiece>(
802 Start, End,
"Loop condition is true. Entering loop body"));
807 case Stmt::IfStmtClass: {
808 PathDiagnosticLocation
End = PDB.ExecutionContinues(N);
810 if (
const Stmt *S = End.asStmt())
811 End = PDB.getEnclosingStmtLocation(S);
814 PD.getActivePath().push_front(
815 std::make_shared<PathDiagnosticControlFlowPiece>(
816 Start, End,
"Taking false branch"));
818 PD.getActivePath().push_front(
819 std::make_shared<PathDiagnosticControlFlowPiece>(
820 Start, End,
"Taking true branch"));
842 const ProgramState *
State,
845 SVal
V = State->getSVal(Ex, LCtx);
846 if (!(R.isInteresting(V) || IE.count(Ex)))
851 if (!isa<CastExpr>(Ex))
854 case Stmt::BinaryOperatorClass:
855 case Stmt::UnaryOperatorClass: {
857 if (
const auto *child = dyn_cast_or_null<Expr>(SubStmt)) {
859 SVal ChildV = State->getSVal(child, LCtx);
860 R.markInteresting(ChildV);
867 R.markInteresting(V);
872 const ProgramState *
State,
878 if (
const auto *CE = dyn_cast_or_null<CallExpr>(CallSite)) {
879 if (
const auto *FD = dyn_cast<FunctionDecl>(CalleeCtx->
getDecl())) {
881 PE = FD->param_end();
883 for (; AI != AE && PI != PE; ++AI, ++PI) {
884 if (
const Expr *ArgE = *AI) {
886 Loc LV = State->getLValue(PD, CalleeCtx);
887 if (R.isInteresting(LV) || R.isInteresting(State->getRawSVal(LV)))
902 case Stmt::ForStmtClass:
903 case Stmt::WhileStmtClass:
904 case Stmt::ObjCForCollectionStmtClass:
905 case Stmt::CXXForRangeStmtClass:
929 const ExplodedNode *N) {
933 const Stmt *S = SP->getStmt();
937 N = N->getFirstPred();
943 const Stmt *LoopBody =
nullptr;
945 case Stmt::CXXForRangeStmtClass: {
946 const auto *FR = cast<CXXForRangeStmt>(Term);
951 LoopBody = FR->getBody();
954 case Stmt::ForStmtClass: {
955 const auto *FS = cast<ForStmt>(Term);
958 LoopBody = FS->getBody();
961 case Stmt::ObjCForCollectionStmtClass: {
962 const auto *FC = cast<ObjCForCollectionStmt>(Term);
963 LoopBody = FC->getBody();
966 case Stmt::WhileStmtClass:
967 LoopBody = cast<WhileStmt>(Term)->getBody();
977 PathDiagnosticLocation &PrevLoc,
978 PathDiagnosticLocation NewLoc) {
979 if (!NewLoc.isValid())
986 if (!PrevLoc.isValid() || !PrevLoc.asLocation().isValid()) {
993 if (NewLoc.asStmt() && NewLoc.asStmt() == PrevLoc.asStmt())
997 std::make_shared<PathDiagnosticControlFlowPiece>(NewLoc, PrevLoc));
1005 if (
const auto *FS = dyn_cast_or_null<ObjCForCollectionStmt>(S))
1006 return FS->getElement();
1013 "Loop body skipped when range is empty";
1015 "Loop body skipped when collection is empty";
1017 static std::unique_ptr<FilesToLineNumsMap>
1026 PathDiagnosticLocation &PrevLoc,
1027 PathDiagnosticBuilder &PDB,
1031 bool AddPathEdges) {
1057 bool VisitedEntireCall = PD.isWithinCall();
1060 PathDiagnosticCallPiece *C;
1061 if (VisitedEntireCall) {
1062 C = cast<PathDiagnosticCallPiece>(PD.getActivePath().front().get());
1064 const Decl *Caller = CE->getLocationContext()->getDecl();
1070 assert(PD.getActivePath().size() == 1 &&
1071 PD.getActivePath().front().get() == C);
1072 LCM[&PD.getActivePath()] =
nullptr;
1077 assert(LCM[&C->path] ==
nullptr ||
1078 LCM[&C->path] == CE->getCalleeContext());
1079 LCM[&C->path] = CE->getCalleeContext();
1085 NewLC = N->getLocationContext();
1089 C->setCallee(*CE, SM);
1092 PrevLoc = C->getLocation();
1094 if (!CallStack.empty()) {
1095 assert(CallStack.back().first == C);
1096 CallStack.pop_back();
1105 PDB.LC = N->getLocationContext();
1109 assert(!LCM[&PD.getActivePath()] || LCM[&PD.getActivePath()] == PDB.LC);
1110 LCM[&PD.getActivePath()] = PDB.LC;
1120 LCM[&C->path] = CE->getCalleeContext();
1123 const Stmt *S = CE->getCalleeContext()->getCallSite();
1125 if (
const auto *Ex = dyn_cast_or_null<Expr>(S)) {
1127 N->getState().get(), Ex,
1128 N->getLocationContext());
1132 PrevLoc.invalidate();
1136 PD.getActivePath().push_front(std::move(C));
1139 PD.pushActivePath(&P->path);
1150 if (
const Expr *Ex = PS->getStmtAs<
Expr>())
1152 N->getState().get(), Ex,
1153 N->getLocationContext());
1158 if (!isa<ObjCForCollectionStmt>(PS->getStmt())) {
1159 PathDiagnosticLocation L =
1160 PathDiagnosticLocation(PS->getStmt(),
SM, PDB.LC);
1166 if (!AddPathEdges) {
1173 if (
const ExplodedNode *NextNode = N->getFirstPred()) {
1176 if (CallerCtx != CalleeCtx && AddPathEdges) {
1178 N->getState().get(), CalleeCtx);
1183 if (
const Stmt *Loop = BE->getSrc()->getLoopTarget()) {
1184 PathDiagnosticLocation L(Loop, SM, PDB.LC);
1185 const Stmt *Body =
nullptr;
1187 if (
const auto *FS = dyn_cast<ForStmt>(Loop))
1188 Body = FS->getBody();
1189 else if (
const auto *WS = dyn_cast<WhileStmt>(Loop))
1190 Body = WS->getBody();
1191 else if (
const auto *OFS = dyn_cast<ObjCForCollectionStmt>(Loop)) {
1192 Body = OFS->getBody();
1193 }
else if (
const auto *FRS = dyn_cast<CXXForRangeStmt>(Loop)) {
1194 Body = FRS->getBody();
1198 auto p = std::make_shared<PathDiagnosticEventPiece>(
1199 L,
"Looping back to the head " 1201 p->setPrunable(
true);
1204 PD.getActivePath().push_front(std::move(
p));
1206 if (
const auto *CS = dyn_cast_or_null<CompoundStmt>(Body)) {
1212 const CFGBlock *BSrc = BE->getSrc();
1215 if (
const Stmt *Term = BSrc->getTerminatorStmt()) {
1223 const char *str =
nullptr;
1226 if (!IsInLoopBody) {
1227 if (isa<ObjCForCollectionStmt>(Term)) {
1229 }
else if (isa<CXXForRangeStmt>(Term)) {
1240 PathDiagnosticLocation L(TermCond ? TermCond : Term, SM, PDB.LC);
1241 auto PE = std::make_shared<PathDiagnosticEventPiece>(L, str);
1242 PE->setPrunable(
true);
1245 PD.getActivePath().push_front(std::move(PE));
1247 }
else if (isa<BreakStmt>(Term) || isa<ContinueStmt>(Term) ||
1248 isa<GotoStmt>(Term)) {
1249 PathDiagnosticLocation L(Term, SM, PDB.LC);
1256 static std::unique_ptr<PathDiagnostic>
1258 const BugType &BT = R->getBugType();
1259 return llvm::make_unique<PathDiagnostic>(
1260 R->getBugType().getCheckName(), R->getDeclWithIssue(),
1261 R->getBugType().getName(), R->getDescription(),
1262 R->getShortDescription(
false), BT.getCategory(),
1263 R->getUniqueingLocation(), R->getUniqueingDecl(),
1277 if (isa<FullExpr>(S) ||
1278 isa<CXXBindTemporaryExpr>(S) ||
1279 isa<SubstNonTypeTemplateParmExpr>(S))
1290 case Stmt::BinaryOperatorClass: {
1291 const auto *BO = cast<BinaryOperator>(S);
1292 if (!BO->isLogicalOp())
1294 return BO->getLHS() == Cond || BO->getRHS() == Cond;
1296 case Stmt::IfStmtClass:
1297 return cast<IfStmt>(S)->getCond() == Cond;
1298 case Stmt::ForStmtClass:
1299 return cast<ForStmt>(S)->getCond() == Cond;
1300 case Stmt::WhileStmtClass:
1301 return cast<WhileStmt>(S)->getCond() == Cond;
1302 case Stmt::DoStmtClass:
1303 return cast<DoStmt>(S)->getCond() == Cond;
1304 case Stmt::ChooseExprClass:
1305 return cast<ChooseExpr>(S)->getCond() == Cond;
1306 case Stmt::IndirectGotoStmtClass:
1307 return cast<IndirectGotoStmt>(S)->getTarget() == Cond;
1308 case Stmt::SwitchStmtClass:
1309 return cast<SwitchStmt>(S)->getCond() == Cond;
1310 case Stmt::BinaryConditionalOperatorClass:
1311 return cast<BinaryConditionalOperator>(S)->getCond() == Cond;
1312 case Stmt::ConditionalOperatorClass: {
1313 const auto *CO = cast<ConditionalOperator>(S);
1314 return CO->getCond() == Cond ||
1315 CO->getLHS() == Cond ||
1316 CO->getRHS() == Cond;
1318 case Stmt::ObjCForCollectionStmtClass:
1319 return cast<ObjCForCollectionStmt>(S)->getElement() == Cond;
1320 case Stmt::CXXForRangeStmtClass: {
1321 const auto *FRS = cast<CXXForRangeStmt>(S);
1322 return FRS->getCond() == Cond || FRS->getRangeInit() == Cond;
1330 if (
const auto *FS = dyn_cast<ForStmt>(FL))
1331 return FS->getInc() == S || FS->getInit() == S;
1332 if (
const auto *FRS = dyn_cast<CXXForRangeStmt>(FL))
1333 return FRS->getInc() == S || FRS->getRangeStmt() == S ||
1334 FRS->getLoopVarStmt() || FRS->getRangeInit() == S;
1347 PathPieces::iterator Prev = pieces.end();
1348 for (PathPieces::iterator I = pieces.begin(), E = Prev; I != E;
1350 auto *Piece = dyn_cast<PathDiagnosticControlFlowPiece>(I->get());
1355 PathDiagnosticLocation SrcLoc = Piece->getStartLocation();
1358 PathDiagnosticLocation NextSrcContext = SrcLoc;
1359 const Stmt *InnerStmt =
nullptr;
1360 while (NextSrcContext.isValid() && NextSrcContext.asStmt() != InnerStmt) {
1361 SrcContexts.push_back(NextSrcContext);
1362 InnerStmt = NextSrcContext.asStmt();
1371 const Stmt *Dst = Piece->getEndLocation().getStmtOrNull();
1375 PathDiagnosticLocation DstContext =
1377 if (!DstContext.isValid() || DstContext.asStmt() == Dst)
1381 if (llvm::find(SrcContexts, DstContext) != SrcContexts.end())
1385 Piece->setStartLocation(DstContext);
1390 auto *PrevPiece = dyn_cast<PathDiagnosticControlFlowPiece>(Prev->get());
1393 if (
const Stmt *PrevSrc =
1394 PrevPiece->getStartLocation().getStmtOrNull()) {
1396 if (PrevSrcParent ==
1398 PrevPiece->setEndLocation(DstContext);
1409 std::make_shared<PathDiagnosticControlFlowPiece>(SrcLoc, DstContext);
1411 I = pieces.insert(I, std::move(
P));
1427 for (PathPieces::iterator I = pieces.begin(), E = pieces.end(); I != E; ++I) {
1428 const auto *PieceI = dyn_cast<PathDiagnosticControlFlowPiece>(I->get());
1433 const Stmt *s1Start = PieceI->getStartLocation().getStmtOrNull();
1434 const Stmt *s1End = PieceI->getEndLocation().getStmtOrNull();
1436 if (!s1Start || !s1End)
1439 PathPieces::iterator NextI = I; ++NextI;
1443 PathDiagnosticControlFlowPiece *PieceNextI =
nullptr;
1449 const auto *EV = dyn_cast<PathDiagnosticEventPiece>(NextI->get());
1451 StringRef S = EV->getString();
1460 PieceNextI = dyn_cast<PathDiagnosticControlFlowPiece>(NextI->get());
1467 const Stmt *s2Start = PieceNextI->getStartLocation().getStmtOrNull();
1468 const Stmt *s2End = PieceNextI->getEndLocation().getStmtOrNull();
1470 if (!s2Start || !s2End || s1End != s2Start)
1475 if (!(isa<ForStmt>(s1Start) || isa<WhileStmt>(s1Start) ||
1476 isa<IfStmt>(s1Start) || isa<ObjCForCollectionStmt>(s1Start) ||
1477 isa<CXXForRangeStmt>(s1Start)))
1486 PieceNextI->setStartLocation(PieceI->getStartLocation());
1487 I = pieces.erase(I);
1502 if (FID != SM.
getFileID(ExpansionRange.getEnd()))
1506 const llvm::MemoryBuffer *Buffer = SM.
getBuffer(FID, &Invalid);
1510 unsigned BeginOffset = SM.
getFileOffset(ExpansionRange.getBegin());
1511 unsigned EndOffset = SM.
getFileOffset(ExpansionRange.getEnd());
1512 StringRef Snippet = Buffer->getBuffer().slice(BeginOffset, EndOffset);
1518 if (Snippet.find_first_of(
"\r\n") != StringRef::npos)
1522 return Snippet.size();
1548 for (PathPieces::iterator I = Path.begin(), E = Path.end(); I != E; ) {
1550 const auto *PieceI = dyn_cast<PathDiagnosticControlFlowPiece>(I->get());
1557 const Stmt *s1Start = PieceI->getStartLocation().getStmtOrNull();
1558 const Stmt *s1End = PieceI->getEndLocation().getStmtOrNull();
1560 PathPieces::iterator NextI = I; ++NextI;
1564 const auto *PieceNextI =
1565 dyn_cast<PathDiagnosticControlFlowPiece>(NextI->get());
1568 if (isa<PathDiagnosticEventPiece>(NextI->get())) {
1572 PieceNextI = dyn_cast<PathDiagnosticControlFlowPiece>(NextI->get());
1581 const Stmt *s2Start = PieceNextI->getStartLocation().getStmtOrNull();
1582 const Stmt *s2End = PieceNextI->getEndLocation().getStmtOrNull();
1584 if (s1Start && s2Start && s1Start == s2End && s2Start == s1End) {
1585 const size_t MAX_SHORT_LINE_LENGTH = 80;
1587 if (s1Length && *s1Length <= MAX_SHORT_LINE_LENGTH) {
1589 if (s2Length && *s2Length <= MAX_SHORT_LINE_LENGTH) {
1591 I = Path.erase(NextI);
1614 bool erased =
false;
1616 for (PathPieces::iterator I = path.begin(), E = path.end(); I != E;
1620 const auto *PieceI = dyn_cast<PathDiagnosticControlFlowPiece>(I->get());
1625 const Stmt *start = PieceI->getStartLocation().getStmtOrNull();
1626 const Stmt *end = PieceI->getEndLocation().getStmtOrNull();
1644 std::swap(SecondLoc, FirstLoc);
1653 const size_t MAX_PUNY_EDGE_LENGTH = 2;
1654 if (*ByteWidth <= MAX_PUNY_EDGE_LENGTH) {
1666 for (PathPieces::iterator I = path.begin(), E = path.end(); I != E; ++I) {
1667 const auto *PieceI = dyn_cast<PathDiagnosticEventPiece>(I->get());
1672 PathPieces::iterator NextI = I; ++NextI;
1676 const auto *PieceNextI = dyn_cast<PathDiagnosticEventPiece>(NextI->get());
1682 if (PieceI->getString() == PieceNextI->getString()) {
1691 bool hasChanges =
false;
1696 for (PathPieces::iterator I = path.begin(), E = path.end(); I != E; ) {
1698 if (
auto *CallI = dyn_cast<PathDiagnosticCallPiece>(I->get())) {
1701 if (!OCS.count(CallI)) {
1710 auto *PieceI = dyn_cast<PathDiagnosticControlFlowPiece>(I->get());
1717 const Stmt *s1Start = PieceI->getStartLocation().getStmtOrNull();
1718 const Stmt *s1End = PieceI->getEndLocation().getStmtOrNull();
1722 PathPieces::iterator NextI = I; ++NextI;
1726 const auto *PieceNextI = dyn_cast<PathDiagnosticControlFlowPiece>(NextI->get());
1733 const Stmt *s2Start = PieceNextI->getStartLocation().getStmtOrNull();
1734 const Stmt *s2End = PieceNextI->getEndLocation().getStmtOrNull();
1752 if (level1 && level1 == level2 && level1 == level3 && level1 == level4) {
1753 PieceI->setEndLocation(PieceNextI->getEndLocation());
1766 if (s1End && s1End == s2Start && level2) {
1767 bool removeEdge =
false;
1793 else if (s1Start && s2End &&
1806 else if (s1Start && s2End &&
1808 SourceRange EdgeRange(PieceI->getEndLocation().asLocation(),
1809 PieceI->getStartLocation().asLocation());
1816 PieceI->setEndLocation(PieceNextI->getEndLocation());
1830 if (s1End == s2Start) {
1831 const auto *FS = dyn_cast_or_null<ObjCForCollectionStmt>(level3);
1832 if (FS && FS->getCollection()->IgnoreParens() == s2Start &&
1833 s2End == FS->getElement()) {
1834 PieceI->setEndLocation(PieceNextI->getEndLocation());
1871 const auto *FirstEdge =
1872 dyn_cast<PathDiagnosticControlFlowPiece>(Path.front().get());
1876 const Decl *D = LCM[&Path]->getDecl();
1878 if (FirstEdge->getStartLocation() != EntryLoc)
1885 std::vector<std::shared_ptr<PathDiagnosticPiece>>>;
1889 PathDiagnostic &PD) {
1891 PathPieces path = PD.path.flatten(
true);
1894 for (
const auto &
P : path) {
1895 FullSourceLoc Loc =
P->getLocation().asLocation().getExpansionLoc();
1899 ExecutedLines[FID].insert(LineNo);
1917 PathDiagnosticBuilder &PDB,
1918 const ExplodedNode *ErrorNode,
1924 BugReport *R = PDB.getBugReport();
1931 if (GenerateDiagnostics) {
1932 auto EndNotes = VisitorsDiagnostics.find(ErrorNode);
1933 std::shared_ptr<PathDiagnosticPiece> LastPiece;
1934 if (EndNotes != VisitorsDiagnostics.end()) {
1935 assert(!EndNotes->second.empty());
1936 LastPiece = EndNotes->second[0];
1938 LastPiece = BugReporterVisitor::getDefaultEndPath(PDB, ErrorNode, *R);
1940 PD->setEndOfPath(LastPiece);
1943 PathDiagnosticLocation PrevLoc = PD->getLocation();
1944 const ExplodedNode *NextNode = ErrorNode->getFirstPred();
1946 if (GenerateDiagnostics)
1948 NextNode, *PD, PrevLoc, PDB, LCM, CallStack, IE, AddPathEdges);
1950 auto VisitorNotes = VisitorsDiagnostics.find(NextNode);
1951 NextNode = NextNode->getFirstPred();
1952 if (!GenerateDiagnostics || VisitorNotes == VisitorsDiagnostics.end())
1957 std::set<llvm::FoldingSetNodeID> DeduplicationSet;
1960 for (
const auto &Note : VisitorNotes->second) {
1961 llvm::FoldingSetNodeID
ID;
1963 auto P = DeduplicationSet.insert(ID);
1968 addEdgeToPath(PD->getActivePath(), PrevLoc, Note->getLocation());
1970 PD->getActivePath().push_front(Note);
1985 if (!PD->path.empty()) {
1986 if (R->shouldPrunePath() && Opts.ShouldPrunePaths) {
1987 bool stillHasNotes =
1989 assert(stillHasNotes);
1990 (void)stillHasNotes;
1994 if (!Opts.ShouldAddPopUpNotes)
2021 if (GenerateDiagnostics && Opts.ShouldDisplayMacroExpansions)
2032 void BugType::anchor() {}
2034 void BuiltinBug::anchor() {}
2040 void BugReport::NodeResolver::anchor() {}
2046 llvm::FoldingSetNodeID
ID;
2047 visitor->Profile(ID);
2049 void *InsertPos =
nullptr;
2050 if (CallbacksSet.FindNodeOrInsertPos(ID, InsertPos)) {
2054 Callbacks.push_back(std::move(visitor));
2062 while (!interestingSymbols.empty()) {
2063 popInterestingSymbolsAndRegions();
2069 return DeclWithIssue;
2080 hash.AddPointer(&BT);
2081 hash.AddString(Description);
2085 }
else if (Location.isValid()) {
2086 Location.Profile(hash);
2093 if (!
range.isValid())
2095 hash.AddInteger(
range.getBegin().getRawEncoding());
2096 hash.AddInteger(
range.getEnd().getRawEncoding());
2104 getInterestingSymbols().insert(sym);
2106 if (
const auto *meta = dyn_cast<SymbolMetadata>(sym))
2107 getInterestingRegions().insert(meta->getRegion());
2115 getInterestingRegions().insert(R);
2117 if (
const auto *SR = dyn_cast<SymbolicRegion>(R))
2118 getInterestingSymbols().insert(SR->getSymbol());
2129 InterestingLocationContexts.insert(LC);
2141 return getInterestingSymbols().count(sym);
2148 bool b = getInterestingRegions().count(R);
2151 if (
const auto *SR = dyn_cast<SymbolicRegion>(R))
2152 return getInterestingSymbols().count(SR->getSymbol());
2159 return InterestingLocationContexts.count(LC);
2162 void BugReport::lazyInitializeInterestingSets() {
2163 if (interestingSymbols.empty()) {
2164 interestingSymbols.push_back(
new Symbols());
2165 interestingRegions.push_back(
new Regions());
2170 lazyInitializeInterestingSets();
2171 return *interestingSymbols.back();
2175 lazyInitializeInterestingSets();
2176 return *interestingRegions.back();
2179 void BugReport::pushInterestingSymbolsAndRegions() {
2180 interestingSymbols.push_back(
new Symbols(getInterestingSymbols()));
2181 interestingRegions.push_back(
new Regions(getInterestingRegions()));
2184 void BugReport::popInterestingSymbolsAndRegions() {
2185 delete interestingSymbols.pop_back_val();
2186 delete interestingRegions.pop_back_val();
2194 const Stmt *S =
nullptr;
2198 if (BE->getBlock() == &Exit)
2210 if (Ranges.empty()) {
2211 if (
const auto *E = dyn_cast_or_null<Expr>(getStmt()))
2212 addRange(E->getSourceRange());
2218 if (Ranges.size() == 1 && !Ranges.begin()->isValid())
2221 return llvm::make_range(Ranges.begin(), Ranges.end());
2226 assert(!Location.isValid() &&
2227 "Either Location or ErrorNode should be specified but not both.");
2231 assert(Location.isValid());
2254 for (
const auto I : EQClassesVector)
2259 if (BugTypes.isEmpty())
2264 for (
const auto EQ : EQClassesVector)
2271 llvm::DeleteContainerSeconds(StrBugTypes);
2274 BugTypes = F.getEmptySet();
2288 std::unique_ptr<ExplodedGraph> Graph;
2294 class TrimmedGraph {
2297 using PriorityMapTy = llvm::DenseMap<const ExplodedNode *, unsigned>;
2299 PriorityMapTy PriorityMap;
2301 using NodeIndexPair = std::pair<const ExplodedNode *, size_t>;
2305 std::unique_ptr<ExplodedGraph> G;
2308 template <
bool Descending>
2309 class PriorityCompare {
2310 const PriorityMapTy &PriorityMap;
2313 PriorityCompare(
const PriorityMapTy &M) : PriorityMap(M) {}
2316 PriorityMapTy::const_iterator LI = PriorityMap.find(LHS);
2317 PriorityMapTy::const_iterator RI = PriorityMap.find(RHS);
2318 PriorityMapTy::const_iterator E = PriorityMap.end();
2325 return Descending ? LI->second > RI->second
2326 : LI->second < RI->second;
2329 bool operator()(
const NodeIndexPair &LHS,
const NodeIndexPair &RHS)
const {
2330 return (*
this)(LHS.first, RHS.first);
2338 bool popNextReportGraph(ReportGraph &GraphWrapper);
2343 TrimmedGraph::TrimmedGraph(
const ExplodedGraph *OriginalGraph,
2348 G = OriginalGraph->
trim(Nodes, &ForwardMap, &InverseMap);
2353 llvm::SmallPtrSet<const ExplodedNode *, 32> RemainingNodes;
2355 for (
unsigned i = 0, count = Nodes.size();
i < count; ++
i) {
2356 if (
const ExplodedNode *NewNode = ForwardMap.lookup(Nodes[
i])) {
2357 ReportNodes.push_back(std::make_pair(NewNode, i));
2358 RemainingNodes.insert(NewNode);
2362 assert(!RemainingNodes.empty() &&
"No error node found in the trimmed graph");
2365 std::queue<const ExplodedNode *> WS;
2367 assert(G->num_roots() == 1);
2368 WS.push(*G->roots_begin());
2369 unsigned Priority = 0;
2371 while (!WS.empty()) {
2375 PriorityMapTy::iterator PriorityEntry;
2377 std::tie(PriorityEntry, IsNew) =
2378 PriorityMap.insert(std::make_pair(Node, Priority));
2382 assert(PriorityEntry->second <= Priority);
2386 if (RemainingNodes.erase(Node))
2387 if (RemainingNodes.empty())
2397 llvm::sort(ReportNodes, PriorityCompare<true>(PriorityMap));
2400 bool TrimmedGraph::popNextReportGraph(ReportGraph &GraphWrapper) {
2401 if (ReportNodes.empty())
2405 std::tie(OrigN, GraphWrapper.Index) = ReportNodes.pop_back_val();
2406 assert(PriorityMap.find(OrigN) != PriorityMap.end() &&
2407 "error node not accessible from root");
2411 auto GNew = llvm::make_unique<ExplodedGraph>();
2412 GraphWrapper.BackMap.clear();
2424 InterExplodedGraphMap::const_iterator IMitr = InverseMap.find(OrigN);
2425 assert(IMitr != InverseMap.end() &&
"No mapping to original node.");
2426 GraphWrapper.BackMap[NewN] = IMitr->second;
2432 GraphWrapper.ErrorNode = NewN;
2438 GNew->addRoot(NewN);
2445 PriorityCompare<false>(PriorityMap));
2448 GraphWrapper.Graph = std::move(GNew);
2457 using MacroStackTy =
2459 std::pair<std::shared_ptr<PathDiagnosticMacroPiece>,
SourceLocation>>;
2461 using PiecesTy = std::vector<std::shared_ptr<PathDiagnosticPiece>>;
2463 MacroStackTy MacroStack;
2466 for (PathPieces::const_iterator I = path.begin(), E = path.end();
2468 const auto &piece = *I;
2471 if (
auto *call = dyn_cast<PathDiagnosticCallPiece>(&*piece)) {
2476 const FullSourceLoc Loc = piece->getLocation().asLocation();
2480 SourceLocation InstantiationLoc = Loc.
isMacroID() ?
2486 Pieces.push_back(piece);
2493 if (!MacroStack.empty() && InstantiationLoc == MacroStack.back().second) {
2494 MacroStack.back().first->subPieces.push_back(piece);
2500 std::shared_ptr<PathDiagnosticMacroPiece> MacroGroup;
2502 SourceLocation ParentInstantiationLoc = InstantiationLoc.
isMacroID() ?
2507 while (!MacroStack.empty()) {
2508 if (InstantiationLoc == MacroStack.back().second) {
2509 MacroGroup = MacroStack.back().first;
2513 if (ParentInstantiationLoc == MacroStack.back().second) {
2514 MacroGroup = MacroStack.back().first;
2518 MacroStack.pop_back();
2521 if (!MacroGroup || ParentInstantiationLoc == MacroStack.back().second) {
2523 auto NewGroup = std::make_shared<PathDiagnosticMacroPiece>(
2527 MacroGroup->subPieces.push_back(NewGroup);
2529 assert(InstantiationLoc.
isFileID());
2530 Pieces.push_back(NewGroup);
2533 MacroGroup = NewGroup;
2534 MacroStack.push_back(std::make_pair(MacroGroup, InstantiationLoc));
2538 MacroGroup->subPieces.push_back(piece);
2544 path.insert(path.end(), Pieces.begin(), Pieces.end());
2550 static std::unique_ptr<VisitorsDiagnosticsTy>
2551 generateVisitorsDiagnostics(BugReport *R,
const ExplodedNode *ErrorNode,
2553 auto Notes = llvm::make_unique<VisitorsDiagnosticsTy>();
2558 const ExplodedNode *NextNode = ErrorNode->getFirstPred();
2563 E = R->visitor_end();
2565 visitors.push_back(std::move(*I));
2569 const ExplodedNode *Pred = NextNode->getFirstPred();
2571 std::shared_ptr<PathDiagnosticPiece> LastPiece;
2572 for (
auto &
V : visitors) {
2573 V->finalizeVisitor(BRC, ErrorNode, *R);
2575 if (
auto Piece =
V->getEndPath(BRC, ErrorNode, *R)) {
2576 assert(!LastPiece &&
2577 "There can only be one final piece in a diagnostic.");
2578 LastPiece = std::move(Piece);
2579 (*Notes)[ErrorNode].push_back(LastPiece);
2585 for (
auto &
V : visitors) {
2586 auto P =
V->VisitNode(NextNode, BRC, *R);
2588 (*Notes)[NextNode].push_back(std::move(
P));
2604 std::pair<BugReport*, std::unique_ptr<VisitorsDiagnosticsTy>> findValidReport(
2605 TrimmedGraph &TrimG,
2606 ReportGraph &ErrorGraph,
2609 GRBugReporter &Reporter) {
2611 while (TrimG.popNextReportGraph(ErrorGraph)) {
2613 assert(ErrorGraph.Index < bugReports.size());
2614 BugReport *R = bugReports[ErrorGraph.Index];
2615 assert(R &&
"No original report found for sliced graph.");
2616 assert(R->isValid() &&
"Report selected by trimmed graph marked invalid.");
2617 const ExplodedNode *ErrorNode = ErrorGraph.ErrorNode;
2621 R->addVisitor(llvm::make_unique<LikelyFalsePositiveSuppressionBRVisitor>());
2624 R->addVisitor(llvm::make_unique<NilReceiverBRVisitor>());
2625 R->addVisitor(llvm::make_unique<ConditionBRVisitor>());
2626 R->addVisitor(llvm::make_unique<TagVisitor>());
2631 std::unique_ptr<VisitorsDiagnosticsTy> visitorNotes =
2632 generateVisitorsDiagnostics(R, ErrorNode, BRC);
2635 if (Opts.ShouldCrosscheckWithZ3) {
2639 R->addVisitor(llvm::make_unique<FalsePositiveRefutationBRVisitor>());
2643 generateVisitorsDiagnostics(R, ErrorGraph.ErrorNode, BRC);
2648 return std::make_pair(R, std::move(visitorNotes));
2652 return std::make_pair(
nullptr, llvm::make_unique<VisitorsDiagnosticsTy>());
2655 std::unique_ptr<DiagnosticForConsumerMapTy>
2659 assert(!bugReports.empty());
2661 auto Out = llvm::make_unique<DiagnosticForConsumerMapTy>();
2662 bool HasValid =
false;
2664 for (
const auto I : bugReports) {
2667 errorNodes.push_back(I->getErrorNode());
2670 errorNodes.push_back(
nullptr);
2679 TrimmedGraph TrimG(&
getGraph(), errorNodes);
2680 ReportGraph ErrorGraph;
2681 auto ReportInfo = findValidReport(TrimG, ErrorGraph, bugReports,
2683 BugReport *R = ReportInfo.first;
2685 if (R && R->isValid()) {
2686 const ExplodedNode *ErrorNode = ErrorGraph.ErrorNode;
2687 for (PathDiagnosticConsumer *PC : consumers) {
2688 PathDiagnosticBuilder PDB(*
this, R, ErrorGraph.BackMap, PC);
2690 PC->getGenerationScheme(), PDB, ErrorNode, *ReportInfo.second);
2691 (*Out)[PC] = std::move(PD);
2699 BugTypes = F.add(BugTypes, BT);
2703 if (
const ExplodedNode *E = R->getErrorNode()) {
2706 assert((E->isSink() || E->getLocation().getTag()) &&
2707 "Error node must either be a sink or have a tag");
2710 E->getLocationContext()->getAnalysisDeclContext();
2721 assert(ValidSourceLoc);
2724 if (!ValidSourceLoc)
2728 llvm::FoldingSetNodeID
ID;
2732 const BugType& BT = R->getBugType();
2735 BugReportEquivClass* EQ = EQClasses.FindNodeOrInsertPos(ID, InsertPos);
2738 EQ =
new BugReportEquivClass(std::move(R));
2739 EQClasses.InsertNode(EQ, InsertPos);
2740 EQClassesVector.push_back(EQ);
2742 EQ->AddReport(std::move(R));
2751 struct FRIEC_WLItem {
2752 const ExplodedNode *N;
2755 FRIEC_WLItem(
const ExplodedNode *n)
2756 : N(n), I(N->succ_begin()), E(N->succ_end()) {}
2761 static const CFGBlock *findBlockForNode(
const ExplodedNode *N) {
2764 return BEP->getBlock();
2768 return N->getLocationContext()->getAnalysisDeclContext()
2769 ->getCFGStmtMap()->getBlock(S);
2780 static bool isImmediateSinkBlock(
const CFGBlock *Blk) {
2792 if (isa<CXXThrowExpr>(StmtElm->getStmt()))
2805 static bool isInevitablySinking(
const ExplodedNode *N) {
2806 const CFG &Cfg = N->getCFG();
2808 const CFGBlock *StartBlk = findBlockForNode(N);
2811 if (isImmediateSinkBlock(StartBlk))
2815 llvm::SmallPtrSet<const CFGBlock *, 32> Visited;
2817 DFSWorkList.push_back(StartBlk);
2818 while (!DFSWorkList.empty()) {
2819 const CFGBlock *Blk = DFSWorkList.back();
2820 DFSWorkList.pop_back();
2821 Visited.insert(Blk);
2830 for (
const auto &Succ : Blk->
succs()) {
2831 if (
const CFGBlock *SuccBlk = Succ.getReachableBlock()) {
2832 if (!isImmediateSinkBlock(SuccBlk) && !Visited.count(SuccBlk)) {
2835 DFSWorkList.push_back(SuccBlk);
2846 FindReportInEquivalenceClass(BugReportEquivClass& EQ,
2850 const BugType& BT = I->getBugType();
2855 if (!BT.isSuppressOnSink()) {
2857 for (
auto &I : EQ) {
2858 const ExplodedNode *N = I.getErrorNode();
2861 bugReports.push_back(R);
2873 BugReport *exampleReport =
nullptr;
2875 for (; I != E; ++I) {
2876 const ExplodedNode *errorNode = I->getErrorNode();
2880 if (errorNode->isSink()) {
2882 "BugType::isSuppressSink() should not be 'true' for sink end nodes");
2885 if (errorNode->succ_empty()) {
2886 bugReports.push_back(&*I);
2888 exampleReport = &*I;
2896 if (isInevitablySinking(errorNode))
2901 using WLItem = FRIEC_WLItem;
2904 llvm::DenseMap<const ExplodedNode *, unsigned> Visited;
2907 WL.push_back(errorNode);
2908 Visited[errorNode] = 1;
2910 while (!WL.empty()) {
2911 WLItem &WI = WL.back();
2912 assert(!WI.N->succ_empty());
2914 for (; WI.I != WI.E; ++WI.I) {
2915 const ExplodedNode *Succ = *WI.I;
2917 if (Succ->succ_empty()) {
2919 if (!Succ->isSink()) {
2920 bugReports.push_back(&*I);
2922 exampleReport = &*I;
2931 unsigned &mark = Visited[Succ];
2941 if (!WL.empty() && &WL.back() == &WI)
2948 return exampleReport;
2951 void BugReporter::FlushReport(BugReportEquivClass& EQ) {
2953 BugReport *report = FindReportInEquivalenceClass(EQ, bugReports);
2958 std::unique_ptr<DiagnosticForConsumerMapTy> Diagnostics =
2959 generateDiagnosticForConsumerMap(report, Consumers, bugReports);
2961 for (
auto &
P : *Diagnostics) {
2962 PathDiagnosticConsumer *Consumer =
P.first;
2963 std::unique_ptr<PathDiagnostic> &PD =
P.second;
2967 if (PD->path.empty()) {
2969 auto piece = llvm::make_unique<PathDiagnosticEventPiece>(
2970 L, report->getDescription());
2972 piece->addRange(Range);
2973 PD->setEndOfPath(std::move(piece));
2976 PathPieces &Pieces = PD->getMutablePieces();
2980 for (
auto I = report->getNotes().rbegin(),
2981 E = report->getNotes().rend(); I != E; ++I) {
2982 PathDiagnosticNotePiece *Piece = I->get();
2983 auto ConvertedPiece = std::make_shared<PathDiagnosticEventPiece>(
2984 Piece->getLocation(), Piece->getString());
2985 for (
const auto &R: Piece->getRanges())
2986 ConvertedPiece->addRange(R);
2988 Pieces.push_front(std::move(ConvertedPiece));
2991 for (
auto I = report->getNotes().rbegin(),
2992 E = report->getNotes().rend(); I != E; ++I)
2993 Pieces.push_front(*I);
2998 for (
const auto &
i : Meta)
3002 Consumer->HandlePathDiagnostic(std::move(PD));
3008 static void populateExecutedLinesWithFunctionSignature(
3013 if (
const auto FD = dyn_cast<FunctionDecl>(Signature)) {
3014 SignatureSourceRange = FD->getSourceRange();
3015 }
else if (
const auto OD = dyn_cast<ObjCMethodDecl>(Signature)) {
3016 SignatureSourceRange = OD->getSourceRange();
3022 : SignatureSourceRange.
getEnd();
3029 for (
unsigned Line = StartLine;
Line <= EndLine;
Line++)
3030 ExecutedLines[FID].insert(
Line);
3033 static void populateExecutedLinesWithStmt(
3042 ExecutedLines[FID].insert(LineNo);
3047 static std::unique_ptr<FilesToLineNumsMap>
3049 auto ExecutedLines = llvm::make_unique<FilesToLineNumsMap>();
3052 if (N->getFirstPred() ==
nullptr) {
3054 const Decl *D = N->getLocationContext()->getDecl();
3055 populateExecutedLinesWithFunctionSignature(D, SM, *ExecutedLines);
3056 }
else if (
auto CE = N->getLocationAs<
CallEnter>()) {
3058 const Decl* D = CE->getCalleeContext()->getDecl();
3059 populateExecutedLinesWithFunctionSignature(D, SM, *ExecutedLines);
3061 populateExecutedLinesWithStmt(S, SM, *ExecutedLines);
3064 const Stmt *
P = N->getParentMap().getParent(S);
3069 if (
const auto *RS = dyn_cast_or_null<ReturnStmt>(P)) {
3070 populateExecutedLinesWithStmt(RS, SM, *ExecutedLines);
3071 P = N->getParentMap().getParent(RS);
3074 if (P && (isa<SwitchCase>(P) || isa<LabelStmt>(P)))
3075 populateExecutedLinesWithStmt(P, SM, *ExecutedLines);
3078 N = N->getFirstPred();
3080 return ExecutedLines;
3083 std::unique_ptr<DiagnosticForConsumerMapTy>
3084 BugReporter::generateDiagnosticForConsumerMap(
3088 if (!report->isPathSensitive()) {
3089 auto Out = llvm::make_unique<DiagnosticForConsumerMapTy>();
3090 for (
auto *Consumer : consumers)
3100 assert(!bugReports.empty());
3101 MaxBugClassSize.updateMax(bugReports.size());
3102 std::unique_ptr<DiagnosticForConsumerMapTy> Out =
3103 generatePathDiagnostics(consumers, bugReports);
3108 MaxValidBugClassSize.updateMax(bugReports.size());
3113 for (
auto const &
P : *Out)
3114 if (Opts.ShouldReportIssuesInMainSourceFile && !Opts.
AnalyzeAll)
3115 P.second->resetDiagnosticLocationToMainFile();
3121 const CheckerBase *Checker,
3122 StringRef Name, StringRef
Category,
3123 StringRef Str, PathDiagnosticLocation Loc,
3125 EmitBasicReport(DeclWithIssue, Checker->getCheckName(), Name,
Category, Str,
3130 CheckName CheckName,
3131 StringRef
name, StringRef category,
3132 StringRef str, PathDiagnosticLocation Loc,
3135 BugType *BT = getBugTypeForName(CheckName,
name, category);
3136 auto R = llvm::make_unique<BugReport>(*BT, str, Loc);
3137 R->setDeclWithIssue(DeclWithIssue);
3141 emitReport(std::move(R));
3144 BugType *BugReporter::getBugTypeForName(CheckName CheckName, StringRef
name,
3145 StringRef category) {
3147 llvm::raw_svector_ostream(fullDesc) << CheckName.getName() <<
":" <<
name 3149 BugType *&BT = StrBugTypes[fullDesc];
3151 BT =
new BugType(CheckName,
name, category);
Indicates that the tracked object is a CF object.
static void removeEdgesToDefaultInitializers(PathPieces &Pieces)
Remove edges in and out of C++ default initializer expressions.
bool isWrittenInSameFile(SourceLocation Loc1, SourceLocation Loc2) const
Returns true if the spelling locations for both SourceLocations are part of the same file buffer...
static DiagnosticBuilder Diag(DiagnosticsEngine *Diags, const LangOptions &Features, FullSourceLoc TokLoc, const char *TokBegin, const char *TokRangeBegin, const char *TokRangeEnd, unsigned DiagID)
Produce a diagnostic highlighting some portion of a literal.
static void removeRedundantMsgs(PathPieces &path)
An optimization pass over PathPieces that removes redundant diagnostics generated by both ConditionBR...
static bool isContainedByStmt(ParentMap &PM, const Stmt *S, const Stmt *SubS)
static Optional< size_t > getLengthOnSingleLine(SourceManager &SM, SourceRange Range)
Returns the number of bytes in the given (character-based) SourceRange.
if(T->getSizeExpr()) TRY_TO(TraverseStmt(T -> getSizeExpr()))
MemRegion - The root abstract class for all memory regions.
static bool removeUnneededCalls(PathPieces &pieces, BugReport *R, LocationContextMap &LCM, bool IsInteresting=false)
Recursively scan through a path and prune out calls and macros pieces that aren't needed...
bool isInteresting(SymbolRef sym)
succ_iterator succ_begin()
virtual Stmt * getBody() const
getBody - If this Decl represents a declaration for a body of code, such as a function or method defi...
AnalyzerOptions & getAnalyzerOptions()
Stmt - This represents one statement.
An instance of this object exists for each enum constant that is defined.
Defines the SourceManager interface.
const CFGBlock * getSrc() const
Decl - This represents one declaration (or definition), e.g.
Represents a point when we begin processing an inlined call.
bool isBeforeInTranslationUnit(SourceLocation LHS, SourceLocation RHS) const
Determines the order of 2 source locations in the translation unit.
static void updateExecutedLinesWithDiagnosticPieces(PathDiagnostic &PD)
Populate executes lines with lines containing at least one diagnostics.
Stmt * getParent(Stmt *) const
void Profile(llvm::FoldingSetNodeID &ID) const
static void adjustCallLocations(PathPieces &Pieces, PathDiagnosticLocation *LastCallLocation=nullptr)
Recursively scan through a path and make sure that all call pieces have valid locations.
const ProgramStateRef & getState() const
ArrayRef< ParmVarDecl * >::const_iterator param_const_iterator
virtual PathDiagnosticLocation getLocation(const SourceManager &SM) const
Return the "definitive" location of the reported bug.
static PathDiagnosticLocation createEndBrace(const CompoundStmt *CS, const SourceManager &SM)
Create a location for the end of the compound statement.
unsigned succ_size() const
static bool optimizeEdges(PathPieces &path, SourceManager &SM, OptimizedCallsSet &OCS, LocationContextMap &LCM)
bool isConsumedExpr(Expr *E) const
static const Stmt * GetCurrentOrPreviousStmt(const ExplodedNode *N)
static bool isConditionForTerminator(const Stmt *S, const Stmt *Cond)
Defines the Objective-C statement AST node classes.
static PathDiagnosticLocation createDeclEnd(const LocationContext *LC, const SourceManager &SM)
Constructs a location for the end of the enclosing declaration body.
Represents a parameter to a function.
Defines the clang::Expr interface and subclasses for C++ expressions.
static PathDiagnosticLocation createSingleLocation(const PathDiagnosticLocation &PDL)
Convert the given location into a single kind location.
static void removePiecesWithInvalidLocations(PathPieces &Pieces)
Remove all pieces with invalid locations as these cannot be serialized.
BoundNodesTreeBuilder Nodes
void clearVisitors()
Remove all visitors attached to this bug report.
static std::unique_ptr< PathDiagnostic > generateEmptyDiagnosticForReport(BugReport *R, SourceManager &SM)
succ_iterator succ_begin()
SourceLocation getBeginLoc() const LLVM_READONLY
static PathDiagnosticLocation getEnclosingStmtLocation(const Stmt *S, SourceManager &SMgr, const ParentMap &P, const LocationContext *LC, bool allowNestedContexts)
AnalysisDeclContext contains the context data for the function or method under analysis.
static void removeIdenticalEvents(PathPieces &path)
static const char StrLoopBodyZero[]
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...
static std::unique_ptr< PathDiagnostic > generatePathDiagnosticForConsumer(PathDiagnosticConsumer::PathGenerationScheme ActiveScheme, PathDiagnosticBuilder &PDB, const ExplodedNode *ErrorNode, const VisitorsDiagnosticsTy &VisitorsDiagnostics)
This function is responsible for generating diagnostic pieces that are not provided by bug report vis...
void addPredecessor(ExplodedNode *V, ExplodedGraph &G)
addPredeccessor - Adds a predecessor to the current node, and in tandem add this node as a successor ...
virtual llvm::iterator_range< ranges_iterator > getRanges()
Get the SourceRanges associated with the report.
const Stmt * getStmt() const
llvm::DenseMap< const ExplodedNode *, std::vector< std::shared_ptr< PathDiagnosticPiece > >> VisitorsDiagnosticsTy
llvm::DenseMap< const PathPieces *, const LocationContext * > LocationContextMap
A map from PathDiagnosticPiece to the LocationContext of the inlined function call it represents...
void emitReport(std::unique_ptr< BugReport > R)
Add the given report to the set of reports tracked by BugReporter.
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified...
static bool isJumpToFalseBranch(const BlockEdge *BE)
SourceLocation getExpansionLoc(SourceLocation Loc) const
Given a SourceLocation object Loc, return the expansion location referenced by the ID...
const LocationContext * getLocationContext() const
ExplodedGraph & getGraph()
SmallVector< StringRef, 2 > ExtraTextList
Expr * IgnoreParenCasts() LLVM_READONLY
Skip past any parentheses and casts which might surround this expression until reaching a fixed point...
const Decl * getDeclWithIssue() const
Return the canonical declaration, be it a method or class, where this issue semantically occurred...
static const Stmt * getStmtBeforeCond(ParentMap &PM, const Stmt *Term, const ExplodedNode *N)
static void reversePropagateIntererstingSymbols(BugReport &R, InterestingExprs &IE, const ProgramState *State, const Expr *Ex, const LocationContext *LCtx)
void addVisitor(std::unique_ptr< BugReporterVisitor > visitor)
Add custom or predefined bug report visitors to this report.
SymbolRef getAsSymbol(bool IncludeBaseRegions=false) const
If this SVal wraps a symbol return that SymbolRef.
const ExplodedNode *const * const_succ_iterator
const Stmt * getCallSite() const
VisitorList::iterator visitor_iterator
Represents a single basic block in a source-level CFG.
Represents a point when we finish the call exit sequence (for inlined call).
bool isBodyAutosynthesizedFromModelFile() const
Checks if the body of the Decl is generated by the BodyFarm from a model file.
STATISTIC(MaxBugClassSize, "The maximum number of bug reports in the same equivalence class")
This represents one expression.
Stmt * getTerminatorCondition(bool StripParens=true)
Represents a source-level, intra-procedural CFG that represents the control-flow of a Stmt...
const AnnotatedLine * Line
~GRBugReporter() override
unsigned getLineNumber(bool *Invalid=nullptr) const
bool isImplicit() const
isImplicit - Indicates whether the declaration was implicitly generated by the implementation.
static bool lexicalContains(ParentMap &PM, const Stmt *X, const Stmt *Y)
Return true if X is contained by Y.
static const Stmt * getNextStmt(const ExplodedNode *N)
Retrieve the statement corresponding to the successor node.
void FlushReports()
Generate and flush diagnostics for all bug reports.
const CFGBlock * getDst() const
static void dropFunctionEntryEdge(PathPieces &Path, LocationContextMap &LCM, SourceManager &SM)
Drop the very first edge in a path, which should be a function entry edge.
bool isBodyAutosynthesized() const
Checks if the body of the Decl is generated by the BodyFarm.
SourceLocation getEnd() const
BugReporterContext(GRBugReporter &br, InterExplodedGraphMap &Backmap)
void markInteresting(SymbolRef sym)
static const Stmt * GetPreviousStmt(const ExplodedNode *N)
std::map< FileID, std::set< unsigned > > FilesToLineNumsMap
File IDs mapped to sets of line numbers.
unsigned getExpansionLineNumber(SourceLocation Loc, bool *Invalid=nullptr) const
static void removePopUpNotes(PathPieces &Path)
Same logic as above to remove extra pieces.
ParentMap & getParentMap() const
virtual bool hasBody() const
Returns true if this Decl represents a declaration for a body of code, such as a function or method d...
Only runs visitors, no output generated.
static const Stmt * getStmt(const ExplodedNode *N)
Given an exploded node, retrieve the statement that should be used for the diagnostic location...
unsigned getFileOffset(SourceLocation SpellingLoc) const
Returns the offset from the start of the file that the specified SourceLocation represents.
void Register(const BugType *BT)
static PathDiagnosticLocation createBegin(const Decl *D, const SourceManager &SM)
Create a location for the beginning of the declaration.
static PathDiagnosticEventPiece * eventsDescribeSameCondition(PathDiagnosticEventPiece *X, PathDiagnosticEventPiece *Y)
static void simplifySimpleBranches(PathPieces &pieces)
Move edges from a branch condition to a branch target when the condition is simple.
Encodes a location in the source.
Stmt * getParentIgnoreParens(Stmt *) const
const MemRegion * getAsRegion() const
ExplodedGraph & getGraph()
getGraph - Get the exploded graph created by the analysis engine for the analyzed method or function...
static bool isIncrementOrInitInForLoop(const Stmt *S, const Stmt *FL)
SmallVector< std::unique_ptr< BugReporterVisitor >, 8 > VisitorList
std::shared_ptr< PathDiagnosticControlFlowPiece > generateDiagForGotoOP(const Stmt *S, PathDiagnosticBuilder &PDB, PathDiagnosticLocation &Start)
ProgramPoint getLocation() const
getLocation - Returns the edge associated with the given node.
SVal - This represents a symbolic expression, which can be either an L-value or an R-value...
std::shared_ptr< PathDiagnosticControlFlowPiece > generateDiagForSwitchOP(const ExplodedNode *N, const CFGBlock *Dst, const SourceManager &SM, const LocationContext *LC, PathDiagnosticBuilder &PDB, PathDiagnosticLocation &Start)
static const Stmt * getEnclosingParent(const Stmt *S, const ParentMap &PM)
Used for plist output, used for "arrows" generation.
static void removePunyEdges(PathPieces &path, SourceManager &SM, ParentMap &PM)
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...
ast_type_traits::DynTypedNode Node
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
std::unique_ptr< DiagnosticForConsumerMapTy > generatePathDiagnostics(ArrayRef< PathDiagnosticConsumer *> consumers, ArrayRef< BugReport *> &bugReports) override
bugReports A set of bug reports within a single equivalence class
const llvm::MemoryBuffer * getBuffer(FileID FID, SourceLocation Loc, bool *Invalid=nullptr) const
Return the buffer for the specified FileID.
Dataflow Directional Tag Classes.
bool isValid() const
Return true if this is a valid SourceLocation object.
static const char StrLoopCollectionEmpty[]
std::pair< PathDiagnosticCallPiece *, const ExplodedNode * > StackDiagPair
static void addEdgeToPath(PathPieces &path, PathDiagnosticLocation &PrevLoc, PathDiagnosticLocation NewLoc)
Adds a sanitized control-flow diagnostic edge to a path.
virtual ~BugReporterData()
StmtClass getStmtClass() const
static void updateStackPiecesWithMessage(PathDiagnosticPiece &P, StackDiagVector &CallStack)
Stmt * getTerminatorStmt()
static const Stmt * getTerminatorCondition(const CFGBlock *B)
A customized wrapper for CFGBlock::getTerminatorCondition() which returns the element for ObjCForColl...
static std::unique_ptr< FilesToLineNumsMap > findExecutedLines(SourceManager &SM, const ExplodedNode *N)
const Decl * getDecl() const
llvm::DenseMap< const ExplodedNode *, const ExplodedNode * > InterExplodedGraphMap
static bool isLoop(const Stmt *Term)
FileID getFileID(SourceLocation SpellingLoc) const
Return the FileID for a SourceLocation.
Iterator for iterating over Stmt * arrays that contain only T *.
static void removeContextCycles(PathPieces &Path, SourceManager &SM)
Eliminate two-edge cycles created by addContextEdges().
const LocationContext * getLocationContext() const
virtual void Profile(llvm::FoldingSetNodeID &hash) const
Profile to identify equivalent bug reports for error report coalescing.
const StackFrameContext * getStackFrame() const
CharSourceRange getExpansionRange(SourceLocation Loc) const
Given a SourceLocation object, return the range of tokens covered by the expansion in the ultimate fi...
Stores options for the analyzer from the command line.
static std::shared_ptr< PathDiagnosticCallPiece > construct(const CallExitEnd &CE, const SourceManager &SM)
void generateMinimalDiagForBlockEdge(const ExplodedNode *N, BlockEdge BE, const SourceManager &SM, PathDiagnosticBuilder &PDB, PathDiagnostic &PD)
bool hasNoReturnElement() const
static PathDiagnosticLocation createOperatorLoc(const BinaryOperator *BO, const SourceManager &SM)
Create the location for the operator of the binary expression.
X
Add a minimal nested name specifier fixit hint to allow lookup of a tag name from an outer enclosing ...
llvm::ilist< BugReport >::iterator iterator
ProgramStateManager & getStateManager()
getStateManager - Return the state manager used by the analysis engine.
Used for HTML, SARIF, and text output.
Defines the clang::SourceLocation class and associated facilities.
static void reversePropagateInterestingSymbols(BugReport &R, InterestingExprs &IE, const ProgramState *State, const LocationContext *CalleeCtx)
pred_iterator pred_begin()
static const Stmt * getStmtParent(const Stmt *S, const ParentMap &PM)
static PathDiagnosticLocation createEndOfPath(const ExplodedNode *N, const SourceManager &SM)
Create a location corresponding to the next valid ExplodedNode as end of path location.
Represents a top-level expression in a basic block.
const MemRegion * getBaseRegion() const
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
A SourceLocation and its associated SourceManager.
static void generatePathDiagnosticsForNode(const ExplodedNode *N, PathDiagnostic &PD, PathDiagnosticLocation &PrevLoc, PathDiagnosticBuilder &PDB, LocationContextMap &LCM, StackDiagVector &CallStack, InterestingExprs &IE, bool AddPathEdges)
Generate diagnostics for the node N, and write it into PD.
const ExplodedNode *const * const_pred_iterator
std::shared_ptr< PathDiagnosticControlFlowPiece > generateDiagForBinaryOP(const ExplodedNode *N, const Stmt *T, const CFGBlock *Src, const CFGBlock *Dst, const SourceManager &SM, PathDiagnosticBuilder &PDB, const LocationContext *LC)
A trivial tuple used to represent a source range.
static void addContextEdges(PathPieces &pieces, SourceManager &SM, const ParentMap &PM, const LocationContext *LCtx)
Adds synthetic edges from top-level statements to their subexpressions.
Optional< T > getAs() const
Convert to the specified ProgramPoint type, returning None if this ProgramPoint is not of the desired...
static void CompactMacroExpandedPieces(PathPieces &path, const SourceManager &SM)
CompactMacroExpandedPieces - This function postprocesses a PathDiagnostic object and collapses PathDi...
void EmitBasicReport(const Decl *DeclWithIssue, const CheckerBase *Checker, StringRef BugName, StringRef BugCategory, StringRef BugStr, PathDiagnosticLocation Loc, ArrayRef< SourceRange > Ranges=None)
static const char StrEnteringLoop[]
SourceLocation getBegin() const
static const char StrLoopRangeEmpty[]
This class handles loading and caching of source files into memory.
SourceManager & getSourceManager()
static bool isInLoopBody(ParentMap &PM, const Stmt *S, const Stmt *Term)