clang: lib/StaticAnalyzer/Core/BugReporter.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

13

47#include "llvm/ADT/ArrayRef.h"

48#include "llvm/ADT/DenseMap.h"

49#include "llvm/ADT/DenseSet.h"

50#include "llvm/ADT/FoldingSet.h"

51#include "llvm/ADT/STLExtras.h"

52#include "llvm/ADT/SmallPtrSet.h"

53#include "llvm/ADT/StringExtras.h"

54#include "llvm/ADT/StringRef.h"

55#include "llvm/Support/Compiler.h"

56#include "llvm/Support/ErrorHandling.h"

57#include "llvm/Support/TimeProfiler.h"

58#include "llvm/Support/raw_ostream.h"

59#include

60#include

61#include

62#include

63#include

64#include

65#include

66#include

67#include

68#include

69#include

70

71using namespace clang;

72using namespace ento;

73using namespace llvm;

74

75#define DEBUG_TYPE "BugReporter"

76

78 "The maximum number of bug reports in the same equivalence class");

80 "The maximum number of bug reports in the same equivalence class "

81 "where at least one report is valid (not suppressed)");

82

83STAT_COUNTER(NumTimesReportPassesZ3, "Number of reports passed Z3");

84STAT_COUNTER(NumTimesReportRefuted, "Number of reports refuted by Z3");

86 "Number of times a report equivalence class was aborted by the Z3 "

87 "oracle heuristic");

89 "Number of times all reports of an equivalence class was refuted");

90

92

93void BugReporterContext::anchor() {}

94

95

96

97

98

99namespace {

100

101

102using CallWithEntry =

103 std::pair<PathDiagnosticCallPiece *, const ExplodedNode *>;

104using CallWithEntryStack = SmallVector<CallWithEntry, 6>;

105

106

107using VisitorsDiagnosticsTy =

108 llvm::DenseMap<const ExplodedNode *, std::vector>;

109

110

111

112using LocationContextMap =

113 llvm::DenseMap<const PathPieces *, const LocationContext *>;

114

115

116

117

118class PathDiagnosticConstruct {

119

120 const PathDiagnosticConsumer *Consumer;

121

122

123 const ExplodedNode *CurrentNode;

124

125

126

127 LocationContextMap LCM;

128 const SourceManager &SM;

129

130public:

131

132

133

134 CallWithEntryStack CallStack;

135

136

137

138 std::unique_ptr PD;

139

140public:

141 PathDiagnosticConstruct(const PathDiagnosticConsumer *PDC,

142 const ExplodedNode *ErrorNode,

143 const PathSensitiveBugReport *R,

144 const Decl *AnalysisEntryPoint);

145

146

147

148 const LocationContext *getCurrLocationContext() const {

149 assert(CurrentNode && "Already reached the root!");

151 }

152

153

154

155

156 const LocationContext *getLocationContextForActivePath() const {

157 return LCM.find(&PD->getActivePath())->getSecond();

158 }

159

160 const ExplodedNode *getCurrentNode() const { return CurrentNode; }

161

162

163

164 bool ascendToPrevNode() {

166 return static_cast<bool>(CurrentNode);

167 }

168

169 const ParentMap &getParentMap() const {

170 return getCurrLocationContext()->getParentMap();

171 }

172

173 const SourceManager &getSourceManager() const { return SM; }

174

175 const Stmt *getParent(const Stmt *S) const {

176 return getParentMap().getParent(S);

177 }

178

179 void updateLocCtxMap(const PathPieces *Path, const LocationContext *LC) {

180 assert(Path && LC);

181 LCM[Path] = LC;

182 }

183

184 const LocationContext *getLocationContextFor(const PathPieces *Path) const {

185 assert(LCM.count(Path) &&

186 "Failed to find the context associated with these pieces!");

187 return LCM.find(Path)->getSecond();

188 }

189

190 bool isInLocCtxMap(const PathPieces *Path) const { return LCM.count(Path); }

191

192 PathPieces &getActivePath() { return PD->getActivePath(); }

193 PathPieces &getMutablePieces() { return PD->getMutablePieces(); }

194

195 bool shouldAddPathEdges() const { return Consumer->shouldAddPathEdges(); }

196 bool shouldAddControlNotes() const {

198 }

199 bool shouldGenerateDiagnostics() const {

201 }

202 bool supportsLogicalOpControlFlow() const {

204 }

205};

206

207

208

209

210

212

213 std::unique_ptr BugPath;

214

215

216

217

218 const PathSensitiveBugReport *R;

219

220

221 const ExplodedNode *const ErrorNode;

222

223

224 std::unique_ptr VisitorsDiagnostics;

225

226public:

227

228

229

230 static std::optional

231 findValidReport(ArrayRef<PathSensitiveBugReport *> &bugReports,

232 PathSensitiveBugReporter &Reporter);

233

234 PathDiagnosticBuilder(

235 BugReporterContext BRC, std::unique_ptr BugPath,

236 PathSensitiveBugReport *r, const ExplodedNode *ErrorNode,

237 std::unique_ptr VisitorsDiagnostics);

238

239

240

241

242

243

244

245

246

247

248

249 std::unique_ptr

250 generate(const PathDiagnosticConsumer *PDC) const;

251

252private:

254 const CallWithEntryStack &CallStack) const;

255 void generatePathDiagnosticsForNode(PathDiagnosticConstruct &C,

256 PathDiagnosticLocation &PrevLoc) const;

257

258 void generateMinimalDiagForBlockEdge(PathDiagnosticConstruct &C,

259 BlockEdge BE) const;

260

262 generateDiagForGotoOP(const PathDiagnosticConstruct &C, const Stmt *S,

263 PathDiagnosticLocation &Start) const;

264

266 generateDiagForSwitchOP(const PathDiagnosticConstruct &C, const CFGBlock *Dst,

267 PathDiagnosticLocation &Start) const;

268

270 generateDiagForBinaryOP(const PathDiagnosticConstruct &C, const Stmt *T,

271 const CFGBlock *Src, const CFGBlock *DstC) const;

272

273 PathDiagnosticLocation

274 ExecutionContinues(const PathDiagnosticConstruct &C) const;

275

276 PathDiagnosticLocation

277 ExecutionContinues(llvm::raw_string_ostream &os,

278 const PathDiagnosticConstruct &C) const;

279

280 const PathSensitiveBugReport *getBugReport() const { return R; }

281};

282

284 if (!llvm::timeTraceProfilerEnabled())

285 return "";

286 const auto &BugReports = EQ.getReports();

287 if (BugReports.empty())

288 return "Empty Equivalence Class";

289 const BugReport *R = BugReports.front().get();

291 return ("Flushing EQC " + BT.getDescription()).str();

292}

293

295 const SourceManager &SM) {

296

297 assert(llvm::timeTraceProfilerEnabled());

298

299 const auto &BugReports = EQ.getReports();

300 if (BugReports.empty())

301 return {};

302 const BugReport *R = BugReports.front().get();

305 std::string File = SM.getFilename(Loc).str();

306 return {BT.getCheckerName().str(), std::move(File),

307 static_cast<int>(Loc.getLineNumber())};

308}

309

310}

311

312

313

314

315

317

319 if (!N)

321

324

325

327 const auto *CE = dyn_cast_or_null(CallSite);

328 if (!CE)

329 return {};

330

331

332 for (auto [Idx, ArgExpr] : llvm::enumerate(CE->arguments())) {

334

335

337 if (AS == Sym) {

339 }

340

341

343

344 if (ArgExpr->getType()->isVoidPointerType())

345 continue;

346 SVal PSV = N->getState()->getSVal(Reg->getRegion());

348 if (AS == Sym) {

350 }

351 }

352 }

353

354

357 if (RetSym == Sym) {

359 }

360

362}

363

365 unsigned ArgIndex) {

366

367 ++ArgIndex;

368

369 return (llvm::Twine(Msg) + " via " + std::to_string(ArgIndex) +

370 llvm::getOrdinalSuffix(ArgIndex) + " parameter").str();

371}

372

373

374

375

376

380

381

382

383

386

388 return nullptr;

389

390 if (X->getTag() == tagPreferred && Y->getTag() == tagLesser)

392

393 if (Y->getTag() == tagPreferred && X->getTag() == tagLesser)

395

396 return nullptr;

397}

398

399

400

401

402

403

405 unsigned N = path.size();

406 if (N < 2)

407 return;

408

409

410

411

412 for (unsigned i = 0; i < N; ++i) {

413 auto piece = std::move(path.front());

414 path.pop_front();

415

416 switch (piece->getKind()) {

419 break;

422 break;

424 if (i == N-1)

425 break;

426

427 if (auto *nextEvent =

428 dyn_cast(path.front().get())) {

430

431

432

433 if (auto *pieceToKeep =

435 piece = std::move(pieceToKeep == event ? piece : path.front());

436 path.pop_front();

437 ++i;

438 }

439 }

440 break;

441 }

445 break;

446 }

447 path.push_back(std::move(piece));

448 }

449}

450

451

452

453

457 bool IsInteresting = false) {

458 bool containsSomethingInteresting = IsInteresting;

459 const unsigned N = pieces.size();

460

461 for (unsigned i = 0 ; i < N ; ++i) {

462

463

464 auto piece = std::move(pieces.front());

465 pieces.pop_front();

466

467 switch (piece->getKind()) {

470

472 C, call.path, R,

473 R->isInteresting(C.getLocationContextFor(&call.path))))

474 continue;

475

476 containsSomethingInteresting = true;

477 break;

478 }

482 continue;

483 containsSomethingInteresting = true;

484 break;

485 }

488

489

490

491 containsSomethingInteresting |= !event.isPrunable();

492 break;

493 }

497 break;

498 }

499

500 pieces.push_back(std::move(piece));

501 }

502

503 return containsSomethingInteresting;

504}

505

506

508 for (unsigned int i = 0; i < Path.size(); ++i) {

509 auto Piece = std::move(Path.front());

510 Path.pop_front();

512 Path.push_back(std::move(Piece));

513 }

514}

515

516

517

522

523

524

525static void

528 for (const auto &I : Pieces) {

529 auto *Call = dyn_cast(I.get());

530

532 continue;

533

534 if (LastCallLocation) {

536 if (CallerIsImplicit || Call->callEnter.asLocation().isValid())

537 Call->callEnter = *LastCallLocation;

538 if (CallerIsImplicit || Call->callReturn.asLocation().isValid())

539 Call->callReturn = *LastCallLocation;

540 }

541

542

543

545 if (Call->callEnterWithin.asLocation().isValid() &&

547 ThisCallLocation = &Call->callEnterWithin;

548 else

549 ThisCallLocation = &Call->callEnter;

550

551 assert(ThisCallLocation && "Outermost call has an invalid location");

553 }

554}

555

556

557

558

560 for (PathPieces::iterator I = Pieces.begin(), E = Pieces.end(); I != E;) {

561 if (auto *C = dyn_cast(I->get()))

563

564 if (auto *M = dyn_cast(I->get()))

566

567 if (auto *CF = dyn_cast(I->get())) {

568 const Stmt *Start = CF->getStartLocation().asStmt();

569 const Stmt *End = CF->getEndLocation().asStmt();

570 if (isa_and_nonnull(Start)) {

571 I = Pieces.erase(I);

572 continue;

573 } else if (isa_and_nonnull(End)) {

574 PathPieces::iterator Next = std::next(I);

575 if (Next != E) {

576 if (auto *NextCF =

577 dyn_cast(Next->get())) {

578 NextCF->setStartLocation(CF->getStartLocation());

579 }

580 }

581 I = Pieces.erase(I);

582 continue;

583 }

584 }

585

586 I++;

587 }

588}

589

590

591

592

594 for (PathPieces::iterator I = Pieces.begin(), E = Pieces.end(); I != E;) {

595 if (auto *C = dyn_cast(I->get()))

597

598 if (auto *M = dyn_cast(I->get()))

600

601 if (!(*I)->getLocation().isValid() ||

602 !(*I)->getLocation().asLocation().isValid()) {

603 I = Pieces.erase(I);

604 continue;

605 }

606 I++;

607 }

608}

609

611 const PathDiagnosticConstruct &C) const {

612 if (const Stmt *S = C.getCurrentNode()->getNextStmtForDiagnostics())

614 C.getCurrLocationContext());

615

617 getSourceManager());

618}

619

621 llvm::raw_string_ostream &os, const PathDiagnosticConstruct &C) const {

622

623 if (os.str().empty())

624 os << ' ';

625

627

628 if (Loc.asStmt())

629 os << "Execution continues on line "

630 << getSourceManager().getExpansionLineNumber(Loc.asLocation())

631 << '.';

632 else {

633 os << "Execution jumps to the end of the ";

634 const Decl *D = C.getCurrLocationContext()->getDecl();

636 os << "method";

638 os << "function";

639 else {

641 os << "anonymous block";

642 }

643 os << '.';

644 }

645

646 return Loc;

647}

648

652

654 if (!Parent)

655 return nullptr;

656

658 case Stmt::ForStmtClass:

659 case Stmt::DoStmtClass:

660 case Stmt::WhileStmtClass:

661 case Stmt::ObjCForCollectionStmtClass:

662 case Stmt::CXXForRangeStmtClass:

663 return Parent;

664 default:

665 break;

666 }

667

668 return nullptr;

669}

670

673 bool allowNestedContexts = false) {

674 if (!S)

675 return {};

676

678

680 switch (Parent->getStmtClass()) {

681 case Stmt::BinaryOperatorClass: {

683 if (B->isLogicalOp())

685 break;

686 }

687 case Stmt::CompoundStmtClass:

688 case Stmt::StmtExprClass:

690 case Stmt::ChooseExprClass:

691

692

693 if (allowNestedContexts || cast(Parent)->getCond() == S)

695 else

697 case Stmt::BinaryConditionalOperatorClass:

698 case Stmt::ConditionalOperatorClass:

699

700

701 if (allowNestedContexts ||

704 else

706 case Stmt::CXXForRangeStmtClass:

709 break;

710 case Stmt::DoStmtClass:

712 case Stmt::ForStmtClass:

715 break;

716 case Stmt::IfStmtClass:

719 break;

720 case Stmt::ObjCForCollectionStmtClass:

723 break;

724 case Stmt::WhileStmtClass:

727 break;

728 default:

729 break;

730 }

731

732 S = Parent;

733 }

734

735 assert(S && "Cannot have null Stmt for PathDiagnosticLocation");

736

738}

739

740

741

742

743

744

745

746

747

748

749

750

751

752

753

754void PathDiagnosticBuilder::updateStackPiecesWithMessage(

756 if (R->hasCallStackHint(P))

757 for (const auto &I : CallStack) {

760 std::string stackMsg = R->getCallStackMessage(P, N);

761

762

763

764

767 }

768}

769

771 const SourceManager& SM);

772

774 const PathDiagnosticConstruct &C, const CFGBlock *Dst,

776

777 const SourceManager &SM = getSourceManager();

778

779 std::string sbuf;

780 llvm::raw_string_ostream os(sbuf);

782

783 if (const Stmt *S = Dst->getLabel()) {

785

787 default:

788 os << "No cases match in the switch statement. "

789 "Control jumps to line "

791 break;

792 case Stmt::DefaultStmtClass:

793 os << "Control jumps to the 'default' case at line "

795 break;

796

797 case Stmt::CaseStmtClass: {

798 os << "Control jumps to 'case ";

800 const Expr *LHS = Case->getLHS()->IgnoreParenImpCasts();

801

802

803 bool GetRawInt = true;

804

805 if (const auto *DR = dyn_cast(LHS)) {

806

807

808 const auto *D = dyn_cast(DR->getDecl());

809

810 if (D) {

811 GetRawInt = false;

812 os << *D;

813 }

814 }

815

816 if (GetRawInt)

818

820 break;

821 }

822 }

823 } else {

824 os << "'Default' branch taken. ";

825 End = ExecutionContinues(os, C);

826 }

827 return std::make_shared(Start, End, sbuf);

828}

829

831 const PathDiagnosticConstruct &C, const Stmt *S,

833 std::string sbuf;

834 llvm::raw_string_ostream os(sbuf);

838 return std::make_shared(Start, End, sbuf);

839}

840

842 const PathDiagnosticConstruct &C, const Stmt *T, const CFGBlock *Src,

843 const CFGBlock *Dst) const {

844

845 const SourceManager &SM = getSourceManager();

846

848 std::string sbuf;

849 llvm::raw_string_ostream os(sbuf);

850 os << "Left side of '";

852

853 if (B->getOpcode() == BO_LAnd) {

854 os << "&&"

855 << "' is ";

856

857 if (*(Src->succ_begin() + 1) == Dst) {

858 os << "false";

860 Start =

862 } else {

863 os << "true";

864 Start =

866 End = ExecutionContinues(C);

867 }

868 } else {

869 assert(B->getOpcode() == BO_LOr);

870 os << "||"

871 << "' is ";

872

873 if (*(Src->succ_begin() + 1) == Dst) {

874 os << "false";

875 Start =

877 End = ExecutionContinues(C);

878 } else {

879 os << "true";

881 Start =

883 }

884 }

885 return std::make_shared(Start, End, sbuf);

886}

887

888void PathDiagnosticBuilder::generateMinimalDiagForBlockEdge(

889 PathDiagnosticConstruct &C, BlockEdge BE) const {

890 const SourceManager &SM = getSourceManager();

891 const LocationContext *LC = C.getCurrLocationContext();

892 const CFGBlock *Src = BE.getSrc();

893 const CFGBlock *Dst = BE.getDst();

895 if (T)

896 return;

897

899 switch (T->getStmtClass()) {

900 default:

901 break;

902

903 case Stmt::GotoStmtClass:

904 case Stmt::IndirectGotoStmtClass: {

905 if (const Stmt *S = C.getCurrentNode()->getNextStmtForDiagnostics())

906 C.getActivePath().push_front(generateDiagForGotoOP(C, S, Start));

907 break;

908 }

909

910 case Stmt::SwitchStmtClass: {

911 C.getActivePath().push_front(generateDiagForSwitchOP(C, Dst, Start));

912 break;

913 }

914

915 case Stmt::BreakStmtClass:

916 case Stmt::ContinueStmtClass: {

917 std::string sbuf;

918 llvm::raw_string_ostream os(sbuf);

920 C.getActivePath().push_front(

921 std::make_shared(Start, End, sbuf));

922 break;

923 }

924

925

926 case Stmt::BinaryConditionalOperatorClass:

927 case Stmt::ConditionalOperatorClass: {

928 std::string sbuf;

929 llvm::raw_string_ostream os(sbuf);

930 os << "'?' condition is ";

931

933 os << "false";

934 else

935 os << "true";

936

938

939 if (const Stmt *S = End.asStmt())

941

942 C.getActivePath().push_front(

943 std::make_shared(Start, End, sbuf));

944 break;

945 }

946

947

948 case Stmt::BinaryOperatorClass: {

949 if (C.supportsLogicalOpControlFlow())

950 break;

951

952 C.getActivePath().push_front(generateDiagForBinaryOP(C, T, Src, Dst));

953 break;

954 }

955

956 case Stmt::DoStmtClass:

958 std::string sbuf;

959 llvm::raw_string_ostream os(sbuf);

960

961 os << "Loop condition is true. ";

963

964 if (const Stmt *S = End.asStmt())

966

967 C.getActivePath().push_front(

968 std::make_shared(Start, End, sbuf));

969 } else {

971

972 if (const Stmt *S = End.asStmt())

974

975 C.getActivePath().push_front(

976 std::make_shared(

977 Start, End, "Loop condition is false. Exiting loop"));

978 }

979 break;

980

981 case Stmt::WhileStmtClass:

982 case Stmt::ForStmtClass:

983 if (*(Src->succ_begin() + 1) == Dst) {

984 std::string sbuf;

985 llvm::raw_string_ostream os(sbuf);

986

987 os << "Loop condition is false. ";

989 if (const Stmt *S = End.asStmt())

991

992 C.getActivePath().push_front(

993 std::make_shared(Start, End, sbuf));

994 } else {

996 if (const Stmt *S = End.asStmt())

998

999 C.getActivePath().push_front(

1000 std::make_shared(

1001 Start, End, "Loop condition is true. Entering loop body"));

1002 }

1003

1004 break;

1005

1006 case Stmt::IfStmtClass: {

1008

1009 if (const Stmt *S = End.asStmt())

1011

1012 if (*(Src->succ_begin() + 1) == Dst)

1013 C.getActivePath().push_front(

1014 std::make_shared(

1015 Start, End, "Taking false branch"));

1016 else

1017 C.getActivePath().push_front(

1018 std::make_shared(

1019 Start, End, "Taking true branch"));

1020

1021 break;

1022 }

1023 }

1024}

1025

1026

1027

1028

1029

1032 case Stmt::ForStmtClass:

1033 case Stmt::WhileStmtClass:

1034 case Stmt::ObjCForCollectionStmtClass:

1035 case Stmt::CXXForRangeStmtClass:

1036 return true;

1037 default:

1038

1039 return false;

1040 }

1041}

1042

1048

1050 const Stmt *SubS) {

1051 while (SubS) {

1052 if (SubS == S)

1053 return true;

1055 }

1056 return false;

1057}

1058

1061 while (N) {

1063 if (SP) {

1064 const Stmt *S = SP->getStmt();

1066 return S;

1067 }

1069 }

1070 return nullptr;

1071}

1072

1074 const Stmt *LoopBody = nullptr;

1076 case Stmt::CXXForRangeStmtClass: {

1079 return true;

1081 return true;

1082 LoopBody = FR->getBody();

1083 break;

1084 }

1085 case Stmt::ForStmtClass: {

1088 return true;

1089 LoopBody = FS->getBody();

1090 break;

1091 }

1092 case Stmt::ObjCForCollectionStmtClass: {

1094 LoopBody = FC->getBody();

1095 break;

1096 }

1097 case Stmt::WhileStmtClass:

1099 break;

1100 default:

1101 return false;

1102 }

1104}

1105

1106

1111 return;

1112

1115 return;

1116

1118 PrevLoc = NewLoc;

1119 return;

1120 }

1121

1122

1123

1125 return;

1126

1127 path.push_front(

1128 std::make_shared(NewLoc, PrevLoc));

1129 PrevLoc = NewLoc;

1130}

1131

1132

1133

1136 if (const auto *FS = dyn_cast_or_null(S))

1137 return FS->getElement();

1138 return S;

1139}

1140

1142constexpr llvm::StringLiteral StrLoopBodyZero = "Loop body executed 0 times";

1144 "Loop body skipped when range is empty";

1146 "Loop body skipped when collection is empty";

1147

1148static std::unique_ptr

1150

1151void PathDiagnosticBuilder::generatePathDiagnosticsForNode(

1153 ProgramPoint P = C.getCurrentNode()->getLocation();

1155

1156

1157

1158

1159

1161

1162 if (C.shouldAddPathEdges()) {

1163

1166

1167

1168

1169

1170

1171

1175 }

1176

1177

1178 bool VisitedEntireCall = C.PD->isWithinCall();

1179 C.PD->popActivePath();

1180

1182 if (VisitedEntireCall) {

1184 } else {

1185

1186

1187 const Decl *Caller = CE->getLocationContext()->getDecl();

1189 assert(C.getActivePath().size() == 1 &&

1190 C.getActivePath().front().get() == Call);

1191

1192

1193

1194 assert(C.isInLocCtxMap(&C.getActivePath()) &&

1195 "When we ascend to a previously unvisited call, the active path's "

1196 "address shouldn't change, but rather should be compacted into "

1197 "a single CallEvent!");

1198 C.updateLocCtxMap(&C.getActivePath(), C.getCurrLocationContext());

1199

1200

1201 assert(C.isInLocCtxMap(&Call->path) &&

1202 "When we ascend to a previously unvisited call, this must be the "

1203 "first time we encounter the caller context!");

1204 C.updateLocCtxMap(&Call->path, CE->getCalleeContext());

1205 }

1207

1208

1209 PrevLoc = Call->getLocation();

1210

1211 if (C.CallStack.empty()) {

1212 assert(C.CallStack.back().first == Call);

1213 C.CallStack.pop_back();

1214 }

1215 return;

1216 }

1217

1218 assert(C.getCurrLocationContext() == C.getLocationContextForActivePath() &&

1219 "The current position in the bug path is out of sync with the "

1220 "location context associated with the active path!");

1221

1222

1223 if (std::optional CE = P.getAs()) {

1224

1225

1226

1228

1229 assert(C.isInLocCtxMap(&Call->path) &&

1230 "We just entered a call, this must've been the first time we "

1231 "encounter its context!");

1232 C.updateLocCtxMap(&Call->path, CE->getCalleeContext());

1233

1234 if (C.shouldAddPathEdges()) {

1235

1238 }

1239

1240 auto *P = Call.get();

1241 C.getActivePath().push_front(std::move(Call));

1242

1243

1244 C.PD->pushActivePath(&P->path);

1245 C.CallStack.push_back(CallWithEntry(P, C.getCurrentNode()));

1246 return;

1247 }

1248

1249 if (auto PS = P.getAs()) {

1250 if (C.shouldAddPathEdges())

1251 return;

1252

1253

1254

1255

1260 }

1261

1262 } else if (auto BE = P.getAs()) {

1263

1264 if (C.shouldAddControlNotes()) {

1265 generateMinimalDiagForBlockEdge(C, *BE);

1266 }

1267

1268 if (C.shouldAddPathEdges()) {

1269 return;

1270 }

1271

1272

1275 const Stmt *Body = nullptr;

1276

1277 if (const auto *FS = dyn_cast(Loop))

1278 Body = FS->getBody();

1279 else if (const auto *WS = dyn_cast(Loop))

1280 Body = WS->getBody();

1281 else if (const auto *OFS = dyn_cast(Loop)) {

1282 Body = OFS->getBody();

1283 } else if (const auto *FRS = dyn_cast(Loop)) {

1284 Body = FRS->getBody();

1285 }

1286

1287

1288 auto p = std::make_shared(

1289 L, "Looping back to the head of the loop");

1290 p->setPrunable(true);

1291

1292 addEdgeToPath(C.getActivePath(), PrevLoc, p->getLocation());

1293

1294 if (C.shouldAddControlNotes()) {

1295 C.getActivePath().push_front(std::move(p));

1296 }

1297

1298 if (const auto *CS = dyn_cast_or_null(Body)) {

1301 }

1302 }

1303

1304 const CFGBlock *BSrc = BE->getSrc();

1305 const ParentMap &PM = C.getParentMap();

1306

1308

1309

1314

1315 StringRef str;

1316

1318 if (!IsInLoopBody) {

1323 } else {

1325 }

1326 }

1327 } else {

1329 }

1330

1331 if (!str.empty()) {

1333 C.getCurrLocationContext());

1334 auto PE = std::make_shared(L, str);

1335 PE->setPrunable(true);

1336 addEdgeToPath(C.getActivePath(), PrevLoc, PE->getLocation());

1337

1338

1339 if (C.shouldAddControlNotes()) {

1340 C.getActivePath().push_front(std::move(PE));

1341 }

1342 }

1346 }

1347 }

1348 }

1349}

1350

1351static std::unique_ptr

1353 const Decl *AnalysisEntryPoint) {

1355 return std::make_unique(

1359 AnalysisEntryPoint, std::make_unique());

1360}

1361

1362static std::unique_ptr

1365 const Decl *AnalysisEntryPoint) {

1367 return std::make_unique(

1372}

1373

1375 if (!S)

1376 return nullptr;

1377

1378 while (true) {

1380

1381 if (!S)

1382 break;

1383

1385 continue;

1386

1387 break;

1388 }

1389

1390 return S;

1391}

1392

1395 case Stmt::BinaryOperatorClass: {

1397 if (!BO->isLogicalOp())

1398 return false;

1399 return BO->getLHS() == Cond || BO->getRHS() == Cond;

1400 }

1401 case Stmt::IfStmtClass:

1403 case Stmt::ForStmtClass:

1405 case Stmt::WhileStmtClass:

1407 case Stmt::DoStmtClass:

1409 case Stmt::ChooseExprClass:

1411 case Stmt::IndirectGotoStmtClass:

1413 case Stmt::SwitchStmtClass:

1415 case Stmt::BinaryConditionalOperatorClass:

1417 case Stmt::ConditionalOperatorClass: {

1419 return CO->getCond() == Cond ||

1420 CO->getLHS() == Cond ||

1421 CO->getRHS() == Cond;

1422 }

1423 case Stmt::ObjCForCollectionStmtClass:

1425 case Stmt::CXXForRangeStmtClass: {

1427 return FRS->getCond() == Cond || FRS->getRangeInit() == Cond;

1428 }

1429 default:

1430 return false;

1431 }

1432}

1433

1435 if (const auto *FS = dyn_cast(FL))

1436 return FS->getInc() == S || FS->getInit() == S;

1437 if (const auto *FRS = dyn_cast(FL))

1438 return FRS->getInc() == S || FRS->getRangeStmt() == S ||

1439 FRS->getLoopVarStmt() || FRS->getRangeInit() == S;

1440 return false;

1441}

1442

1444

1445

1446

1447

1448

1449

1452 PathPieces::iterator Prev = pieces.end();

1453 for (PathPieces::iterator I = pieces.begin(), E = Prev; I != E;

1454 Prev = I, ++I) {

1455 auto *Piece = dyn_cast(I->get());

1456

1457 if (!Piece)

1458 continue;

1459

1462

1464 const Stmt *InnerStmt = nullptr;

1465 while (NextSrcContext.isValid() && NextSrcContext.asStmt() != InnerStmt) {

1466 SrcContexts.push_back(NextSrcContext);

1467 InnerStmt = NextSrcContext.asStmt();

1469 true);

1470 }

1471

1472

1473

1474

1475 while (true) {

1476 const Stmt *Dst = Piece->getEndLocation().getStmtOrNull();

1477

1478

1479

1482 if (!DstContext.isValid() || DstContext.asStmt() == Dst)

1483 break;

1484

1485

1486 if (llvm::is_contained(SrcContexts, DstContext))

1487 break;

1488

1489

1490 Piece->setStartLocation(DstContext);

1491

1492

1493

1494 if (Prev != E) {

1495 auto *PrevPiece = dyn_cast(Prev->get());

1496

1497 if (PrevPiece) {

1498 if (const Stmt *PrevSrc =

1499 PrevPiece->getStartLocation().getStmtOrNull()) {

1501 if (PrevSrcParent ==

1503 PrevPiece->setEndLocation(DstContext);

1504 break;

1505 }

1506 }

1507 }

1508 }

1509

1510

1511

1512

1513 auto P =

1514 std::make_shared(SrcLoc, DstContext);

1515 Piece = P.get();

1516 I = pieces.insert(I, std::move(P));

1517 }

1518 }

1519}

1520

1521

1522

1523

1524

1525

1526

1527

1528

1529

1530

1532 for (PathPieces::iterator I = pieces.begin(), E = pieces.end(); I != E; ++I) {

1533 const auto *PieceI = dyn_cast(I->get());

1534

1535 if (!PieceI)

1536 continue;

1537

1538 const Stmt *s1Start = PieceI->getStartLocation().getStmtOrNull();

1539 const Stmt *s1End = PieceI->getEndLocation().getStmtOrNull();

1540

1541 if (!s1Start || !s1End)

1542 continue;

1543

1544 PathPieces::iterator NextI = I; ++NextI;

1545 if (NextI == E)

1546 break;

1547

1549

1550 while (true) {

1551 if (NextI == E)

1552 break;

1553

1554 const auto *EV = dyn_cast(NextI->get());

1555 if (EV) {

1556 StringRef S = EV->getString();

1559 ++NextI;

1560 continue;

1561 }

1562 break;

1563 }

1564

1565 PieceNextI = dyn_cast(NextI->get());

1566 break;

1567 }

1568

1569 if (!PieceNextI)

1570 continue;

1571

1574

1575 if (!s2Start || !s2End || s1End != s2Start)

1576 continue;

1577

1578

1579

1582 continue;

1583

1584

1586 continue;

1587

1588

1589

1591 I = pieces.erase(I);

1592 }

1593}

1594

1595

1596

1597

1598

1599

1600

1604 SM.getExpansionRange(Range.getEnd()).getEnd());

1605

1607 if (FID != SM.getFileID(ExpansionRange.getEnd()))

1608 return std::nullopt;

1609

1610 std::optional Buffer = SM.getBufferOrNone(FID);

1611 if (!Buffer)

1612 return std::nullopt;

1613

1614 unsigned BeginOffset = SM.getFileOffset(ExpansionRange.getBegin());

1615 unsigned EndOffset = SM.getFileOffset(ExpansionRange.getEnd());

1616 StringRef Snippet = Buffer->getBuffer().slice(BeginOffset, EndOffset);

1617

1618

1619

1620

1621

1622 if (Snippet.find_first_of("\r\n") != StringRef::npos)

1623 return std::nullopt;

1624

1625

1626 return Snippet.size();

1627}

1628

1629

1631 const Stmt *S) {

1633}

1634

1635

1636

1637

1638

1639

1640

1641

1642

1643

1644

1645

1646

1647

1648

1649

1650

1652 for (PathPieces::iterator I = Path.begin(), E = Path.end(); I != E; ) {

1653

1654 const auto *PieceI = dyn_cast(I->get());

1655

1656 if (!PieceI) {

1657 ++I;

1658 continue;

1659 }

1660

1661 const Stmt *s1Start = PieceI->getStartLocation().getStmtOrNull();

1662 const Stmt *s1End = PieceI->getEndLocation().getStmtOrNull();

1663

1664 PathPieces::iterator NextI = I; ++NextI;

1665 if (NextI == E)

1666 break;

1667

1668 const auto *PieceNextI =

1669 dyn_cast(NextI->get());

1670

1671 if (!PieceNextI) {

1673 ++NextI;

1674 if (NextI == E)

1675 break;

1676 PieceNextI = dyn_cast(NextI->get());

1677 }

1678

1679 if (!PieceNextI) {

1680 ++I;

1681 continue;

1682 }

1683 }

1684

1685 const Stmt *s2Start = PieceNextI->getStartLocation().getStmtOrNull();

1686 const Stmt *s2End = PieceNextI->getEndLocation().getStmtOrNull();

1687

1688 if (s1Start && s2Start && s1Start == s2End && s2Start == s1End) {

1689 const size_t MAX_SHORT_LINE_LENGTH = 80;

1691 if (s1Length && *s1Length <= MAX_SHORT_LINE_LENGTH) {

1693 if (s2Length && *s2Length <= MAX_SHORT_LINE_LENGTH) {

1694 Path.erase(I);

1695 I = Path.erase(NextI);

1696 continue;

1697 }

1698 }

1699 }

1700

1701 ++I;

1702 }

1703}

1704

1705

1707 while (X) {

1708 if (X == Y)

1709 return true;

1711 }

1712 return false;

1713}

1714

1715

1718 bool erased = false;

1719

1720 for (PathPieces::iterator I = path.begin(), E = path.end(); I != E;

1721 erased ? I : ++I) {

1722 erased = false;

1723

1724 const auto *PieceI = dyn_cast(I->get());

1725

1726 if (!PieceI)

1727 continue;

1728

1729 const Stmt *start = PieceI->getStartLocation().getStmtOrNull();

1730 const Stmt *end = PieceI->getEndLocation().getStmtOrNull();

1731

1732 if (!start || !end)

1733 continue;

1734

1736 if (!endParent)

1737 continue;

1738

1740 continue;

1741

1744

1745 if (SM.isWrittenInSameFile(FirstLoc, SecondLoc))

1746 continue;

1747 if (SM.isBeforeInTranslationUnit(SecondLoc, FirstLoc))

1748 std::swap(SecondLoc, FirstLoc);

1749

1750 SourceRange EdgeRange(FirstLoc, SecondLoc);

1752

1753

1754 if (!ByteWidth)

1755 continue;

1756

1757 const size_t MAX_PUNY_EDGE_LENGTH = 2;

1758 if (*ByteWidth <= MAX_PUNY_EDGE_LENGTH) {

1759

1760

1761

1762 I = path.erase(I);

1763 erased = true;

1764 continue;

1765 }

1766 }

1767}

1768

1770 for (PathPieces::iterator I = path.begin(), E = path.end(); I != E; ++I) {

1771 const auto *PieceI = dyn_cast(I->get());

1772

1773 if (!PieceI)

1774 continue;

1775

1776 PathPieces::iterator NextI = I; ++NextI;

1777 if (NextI == E)

1778 return;

1779

1780 const auto *PieceNextI = dyn_cast(NextI->get());

1781

1782 if (!PieceNextI)

1783 continue;

1784

1785

1786 if (PieceI->getString() == PieceNextI->getString()) {

1787 path.erase(NextI);

1788 }

1789 }

1790}

1791

1794 bool hasChanges = false;

1796 assert(LC);

1799

1800 for (PathPieces::iterator I = path.begin(), E = path.end(); I != E; ) {

1801

1802 if (auto *CallI = dyn_cast(I->get())) {

1803

1804

1805 if (!OCS.count(CallI)) {

1807 }

1808 OCS.insert(CallI);

1809 }

1810 ++I;

1811 continue;

1812 }

1813

1814

1815 auto *PieceI = dyn_cast(I->get());

1816

1817 if (!PieceI) {

1818 ++I;

1819 continue;

1820 }

1821

1822 const Stmt *s1Start = PieceI->getStartLocation().getStmtOrNull();

1823 const Stmt *s1End = PieceI->getEndLocation().getStmtOrNull();

1826

1827 PathPieces::iterator NextI = I; ++NextI;

1828 if (NextI == E)

1829 break;

1830

1831 const auto *PieceNextI = dyn_cast(NextI->get());

1832

1833 if (!PieceNextI) {

1834 ++I;

1835 continue;

1836 }

1837

1838 const Stmt *s2Start = PieceNextI->getStartLocation().getStmtOrNull();

1839 const Stmt *s2End = PieceNextI->getEndLocation().getStmtOrNull();

1842

1843

1844

1845

1846

1847

1848

1849

1850

1851

1852

1853

1854

1855

1856

1857 if (level1 && level1 == level2 && level1 == level3 && level1 == level4) {

1858 PieceI->setEndLocation(PieceNextI->getEndLocation());

1859 path.erase(NextI);

1860 hasChanges = true;

1861 continue;

1862 }

1863

1864

1865

1866

1867

1868

1869

1870

1871 if (s1End && s1End == s2Start && level2) {

1872 bool removeEdge = false;

1873

1874

1875

1877 removeEdge = true;

1878

1879

1880

1882

1883

1885 removeEdge = true;

1886 }

1887

1888

1889

1890

1891

1892

1893

1894

1895

1896

1897

1898 else if (s1Start && s2End &&

1901 removeEdge = true;

1902 }

1903

1904

1905

1906

1907

1908

1909

1910

1911 else if (s1Start && s2End &&

1913 SourceRange EdgeRange(PieceI->getEndLocation().asLocation(),

1914 PieceI->getStartLocation().asLocation());

1916 removeEdge = true;

1917 }

1918 }

1919

1920 if (removeEdge) {

1921 PieceI->setEndLocation(PieceNextI->getEndLocation());

1922 path.erase(NextI);

1923 hasChanges = true;

1924 continue;

1925 }

1926 }

1927

1928

1929

1930

1931

1932

1933

1934

1935 if (s1End == s2Start) {

1936 const auto *FS = dyn_cast_or_null(level3);

1937 if (FS && FS->getCollection()->IgnoreParens() == s2Start &&

1938 s2End == FS->getElement()) {

1939 PieceI->setEndLocation(PieceNextI->getEndLocation());

1940 path.erase(NextI);

1941 hasChanges = true;

1942 continue;

1943 }

1944 }

1945

1946

1947 ++I;

1948 }

1949

1950 if (!hasChanges) {

1951

1952

1954

1956

1957

1959

1961

1963 }

1964

1965 return hasChanges;

1966}

1967

1968

1969

1970

1971

1972

1973

1976 const auto *FirstEdge =

1977 dyn_cast(Path.front().get());

1978 if (!FirstEdge)

1979 return;

1980

1981 const Decl *D = C.getLocationContextFor(&Path)->getDecl();

1984 if (FirstEdge->getStartLocation() != EntryLoc)

1985 return;

1986

1987 Path.pop_front();

1988}

1989

1990

1992

1995

1996 for (const auto &P : path) {

1997 FullSourceLoc Loc = P->getLocation().asLocation().getExpansionLoc();

1999 unsigned LineNo = Loc.getLineNumber();

2001 ExecutedLines[FID].insert(LineNo);

2002 }

2003}

2004

2005PathDiagnosticConstruct::PathDiagnosticConstruct(

2008 : Consumer(PDC), CurrentNode(ErrorNode),

2009 SM(CurrentNode->getCodeDecl().getASTContext().getSourceManager()),

2011 AnalysisEntryPoint)) {

2013}

2014

2015PathDiagnosticBuilder::PathDiagnosticBuilder(

2018 std::unique_ptr VisitorsDiagnostics)

2020 ErrorNode(ErrorNode),

2021 VisitorsDiagnostics(std::move(VisitorsDiagnostics)) {}

2022

2023std::unique_ptr

2025 const Decl *EntryPoint = getBugReporter().getAnalysisEntryPoint();

2026 PathDiagnosticConstruct Construct(PDC, ErrorNode, R, EntryPoint);

2027

2028 const SourceManager &SM = getSourceManager();

2029 const AnalyzerOptions &Opts = getAnalyzerOptions();

2030

2033

2034

2035 auto EndNotes = VisitorsDiagnostics->find(ErrorNode);

2037 if (EndNotes != VisitorsDiagnostics->end()) {

2038 assert(!EndNotes->second.empty());

2039 LastPiece = EndNotes->second[0];

2040 } else {

2042 *getBugReport());

2043 }

2044 Construct.PD->setEndOfPath(LastPiece);

2045

2046 PathDiagnosticLocation PrevLoc = Construct.PD->getLocation();

2047

2048

2049 while (Construct.ascendToPrevNode()) {

2050 generatePathDiagnosticsForNode(Construct, PrevLoc);

2051

2052 auto VisitorNotes = VisitorsDiagnostics->find(Construct.getCurrentNode());

2053 if (VisitorNotes == VisitorsDiagnostics->end())

2054 continue;

2055

2056

2057

2058 std::setllvm::FoldingSetNodeID DeduplicationSet;

2059

2060

2062 llvm::FoldingSetNodeID ID;

2063 Note->Profile(ID);

2064 if (!DeduplicationSet.insert(ID).second)

2065 continue;

2066

2068 addEdgeToPath(Construct.getActivePath(), PrevLoc, Note->getLocation());

2069 updateStackPiecesWithMessage(Note, Construct.CallStack);

2070 Construct.getActivePath().push_front(Note);

2071 }

2072 }

2073

2075

2076

2077 const StackFrameContext *CalleeLC =

2078 Construct.getLocationContextForActivePath()->getStackFrame();

2080 addEdgeToPath(Construct.getActivePath(), PrevLoc,

2082 }

2083

2084

2085

2086 if (!Construct.PD->path.empty()) {

2088 bool stillHasNotes =

2090 assert(stillHasNotes);

2091 (void)stillHasNotes;

2092 }

2093

2094

2095 if (!Opts.ShouldAddPopUpNotes)

2097

2098

2101

2103

2104

2105

2106

2108 while (optimizeEdges(Construct, Construct.getMutablePieces(), OCS)) {

2109 }

2110

2111

2112

2114 }

2115

2116

2117

2118

2121 }

2122

2123 if (Opts.ShouldDisplayMacroExpansions)

2125

2126 return std::move(Construct.PD);

2127}

2128

2129

2130

2131

2132

2133void BugType::anchor() {}

2134

2135

2136

2137

2138

2139LLVM_ATTRIBUTE_USED static bool

2141 for (const std::pair<StringRef, StringRef> &Pair : Registry.Dependencies) {

2142 if (Pair.second == CheckerName)

2143 return true;

2144 }

2145 return false;

2146}

2147

2149 StringRef CheckerName) {

2151 if (Checker.FullName == CheckerName)

2152 return Checker.IsHidden;

2153 }

2154 llvm_unreachable(

2155 "Checker name not found in CheckerRegistry -- did you retrieve it "

2156 "correctly from CheckerManager::getCurrentCheckerName?");

2157}

2158

2160 const BugType &bt, StringRef shortDesc, StringRef desc,

2162 const Decl *DeclToUnique)

2166 assert(ErrorNode && "The error node must be non-null!");

2168 ->getAnalysisManager()

2169 .getCheckerManager()

2170 ->getCheckerRegistryData(),

2172 "Some checkers depend on this one! We don't allow dependency "

2173 "checkers to emit warnings, because checkers should depend on "

2174 "*modeling*, not *diagnostics*.");

2175

2178 ->getAnalysisManager()

2179 .getCheckerManager()

2180 ->getCheckerRegistryData(),

2182 "Hidden checkers musn't emit diagnostics as they are by definition "

2183 "non-user facing!");

2184}

2185

2187 std::unique_ptr visitor) {

2188 if (!visitor)

2189 return;

2190

2191 llvm::FoldingSetNodeID ID;

2192 visitor->Profile(ID);

2193

2194 void *InsertPos = nullptr;

2195 if (CallbacksSet.FindNodeOrInsertPos(ID, InsertPos)) {

2196 return;

2197 }

2198

2199 Callbacks.push_back(std::move(visitor));

2200}

2201

2205

2208 if (!N)

2209 return nullptr;

2210

2213}

2214

2216 hash.AddInteger(static_cast<int>(getKind()));

2217 hash.AddPointer(&BT);

2219 assert(Location.isValid());

2220 Location.Profile(hash);

2221

2223 if (!range.isValid())

2224 continue;

2225 hash.Add(range.getBegin());

2226 hash.Add(range.getEnd());

2227 }

2228}

2229

2231 hash.AddInteger(static_cast<int>(getKind()));

2232 hash.AddPointer(&BT);

2237 } else {

2238

2239

2240

2241

2242 hash.AddPointer(ErrorNode->getCurrentOrPreviousStmtForDiagnostics());

2243 }

2244

2246 if (!range.isValid())

2247 continue;

2248 hash.Add(range.getBegin());

2249 hash.Add(range.getEnd());

2250 }

2251}

2252

2253template

2255 llvm::DenseMap<T, bugreporter::TrackingKind> &InterestingnessMap, T Val,

2257 auto Result = InterestingnessMap.insert({Val, TKind});

2258

2259 if (Result.second)

2260 return;

2261

2262

2263

2264

2265

2266

2267

2268 switch (TKind) {

2271 return;

2273 return;

2274 }

2275

2276 llvm_unreachable(

2277 "BugReport::markInteresting currently can only handle 2 different "

2278 "tracking kinds! Please define what tracking kind should this entitiy"

2279 "have, if it was already marked as interesting with a different kind!");

2280}

2281

2284 if (!sym)

2285 return;

2286

2288

2289

2290

2291 if (const auto *meta = dyn_cast(sym))

2293}

2294

2296 if (!sym)

2297 return;

2299

2300

2301

2302

2303 if (const auto *meta = dyn_cast(sym))

2305}

2306

2309 if (!R)

2310 return;

2311

2314

2315 if (const auto *SR = dyn_cast(R))

2317}

2318

2320 if (!R)

2321 return;

2322

2325

2326 if (const auto *SR = dyn_cast(R))

2328}

2329

2335

2337 if (!LC)

2338 return;

2340}

2341

2342std::optionalbugreporter::TrackingKind

2346 if (!RKind)

2347 return SKind;

2348 if (!SKind)

2349 return RKind;

2350

2351

2352

2353 switch(*RKind) {

2355 return RKind;

2357 return SKind;

2358 }

2359

2360 llvm_unreachable(

2361 "BugReport::getInterestingnessKind currently can only handle 2 different "

2362 "tracking kinds! Please define what tracking kind should we return here "

2363 "when the kind of getAsRegion() and getAsSymbol() is different!");

2364 return std::nullopt;

2365}

2366

2367std::optionalbugreporter::TrackingKind

2369 if (!sym)

2370 return std::nullopt;

2371

2372

2375 return std::nullopt;

2376 return It->getSecond();

2377}

2378

2379std::optionalbugreporter::TrackingKind

2381 if (!R)

2382 return std::nullopt;

2383

2387 return It->getSecond();

2388

2389 if (const auto *SR = dyn_cast(R))

2391 return std::nullopt;

2392}

2393

2397

2401

2405

2407 if (!LC)

2408 return false;

2410}

2411

2414 return nullptr;

2415

2417 const Stmt *S = nullptr;

2418

2419 if (std::optional BE = ProgP.getAs<BlockEntrance>()) {

2421 if (BE->getBlock() == &Exit)

2422 S = ErrorNode->getPreviousStmtForDiagnostics();

2423 }

2424 if (!S)

2425 S = ErrorNode->getStmtForDiagnostics();

2426

2427 return S;

2428}

2429

2432

2433

2434 if (Ranges.empty() && isa_and_nonnull(getStmt()))

2436

2438}

2439

2448

2449static const Stmt *

2452

2453

2455 return S;

2456

2457

2458 }

2460}

2461

2464 assert(ErrorNode && "Cannot create a location with a null node.");

2465 const Stmt *S = ErrorNode->getStmtForDiagnostics();

2469 ErrorNode->getState()->getStateManager().getContext().getSourceManager();

2470

2471 if (!S) {

2472

2476 if (const ReturnStmt *RS = FE->getStmt())

2478

2480 }

2481 if (!S)

2482 S = ErrorNode->getNextStmtForDiagnostics();

2483 }

2484

2485 if (S) {

2486

2487

2488

2489 if (const auto *AS = dyn_cast(S))

2490 S = AS->getSubStmt();

2491

2492

2493 if (const auto *ME = dyn_cast(S))

2495

2496

2497 if (const auto *B = dyn_cast(S))

2499

2502

2505

2508 }

2509

2511 SM);

2512}

2513

2514

2515

2516

2517

2519 return Eng.getGraph();

2520}

2521

2523 return Eng.getStateManager();

2524}

2525

2527 : D(D), UserSuppressions(D.getASTContext()) {}

2528

2530

2531 assert(StrBugTypes.empty() &&

2532 "Destroying BugReporter before diagnostics are emitted!");

2533

2534

2535 for (const auto I : EQClassesVector)

2536 delete I;

2537}

2538

2540

2541

2542 for (const auto EQ : EQClassesVector)

2543 FlushReport(*EQ);

2544

2545

2546

2547

2548

2549 StrBugTypes.clear();

2550}

2551

2552

2553

2554

2555

2556namespace {

2557

2558

2559

2560class BugPathInfo {

2561public:

2562 std::unique_ptr BugPath;

2565};

2566

2567

2568

2569class BugPathGetter {

2570 std::unique_ptr TrimmedGraph;

2571

2572 using PriorityMapTy = llvm::DenseMap<const ExplodedNode *, unsigned>;

2573

2574

2575 PriorityMapTy PriorityMap;

2576

2577

2578

2579 using ReportNewNodePair =

2580 std::pair<PathSensitiveBugReport *, const ExplodedNode *>;

2582

2583 BugPathInfo CurrentBugPath;

2584

2585

2586 template

2587 class PriorityCompare {

2588 const PriorityMapTy &PriorityMap;

2589

2590 public:

2591 PriorityCompare(const PriorityMapTy &M) : PriorityMap(M) {}

2592

2594 PriorityMapTy::const_iterator LI = PriorityMap.find(LHS);

2595 PriorityMapTy::const_iterator RI = PriorityMap.find(RHS);

2596 PriorityMapTy::const_iterator E = PriorityMap.end();

2597

2598 if (LI == E)

2599 return Descending;

2600 if (RI == E)

2601 return !Descending;

2602

2603 return Descending ? LI->second > RI->second

2604 : LI->second < RI->second;

2605 }

2606

2607 bool operator()(const ReportNewNodePair &LHS,

2608 const ReportNewNodePair &RHS) const {

2609 return (*this)(LHS.second, RHS.second);

2610 }

2611 };

2612

2613public:

2614 BugPathGetter(const ExplodedGraph *OriginalGraph,

2615 ArrayRef<PathSensitiveBugReport *> &bugReports);

2616

2617 BugPathInfo *getNextBugPath();

2618};

2619

2620}

2621

2622BugPathGetter::BugPathGetter(const ExplodedGraph *OriginalGraph,

2623 ArrayRef<PathSensitiveBugReport *> &bugReports) {

2624 SmallVector<const ExplodedNode *, 32> Nodes;

2625 for (const auto I : bugReports) {

2626 assert(I->isValid() &&

2627 "We only allow BugReporterVisitors and BugReporter itself to "

2628 "invalidate reports!");

2629 Nodes.emplace_back(I->getErrorNode());

2630 }

2631

2632

2633

2635 TrimmedGraph = OriginalGraph->trim(Nodes, &ForwardMap);

2636

2637

2638

2639

2640 llvm::SmallPtrSet<const ExplodedNode *, 32> RemainingNodes;

2641

2643 const ExplodedNode *NewNode = ForwardMap.lookup(Report->getErrorNode());

2644 assert(NewNode &&

2645 "Failed to construct a trimmed graph that contains this error "

2646 "node!");

2647 ReportNodes.emplace_back(Report, NewNode);

2648 RemainingNodes.insert(NewNode);

2649 }

2650

2651 assert(!RemainingNodes.empty() && "No error node found in the trimmed graph");

2652

2653

2654 std::queue<const ExplodedNode *> WS;

2655

2656 WS.push(TrimmedGraph->getRoot());

2657 unsigned Priority = 0;

2658

2659 while (!WS.empty()) {

2661 WS.pop();

2662

2663 PriorityMapTy::iterator PriorityEntry;

2664 bool IsNew;

2665 std::tie(PriorityEntry, IsNew) = PriorityMap.insert({Node, Priority});

2666 ++Priority;

2667

2668 if (!IsNew) {

2669 assert(PriorityEntry->second <= Priority);

2670 continue;

2671 }

2672

2673 if (RemainingNodes.erase(Node))

2674 if (RemainingNodes.empty())

2675 break;

2676

2678 WS.push(Succ);

2679 }

2680

2681

2682 llvm::sort(ReportNodes, PriorityCompare(PriorityMap));

2683}

2684

2685BugPathInfo *BugPathGetter::getNextBugPath() {

2686 if (ReportNodes.empty())

2687 return nullptr;

2688

2690 std::tie(CurrentBugPath.Report, OrigN) = ReportNodes.pop_back_val();

2691 assert(PriorityMap.contains(OrigN) && "error node not accessible from root");

2692

2693

2694

2695 auto GNew = std::make_unique();

2696

2697

2698

2700 while (true) {

2701

2702

2703 ExplodedNode *NewN = GNew->createUncachedNode(

2706

2707

2708 if (Succ)

2710 else

2711 CurrentBugPath.ErrorNode = NewN;

2712

2713 Succ = NewN;

2714

2715

2717 assert(OrigN == TrimmedGraph->getRoot() &&

2718 "There should be only one root!");

2719 GNew->designateAsRoot(NewN);

2720 break;

2721 }

2722

2723

2724

2726 PriorityCompare(PriorityMap));

2727 }

2728

2729 CurrentBugPath.BugPath = std::move(GNew);

2730

2731 return &CurrentBugPath;

2732}

2733

2734

2735

2738 using MacroStackTy = std::vector<

2739 std::pair<std::shared_ptr, SourceLocation>>;

2740

2741 using PiecesTy = std::vector;

2742

2743 MacroStackTy MacroStack;

2744 PiecesTy Pieces;

2745

2746 for (PathPieces::const_iterator I = path.begin(), E = path.end();

2747 I != E; ++I) {

2748 const auto &piece = *I;

2749

2750

2751 if (auto *call = dyn_cast(&*piece)) {

2753 }

2754

2755

2756 const FullSourceLoc Loc = piece->getLocation().asLocation();

2757

2758

2759

2761 SM.getExpansionLoc(Loc) :

2763

2764 if (Loc.isFileID()) {

2765 MacroStack.clear();

2766 Pieces.push_back(piece);

2767 continue;

2768 }

2769

2770 assert(Loc.isMacroID());

2771

2772

2773 if (!MacroStack.empty() && InstantiationLoc == MacroStack.back().second) {

2774 MacroStack.back().first->subPieces.push_back(piece);

2775 continue;

2776 }

2777

2778

2779

2780 std::shared_ptr MacroGroup;

2781

2783 SM.getExpansionLoc(Loc) :

2785

2786

2787 while (!MacroStack.empty()) {

2788 if (InstantiationLoc == MacroStack.back().second) {

2789 MacroGroup = MacroStack.back().first;

2790 break;

2791 }

2792

2793 if (ParentInstantiationLoc == MacroStack.back().second) {

2794 MacroGroup = MacroStack.back().first;

2795 break;

2796 }

2797

2798 MacroStack.pop_back();

2799 }

2800

2801 if (!MacroGroup || ParentInstantiationLoc == MacroStack.back().second) {

2802

2803 auto NewGroup = std::make_shared(

2805

2806 if (MacroGroup)

2807 MacroGroup->subPieces.push_back(NewGroup);

2808 else {

2809 assert(InstantiationLoc.isFileID());

2810 Pieces.push_back(NewGroup);

2811 }

2812

2813 MacroGroup = NewGroup;

2814 MacroStack.push_back(std::make_pair(MacroGroup, InstantiationLoc));

2815 }

2816

2817

2818 MacroGroup->subPieces.push_back(piece);

2819 }

2820

2821

2822 path.clear();

2823

2824 llvm::append_range(path, Pieces);

2825}

2826

2827

2828

2829

2830static std::unique_ptr

2834 std::unique_ptr Notes =

2835 std::make_unique();

2837

2838

2839

2841 while (NextNode) {

2842

2843

2844

2845

2846

2847

2848 for (std::unique_ptr &Visitor : R->visitors())

2849 visitors.push_back(std::move(Visitor));

2850

2852

2854 if (!Pred) {

2856 for (auto &V : visitors) {

2857 V->finalizeVisitor(BRC, ErrorNode, *R);

2858

2859 if (auto Piece = V->getEndPath(BRC, ErrorNode, *R)) {

2860 assert(!LastPiece &&

2861 "There can only be one final piece in a diagnostic.");

2863 "The final piece must contain a message!");

2864 LastPiece = std::move(Piece);

2865 (*Notes)[ErrorNode].push_back(LastPiece);

2866 }

2867 }

2868 break;

2869 }

2870

2871 for (auto &V : visitors) {

2872 auto P = V->VisitNode(NextNode, BRC, *R);

2873 if (P)

2874 (*Notes)[NextNode].push_back(std::move(P));

2875 }

2876

2878 break;

2879

2880 NextNode = Pred;

2881 }

2882

2883 return Notes;

2884}

2885

2886std::optional PathDiagnosticBuilder::findValidReport(

2887 ArrayRef<PathSensitiveBugReport *> &bugReports,

2890

2891 BugPathGetter BugGraph(&Reporter.getGraph(), bugReports);

2892

2893 while (BugPathInfo *BugPath = BugGraph.getNextBugPath()) {

2894

2896 assert(R && "No original report found for sliced graph.");

2897 assert(R->isValid() && "Report selected by trimmed graph marked invalid.");

2898 const ExplodedNode *ErrorNode = BugPath->ErrorNode;

2899

2900

2901

2903

2904

2908

2910

2911

2912 std::unique_ptr visitorNotes =

2914

2917 llvm::TimeTraceScope TCS{"Crosscheck with Z3"};

2918

2919

2924

2925

2926

2928 switch (Z3Oracle.interpretQueryResult(CrosscheckResult)) {

2930 ++NumTimesReportRefuted;

2931 R->markInvalid("Infeasible constraints", nullptr);

2932 continue;

2934 ++NumTimesReportEQClassAborted;

2935 return {};

2937 ++NumTimesReportPassesZ3;

2938 break;

2939 }

2940 }

2941

2943 return PathDiagnosticBuilder(std::move(BRC), std::move(BugPath->BugPath),

2944 BugPath->Report, BugPath->ErrorNode,

2945 std::move(visitorNotes));

2946 }

2947 }

2948

2949 ++NumTimesReportEQClassWasExhausted;

2950 return {};

2951}

2952

2953std::unique_ptr

2955 ArrayRef<std::unique_ptr> consumers,

2957 assert(!bugReports.empty());

2958

2959 auto Out = std::make_unique();

2960

2961 std::optional PDB =

2962 PathDiagnosticBuilder::findValidReport(bugReports, *this);

2963

2964 if (PDB) {

2965 for (const auto &PC : consumers) {

2966 if (std::unique_ptr PD = PDB->generate(PC.get())) {

2967 (*Out)[PC.get()] = std::move(PD);

2968 }

2969 }

2970 }

2971

2972 return Out;

2973}

2974

2976 bool ValidSourceLoc = R->getLocation().isValid();

2977 assert(ValidSourceLoc);

2978

2979

2980 if (!ValidSourceLoc)

2981 return;

2982

2983

2984 if (UserSuppressions.isSuppressed(*R))

2985 return;

2986

2987

2988 llvm::FoldingSetNodeID ID;

2989 R->Profile(ID);

2990

2991

2992 void *InsertPos;

2994

2995 if (!EQ) {

2997 EQClasses.InsertNode(EQ, InsertPos);

2998 EQClassesVector.push_back(EQ);

2999 } else

3000 EQ->AddReport(std::move(R));

3001}

3002

3004 if (auto PR = dyn_cast(R.get()))

3005 if (const ExplodedNode *E = PR->getErrorNode()) {

3006

3007

3008 assert((E->isSink() || E->getLocation().getTag()) &&

3009 "Error node must either be a sink or have a tag");

3010

3012 E->getLocationContext()->getAnalysisDeclContext();

3013

3014

3015

3016

3019 return;

3020 }

3021

3023}

3024

3025

3026

3027

3028

3029namespace {

3030

3031struct FRIEC_WLItem {

3034

3036 : N(n), I(N->succ_begin()), E(N->succ_end()) {}

3037};

3038

3039}

3040

3041BugReport *PathSensitiveBugReporter::findReportInEquivalenceClass(

3043

3044

3045

3046 assert(EQ.getReports().size() > 0);

3047 const BugType& BT = EQ.getReports()[0]->getBugType();

3049 BugReport *R = EQ.getReports()[0].get();

3050 for (auto &J : EQ.getReports()) {

3051 if (auto *PR = dyn_cast(J.get())) {

3052 R = PR;

3053 bugReports.push_back(PR);

3054 }

3055 }

3056 return R;

3057 }

3058

3059

3060

3061

3062

3063

3064

3065 BugReport *exampleReport = nullptr;

3066

3067 for (const auto &I: EQ.getReports()) {

3068 auto *R = dyn_cast(I.get());

3069 if (!R)

3070 continue;

3071

3072 const ExplodedNode *errorNode = R->getErrorNode();

3073 if (errorNode->isSink()) {

3074 llvm_unreachable(

3075 "BugType::isSuppressSink() should not be 'true' for sink end nodes");

3076 }

3077

3079 bugReports.push_back(R);

3080 if (!exampleReport)

3081 exampleReport = R;

3082 continue;

3083 }

3084

3085

3086

3087

3088

3089 if (const CFGBlock *ErrorB = errorNode->getCFGBlock())

3090 if (ErrorB->isInevitablySinking())

3091 continue;

3092

3093

3094

3095 using WLItem = FRIEC_WLItem;

3096 using DFSWorkList = SmallVector<WLItem, 10>;

3097

3098 llvm::DenseMap<const ExplodedNode *, unsigned> Visited;

3099

3100 DFSWorkList WL;

3101 WL.push_back(errorNode);

3102 Visited[errorNode] = 1;

3103

3104 while (!WL.empty()) {

3105 WLItem &WI = WL.back();

3106 assert(!WI.N->succ_empty());

3107

3108 for (; WI.I != WI.E; ++WI.I) {

3109 const ExplodedNode *Succ = *WI.I;

3110

3112

3113 if (!Succ->isSink()) {

3114 bugReports.push_back(R);

3115 if (!exampleReport)

3116 exampleReport = R;

3117 WL.clear();

3118 break;

3119 }

3120

3121 continue;

3122 }

3123

3124

3125 unsigned &mark = Visited[Succ];

3126 if (!mark) {

3127 mark = 1;

3128 WL.push_back(Succ);

3129 break;

3130 }

3131 }

3132

3133

3134

3135 if (!WL.empty() && &WL.back() == &WI)

3136 WL.pop_back();

3137 }

3138 }

3139

3140

3141

3142 return exampleReport;

3143}

3144

3146 llvm::TimeTraceScope TCS{timeTraceName(EQ), [&]() {

3148 }};

3149 SmallVector<BugReport*, 10> bugReports;

3150 BugReport *report = findReportInEquivalenceClass(EQ, bugReports);

3151 if (!report)

3152 return;

3153

3154

3155 for (const std::string &CheckerOrPackage :

3158 return;

3159 }

3160

3162 std::unique_ptr Diagnostics =

3164

3165 for (auto &P : *Diagnostics) {

3166 PathDiagnosticConsumer *Consumer = P.first;

3167 std::unique_ptr &PD = P.second;

3168

3169

3170

3171 if (PD->path.empty()) {

3172 PathDiagnosticLocation L = report->getLocation();

3173 auto piece = std::make_unique(

3175 for (SourceRange Range : report->getRanges())

3176 piece->addRange(Range);

3177 PD->setEndOfPath(std::move(piece));

3178 }

3179

3180 PathPieces &Pieces = PD->getMutablePieces();

3182

3183

3184 for (const auto &I : llvm::reverse(report->getNotes())) {

3185 PathDiagnosticNotePiece *Piece = I.get();

3186 auto ConvertedPiece = std::make_shared(

3188 for (const auto &R: Piece->getRanges())

3189 ConvertedPiece->addRange(R);

3190

3191 Pieces.push_front(std::move(ConvertedPiece));

3192 }

3193 } else {

3194 for (const auto &I : llvm::reverse(report->getNotes()))

3195 Pieces.push_front(I);

3196 }

3197

3198 for (const auto &I : report->getFixits())

3199 Pieces.back()->addFixit(I);

3200

3202

3203

3207 Pieces.push_front(std::make_shared(

3209 "[debug] analyzing from " +

3211 }

3213 }

3214}

3215

3216

3217

3222 const Stmt* Body = Signature->getBody();

3223 if (const auto FD = dyn_cast(Signature)) {

3224 SignatureSourceRange = FD->getSourceRange();

3225 } else if (const auto OD = dyn_cast(Signature)) {

3226 SignatureSourceRange = OD->getSourceRange();

3227 } else {

3228 return;

3229 }

3232 : SignatureSourceRange.getEnd();

3234 return;

3235 unsigned StartLine = SM.getExpansionLineNumber(Start);

3236 unsigned EndLine = SM.getExpansionLineNumber(End);

3237

3238 FileID FID = SM.getFileID(SM.getExpansionLoc(Start));

3239 for (unsigned Line = StartLine; Line <= EndLine; Line++)

3240 ExecutedLines[FID].insert(Line);

3241}

3242

3248 return;

3250 FileID FID = SM.getFileID(ExpansionLoc);

3251 unsigned LineNo = SM.getExpansionLineNumber(ExpansionLoc);

3252 ExecutedLines[FID].insert(LineNo);

3253}

3254

3255

3256

3257static std::unique_ptr

3259 auto ExecutedLines = std::make_unique();

3260

3261 while (N) {

3263

3267

3268 const Decl* D = CE->getCalleeContext()->getDecl();

3272

3273

3275

3276

3277

3278

3279 if (const auto *RS = dyn_cast_or_null(P)) {

3282 }

3283

3284 if (isa_and_nonnull<SwitchCase, LabelStmt>(P))

3286 }

3287

3289 }

3290 return ExecutedLines;

3291}

3292

3293std::unique_ptr

3296 ArrayRef<std::unique_ptr> consumers,

3299 auto Out = std::make_unique();

3300 for (const auto &Consumer : consumers)

3301 (*Out)[Consumer.get()] =

3303 return Out;

3304}

3305

3310

3311

3313 return nullptr;

3314

3316 "The call piece should not be in a header file.");

3317

3318

3320 return CP;

3321

3323 if (Path.empty())

3324 return nullptr;

3325

3326

3327

3328 if (auto *CPInner = dyn_cast(Path.back().get()))

3330

3331

3332 return nullptr;

3333}

3334

3336 if (PD.path.empty())

3337 return;

3338

3340 assert(LastP);

3342

3343

3344

3345 if (auto *CP = dyn_cast(LastP)) {

3347 if (CP) {

3348

3350

3351

3352 const auto *ND = dyn_cast(CP->getCallee());

3353 if (ND) {

3355 llvm::raw_svector_ostream os(buf);

3356 os << " (within a call to '" << ND->getDeclName() << "')";

3358 }

3359

3360

3363

3364 return;

3365 }

3366 }

3367}

3368

3369std::unique_ptr

3370PathSensitiveBugReporter::generateDiagnosticForConsumerMap(

3372 ArrayRef<std::unique_ptr> consumers,

3373 ArrayRef<BugReport *> bugReports) {

3376 consumers, bugReports);

3377

3378

3379

3380

3381

3382 assert(!bugReports.empty());

3383 MaxBugClassSize.updateMax(bugReports.size());

3384

3385

3386 ArrayRef<PathSensitiveBugReport *> convertedArrayOfReports(

3387 reinterpret_cast<PathSensitiveBugReport *const *>(&*bugReports.begin()),

3388 reinterpret_cast<PathSensitiveBugReport *const *>(&*bugReports.end()));

3390 consumers, convertedArrayOfReports);

3391

3392 if (Out->empty())

3393 return Out;

3394

3395 MaxValidBugClassSize.updateMax(bugReports.size());

3396

3397

3398

3400 for (auto const &P : *Out)

3401 if (Opts.ShouldReportIssuesInMainSourceFile && !Opts.AnalyzeAll)

3403

3404 return Out;

3405}

3406

3409 StringRef Name, StringRef Category,

3414 Ranges, Fixits);

3415}

3416

3419 StringRef name, StringRef category,

3423

3424 BugType *BT = getBugTypeForName(CheckName, name, category);

3425 auto R = std::make_unique(*BT, str, Loc);

3426 R->setDeclWithIssue(DeclWithIssue);

3427 for (const auto &SR : Ranges)

3429 for (const auto &FH : Fixits)

3432}

3433

3435 StringRef name, StringRef category) {

3437 llvm::raw_svector_ostream(fullDesc)

3438 << CheckName << ":" << name << ":" << category;

3439 std::unique_ptr &BT = StrBugTypes[fullDesc];

3440 if (!BT)

3441 BT = std::make_unique(CheckName, name, category);

3442 return BT.get();

3443}

This file defines AnalysisDeclContext, a class that manages the analysis context data for context sen...

static void dropFunctionEntryEdge(const PathDiagnosticConstruct &C, PathPieces &Path)

Drop the very first edge in a path, which should be a function entry edge.

Definition BugReporter.cpp:1974

constexpr llvm::StringLiteral StrLoopRangeEmpty

Definition BugReporter.cpp:1143

static PathDiagnosticLocation getEnclosingStmtLocation(const Stmt *S, const LocationContext *LC, bool allowNestedContexts=false)

Definition BugReporter.cpp:672

static std::unique_ptr< FilesToLineNumsMap > findExecutedLines(const SourceManager &SM, const ExplodedNode *N)

Definition BugReporter.cpp:3258

static bool isConditionForTerminator(const Stmt *S, const Stmt *Cond)

Definition BugReporter.cpp:1393

static void updateExecutedLinesWithDiagnosticPieces(PathDiagnostic &PD)

Populate executes lines with lines containing at least one diagnostics.

Definition BugReporter.cpp:1991

static void removeRedundantMsgs(PathPieces &path)

An optimization pass over PathPieces that removes redundant diagnostics generated by both ConditionBR...

Definition BugReporter.cpp:404

constexpr llvm::StringLiteral StrLoopCollectionEmpty

Definition BugReporter.cpp:1145

static void adjustCallLocations(PathPieces &Pieces, PathDiagnosticLocation *LastCallLocation=nullptr)

Recursively scan through a path and make sure that all call pieces have valid locations.

Definition BugReporter.cpp:526

static void removeIdenticalEvents(PathPieces &path)

Definition BugReporter.cpp:1769

static const Stmt * getTerminatorCondition(const CFGBlock *B)

A customized wrapper for CFGBlock::getTerminatorCondition() which returns the element for ObjCForColl...

Definition BugReporter.cpp:1134

static std::unique_ptr< VisitorsDiagnosticsTy > generateVisitorsDiagnostics(PathSensitiveBugReport *R, const ExplodedNode *ErrorNode, BugReporterContext &BRC)

Generate notes from all visitors.

Definition BugReporter.cpp:2831

static bool removeUnneededCalls(const PathDiagnosticConstruct &C, PathPieces &pieces, const PathSensitiveBugReport *R, bool IsInteresting=false)

Recursively scan through a path and prune out calls and macros pieces that aren't needed.

Definition BugReporter.cpp:454

static const Stmt * findReasonableStmtCloseToFunctionExit(const ExplodedNode *N)

Definition BugReporter.cpp:2450

static void populateExecutedLinesWithStmt(const Stmt *S, const SourceManager &SM, FilesToLineNumsMap &ExecutedLines)

Definition BugReporter.cpp:3243

static bool isJumpToFalseBranch(const BlockEdge *BE)

Definition BugReporter.cpp:1043

static std::optional< size_t > getLengthOnSingleLine(const SourceManager &SM, SourceRange Range)

Returns the number of bytes in the given (character-based) SourceRange.

Definition BugReporter.cpp:1601

static bool isContainedByStmt(const ParentMap &PM, const Stmt *S, const Stmt *SubS)

Definition BugReporter.cpp:1049

constexpr llvm::StringLiteral StrEnteringLoop

Definition BugReporter.cpp:1141

static void addEdgeToPath(PathPieces &path, PathDiagnosticLocation &PrevLoc, PathDiagnosticLocation NewLoc)

Adds a sanitized control-flow diagnostic edge to a path.

Definition BugReporter.cpp:1107

static bool isIncrementOrInitInForLoop(const Stmt *S, const Stmt *FL)

Definition BugReporter.cpp:1434

static std::unique_ptr< PathDiagnostic > generateEmptyDiagnosticForReport(const PathSensitiveBugReport *R, const SourceManager &SM, const Decl *AnalysisEntryPoint)

Definition BugReporter.cpp:1363

static void removeContextCycles(PathPieces &Path, const SourceManager &SM)

Eliminate two-edge cycles created by addContextEdges().

Definition BugReporter.cpp:1651

static bool lexicalContains(const ParentMap &PM, const Stmt *X, const Stmt *Y)

Return true if X is contained by Y.

Definition BugReporter.cpp:1706

static std::unique_ptr< PathDiagnostic > generateDiagnosticForBasicReport(const BasicBugReport *R, const Decl *AnalysisEntryPoint)

Definition BugReporter.cpp:1352

static void removePopUpNotes(PathPieces &Path)

Same logic as above to remove extra pieces.

Definition BugReporter.cpp:507

static void insertToInterestingnessMap(llvm::DenseMap< T, bugreporter::TrackingKind > &InterestingnessMap, T Val, bugreporter::TrackingKind TKind)

Definition BugReporter.cpp:2254

constexpr llvm::StringLiteral StrLoopBodyZero

Definition BugReporter.cpp:1142

static const Stmt * getEnclosingParent(const Stmt *S, const ParentMap &PM)

Definition BugReporter.cpp:649

static void removePunyEdges(PathPieces &path, const SourceManager &SM, const ParentMap &PM)

Definition BugReporter.cpp:1716

static const Stmt * getStmtParent(const Stmt *S, const ParentMap &PM)

Definition BugReporter.cpp:1374

static bool exitingDestructor(const ExplodedNode *N)

Definition BugReporter.cpp:2440

static void CompactMacroExpandedPieces(PathPieces &path, const SourceManager &SM)

CompactMacroExpandedPieces - This function postprocesses a PathDiagnostic object and collapses PathDi...

Definition BugReporter.cpp:2736

static void simplifySimpleBranches(PathPieces &pieces)

Move edges from a branch condition to a branch target when the condition is simple.

Definition BugReporter.cpp:1531

static void populateExecutedLinesWithFunctionSignature(const Decl *Signature, const SourceManager &SM, FilesToLineNumsMap &ExecutedLines)

Insert all lines participating in the function signature Signature into ExecutedLines.

Definition BugReporter.cpp:3218

static void resetDiagnosticLocationToMainFile(PathDiagnostic &PD)

Definition BugReporter.cpp:3335

static bool optimizeEdges(const PathDiagnosticConstruct &C, PathPieces &path, OptimizedCallsSet &OCS)

Definition BugReporter.cpp:1792

static bool hasImplicitBody(const Decl *D)

Returns true if the given decl has been implicitly given a body, either by the analyzer or by the com...

Definition BugReporter.cpp:518

static PathDiagnosticCallPiece * getFirstStackedCallToHeaderFile(PathDiagnosticCallPiece *CP, const SourceManager &SMgr)

Definition BugReporter.cpp:3307

llvm::DenseSet< const PathDiagnosticCallPiece * > OptimizedCallsSet

Definition BugReporter.cpp:1443

static void addContextEdges(PathPieces &pieces, const LocationContext *LC)

Adds synthetic edges from top-level statements to their subexpressions.

Definition BugReporter.cpp:1450

static LLVM_ATTRIBUTE_USED bool isDependency(const CheckerRegistryData &Registry, StringRef CheckerName)

Definition BugReporter.cpp:2140

static PathDiagnosticEventPiece * eventsDescribeSameCondition(PathDiagnosticEventPiece *X, PathDiagnosticEventPiece *Y)

Definition BugReporter.cpp:378

static bool isInLoopBody(const ParentMap &PM, const Stmt *S, const Stmt *Term)

Definition BugReporter.cpp:1073

static void removeEdgesToDefaultInitializers(PathPieces &Pieces)

Remove edges in and out of C++ default initializer expressions.

Definition BugReporter.cpp:559

static const Stmt * getStmtBeforeCond(const ParentMap &PM, const Stmt *Term, const ExplodedNode *N)

Definition BugReporter.cpp:1059

static void removePiecesWithInvalidLocations(PathPieces &Pieces)

Remove all pieces with invalid locations as these cannot be serialized.

Definition BugReporter.cpp:593

static LLVM_ATTRIBUTE_USED bool isHidden(const CheckerRegistryData &Registry, StringRef CheckerName)

Definition BugReporter.cpp:2148

static llvm::TimeTraceMetadata timeTraceMetadata(const ExplodedNode *Pred, const ProgramPoint &Loc)

#define STAT_COUNTER(VARNAME, DESC)

#define STAT_MAX(VARNAME, DESC)

Defines the clang::Expr interface and subclasses for C++ expressions.

bool isLoop(const FormatStyle &Style) const

FormatToken * Next

The next token in the unwrapped line.

Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.

Defines the clang::SourceLocation class and associated facilities.

Defines the SourceManager interface.

Defines the Objective-C statement AST node classes.

SourceManager & getSourceManager()

AnalysisDeclContext contains the context data for the function, method or block under analysis.

static std::string getFunctionName(const Decl *D)

bool isBodyAutosynthesized() const

bool isBodyAutosynthesizedFromModelFile() const

const CFGBlock * getSrc() const

const CFGBlock * getDst() const

Represents a single basic block in a source-level CFG.

succ_iterator succ_begin()

Stmt * getTerminatorStmt()

const Stmt * getLoopTarget() const

const Stmt * getTerminatorCondition(bool StripParens=true) const

unsigned succ_size() const

CXXForRangeStmt - This represents C++0x [stmt.ranged]'s ranged for statement, represented as 'for (ra...

Represents a point when we begin processing an inlined call.

Represents a point when we finish the call exit sequence (for inlined call).

const StackFrameContext * getCalleeContext() const

Decl - This represents one declaration (or definition), e.g.

ASTContext & getASTContext() const LLVM_READONLY

bool isImplicit() const

isImplicit - Indicates whether the declaration was implicitly generated by the implementation.

virtual Stmt * getBody() const

getBody - If this Decl represents a declaration for a body of code, such as a function or method defi...

virtual bool hasBody() const

Returns true if this Decl represents a declaration for a body of code, such as a function or method d...

SourceLocation getLocation() const

This represents one expression.

llvm::APSInt EvaluateKnownConstInt(const ASTContext &Ctx) const

EvaluateKnownConstInt - Call EvaluateAsRValue and return the folded integer.

An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...

ForStmt - This represents a 'for (init;cond;inc)' stmt.

A SourceLocation and its associated SourceManager.

unsigned getExpansionLineNumber(bool *Invalid=nullptr) const

IfStmt - This represents an if/then/else.

It wraps the AnalysisDeclContext to represent both the call stack with the help of StackFrameContext ...

const Decl * getDecl() const

const ParentMap & getParentMap() const

const StackFrameContext * getStackFrame() const

Represents Objective-C's collection statement.

bool isConsumedExpr(Expr *E) const

Stmt * getParent(Stmt *) const

Stmt * getParentIgnoreParens(Stmt *) const

Represents a point after we ran remove dead bindings AFTER processing the given statement.

Represents a program point just before an implicit call event.

T castAs() const

Convert to the specified ProgramPoint type, asserting that this ProgramPoint is of the desired type.

std::optional< T > getAs() const

Convert to the specified ProgramPoint type, returning std::nullopt if this ProgramPoint is not of the...

const LocationContext * getLocationContext() const

ReturnStmt - This represents a return, optionally of an expression: return; return 4;.

Encodes a location in the source.

bool isValid() const

Return true if this is a valid SourceLocation object.

This class handles loading and caching of source files into memory.

A trivial tuple used to represent a source range.

SourceLocation getEnd() const

SourceLocation getBegin() const

It represents a stack frame of the call stack (based on CallEvent).

const Stmt * getCallSite() const

Stmt - This represents one statement.

StmtClass getStmtClass() const

SourceRange getSourceRange() const LLVM_READONLY

SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...

SourceLocation getBeginLoc() const LLVM_READONLY

WhileStmt - This represents a 'while' stmt.

static bool isInCodeFile(SourceLocation SL, const SourceManager &SM)

const Decl * getDeclWithIssue() const override

The smallest declaration that contains the bug location.

PathDiagnosticLocation getUniqueingLocation() const override

Get the location on which the report should be uniqued.

void Profile(llvm::FoldingSetNodeID &hash) const override

Reports are uniqued to ensure that we do not emit multiple diagnostics for each bug.

Definition BugReporter.cpp:2215

const Decl * getUniqueingDecl() const override

Get the declaration that corresponds to (usually contains) the uniqueing location.

This class provides an interface through which checkers can create individual bug reports.

llvm::ArrayRef< FixItHint > getFixits() const

void addRange(SourceRange R)

Add a range to a bug report.

SmallVector< SourceRange, 4 > Ranges

virtual PathDiagnosticLocation getLocation() const =0

The primary location of the bug report that points at the undesirable behavior in the code.

ArrayRef< std::shared_ptr< PathDiagnosticNotePiece > > getNotes()

BugReport(Kind kind, const BugType &bt, StringRef desc)

void addFixItHint(const FixItHint &F)

Add a fix-it hint to the bug report.

StringRef getDescription() const

A verbose warning message that is appropriate for displaying next to the source code that introduces ...

const BugType & getBugType() const

StringRef getShortDescription(bool UseFallback=true) const

A short general warning message that is appropriate for displaying in the list of all reported bugs.

virtual ArrayRef< SourceRange > getRanges() const

Get the SourceRanges associated with the report.

static PathDiagnosticPieceRef getDefaultEndPath(const BugReporterContext &BRC, const ExplodedNode *N, const PathSensitiveBugReport &BR)

Generates the default final diagnostic piece.

virtual ~BugReporterVisitor()

void FlushReports()

Generate and flush diagnostics for all bug reports.

Definition BugReporter.cpp:2539

BugReporter(BugReporterData &d)

Definition BugReporter.cpp:2526

const SourceManager & getSourceManager()

const Decl * getAnalysisEntryPoint() const

Get the top-level entry point for the issue to be reported.

ArrayRef< std::unique_ptr< PathDiagnosticConsumer > > getPathDiagnosticConsumers()

virtual ~BugReporter()

Definition BugReporter.cpp:2529

void EmitBasicReport(const Decl *DeclWithIssue, const CheckerFrontend *Checker, StringRef BugName, StringRef BugCategory, StringRef BugStr, PathDiagnosticLocation Loc, ArrayRef< SourceRange > Ranges={}, ArrayRef< FixItHint > Fixits={})

Definition BugReporter.cpp:3407

virtual std::unique_ptr< DiagnosticForConsumerMapTy > generateDiagnosticForConsumerMap(BugReport *exampleReport, ArrayRef< std::unique_ptr< PathDiagnosticConsumer > > consumers, ArrayRef< BugReport * > bugReports)

Generate the diagnostics for the given bug report.

Definition BugReporter.cpp:3294

const AnalyzerOptions & getAnalyzerOptions()

virtual void emitReport(std::unique_ptr< BugReport > R)

Add the given report to the set of reports tracked by BugReporter.

Definition BugReporter.cpp:2975

bool isSuppressOnSink() const

isSuppressOnSink - Returns true if bug reports associated with this bug type should be suppressed if ...

StringRef getCategory() const

StringRef getDescription() const

StringRef getCheckerName() const

A CheckerFrontend instance is what the user recognizes as "one checker": it has a public canonical na...

CheckerNameRef getName() const

This wrapper is used to ensure that only StringRefs originating from the CheckerRegistry are used as ...

Simple checker classes that implement one frontend (i.e.

Visitor that tries to report interesting diagnostics from conditions.

static bool isPieceMessageGeneric(const PathDiagnosticPiece *Piece)

static const char * getTag()

Return the tag associated with this visitor.

bool isValid() const =delete

std::unique_ptr< ExplodedGraph > trim(ArrayRef< const NodeTy * > Nodes, InterExplodedGraphMap *ForwardMap=nullptr, InterExplodedGraphMap *InverseMap=nullptr) const

Creates a trimmed version of the graph that only contains paths leading to the given nodes.

const CFGBlock * getCFGBlock() const

const ProgramStateRef & getState() const

pred_iterator pred_begin()

const Stmt * getStmtForDiagnostics() const

If the node's program point corresponds to a statement, retrieve that statement.

const Stmt * getPreviousStmtForDiagnostics() const

Find the statement that was executed immediately before this node.

ProgramPoint getLocation() const

getLocation - Returns the edge associated with the given node.

void addPredecessor(ExplodedNode *V, ExplodedGraph &G)

addPredeccessor - Adds a predecessor to the current node, and in tandem add this node as a successor ...

const Stmt * getNextStmtForDiagnostics() const

Find the next statement that was executed on this node's execution path.

const ParentMap & getParentMap() const

SVal getSVal(const Stmt *S) const

Get the value of an arbitrary expression at this node.

const LocationContext * getLocationContext() const

std::optional< T > getLocationAs() const &

ExplodedNode * getFirstPred()

const ExplodedNode *const * const_succ_iterator

Suppress reports that might lead to known false positives.

MemRegion - The root abstract class for all memory regions.

LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * getBaseRegion() const

Prints path notes when a message is sent to a nil receiver.

PathDiagnosticLocation getLocation() const override

void setCallee(const CallEnter &CE, const SourceManager &SM)

PathDiagnosticLocation callEnter

void setCallStackMessage(StringRef st)

bool hasCallStackMessage()

const Decl * getCallee() const

static std::shared_ptr< PathDiagnosticCallPiece > construct(const CallExitEnd &CE, const SourceManager &SM)

const Decl * getCaller() const

PathDiagnosticLocation callEnterWithin

virtual bool supportsLogicalOpControlFlow() const

bool shouldAddPathEdges() const

void HandlePathDiagnostic(std::unique_ptr< PathDiagnostic > D)

bool shouldAddControlNotes() const

bool shouldGenerateDiagnostics() const

PathDiagnosticLocation getStartLocation() const

void setStartLocation(const PathDiagnosticLocation &L)

PathDiagnosticLocation getEndLocation() const

static PathDiagnosticLocation createMemberLoc(const MemberExpr *ME, const SourceManager &SM)

For member expressions, return the location of the '.

const Stmt * asStmt() const

void Profile(llvm::FoldingSetNodeID &ID) const

const SourceManager & getManager() const

static PathDiagnosticLocation createOperatorLoc(const BinaryOperator *BO, const SourceManager &SM)

Create the location for the operator of the binary expression.

static PathDiagnosticLocation createEndBrace(const CompoundStmt *CS, const SourceManager &SM)

Create a location for the end of the compound statement.

static SourceLocation getValidSourceLocation(const Stmt *S, LocationOrAnalysisDeclContext LAC, bool UseEndOfStatement=false)

Construct a source location that corresponds to either the beginning or the end of the given statemen...

static PathDiagnosticLocation createEnd(const Stmt *S, const SourceManager &SM, const LocationOrAnalysisDeclContext LAC)

Create a location for the end of the statement.

static PathDiagnosticLocation createBegin(const Decl *D, const SourceManager &SM)

Create a location for the beginning of the declaration.

FullSourceLoc asLocation() const

static PathDiagnosticLocation createDeclEnd(const LocationContext *LC, const SourceManager &SM)

Constructs a location for the end of the enclosing declaration body.

const Stmt * getStmtOrNull() const

static PathDiagnosticLocation createSingleLocation(const PathDiagnosticLocation &PDL)

Convert the given location into a single kind location.

ArrayRef< SourceRange > getRanges() const

Return the SourceRanges associated with this PathDiagnosticPiece.

virtual PathDiagnosticLocation getLocation() const =0

void setAsLastInMainSourceFile()

const void * getTag() const

Return the opaque tag (if any) on the PathDiagnosticPiece.

StringRef getString() const

PathDiagnosticLocation getLocation() const override

PathDiagnostic - PathDiagnostic objects represent a single path-sensitive diagnostic.

void setDeclWithIssue(const Decl *D)

void appendToDesc(StringRef S)

void setLocation(PathDiagnosticLocation NewLoc)

const FilesToLineNumsMap & getExecutedLines() const

PathPieces flatten(bool ShouldFlattenMacros) const

void markInteresting(SymbolRef sym, bugreporter::TrackingKind TKind=bugreporter::TrackingKind::Thorough)

Marks a symbol as interesting.

Definition BugReporter.cpp:2282

SmallVector< std::unique_ptr< BugReporterVisitor >, 8 > VisitorList

PathDiagnosticLocation getUniqueingLocation() const override

Get the location on which the report should be uniqued.

VisitorList Callbacks

A set of custom visitors which generate "event" diagnostics at interesting points in the path.

const Stmt * getStmt() const

Definition BugReporter.cpp:2412

PathDiagnosticLocation getLocation() const override

The primary location of the bug report that points at the undesirable behavior in the code.

Definition BugReporter.cpp:2463

const Decl * getDeclWithIssue() const override

The smallest declaration that contains the bug location.

Definition BugReporter.cpp:2206

bool shouldPrunePath() const

Indicates whether or not any path pruning should take place when generating a PathDiagnostic from thi...

PathDiagnosticLocation UniqueingLocation

Reports with different uniqueing locations are considered to be different for the purposes of dedupli...

ArrayRef< SourceRange > getRanges() const override

Get the SourceRanges associated with the report.

Definition BugReporter.cpp:2431

llvm::DenseMap< SymbolRef, bugreporter::TrackingKind > InterestingSymbols

Profile to identify equivalent bug reports for error report coalescing.

const Decl * getUniqueingDecl() const override

Get the declaration containing the uniqueing location.

const ExplodedNode * getErrorNode() const

PathSensitiveBugReport(const BugType &bt, StringRef desc, const ExplodedNode *errorNode)

const ExplodedNode * ErrorNode

The ExplodedGraph node against which the report was thrown.

void markInvalid(const void *Tag, const void *Data)

Marks the current report as invalid, meaning that it is probably a false positive and should not be r...

void Profile(llvm::FoldingSetNodeID &hash) const override

Profile to identify equivalent bug reports for error report coalescing.

Definition BugReporter.cpp:2230

void clearVisitors()

Remove all visitors attached to this bug report.

Definition BugReporter.cpp:2202

void addVisitor(std::unique_ptr< BugReporterVisitor > visitor)

Add custom or predefined bug report visitors to this report.

Definition BugReporter.cpp:2186

bool isValid() const

Returns whether or not this report should be considered valid.

std::optional< bugreporter::TrackingKind > getInterestingnessKind(SymbolRef sym) const

Definition BugReporter.cpp:2368

void markNotInteresting(SymbolRef sym)

Definition BugReporter.cpp:2295

llvm::DenseMap< const MemRegion *, bugreporter::TrackingKind > InterestingRegions

A (stack of) set of regions that are registered with this report as being "interesting",...

bool isInteresting(SymbolRef sym) const

Definition BugReporter.cpp:2398

const SourceRange ErrorNodeRange

The range that corresponds to ErrorNode's program point.

llvm::FoldingSet< BugReporterVisitor > CallbacksSet

Used for ensuring the visitors are only added once.

llvm::SmallPtrSet< const LocationContext *, 2 > InterestingLocationContexts

A set of location contexts that correspoind to call sites which should be considered "interesting".

const Decl * UniqueingDecl

GRBugReporter is used for generating path-sensitive reports.

const ExplodedGraph & getGraph() const

getGraph - Get the exploded graph created by the analysis engine for the analyzed method or function.

Definition BugReporter.cpp:2518

void emitReport(std::unique_ptr< BugReport > R) override

Add the given report to the set of reports tracked by BugReporter.

Definition BugReporter.cpp:3003

std::unique_ptr< DiagnosticForConsumerMapTy > generatePathDiagnostics(ArrayRef< std::unique_ptr< PathDiagnosticConsumer > > consumers, ArrayRef< PathSensitiveBugReport * > &bugReports)

bugReports A set of bug reports within a single equivalence class

Definition BugReporter.cpp:2954

ProgramStateManager & getStateManager() const

getStateManager - Return the state manager used by the analysis engine.

Definition BugReporter.cpp:2522

A Range represents the closed range [from, to].

SVal - This represents a symbolic expression, which can be either an L-value or an R-value.

std::optional< T > getAs() const

Convert to the specified SVal type, returning std::nullopt if this SVal is not of the desired type.

SymbolRef getAsLocSymbol(bool IncludeBaseRegions=false) const

If this SVal is a location and wraps a symbol, return that SymbolRef.

std::string getMessage(const ExplodedNode *N) override

Search the call expression for the symbol Sym and dispatch the 'getMessageForX()' methods to construc...

Definition BugReporter.cpp:318

virtual std::string getMessageForSymbolNotFound()

virtual std::string getMessageForReturn(const CallExpr *CallExpr)

virtual std::string getMessageForArg(const Expr *ArgE, unsigned ArgIndex)

Produces the message of the following form: 'Msg via Nth parameter'.

Definition BugReporter.cpp:364

virtual ~StackHintGenerator()=0

The visitor detects NoteTags and displays the event notes they contain.

static const char * getTag()

Return the tag associated with this visitor.

The oracle will decide if a report should be accepted or rejected based on the results of the Z3 solv...

The bug visitor will walk all the nodes in a path and collect all the constraints.

TrackingKind

Specifies the type of tracking for an expression.

@ Thorough

Default tracking kind – specifies that as much information should be gathered about the tracked expre...

@ Condition

Specifies that a more moderate tracking should be used for the expression value.

llvm::DenseMap< const ExplodedNode *, const ExplodedNode * > InterExplodedGraphMap

const SymExpr * SymbolRef

@ CF

Indicates that the tracked object is a CF object.

std::shared_ptr< PathDiagnosticPiece > PathDiagnosticPieceRef

std::map< FileID, std::set< unsigned > > FilesToLineNumsMap

File IDs mapped to sets of line numbers.

bool EQ(InterpState &S, CodePtr OpPC)

std::variant< struct RequiresDecl, struct HeaderDecl, struct UmbrellaDirDecl, struct ModuleDecl, struct ExcludeDecl, struct ExportDecl, struct ExportAsDecl, struct ExternModuleDecl, struct UseDecl, struct LinkDecl, struct ConfigMacrosDecl, struct ConflictDecl > Decl

All declarations that can appear in a module declaration.

The JSON file list parser is used to communicate input to InstallAPI.

bool isa(CodeGen::Address addr)

const FunctionProtoType * T

U cast(CodeGen::Address addr)

Diagnostic wrappers for TextAPI types for error reporting.