44 #include "llvm/ADT/ArrayRef.h" 45 #include "llvm/ADT/DenseMap.h" 46 #include "llvm/ADT/DenseSet.h" 47 #include "llvm/ADT/FoldingSet.h" 48 #include "llvm/ADT/None.h" 49 #include "llvm/ADT/Optional.h" 50 #include "llvm/ADT/STLExtras.h" 51 #include "llvm/ADT/SmallPtrSet.h" 52 #include "llvm/ADT/SmallString.h" 53 #include "llvm/ADT/SmallVector.h" 54 #include "llvm/ADT/Statistic.h" 55 #include "llvm/ADT/StringRef.h" 56 #include "llvm/ADT/iterator_range.h" 57 #include "llvm/Support/Casting.h" 58 #include "llvm/Support/Compiler.h" 59 #include "llvm/Support/ErrorHandling.h" 60 #include "llvm/Support/MemoryBuffer.h" 61 #include "llvm/Support/raw_ostream.h" 73 using namespace clang;
76 #define DEBUG_TYPE "BugReporter" 79 "The maximum number of bug reports in the same equivalence class");
81 "The maximum number of bug reports in the same equivalence class " 82 "where at least one report is valid (not suppressed)");
84 BugReporterVisitor::~BugReporterVisitor() =
default;
86 void BugReporterContext::anchor() {}
93 for (N = N->getFirstPred(); N; N = N->getFirstPred())
100 static inline const Stmt*
112 static PathDiagnosticEventPiece *
114 PathDiagnosticEventPiece *Y) {
119 const void *tagPreferred = ConditionBRVisitor::getTag();
120 const void *tagLesser = TrackConstraintBRVisitor::getTag();
122 if (X->getLocation() != Y->getLocation())
125 if (X->getTag() == tagPreferred && Y->getTag() == tagLesser)
126 return ConditionBRVisitor::isPieceMessageGeneric(X) ? Y :
X;
128 if (Y->getTag() == tagPreferred && X->getTag() == tagLesser)
129 return ConditionBRVisitor::isPieceMessageGeneric(Y) ?
X : Y;
140 unsigned N = path.size();
147 for (
unsigned i = 0; i < N; ++i) {
148 auto piece = std::move(path.front());
151 switch (piece->getKind()) {
164 if (
auto *nextEvent =
165 dyn_cast<PathDiagnosticEventPiece>(path.front().get())) {
166 auto *
event = cast<PathDiagnosticEventPiece>(piece.get());
170 if (
auto *pieceToKeep =
172 piece = std::move(pieceToKeep == event ? piece : path.front());
182 path.push_back(std::move(piece));
189 llvm::DenseMap<const PathPieces *, const LocationContext *>;
196 bool IsInteresting =
false) {
197 bool containsSomethingInteresting = IsInteresting;
198 const unsigned N = pieces.size();
200 for (
unsigned i = 0 ; i < N ; ++i) {
203 auto piece = std::move(pieces.front());
206 switch (piece->getKind()) {
208 auto &call = cast<PathDiagnosticCallPiece>(*piece);
210 assert(LCM.count(&call.path));
212 R->isInteresting(LCM[&call.path])))
215 containsSomethingInteresting =
true;
219 auto ¯o = cast<PathDiagnosticMacroPiece>(*piece);
222 containsSomethingInteresting =
true;
226 auto &
event = cast<PathDiagnosticEventPiece>(*piece);
230 containsSomethingInteresting |= !
event.isPrunable();
240 pieces.push_back(std::move(piece));
243 return containsSomethingInteresting;
257 PathDiagnosticLocation *LastCallLocation =
nullptr) {
258 for (
const auto &I : Pieces) {
259 auto *Call = dyn_cast<PathDiagnosticCallPiece>(I.get());
264 if (LastCallLocation) {
266 if (CallerIsImplicit || !Call->callEnter.asLocation().isValid())
267 Call->callEnter = *LastCallLocation;
268 if (CallerIsImplicit || !Call->callReturn.asLocation().isValid())
269 Call->callReturn = *LastCallLocation;
274 PathDiagnosticLocation *ThisCallLocation;
275 if (Call->callEnterWithin.asLocation().isValid() &&
277 ThisCallLocation = &Call->callEnterWithin;
279 ThisCallLocation = &Call->callEnter;
281 assert(ThisCallLocation &&
"Outermost call has an invalid location");
290 for (PathPieces::iterator I = Pieces.begin(), E = Pieces.end(); I != E;) {
291 if (
auto *C = dyn_cast<PathDiagnosticCallPiece>(I->get()))
294 if (
auto *M = dyn_cast<PathDiagnosticMacroPiece>(I->get()))
297 if (
auto *
CF = dyn_cast<PathDiagnosticControlFlowPiece>(I->get())) {
298 const Stmt *Start =
CF->getStartLocation().asStmt();
299 const Stmt *
End =
CF->getEndLocation().asStmt();
300 if (Start && isa<CXXDefaultInitExpr>(Start)) {
303 }
else if (End && isa<CXXDefaultInitExpr>(End)) {
304 PathPieces::iterator Next = std::next(I);
307 dyn_cast<PathDiagnosticControlFlowPiece>(Next->get())) {
308 NextCF->setStartLocation(
CF->getStartLocation());
324 for (PathPieces::iterator I = Pieces.begin(), E = Pieces.end(); I != E;) {
325 if (
auto *C = dyn_cast<PathDiagnosticCallPiece>(I->get()))
328 if (
auto *M = dyn_cast<PathDiagnosticMacroPiece>(I->get()))
331 if (!(*I)->getLocation().isValid() ||
332 !(*I)->getLocation().asLocation().isValid()) {
348 PathDiagnosticConsumer *PDC;
353 PathDiagnosticBuilder(GRBugReporter &br,
355 PathDiagnosticConsumer *pdc)
357 LC(r->getErrorNode()->getLocationContext()) {}
359 PathDiagnosticLocation ExecutionContinues(
const ExplodedNode *N);
361 PathDiagnosticLocation ExecutionContinues(llvm::raw_string_ostream &os,
362 const ExplodedNode *N);
364 BugReport *getBugReport() {
return R; }
366 Decl const &getCodeDecl() {
return R->getErrorNode()->getCodeDecl(); }
370 const Stmt *getParent(
const Stmt *S) {
371 return getParentMap().getParent(S);
380 bool supportsLogicalOpControlFlow()
const {
381 return PDC ? PDC->supportsLogicalOpControlFlow() :
true;
387 PathDiagnosticLocation
388 PathDiagnosticBuilder::ExecutionContinues(
const ExplodedNode *N) {
396 PathDiagnosticLocation
397 PathDiagnosticBuilder::ExecutionContinues(llvm::raw_string_ostream &os,
398 const ExplodedNode *N) {
400 if (os.str().empty())
403 const PathDiagnosticLocation &Loc = ExecutionContinues(N);
406 os <<
"Execution continues on line " 410 os <<
"Execution jumps to the end of the ";
411 const Decl *D = N->getLocationContext()->getDecl();
412 if (isa<ObjCMethodDecl>(D))
414 else if (isa<FunctionDecl>(D))
417 assert(isa<BlockDecl>(D));
418 os <<
"anonymous block";
435 case Stmt::ForStmtClass:
436 case Stmt::DoStmtClass:
437 case Stmt::WhileStmtClass:
438 case Stmt::ObjCForCollectionStmtClass:
439 case Stmt::CXXForRangeStmtClass:
448 static PathDiagnosticLocation
455 switch (
Parent->getStmtClass()) {
456 case Stmt::BinaryOperatorClass: {
457 const auto *B = cast<BinaryOperator>(
Parent);
458 if (B->isLogicalOp())
459 return PathDiagnosticLocation(allowNestedContexts ? B : S, SMgr, LC);
462 case Stmt::CompoundStmtClass:
463 case Stmt::StmtExprClass:
464 return PathDiagnosticLocation(S, SMgr, LC);
465 case Stmt::ChooseExprClass:
468 if (allowNestedContexts || cast<ChooseExpr>(
Parent)->getCond() == S)
469 return PathDiagnosticLocation(
Parent, SMgr, LC);
471 return PathDiagnosticLocation(S, SMgr, LC);
472 case Stmt::BinaryConditionalOperatorClass:
473 case Stmt::ConditionalOperatorClass:
476 if (allowNestedContexts ||
477 cast<AbstractConditionalOperator>(
Parent)->getCond() == S)
478 return PathDiagnosticLocation(
Parent, SMgr, LC);
480 return PathDiagnosticLocation(S, SMgr, LC);
481 case Stmt::CXXForRangeStmtClass:
482 if (cast<CXXForRangeStmt>(
Parent)->getBody() == S)
483 return PathDiagnosticLocation(S, SMgr, LC);
485 case Stmt::DoStmtClass:
486 return PathDiagnosticLocation(S, SMgr, LC);
487 case Stmt::ForStmtClass:
488 if (cast<ForStmt>(
Parent)->getBody() == S)
489 return PathDiagnosticLocation(S, SMgr, LC);
491 case Stmt::IfStmtClass:
492 if (cast<IfStmt>(
Parent)->getCond() != S)
493 return PathDiagnosticLocation(S, SMgr, LC);
495 case Stmt::ObjCForCollectionStmtClass:
496 if (cast<ObjCForCollectionStmt>(
Parent)->getBody() == S)
497 return PathDiagnosticLocation(S, SMgr, LC);
499 case Stmt::WhileStmtClass:
500 if (cast<WhileStmt>(
Parent)->getCond() != S)
501 return PathDiagnosticLocation(S, SMgr, LC);
510 assert(S &&
"Cannot have null Stmt for PathDiagnosticLocation");
512 return PathDiagnosticLocation(S, SMgr, LC);
515 PathDiagnosticLocation
517 assert(S &&
"Null Stmt passed to getEnclosingStmtLocation");
526 std::pair<PathDiagnosticCallPiece *, const ExplodedNode *>;
533 if (
auto *ep = dyn_cast<PathDiagnosticEventPiece>(&P)) {
534 if (ep->hasCallStackHint())
535 for (
const auto &I : CallStack) {
536 PathDiagnosticCallPiece *CP = I.first;
537 const ExplodedNode *N = I.second;
538 std::string stackMsg = ep->getCallStackMessage(N);
543 if (!CP->hasCallStackMessage())
544 CP->setCallStackMessage(stackMsg);
554 const ExplodedNode *N,
558 PathDiagnosticBuilder &PDB,
559 PathDiagnosticLocation &Start
563 llvm::raw_string_ostream os(sbuf);
564 PathDiagnosticLocation
End;
567 End = PathDiagnosticLocation(S, SM, LC);
571 os <<
"No cases match in the switch statement. " 572 "Control jumps to line " 573 << End.asLocation().getExpansionLineNumber();
575 case Stmt::DefaultStmtClass:
576 os <<
"Control jumps to the 'default' case at line " 577 << End.asLocation().getExpansionLineNumber();
580 case Stmt::CaseStmtClass: {
581 os <<
"Control jumps to 'case ";
582 const auto *Case = cast<CaseStmt>(S);
586 bool GetRawInt =
true;
588 if (
const auto *DR = dyn_cast<DeclRefExpr>(LHS)) {
600 os << LHS->EvaluateKnownConstInt(PDB.getASTContext());
602 os <<
":' at line " << End.asLocation().getExpansionLineNumber();
607 os <<
"'Default' branch taken. ";
608 End = PDB.ExecutionContinues(os, N);
610 return std::make_shared<PathDiagnosticControlFlowPiece>(Start,
End,
617 PathDiagnosticBuilder &PDB,
618 PathDiagnosticLocation &Start) {
620 llvm::raw_string_ostream os(sbuf);
621 const PathDiagnosticLocation &
End = PDB.getEnclosingStmtLocation(S);
622 os <<
"Control jumps to line " << End.asLocation().getExpansionLineNumber();
623 return std::make_shared<PathDiagnosticControlFlowPiece>(Start,
End, os.str());
628 const ExplodedNode *N,
633 PathDiagnosticBuilder &PDB,
635 const auto *B = cast<BinaryOperator>(T);
637 llvm::raw_string_ostream os(sbuf);
638 os <<
"Left side of '";
639 PathDiagnosticLocation Start,
End;
641 if (B->getOpcode() == BO_LAnd) {
647 End = PathDiagnosticLocation(B->getLHS(),
SM, LC);
652 Start = PathDiagnosticLocation(B->getLHS(),
SM, LC);
653 End = PDB.ExecutionContinues(N);
656 assert(B->getOpcode() == BO_LOr);
662 Start = PathDiagnosticLocation(B->getLHS(),
SM, LC);
663 End = PDB.ExecutionContinues(N);
666 End = PathDiagnosticLocation(B->getLHS(),
SM, LC);
671 return std::make_shared<PathDiagnosticControlFlowPiece>(Start,
End,
677 PathDiagnosticBuilder &PDB,
678 PathDiagnostic &PD) {
691 case Stmt::GotoStmtClass:
692 case Stmt::IndirectGotoStmtClass: {
698 case Stmt::SwitchStmtClass: {
699 PD.getActivePath().push_front(
704 case Stmt::BreakStmtClass:
705 case Stmt::ContinueStmtClass: {
707 llvm::raw_string_ostream os(sbuf);
708 PathDiagnosticLocation
End = PDB.ExecutionContinues(os, N);
709 PD.getActivePath().push_front(
710 std::make_shared<PathDiagnosticControlFlowPiece>(Start, End, os.str()));
715 case Stmt::BinaryConditionalOperatorClass:
716 case Stmt::ConditionalOperatorClass: {
718 llvm::raw_string_ostream os(sbuf);
719 os <<
"'?' condition is ";
726 PathDiagnosticLocation
End = PDB.ExecutionContinues(N);
728 if (
const Stmt *S = End.asStmt())
729 End = PDB.getEnclosingStmtLocation(S);
731 PD.getActivePath().push_front(
732 std::make_shared<PathDiagnosticControlFlowPiece>(Start, End, os.str()));
737 case Stmt::BinaryOperatorClass: {
738 if (!PDB.supportsLogicalOpControlFlow())
741 std::shared_ptr<PathDiagnosticControlFlowPiece>
Diag =
743 PD.getActivePath().push_front(Diag);
747 case Stmt::DoStmtClass:
750 llvm::raw_string_ostream os(sbuf);
752 os <<
"Loop condition is true. ";
753 PathDiagnosticLocation
End = PDB.ExecutionContinues(os, N);
755 if (
const Stmt *S = End.asStmt())
756 End = PDB.getEnclosingStmtLocation(S);
758 PD.getActivePath().push_front(
759 std::make_shared<PathDiagnosticControlFlowPiece>(Start, End,
762 PathDiagnosticLocation
End = PDB.ExecutionContinues(N);
764 if (
const Stmt *S = End.asStmt())
765 End = PDB.getEnclosingStmtLocation(S);
767 PD.getActivePath().push_front(
768 std::make_shared<PathDiagnosticControlFlowPiece>(
769 Start, End,
"Loop condition is false. Exiting loop"));
773 case Stmt::WhileStmtClass:
774 case Stmt::ForStmtClass:
777 llvm::raw_string_ostream os(sbuf);
779 os <<
"Loop condition is false. ";
780 PathDiagnosticLocation
End = PDB.ExecutionContinues(os, N);
781 if (
const Stmt *S = End.asStmt())
782 End = PDB.getEnclosingStmtLocation(S);
784 PD.getActivePath().push_front(
785 std::make_shared<PathDiagnosticControlFlowPiece>(Start, End,
788 PathDiagnosticLocation
End = PDB.ExecutionContinues(N);
789 if (
const Stmt *S = End.asStmt())
790 End = PDB.getEnclosingStmtLocation(S);
792 PD.getActivePath().push_front(
793 std::make_shared<PathDiagnosticControlFlowPiece>(
794 Start, End,
"Loop condition is true. Entering loop body"));
799 case Stmt::IfStmtClass: {
800 PathDiagnosticLocation
End = PDB.ExecutionContinues(N);
802 if (
const Stmt *S = End.asStmt())
803 End = PDB.getEnclosingStmtLocation(S);
806 PD.getActivePath().push_front(
807 std::make_shared<PathDiagnosticControlFlowPiece>(
808 Start, End,
"Taking false branch"));
810 PD.getActivePath().push_front(
811 std::make_shared<PathDiagnosticControlFlowPiece>(
812 Start, End,
"Taking true branch"));
834 const ProgramState *
State,
837 SVal V = State->getSVal(Ex, LCtx);
838 if (!(R.isInteresting(V) || IE.count(Ex)))
843 if (!isa<CastExpr>(Ex))
846 case Stmt::BinaryOperatorClass:
847 case Stmt::UnaryOperatorClass: {
849 if (
const auto *child = dyn_cast_or_null<Expr>(SubStmt)) {
851 SVal ChildV = State->getSVal(child, LCtx);
852 R.markInteresting(ChildV);
859 R.markInteresting(V);
864 const ProgramState *
State,
870 if (
const auto *CE = dyn_cast_or_null<CallExpr>(CallSite)) {
871 if (
const auto *FD = dyn_cast<FunctionDecl>(CalleeCtx->
getDecl())) {
873 PE = FD->param_end();
875 for (; AI != AE && PI != PE; ++AI, ++PI) {
876 if (
const Expr *ArgE = *AI) {
878 Loc LV = State->getLValue(PD, CalleeCtx);
879 if (R.isInteresting(LV) || R.isInteresting(State->getRawSVal(LV)))
894 case Stmt::ForStmtClass:
895 case Stmt::WhileStmtClass:
896 case Stmt::ObjCForCollectionStmtClass:
897 case Stmt::CXXForRangeStmtClass:
921 const ExplodedNode *N) {
925 const Stmt *S = SP->getStmt();
929 N = N->getFirstPred();
935 const Stmt *LoopBody =
nullptr;
937 case Stmt::CXXForRangeStmtClass: {
938 const auto *FR = cast<CXXForRangeStmt>(Term);
943 LoopBody = FR->getBody();
946 case Stmt::ForStmtClass: {
947 const auto *FS = cast<ForStmt>(Term);
950 LoopBody = FS->getBody();
953 case Stmt::ObjCForCollectionStmtClass: {
954 const auto *FC = cast<ObjCForCollectionStmt>(Term);
955 LoopBody = FC->getBody();
958 case Stmt::WhileStmtClass:
959 LoopBody = cast<WhileStmt>(Term)->getBody();
969 PathDiagnosticLocation &PrevLoc,
970 PathDiagnosticLocation NewLoc) {
971 if (!NewLoc.isValid())
978 if (!PrevLoc.isValid() || !PrevLoc.asLocation().isValid()) {
985 if (NewLoc.asStmt() && NewLoc.asStmt() == PrevLoc.asStmt())
989 std::make_shared<PathDiagnosticControlFlowPiece>(NewLoc, PrevLoc));
997 if (
const auto *FS = dyn_cast_or_null<ObjCForCollectionStmt>(S))
998 return FS->getElement();
1005 "Loop body skipped when range is empty";
1007 "Loop body skipped when collection is empty";
1009 static std::unique_ptr<FilesToLineNumsMap>
1018 PathDiagnosticLocation &PrevLoc,
1019 PathDiagnosticBuilder &PDB,
1023 bool AddPathEdges) {
1049 bool VisitedEntireCall = PD.isWithinCall();
1052 PathDiagnosticCallPiece *C;
1053 if (VisitedEntireCall) {
1054 C = cast<PathDiagnosticCallPiece>(PD.getActivePath().front().get());
1056 const Decl *Caller = CE->getLocationContext()->getDecl();
1062 assert(PD.getActivePath().size() == 1 &&
1063 PD.getActivePath().front().get() == C);
1064 LCM[&PD.getActivePath()] =
nullptr;
1069 assert(LCM[&C->path] ==
nullptr ||
1070 LCM[&C->path] == CE->getCalleeContext());
1071 LCM[&C->path] = CE->getCalleeContext();
1077 NewLC = N->getLocationContext();
1081 C->setCallee(*CE, SM);
1084 PrevLoc = C->getLocation();
1086 if (!CallStack.empty()) {
1087 assert(CallStack.back().first == C);
1088 CallStack.pop_back();
1097 PDB.LC = N->getLocationContext();
1101 assert(!LCM[&PD.getActivePath()] || LCM[&PD.getActivePath()] == PDB.LC);
1102 LCM[&PD.getActivePath()] = PDB.LC;
1112 LCM[&C->path] = CE->getCalleeContext();
1115 const Stmt *S = CE->getCalleeContext()->getCallSite();
1117 if (
const auto *Ex = dyn_cast_or_null<Expr>(S)) {
1119 N->getState().get(), Ex,
1120 N->getLocationContext());
1124 PrevLoc.invalidate();
1128 PD.getActivePath().push_front(std::move(C));
1131 PD.pushActivePath(&P->path);
1142 if (
const Expr *Ex = PS->getStmtAs<
Expr>())
1144 N->getState().get(), Ex,
1145 N->getLocationContext());
1150 if (!isa<ObjCForCollectionStmt>(PS->getStmt())) {
1151 PathDiagnosticLocation L =
1152 PathDiagnosticLocation(PS->getStmt(),
SM, PDB.LC);
1158 if (!AddPathEdges) {
1165 if (
const ExplodedNode *NextNode = N->getFirstPred()) {
1168 if (CallerCtx != CalleeCtx && AddPathEdges) {
1170 N->getState().get(), CalleeCtx);
1175 if (
const Stmt *Loop = BE->getSrc()->getLoopTarget()) {
1176 PathDiagnosticLocation L(Loop, SM, PDB.LC);
1177 const Stmt *Body =
nullptr;
1179 if (
const auto *FS = dyn_cast<ForStmt>(Loop))
1180 Body = FS->getBody();
1181 else if (
const auto *WS = dyn_cast<WhileStmt>(Loop))
1182 Body = WS->getBody();
1183 else if (
const auto *OFS = dyn_cast<ObjCForCollectionStmt>(Loop)) {
1184 Body = OFS->getBody();
1185 }
else if (
const auto *FRS = dyn_cast<CXXForRangeStmt>(Loop)) {
1186 Body = FRS->getBody();
1190 auto p = std::make_shared<PathDiagnosticEventPiece>(
1191 L,
"Looping back to the head " 1193 p->setPrunable(
true);
1195 addEdgeToPath(PD.getActivePath(), PrevLoc, p->getLocation());
1196 PD.getActivePath().push_front(std::move(p));
1198 if (
const auto *CS = dyn_cast_or_null<CompoundStmt>(Body)) {
1204 const CFGBlock *BSrc = BE->getSrc();
1207 if (
const Stmt *Term = BSrc->getTerminator()) {
1215 const char *
str =
nullptr;
1218 if (!IsInLoopBody) {
1219 if (isa<ObjCForCollectionStmt>(Term)) {
1221 }
else if (isa<CXXForRangeStmt>(Term)) {
1232 PathDiagnosticLocation L(TermCond ? TermCond : Term, SM, PDB.LC);
1233 auto PE = std::make_shared<PathDiagnosticEventPiece>(L,
str);
1234 PE->setPrunable(
true);
1237 PD.getActivePath().push_front(std::move(PE));
1239 }
else if (isa<BreakStmt>(Term) || isa<ContinueStmt>(Term) ||
1240 isa<GotoStmt>(Term)) {
1241 PathDiagnosticLocation L(Term, SM, PDB.LC);
1248 static std::unique_ptr<PathDiagnostic>
1250 BugType &BT = R->getBugType();
1251 return llvm::make_unique<PathDiagnostic>(
1252 R->getBugType().getCheckName(), R->getDeclWithIssue(),
1253 R->getBugType().getName(), R->getDescription(),
1254 R->getShortDescription(
false), BT.getCategory(),
1255 R->getUniqueingLocation(), R->getUniqueingDecl(),
1269 if (isa<FullExpr>(S) ||
1270 isa<CXXBindTemporaryExpr>(S) ||
1271 isa<SubstNonTypeTemplateParmExpr>(S))
1282 case Stmt::BinaryOperatorClass: {
1283 const auto *BO = cast<BinaryOperator>(S);
1284 if (!BO->isLogicalOp())
1286 return BO->getLHS() == Cond || BO->getRHS() == Cond;
1288 case Stmt::IfStmtClass:
1289 return cast<IfStmt>(S)->getCond() == Cond;
1290 case Stmt::ForStmtClass:
1291 return cast<ForStmt>(S)->getCond() == Cond;
1292 case Stmt::WhileStmtClass:
1293 return cast<WhileStmt>(S)->getCond() == Cond;
1294 case Stmt::DoStmtClass:
1295 return cast<DoStmt>(S)->getCond() == Cond;
1296 case Stmt::ChooseExprClass:
1297 return cast<ChooseExpr>(S)->getCond() == Cond;
1298 case Stmt::IndirectGotoStmtClass:
1299 return cast<IndirectGotoStmt>(S)->getTarget() == Cond;
1300 case Stmt::SwitchStmtClass:
1301 return cast<SwitchStmt>(S)->getCond() == Cond;
1302 case Stmt::BinaryConditionalOperatorClass:
1303 return cast<BinaryConditionalOperator>(S)->getCond() == Cond;
1304 case Stmt::ConditionalOperatorClass: {
1305 const auto *CO = cast<ConditionalOperator>(S);
1306 return CO->getCond() == Cond ||
1307 CO->getLHS() == Cond ||
1308 CO->getRHS() == Cond;
1310 case Stmt::ObjCForCollectionStmtClass:
1311 return cast<ObjCForCollectionStmt>(S)->getElement() == Cond;
1312 case Stmt::CXXForRangeStmtClass: {
1313 const auto *FRS = cast<CXXForRangeStmt>(S);
1314 return FRS->getCond() == Cond || FRS->getRangeInit() == Cond;
1322 if (
const auto *FS = dyn_cast<ForStmt>(FL))
1323 return FS->getInc() == S || FS->getInit() == S;
1324 if (
const auto *FRS = dyn_cast<CXXForRangeStmt>(FL))
1325 return FRS->getInc() == S || FRS->getRangeStmt() == S ||
1326 FRS->getLoopVarStmt() || FRS->getRangeInit() == S;
1339 PathPieces::iterator Prev = pieces.end();
1340 for (PathPieces::iterator I = pieces.begin(), E = Prev; I != E;
1342 auto *Piece = dyn_cast<PathDiagnosticControlFlowPiece>(I->get());
1347 PathDiagnosticLocation SrcLoc = Piece->getStartLocation();
1350 PathDiagnosticLocation NextSrcContext = SrcLoc;
1351 const Stmt *InnerStmt =
nullptr;
1352 while (NextSrcContext.isValid() && NextSrcContext.asStmt() != InnerStmt) {
1353 SrcContexts.push_back(NextSrcContext);
1354 InnerStmt = NextSrcContext.asStmt();
1363 const Stmt *Dst = Piece->getEndLocation().getStmtOrNull();
1367 PathDiagnosticLocation DstContext =
1369 if (!DstContext.isValid() || DstContext.asStmt() == Dst)
1373 if (std::find(SrcContexts.begin(), SrcContexts.end(), DstContext) !=
1378 Piece->setStartLocation(DstContext);
1383 auto *PrevPiece = dyn_cast<PathDiagnosticControlFlowPiece>(Prev->get());
1386 if (
const Stmt *PrevSrc =
1387 PrevPiece->getStartLocation().getStmtOrNull()) {
1389 if (PrevSrcParent ==
1391 PrevPiece->setEndLocation(DstContext);
1402 std::make_shared<PathDiagnosticControlFlowPiece>(SrcLoc, DstContext);
1404 I = pieces.insert(I, std::move(
P));
1420 for (PathPieces::iterator I = pieces.begin(), E = pieces.end(); I != E; ++I) {
1421 const auto *PieceI = dyn_cast<PathDiagnosticControlFlowPiece>(I->get());
1426 const Stmt *s1Start = PieceI->getStartLocation().getStmtOrNull();
1427 const Stmt *s1End = PieceI->getEndLocation().getStmtOrNull();
1429 if (!s1Start || !s1End)
1432 PathPieces::iterator NextI = I; ++NextI;
1436 PathDiagnosticControlFlowPiece *PieceNextI =
nullptr;
1442 const auto *EV = dyn_cast<PathDiagnosticEventPiece>(NextI->get());
1444 StringRef S = EV->getString();
1453 PieceNextI = dyn_cast<PathDiagnosticControlFlowPiece>(NextI->get());
1460 const Stmt *s2Start = PieceNextI->getStartLocation().getStmtOrNull();
1461 const Stmt *s2End = PieceNextI->getEndLocation().getStmtOrNull();
1463 if (!s2Start || !s2End || s1End != s2Start)
1468 if (!(isa<ForStmt>(s1Start) || isa<WhileStmt>(s1Start) ||
1469 isa<IfStmt>(s1Start) || isa<ObjCForCollectionStmt>(s1Start) ||
1470 isa<CXXForRangeStmt>(s1Start)))
1479 PieceNextI->setStartLocation(PieceI->getStartLocation());
1480 I = pieces.erase(I);
1495 if (FID != SM.
getFileID(ExpansionRange.getEnd()))
1499 const llvm::MemoryBuffer *Buffer = SM.
getBuffer(FID, &Invalid);
1503 unsigned BeginOffset = SM.
getFileOffset(ExpansionRange.getBegin());
1504 unsigned EndOffset = SM.
getFileOffset(ExpansionRange.getEnd());
1505 StringRef Snippet = Buffer->getBuffer().slice(BeginOffset, EndOffset);
1511 if (Snippet.find_first_of(
"\r\n") != StringRef::npos)
1515 return Snippet.size();
1541 for (PathPieces::iterator I = Path.begin(), E = Path.end(); I != E; ) {
1543 const auto *PieceI = dyn_cast<PathDiagnosticControlFlowPiece>(I->get());
1550 const Stmt *s1Start = PieceI->getStartLocation().getStmtOrNull();
1551 const Stmt *s1End = PieceI->getEndLocation().getStmtOrNull();
1553 PathPieces::iterator NextI = I; ++NextI;
1557 const auto *PieceNextI =
1558 dyn_cast<PathDiagnosticControlFlowPiece>(NextI->get());
1561 if (isa<PathDiagnosticEventPiece>(NextI->get())) {
1565 PieceNextI = dyn_cast<PathDiagnosticControlFlowPiece>(NextI->get());
1574 const Stmt *s2Start = PieceNextI->getStartLocation().getStmtOrNull();
1575 const Stmt *s2End = PieceNextI->getEndLocation().getStmtOrNull();
1577 if (s1Start && s2Start && s1Start == s2End && s2Start == s1End) {
1578 const size_t MAX_SHORT_LINE_LENGTH = 80;
1580 if (s1Length && *s1Length <= MAX_SHORT_LINE_LENGTH) {
1582 if (s2Length && *s2Length <= MAX_SHORT_LINE_LENGTH) {
1584 I = Path.erase(NextI);
1607 bool erased =
false;
1609 for (PathPieces::iterator I = path.begin(), E = path.end(); I != E;
1613 const auto *PieceI = dyn_cast<PathDiagnosticControlFlowPiece>(I->get());
1618 const Stmt *start = PieceI->getStartLocation().getStmtOrNull();
1619 const Stmt *end = PieceI->getEndLocation().getStmtOrNull();
1637 std::swap(SecondLoc, FirstLoc);
1646 const size_t MAX_PUNY_EDGE_LENGTH = 2;
1647 if (*ByteWidth <= MAX_PUNY_EDGE_LENGTH) {
1659 for (PathPieces::iterator I = path.begin(), E = path.end(); I != E; ++I) {
1660 const auto *PieceI = dyn_cast<PathDiagnosticEventPiece>(I->get());
1665 PathPieces::iterator NextI = I; ++NextI;
1669 const auto *PieceNextI = dyn_cast<PathDiagnosticEventPiece>(NextI->get());
1675 if (PieceI->getString() == PieceNextI->getString()) {
1684 bool hasChanges =
false;
1689 for (PathPieces::iterator I = path.begin(), E = path.end(); I != E; ) {
1691 if (
auto *CallI = dyn_cast<PathDiagnosticCallPiece>(I->get())) {
1694 if (!OCS.count(CallI)) {
1703 auto *PieceI = dyn_cast<PathDiagnosticControlFlowPiece>(I->get());
1710 const Stmt *s1Start = PieceI->getStartLocation().getStmtOrNull();
1711 const Stmt *s1End = PieceI->getEndLocation().getStmtOrNull();
1715 PathPieces::iterator NextI = I; ++NextI;
1719 const auto *PieceNextI = dyn_cast<PathDiagnosticControlFlowPiece>(NextI->get());
1726 const Stmt *s2Start = PieceNextI->getStartLocation().getStmtOrNull();
1727 const Stmt *s2End = PieceNextI->getEndLocation().getStmtOrNull();
1745 if (level1 && level1 == level2 && level1 == level3 && level1 == level4) {
1746 PieceI->setEndLocation(PieceNextI->getEndLocation());
1759 if (s1End && s1End == s2Start && level2) {
1760 bool removeEdge =
false;
1786 else if (s1Start && s2End &&
1799 else if (s1Start && s2End &&
1801 SourceRange EdgeRange(PieceI->getEndLocation().asLocation(),
1802 PieceI->getStartLocation().asLocation());
1809 PieceI->setEndLocation(PieceNextI->getEndLocation());
1823 if (s1End == s2Start) {
1824 const auto *FS = dyn_cast_or_null<ObjCForCollectionStmt>(level3);
1825 if (FS && FS->getCollection()->IgnoreParens() == s2Start &&
1826 s2End == FS->getElement()) {
1827 PieceI->setEndLocation(PieceNextI->getEndLocation());
1864 const auto *FirstEdge =
1865 dyn_cast<PathDiagnosticControlFlowPiece>(Path.front().get());
1869 const Decl *D = LCM[&Path]->getDecl();
1871 if (FirstEdge->getStartLocation() != EntryLoc)
1878 std::vector<std::shared_ptr<PathDiagnosticPiece>>>;
1882 PathDiagnostic &PD) {
1884 PathPieces path = PD.path.flatten(
true);
1887 for (
const auto &
P : path) {
1888 FullSourceLoc Loc =
P->getLocation().asLocation().getExpansionLoc();
1892 ExecutedLines[FID].insert(LineNo);
1910 PathDiagnosticBuilder &PDB,
1911 const ExplodedNode *ErrorNode,
1917 BugReport *R = PDB.getBugReport();
1924 if (GenerateDiagnostics) {
1925 auto EndNotes = VisitorsDiagnostics.find(ErrorNode);
1926 std::shared_ptr<PathDiagnosticPiece> LastPiece;
1927 if (EndNotes != VisitorsDiagnostics.end()) {
1928 assert(!EndNotes->second.empty());
1929 LastPiece = EndNotes->second[0];
1931 LastPiece = BugReporterVisitor::getDefaultEndPath(PDB, ErrorNode, *R);
1933 PD->setEndOfPath(LastPiece);
1936 PathDiagnosticLocation PrevLoc = PD->getLocation();
1937 const ExplodedNode *NextNode = ErrorNode->getFirstPred();
1939 if (GenerateDiagnostics)
1941 NextNode, *PD, PrevLoc, PDB, LCM, CallStack, IE, AddPathEdges);
1943 auto VisitorNotes = VisitorsDiagnostics.find(NextNode);
1944 NextNode = NextNode->getFirstPred();
1945 if (!GenerateDiagnostics || VisitorNotes == VisitorsDiagnostics.end())
1950 std::set<llvm::FoldingSetNodeID> DeduplicationSet;
1953 for (
const auto &Note : VisitorNotes->second) {
1954 llvm::FoldingSetNodeID
ID;
1956 auto P = DeduplicationSet.insert(ID);
1961 addEdgeToPath(PD->getActivePath(), PrevLoc, Note->getLocation());
1963 PD->getActivePath().push_front(Note);
1978 if (!PD->path.empty()) {
1979 if (R->shouldPrunePath() && Opts.ShouldPrunePaths) {
1980 bool stillHasNotes =
1982 assert(stillHasNotes);
1983 (void)stillHasNotes;
2010 if (GenerateDiagnostics && Opts.ShouldDisplayMacroExpansions)
2021 void BugType::anchor() {}
2023 void BuiltinBug::anchor() {}
2029 void BugReport::NodeResolver::anchor() {}
2035 llvm::FoldingSetNodeID
ID;
2036 visitor->Profile(ID);
2038 void *InsertPos =
nullptr;
2039 if (CallbacksSet.FindNodeOrInsertPos(ID, InsertPos)) {
2043 Callbacks.push_back(std::move(visitor));
2051 while (!interestingSymbols.empty()) {
2052 popInterestingSymbolsAndRegions();
2058 return DeclWithIssue;
2069 hash.AddPointer(&BT);
2070 hash.AddString(Description);
2074 }
else if (Location.isValid()) {
2075 Location.Profile(hash);
2082 if (!range.isValid())
2084 hash.AddInteger(range.getBegin().getRawEncoding());
2085 hash.AddInteger(range.getEnd().getRawEncoding());
2093 getInterestingSymbols().insert(sym);
2095 if (
const auto *meta = dyn_cast<SymbolMetadata>(sym))
2096 getInterestingRegions().insert(meta->getRegion());
2104 getInterestingRegions().insert(R);
2106 if (
const auto *SR = dyn_cast<SymbolicRegion>(R))
2107 getInterestingSymbols().insert(SR->getSymbol());
2118 InterestingLocationContexts.insert(LC);
2130 return getInterestingSymbols().count(sym);
2137 bool b = getInterestingRegions().count(R);
2140 if (
const auto *SR = dyn_cast<SymbolicRegion>(R))
2141 return getInterestingSymbols().count(SR->getSymbol());
2148 return InterestingLocationContexts.count(LC);
2151 void BugReport::lazyInitializeInterestingSets() {
2152 if (interestingSymbols.empty()) {
2153 interestingSymbols.push_back(
new Symbols());
2154 interestingRegions.push_back(
new Regions());
2159 lazyInitializeInterestingSets();
2160 return *interestingSymbols.back();
2164 lazyInitializeInterestingSets();
2165 return *interestingRegions.back();
2168 void BugReport::pushInterestingSymbolsAndRegions() {
2169 interestingSymbols.push_back(
new Symbols(getInterestingSymbols()));
2170 interestingRegions.push_back(
new Regions(getInterestingRegions()));
2173 void BugReport::popInterestingSymbolsAndRegions() {
2174 delete interestingSymbols.pop_back_val();
2175 delete interestingRegions.pop_back_val();
2183 const Stmt *S =
nullptr;
2187 if (BE->getBlock() == &Exit)
2199 if (Ranges.empty()) {
2200 if (
const auto *E = dyn_cast_or_null<Expr>(getStmt()))
2201 addRange(E->getSourceRange());
2207 if (Ranges.size() == 1 && !Ranges.begin()->isValid())
2210 return llvm::make_range(Ranges.begin(), Ranges.end());
2215 assert(!Location.isValid() &&
2216 "Either Location or ErrorNode should be specified but not both.");
2220 assert(Location.isValid());
2243 for (
const auto I : EQClassesVector)
2248 if (BugTypes.isEmpty())
2253 for (
const auto EQ : EQClassesVector)
2260 llvm::DeleteContainerSeconds(StrBugTypes);
2263 BugTypes = F.getEmptySet();
2277 std::unique_ptr<ExplodedGraph> Graph;
2283 class TrimmedGraph {
2286 using PriorityMapTy = llvm::DenseMap<const ExplodedNode *, unsigned>;
2288 PriorityMapTy PriorityMap;
2290 using NodeIndexPair = std::pair<const ExplodedNode *, size_t>;
2294 std::unique_ptr<ExplodedGraph> G;
2297 template <
bool Descending>
2298 class PriorityCompare {
2299 const PriorityMapTy &PriorityMap;
2302 PriorityCompare(
const PriorityMapTy &M) : PriorityMap(M) {}
2305 PriorityMapTy::const_iterator LI = PriorityMap.find(LHS);
2306 PriorityMapTy::const_iterator RI = PriorityMap.find(RHS);
2307 PriorityMapTy::const_iterator E = PriorityMap.end();
2314 return Descending ? LI->second > RI->second
2315 : LI->second < RI->second;
2318 bool operator()(
const NodeIndexPair &LHS,
const NodeIndexPair &RHS)
const {
2319 return (*
this)(LHS.first, RHS.first);
2327 bool popNextReportGraph(ReportGraph &GraphWrapper);
2332 TrimmedGraph::TrimmedGraph(
const ExplodedGraph *OriginalGraph,
2337 G = OriginalGraph->
trim(Nodes, &ForwardMap, &InverseMap);
2342 llvm::SmallPtrSet<const ExplodedNode *, 32> RemainingNodes;
2344 for (
unsigned i = 0, count = Nodes.size(); i < count; ++i) {
2345 if (
const ExplodedNode *NewNode = ForwardMap.lookup(Nodes[i])) {
2346 ReportNodes.push_back(std::make_pair(NewNode, i));
2347 RemainingNodes.insert(NewNode);
2351 assert(!RemainingNodes.empty() &&
"No error node found in the trimmed graph");
2354 std::queue<const ExplodedNode *> WS;
2356 assert(G->num_roots() == 1);
2357 WS.push(*G->roots_begin());
2358 unsigned Priority = 0;
2360 while (!WS.empty()) {
2364 PriorityMapTy::iterator PriorityEntry;
2366 std::tie(PriorityEntry, IsNew) =
2367 PriorityMap.insert(std::make_pair(Node, Priority));
2371 assert(PriorityEntry->second <= Priority);
2375 if (RemainingNodes.erase(Node))
2376 if (RemainingNodes.empty())
2386 llvm::sort(ReportNodes, PriorityCompare<true>(PriorityMap));
2389 bool TrimmedGraph::popNextReportGraph(ReportGraph &GraphWrapper) {
2390 if (ReportNodes.empty())
2394 std::tie(OrigN, GraphWrapper.Index) = ReportNodes.pop_back_val();
2395 assert(PriorityMap.find(OrigN) != PriorityMap.end() &&
2396 "error node not accessible from root");
2400 auto GNew = llvm::make_unique<ExplodedGraph>();
2401 GraphWrapper.BackMap.clear();
2413 InterExplodedGraphMap::const_iterator IMitr = InverseMap.find(OrigN);
2414 assert(IMitr != InverseMap.end() &&
"No mapping to original node.");
2415 GraphWrapper.BackMap[NewN] = IMitr->second;
2421 GraphWrapper.ErrorNode = NewN;
2427 GNew->addRoot(NewN);
2434 PriorityCompare<false>(PriorityMap));
2437 GraphWrapper.Graph = std::move(GNew);
2446 using MacroStackTy =
2448 std::pair<std::shared_ptr<PathDiagnosticMacroPiece>,
SourceLocation>>;
2450 using PiecesTy = std::vector<std::shared_ptr<PathDiagnosticPiece>>;
2452 MacroStackTy MacroStack;
2455 for (PathPieces::const_iterator I = path.begin(), E = path.end();
2457 const auto &piece = *I;
2460 if (
auto *call = dyn_cast<PathDiagnosticCallPiece>(&*piece)) {
2465 const FullSourceLoc Loc = piece->getLocation().asLocation();
2469 SourceLocation InstantiationLoc = Loc.
isMacroID() ?
2475 Pieces.push_back(piece);
2482 if (!MacroStack.empty() && InstantiationLoc == MacroStack.back().second) {
2483 MacroStack.back().first->subPieces.push_back(piece);
2489 std::shared_ptr<PathDiagnosticMacroPiece> MacroGroup;
2491 SourceLocation ParentInstantiationLoc = InstantiationLoc.
isMacroID() ?
2496 while (!MacroStack.empty()) {
2497 if (InstantiationLoc == MacroStack.back().second) {
2498 MacroGroup = MacroStack.back().first;
2502 if (ParentInstantiationLoc == MacroStack.back().second) {
2503 MacroGroup = MacroStack.back().first;
2507 MacroStack.pop_back();
2510 if (!MacroGroup || ParentInstantiationLoc == MacroStack.back().second) {
2512 auto NewGroup = std::make_shared<PathDiagnosticMacroPiece>(
2516 MacroGroup->subPieces.push_back(NewGroup);
2518 assert(InstantiationLoc.
isFileID());
2519 Pieces.push_back(NewGroup);
2522 MacroGroup = NewGroup;
2523 MacroStack.push_back(std::make_pair(MacroGroup, InstantiationLoc));
2527 MacroGroup->subPieces.push_back(piece);
2533 path.insert(path.end(), Pieces.begin(), Pieces.end());
2539 static std::unique_ptr<VisitorsDiagnosticsTy>
2540 generateVisitorsDiagnostics(BugReport *R,
const ExplodedNode *ErrorNode,
2542 auto Notes = llvm::make_unique<VisitorsDiagnosticsTy>();
2547 const ExplodedNode *NextNode = ErrorNode->getFirstPred();
2552 E = R->visitor_end();
2554 visitors.push_back(std::move(*I));
2558 const ExplodedNode *Pred = NextNode->getFirstPred();
2560 std::shared_ptr<PathDiagnosticPiece> LastPiece;
2561 for (
auto &V : visitors) {
2562 V->finalizeVisitor(BRC, ErrorNode, *R);
2564 if (
auto Piece = V->getEndPath(BRC, ErrorNode, *R)) {
2565 assert(!LastPiece &&
2566 "There can only be one final piece in a diagnostic.");
2567 LastPiece = std::move(Piece);
2568 (*Notes)[ErrorNode].push_back(LastPiece);
2574 for (
auto &V : visitors) {
2575 auto P = V->VisitNode(NextNode, BRC, *R);
2577 (*Notes)[NextNode].push_back(std::move(
P));
2593 std::pair<BugReport*, std::unique_ptr<VisitorsDiagnosticsTy>> findValidReport(
2594 TrimmedGraph &TrimG,
2595 ReportGraph &ErrorGraph,
2598 GRBugReporter &Reporter) {
2600 while (TrimG.popNextReportGraph(ErrorGraph)) {
2602 assert(ErrorGraph.Index < bugReports.size());
2603 BugReport *R = bugReports[ErrorGraph.Index];
2604 assert(R &&
"No original report found for sliced graph.");
2605 assert(R->isValid() &&
"Report selected by trimmed graph marked invalid.");
2606 const ExplodedNode *ErrorNode = ErrorGraph.ErrorNode;
2610 R->addVisitor(llvm::make_unique<LikelyFalsePositiveSuppressionBRVisitor>());
2613 R->addVisitor(llvm::make_unique<NilReceiverBRVisitor>());
2614 R->addVisitor(llvm::make_unique<ConditionBRVisitor>());
2615 R->addVisitor(llvm::make_unique<CXXSelfAssignmentBRVisitor>());
2620 std::unique_ptr<VisitorsDiagnosticsTy> visitorNotes =
2621 generateVisitorsDiagnostics(R, ErrorNode, BRC);
2624 if (Opts.ShouldCrosscheckWithZ3) {
2628 R->addVisitor(llvm::make_unique<FalsePositiveRefutationBRVisitor>());
2632 generateVisitorsDiagnostics(R, ErrorGraph.ErrorNode, BRC);
2637 return std::make_pair(R, std::move(visitorNotes));
2641 return std::make_pair(
nullptr, llvm::make_unique<VisitorsDiagnosticsTy>());
2644 std::unique_ptr<DiagnosticForConsumerMapTy>
2648 assert(!bugReports.empty());
2650 auto Out = llvm::make_unique<DiagnosticForConsumerMapTy>();
2651 bool HasValid =
false;
2653 for (
const auto I : bugReports) {
2656 errorNodes.push_back(I->getErrorNode());
2659 errorNodes.push_back(
nullptr);
2668 TrimmedGraph TrimG(&
getGraph(), errorNodes);
2669 ReportGraph ErrorGraph;
2670 auto ReportInfo = findValidReport(TrimG, ErrorGraph, bugReports,
2672 BugReport *R = ReportInfo.first;
2674 if (R && R->isValid()) {
2675 const ExplodedNode *ErrorNode = ErrorGraph.ErrorNode;
2676 for (PathDiagnosticConsumer *PC : consumers) {
2677 PathDiagnosticBuilder PDB(*
this, R, ErrorGraph.BackMap, PC);
2679 PC->getGenerationScheme(), PDB, ErrorNode, *ReportInfo.second);
2680 (*Out)[PC] = std::move(PD);
2688 BugTypes = F.add(BugTypes, BT);
2692 if (
const ExplodedNode *E = R->getErrorNode()) {
2695 assert((E->isSink() || E->getLocation().getTag()) &&
2696 "Error node must either be a sink or have a tag");
2699 E->getLocationContext()->getAnalysisDeclContext();
2710 assert(ValidSourceLoc);
2713 if (!ValidSourceLoc)
2717 llvm::FoldingSetNodeID
ID;
2721 BugType& BT = R->getBugType();
2724 BugReportEquivClass* EQ = EQClasses.FindNodeOrInsertPos(ID, InsertPos);
2727 EQ =
new BugReportEquivClass(std::move(R));
2728 EQClasses.InsertNode(EQ, InsertPos);
2729 EQClassesVector.push_back(EQ);
2731 EQ->AddReport(std::move(R));
2740 struct FRIEC_WLItem {
2741 const ExplodedNode *N;
2744 FRIEC_WLItem(
const ExplodedNode *n)
2745 : N(n), I(N->succ_begin()), E(N->succ_end()) {}
2750 static const CFGBlock *findBlockForNode(
const ExplodedNode *N) {
2753 return BEP->getBlock();
2757 return N->getLocationContext()->getAnalysisDeclContext()
2758 ->getCFGStmtMap()->getBlock(S);
2769 static bool isImmediateSinkBlock(
const CFGBlock *Blk) {
2781 if (isa<CXXThrowExpr>(StmtElm->getStmt()))
2794 static bool isInevitablySinking(
const ExplodedNode *N) {
2795 const CFG &Cfg = N->getCFG();
2797 const CFGBlock *StartBlk = findBlockForNode(N);
2800 if (isImmediateSinkBlock(StartBlk))
2804 llvm::SmallPtrSet<const CFGBlock *, 32> Visited;
2806 DFSWorkList.push_back(StartBlk);
2807 while (!DFSWorkList.empty()) {
2808 const CFGBlock *Blk = DFSWorkList.back();
2809 DFSWorkList.pop_back();
2810 Visited.insert(Blk);
2819 for (
const auto &Succ : Blk->
succs()) {
2820 if (
const CFGBlock *SuccBlk = Succ.getReachableBlock()) {
2821 if (!isImmediateSinkBlock(SuccBlk) && !Visited.count(SuccBlk)) {
2824 DFSWorkList.push_back(SuccBlk);
2835 FindReportInEquivalenceClass(BugReportEquivClass& EQ,
2839 BugType& BT = I->getBugType();
2844 if (!BT.isSuppressOnSink()) {
2846 for (
auto &I : EQ) {
2847 const ExplodedNode *N = I.getErrorNode();
2850 bugReports.push_back(R);
2862 BugReport *exampleReport =
nullptr;
2864 for (; I != E; ++I) {
2865 const ExplodedNode *errorNode = I->getErrorNode();
2869 if (errorNode->isSink()) {
2871 "BugType::isSuppressSink() should not be 'true' for sink end nodes");
2874 if (errorNode->succ_empty()) {
2875 bugReports.push_back(&*I);
2877 exampleReport = &*I;
2885 if (isInevitablySinking(errorNode))
2890 using WLItem = FRIEC_WLItem;
2893 llvm::DenseMap<const ExplodedNode *, unsigned> Visited;
2896 WL.push_back(errorNode);
2897 Visited[errorNode] = 1;
2899 while (!WL.empty()) {
2900 WLItem &WI = WL.back();
2901 assert(!WI.N->succ_empty());
2903 for (; WI.I != WI.E; ++WI.I) {
2904 const ExplodedNode *Succ = *WI.I;
2906 if (Succ->succ_empty()) {
2908 if (!Succ->isSink()) {
2909 bugReports.push_back(&*I);
2911 exampleReport = &*I;
2920 unsigned &mark = Visited[Succ];
2930 if (!WL.empty() && &WL.back() == &WI)
2937 return exampleReport;
2940 void BugReporter::FlushReport(BugReportEquivClass& EQ) {
2942 BugReport *report = FindReportInEquivalenceClass(EQ, bugReports);
2947 std::unique_ptr<DiagnosticForConsumerMapTy> Diagnostics =
2948 generateDiagnosticForConsumerMap(report, Consumers, bugReports);
2950 for (
auto &
P : *Diagnostics) {
2951 PathDiagnosticConsumer *Consumer =
P.first;
2952 std::unique_ptr<PathDiagnostic> &PD =
P.second;
2956 if (PD->path.empty()) {
2958 auto piece = llvm::make_unique<PathDiagnosticEventPiece>(
2959 L, report->getDescription());
2961 piece->addRange(Range);
2962 PD->setEndOfPath(std::move(piece));
2965 PathPieces &Pieces = PD->getMutablePieces();
2969 for (
auto I = report->getNotes().rbegin(),
2970 E = report->getNotes().rend(); I != E; ++I) {
2971 PathDiagnosticNotePiece *Piece = I->get();
2972 auto ConvertedPiece = std::make_shared<PathDiagnosticEventPiece>(
2973 Piece->getLocation(), Piece->getString());
2974 for (
const auto &R: Piece->getRanges())
2975 ConvertedPiece->addRange(R);
2977 Pieces.push_front(std::move(ConvertedPiece));
2980 for (
auto I = report->getNotes().rbegin(),
2981 E = report->getNotes().rend(); I != E; ++I)
2982 Pieces.push_front(*I);
2987 for (
const auto &i : Meta)
2991 Consumer->HandlePathDiagnostic(std::move(PD));
2997 static void populateExecutedLinesWithFunctionSignature(
3002 if (
const auto FD = dyn_cast<FunctionDecl>(Signature)) {
3003 SignatureSourceRange = FD->getSourceRange();
3004 }
else if (
const auto OD = dyn_cast<ObjCMethodDecl>(Signature)) {
3005 SignatureSourceRange = OD->getSourceRange();
3011 : SignatureSourceRange.
getEnd();
3018 for (
unsigned Line = StartLine;
Line <= EndLine;
Line++)
3019 ExecutedLines[FID].insert(
Line);
3022 static void populateExecutedLinesWithStmt(
3031 ExecutedLines[FID].insert(LineNo);
3036 static std::unique_ptr<FilesToLineNumsMap>
3038 auto ExecutedLines = llvm::make_unique<FilesToLineNumsMap>();
3041 if (N->getFirstPred() ==
nullptr) {
3043 const Decl *D = N->getLocationContext()->getDecl();
3044 populateExecutedLinesWithFunctionSignature(D, SM, *ExecutedLines);
3045 }
else if (
auto CE = N->getLocationAs<
CallEnter>()) {
3047 const Decl* D = CE->getCalleeContext()->getDecl();
3048 populateExecutedLinesWithFunctionSignature(D, SM, *ExecutedLines);
3050 populateExecutedLinesWithStmt(S, SM, *ExecutedLines);
3053 const Stmt *
P = N->getParentMap().getParent(S);
3058 if (
const auto *RS = dyn_cast_or_null<ReturnStmt>(P)) {
3059 populateExecutedLinesWithStmt(RS, SM, *ExecutedLines);
3060 P = N->getParentMap().getParent(RS);
3063 if (P && (isa<SwitchCase>(P) || isa<LabelStmt>(P)))
3064 populateExecutedLinesWithStmt(P, SM, *ExecutedLines);
3067 N = N->getFirstPred();
3069 return ExecutedLines;
3072 std::unique_ptr<DiagnosticForConsumerMapTy>
3073 BugReporter::generateDiagnosticForConsumerMap(
3077 if (!report->isPathSensitive()) {
3078 auto Out = llvm::make_unique<DiagnosticForConsumerMapTy>();
3079 for (
auto *Consumer : consumers)
3089 assert(!bugReports.empty());
3090 MaxBugClassSize.updateMax(bugReports.size());
3091 std::unique_ptr<DiagnosticForConsumerMapTy> Out =
3092 generatePathDiagnostics(consumers, bugReports);
3097 MaxValidBugClassSize.updateMax(bugReports.size());
3102 for (
auto const &
P : *Out)
3103 if (Opts.ShouldReportIssuesInMainSourceFile && !Opts.
AnalyzeAll)
3104 P.second->resetDiagnosticLocationToMainFile();
3110 const CheckerBase *Checker,
3111 StringRef Name, StringRef
Category,
3112 StringRef Str, PathDiagnosticLocation Loc,
3114 EmitBasicReport(DeclWithIssue, Checker->getCheckName(), Name,
Category, Str,
3119 CheckName CheckName,
3120 StringRef name, StringRef category,
3121 StringRef
str, PathDiagnosticLocation Loc,
3124 BugType *BT = getBugTypeForName(CheckName, name, category);
3125 auto R = llvm::make_unique<BugReport>(*BT,
str, Loc);
3126 R->setDeclWithIssue(DeclWithIssue);
3130 emitReport(std::move(R));
3133 BugType *BugReporter::getBugTypeForName(CheckName CheckName, StringRef name,
3134 StringRef category) {
3136 llvm::raw_svector_ostream(fullDesc) << CheckName.getName() <<
":" << name
3138 BugType *&BT = StrBugTypes[fullDesc];
3140 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
IgnoreParenCasts - Ignore parentheses and casts.
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 iterator for iterating over Stmt * arrays that contain only Expr *.
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
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.
CFGTerminator getTerminator()
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)
llvm::MemoryBuffer * getBuffer(FileID FID, SourceLocation Loc, bool *Invalid=nullptr) const
Return the buffer for the specified FileID.
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
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)
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.
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.
void Register(BugType *BT)
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)