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

1

2

3

4

5

6

7

8

9

10

11

12

13

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

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

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

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

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

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

55#include "llvm/ADT/SmallString.h"

56#include "llvm/ADT/SmallVector.h"

57#include "llvm/ADT/Statistic.h"

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

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

60#include "llvm/ADT/iterator_range.h"

61#include "llvm/Support/Casting.h"

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

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

64#include "llvm/Support/MemoryBuffer.h"

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

66#include

67#include

68#include

69#include

70#include

71#include

72#include

73#include

74#include

75#include

76#include

77

78using namespace clang;

79using namespace ento;

80using namespace llvm;

81

82#define DEBUG_TYPE "BugReporter"

83

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

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

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

89

90STATISTIC(NumTimesReportPassesZ3, "Number of reports passed Z3");

91STATISTIC(NumTimesReportRefuted, "Number of reports refuted by Z3");

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

94 "oracle heuristic");

95STATISTIC(NumTimesReportEQClassWasExhausted,

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

97

99

100void BugReporterContext::anchor() {}

101

102

103

104

105

106namespace {

107

108

109using CallWithEntry =

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

112

113

114using VisitorsDiagnosticsTy =

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

116

117

118

119using LocationContextMap =

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

121

122

123

124

125class PathDiagnosticConstruct {

126

128

129

131

132

133

134 LocationContextMap LCM;

136

137public:

138

139

140

141 CallWithEntryStack CallStack;

142

143

144

145 std::unique_ptr PD;

146

147public:

151 const Decl *AnalysisEntryPoint);

152

153

154

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

158 }

159

160

161

162

163 const LocationContext *getLocationContextForActivePath() const {

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

165 }

166

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

168

169

170

171 bool ascendToPrevNode() {

173 return static_cast<bool>(CurrentNode);

174 }

175

176 const ParentMap &getParentMap() const {

177 return getCurrLocationContext()->getParentMap();

178 }

179

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

181

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

183 return getParentMap().getParent(S);

184 }

185

187 assert(Path && LC);

188 LCM[Path] = LC;

189 }

190

192 assert(LCM.count(Path) &&

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

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

195 }

196

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

198

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

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

201

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

203 bool shouldAddControlNotes() const {

205 }

206 bool shouldGenerateDiagnostics() const {

208 }

209 bool supportsLogicalOpControlFlow() const {

211 }

212};

213

214

215

216

217

219

220 std::unique_ptr BugPath;

221

222

223

224

226

227

229

230

231 std::unique_ptr VisitorsDiagnostics;

232

233public:

234

235

236

237 static std::optional

240

241 PathDiagnosticBuilder(

244 std::unique_ptr VisitorsDiagnostics);

245

246

247

248

249

250

251

252

253

254

255

256 std::unique_ptr

258

259private:

261 const CallWithEntryStack &CallStack) const;

262 void generatePathDiagnosticsForNode(PathDiagnosticConstruct &C,

264

265 void generateMinimalDiagForBlockEdge(PathDiagnosticConstruct &C,

267

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

271

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

275

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

279

281 ExecutionContinues(const PathDiagnosticConstruct &C) const;

282

284 ExecutionContinues(llvm::raw_string_ostream &os,

285 const PathDiagnosticConstruct &C) const;

286

288};

289

290}

291

292

293

294

295

297

299 if (!N)

301

304

305

307 const auto *CE = dyn_cast_or_null(CallSite);

308 if (!CE)

309 return {};

310

311

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

314

315

317 if (AS == Sym) {

319 }

320

321

323

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

325 continue;

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

328 if (AS == Sym) {

330 }

331 }

332 }

333

334

337 if (RetSym == Sym) {

339 }

340

342}

343

345 unsigned ArgIndex) {

346

347 ++ArgIndex;

348

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

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

351}

352

353

354

355

356

360

361

362

363

366

368 return nullptr;

369

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

372

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

375

376 return nullptr;

377}

378

379

380

381

382

383

385 unsigned N = path.size();

386 if (N < 2)

387 return;

388

389

390

391

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

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

394 path.pop_front();

395

396 switch (piece->getKind()) {

399 break;

402 break;

404 if (i == N-1)

405 break;

406

407 if (auto *nextEvent =

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

409 auto *event = cast(piece.get());

410

411

412

413 if (auto *pieceToKeep =

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

416 path.pop_front();

417 ++i;

418 }

419 }

420 break;

421 }

425 break;

426 }

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

428 }

429}

430

431

432

433

437 bool IsInteresting = false) {

438 bool containsSomethingInteresting = IsInteresting;

439 const unsigned N = pieces.size();

440

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

442

443

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

445 pieces.pop_front();

446

447 switch (piece->getKind()) {

449 auto &call = cast(*piece);

450

452 C, call.path, R,

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

454 continue;

455

456 containsSomethingInteresting = true;

457 break;

458 }

460 auto &macro = cast(*piece);

462 continue;

463 containsSomethingInteresting = true;

464 break;

465 }

467 auto &event = cast(*piece);

468

469

470

471 containsSomethingInteresting |= !event.isPrunable();

472 break;

473 }

477 break;

478 }

479

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

481 }

482

483 return containsSomethingInteresting;

484}

485

486

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

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

490 Path.pop_front();

491 if (!isa(*Piece))

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

493 }

494}

495

496

497

499 assert(D);

501}

502

503

504

505static void

508 for (const auto &I : Pieces) {

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

510

512 continue;

513

514 if (LastCallLocation) {

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

517 Call->callEnter = *LastCallLocation;

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

519 Call->callReturn = *LastCallLocation;

520 }

521

522

523

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

527 ThisCallLocation = &Call->callEnterWithin;

528 else

529 ThisCallLocation = &Call->callEnter;

530

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

533 }

534}

535

536

537

538

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

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

543

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

546

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

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

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

550 if (isa_and_nonnull(Start)) {

551 I = Pieces.erase(I);

552 continue;

553 } else if (isa_and_nonnull(End)) {

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

555 if (Next != E) {

556 if (auto *NextCF =

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

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

559 }

560 }

561 I = Pieces.erase(I);

562 continue;

563 }

564 }

565

566 I++;

567 }

568}

569

570

571

572

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

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

577

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

580

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

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

583 I = Pieces.erase(I);

584 continue;

585 }

586 I++;

587 }

588}

589

591 const PathDiagnosticConstruct &C) const {

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

594 C.getCurrLocationContext());

595

597 getSourceManager());

598}

599

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

602

603 if (os.str().empty())

604 os << ' ';

605

607

608 if (Loc.asStmt())

609 os << "Execution continues on line "

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

611 << '.';

612 else {

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

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

615 if (isa(D))

616 os << "method";

617 else if (isa(D))

618 os << "function";

619 else {

620 assert(isa(D));

621 os << "anonymous block";

622 }

623 os << '.';

624 }

625

626 return Loc;

627}

628

630 if (isa(S) && PM.isConsumedExpr(cast(S)))

632

635 return nullptr;

636

637 switch (Parent->getStmtClass()) {

638 case Stmt::ForStmtClass:

639 case Stmt::DoStmtClass:

640 case Stmt::WhileStmtClass:

641 case Stmt::ObjCForCollectionStmtClass:

642 case Stmt::CXXForRangeStmtClass:

644 default:

645 break;

646 }

647

648 return nullptr;

649}

650

653 bool allowNestedContexts = false) {

654 if (!S)

655 return {};

656

658

660 switch (Parent->getStmtClass()) {

661 case Stmt::BinaryOperatorClass: {

662 const auto *B = cast(Parent);

663 if (B->isLogicalOp())

665 break;

666 }

667 case Stmt::CompoundStmtClass:

668 case Stmt::StmtExprClass:

670 case Stmt::ChooseExprClass:

671

672

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

675 else

677 case Stmt::BinaryConditionalOperatorClass:

678 case Stmt::ConditionalOperatorClass:

679

680

681 if (allowNestedContexts ||

682 cast(Parent)->getCond() == S)

684 else

686 case Stmt::CXXForRangeStmtClass:

687 if (cast(Parent)->getBody() == S)

689 break;

690 case Stmt::DoStmtClass:

692 case Stmt::ForStmtClass:

693 if (cast(Parent)->getBody() == S)

695 break;

696 case Stmt::IfStmtClass:

697 if (cast(Parent)->getCond() != S)

699 break;

700 case Stmt::ObjCForCollectionStmtClass:

701 if (cast(Parent)->getBody() == S)

703 break;

704 case Stmt::WhileStmtClass:

705 if (cast(Parent)->getCond() != S)

707 break;

708 default:

709 break;

710 }

711

713 }

714

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

716

718}

719

720

721

722

723

724

725

726

727

728

729

730

731

732

733

734void PathDiagnosticBuilder::updateStackPiecesWithMessage(

736 if (R->hasCallStackHint(P))

737 for (const auto &I : CallStack) {

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

741

742

743

744

747 }

748}

749

752

754 const PathDiagnosticConstruct &C, const CFGBlock *Dst,

756

758

759 std::string sbuf;

760 llvm::raw_string_ostream os(sbuf);

762

765

766 switch (S->getStmtClass()) {

767 default:

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

769 "Control jumps to line "

770 << End.asLocation().getExpansionLineNumber();

771 break;

772 case Stmt::DefaultStmtClass:

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

774 << End.asLocation().getExpansionLineNumber();

775 break;

776

777 case Stmt::CaseStmtClass: {

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

779 const auto *Case = cast(S);

781

782

783 bool GetRawInt = true;

784

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

786

787

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

789

790 if (D) {

791 GetRawInt = false;

792 os << *D;

793 }

794 }

795

796 if (GetRawInt)

798

799 os << ":' at line " << End.asLocation().getExpansionLineNumber();

800 break;

801 }

802 }

803 } else {

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

805 End = ExecutionContinues(os, C);

806 }

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

808}

809

811 const PathDiagnosticConstruct &C, const Stmt *S,

813 std::string sbuf;

814 llvm::raw_string_ostream os(sbuf);

817 os << "Control jumps to line " << End.asLocation().getExpansionLineNumber();

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

819}

820

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

824

826

827 const auto *B = cast(T);

828 std::string sbuf;

829 llvm::raw_string_ostream os(sbuf);

830 os << "Left side of '";

832

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

834 os << "&&"

835 << "' is ";

836

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

838 os << "false";

840 Start =

842 } else {

843 os << "true";

844 Start =

846 End = ExecutionContinues(C);

847 }

848 } else {

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

850 os << "||"

851 << "' is ";

852

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

854 os << "false";

855 Start =

857 End = ExecutionContinues(C);

858 } else {

859 os << "true";

861 Start =

863 }

864 }

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

866}

867

868void PathDiagnosticBuilder::generateMinimalDiagForBlockEdge(

869 PathDiagnosticConstruct &C, BlockEdge BE) const {

875 if (T)

876 return;

877

879 switch (T->getStmtClass()) {

880 default:

881 break;

882

883 case Stmt::GotoStmtClass:

884 case Stmt::IndirectGotoStmtClass: {

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

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

887 break;

888 }

889

890 case Stmt::SwitchStmtClass: {

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

892 break;

893 }

894

895 case Stmt::BreakStmtClass:

896 case Stmt::ContinueStmtClass: {

897 std::string sbuf;

898 llvm::raw_string_ostream os(sbuf);

900 C.getActivePath().push_front(

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

902 break;

903 }

904

905

906 case Stmt::BinaryConditionalOperatorClass:

907 case Stmt::ConditionalOperatorClass: {

908 std::string sbuf;

909 llvm::raw_string_ostream os(sbuf);

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

911

913 os << "false";

914 else

915 os << "true";

916

918

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

921

922 C.getActivePath().push_front(

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

924 break;

925 }

926

927

928 case Stmt::BinaryOperatorClass: {

929 if (C.supportsLogicalOpControlFlow())

930 break;

931

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

933 break;

934 }

935

936 case Stmt::DoStmtClass:

938 std::string sbuf;

939 llvm::raw_string_ostream os(sbuf);

940

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

943

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

946

947 C.getActivePath().push_front(

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

949 } else {

951

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

954

955 C.getActivePath().push_front(

956 std::make_shared(

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

958 }

959 break;

960

961 case Stmt::WhileStmtClass:

962 case Stmt::ForStmtClass:

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

964 std::string sbuf;

965 llvm::raw_string_ostream os(sbuf);

966

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

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

971

972 C.getActivePath().push_front(

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

974 } else {

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

978

979 C.getActivePath().push_front(

980 std::make_shared(

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

982 }

983

984 break;

985

986 case Stmt::IfStmtClass: {

988

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

991

993 C.getActivePath().push_front(

994 std::make_shared(

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

996 else

997 C.getActivePath().push_front(

998 std::make_shared(

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

1000

1001 break;

1002 }

1003 }

1004}

1005

1006

1007

1008

1009

1012 case Stmt::ForStmtClass:

1013 case Stmt::WhileStmtClass:

1014 case Stmt::ObjCForCollectionStmtClass:

1015 case Stmt::CXXForRangeStmtClass:

1016 return true;

1017 default:

1018

1019 return false;

1020 }

1021}

1022

1027}

1028

1030 const Stmt *SubS) {

1031 while (SubS) {

1032 if (SubS == S)

1033 return true;

1035 }

1036 return false;

1037}

1038

1041 while (N) {

1043 if (SP) {

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

1046 return S;

1047 }

1049 }

1050 return nullptr;

1051}

1052

1054 const Stmt *LoopBody = nullptr;

1056 case Stmt::CXXForRangeStmtClass: {

1057 const auto *FR = cast(Term);

1059 return true;

1061 return true;

1062 LoopBody = FR->getBody();

1063 break;

1064 }

1065 case Stmt::ForStmtClass: {

1066 const auto *FS = cast(Term);

1068 return true;

1069 LoopBody = FS->getBody();

1070 break;

1071 }

1072 case Stmt::ObjCForCollectionStmtClass: {

1073 const auto *FC = cast(Term);

1074 LoopBody = FC->getBody();

1075 break;

1076 }

1077 case Stmt::WhileStmtClass:

1078 LoopBody = cast(Term)->getBody();

1079 break;

1080 default:

1081 return false;

1082 }

1084}

1085

1086

1091 return;

1092

1095 return;

1096

1098 PrevLoc = NewLoc;

1099 return;

1100 }

1101

1102

1103

1105 return;

1106

1107 path.push_front(

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

1109 PrevLoc = NewLoc;

1110}

1111

1112

1113

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

1117 return FS->getElement();

1118 return S;

1119}

1120

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

1124 "Loop body skipped when range is empty";

1126 "Loop body skipped when collection is empty";

1127

1128static std::unique_ptr

1130

1131void PathDiagnosticBuilder::generatePathDiagnosticsForNode(

1135

1136

1137

1138

1139

1140 if (auto CE = P.getAs<CallEnter>()) {

1141

1142 if (C.shouldAddPathEdges()) {

1143

1146

1147

1148

1149

1150

1151

1155 }

1156

1157

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

1159 C.PD->popActivePath();

1160

1162 if (VisitedEntireCall) {

1163 Call = cast(C.getActivePath().front().get());

1164 } else {

1165

1166

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

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

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

1171

1172

1173

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

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

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

1177 "a single CallEvent!");

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

1179

1180

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

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

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

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

1185 }

1186 Call->setCallee(*CE, SM);

1187

1188

1189 PrevLoc = Call->getLocation();

1190

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

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

1193 C.CallStack.pop_back();

1194 }

1195 return;

1196 }

1197

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

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

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

1201

1202

1203 if (std::optional CE = P.getAs<CallExitEnd>()) {

1204

1205

1206

1208

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

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

1211 "encounter its context!");

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

1213

1214 if (C.shouldAddPathEdges()) {

1215

1218 }

1219

1220 auto *P = Call.get();

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

1222

1223

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

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

1226 return;

1227 }

1228

1229 if (auto PS = P.getAs<PostStmt>()) {

1230 if (C.shouldAddPathEdges())

1231 return;

1232

1233

1234

1235

1236 if (!isa(PS->getStmt())) {

1240 }

1241

1242 } else if (auto BE = P.getAs<BlockEdge>()) {

1243

1244 if (C.shouldAddControlNotes()) {

1245 generateMinimalDiagForBlockEdge(C, *BE);

1246 }

1247

1248 if (C.shouldAddPathEdges()) {

1249 return;

1250 }

1251

1252

1255 const Stmt *Body = nullptr;

1256

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

1258 Body = FS->getBody();

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

1260 Body = WS->getBody();

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

1262 Body = OFS->getBody();

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

1264 Body = FRS->getBody();

1265 }

1266

1267

1268 auto p = std::make_shared(

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

1270 p->setPrunable(true);

1271

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

1273

1274 if (C.shouldAddControlNotes()) {

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

1276 }

1277

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

1281 }

1282 }

1283

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

1286

1288

1289

1294

1295 StringRef str;

1296

1298 if (!IsInLoopBody) {

1299 if (isa(Term)) {

1301 } else if (isa(Term)) {

1303 } else {

1305 }

1306 }

1307 } else {

1309 }

1310

1311 if (!str.empty()) {

1313 C.getCurrLocationContext());

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

1315 PE->setPrunable(true);

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

1317

1318

1319 if (C.shouldAddControlNotes()) {

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

1321 }

1322 }

1323 } else if (isa<BreakStmt, ContinueStmt, GotoStmt>(Term)) {

1326 }

1327 }

1328 }

1329}

1330

1331static std::unique_ptr

1333 const Decl *AnalysisEntryPoint) {

1335 return std::make_unique(

1339 AnalysisEntryPoint, std::make_unique());

1340}

1341

1342static std::unique_ptr

1345 const Decl *AnalysisEntryPoint) {

1347 return std::make_unique(

1352}

1353

1355 if (!S)

1356 return nullptr;

1357

1358 while (true) {

1360

1361 if (!S)

1362 break;

1363

1364 if (isa<FullExpr, CXXBindTemporaryExpr, SubstNonTypeTemplateParmExpr>(S))

1365 continue;

1366

1367 break;

1368 }

1369

1370 return S;

1371}

1372

1374 switch (S->getStmtClass()) {

1375 case Stmt::BinaryOperatorClass: {

1376 const auto *BO = cast(S);

1377 if (!BO->isLogicalOp())

1378 return false;

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

1380 }

1381 case Stmt::IfStmtClass:

1382 return cast(S)->getCond() == Cond;

1383 case Stmt::ForStmtClass:

1384 return cast(S)->getCond() == Cond;

1385 case Stmt::WhileStmtClass:

1386 return cast(S)->getCond() == Cond;

1387 case Stmt::DoStmtClass:

1388 return cast(S)->getCond() == Cond;

1389 case Stmt::ChooseExprClass:

1390 return cast(S)->getCond() == Cond;

1391 case Stmt::IndirectGotoStmtClass:

1392 return cast(S)->getTarget() == Cond;

1393 case Stmt::SwitchStmtClass:

1394 return cast(S)->getCond() == Cond;

1395 case Stmt::BinaryConditionalOperatorClass:

1396 return cast(S)->getCond() == Cond;

1397 case Stmt::ConditionalOperatorClass: {

1398 const auto *CO = cast(S);

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

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

1401 CO->getRHS() == Cond;

1402 }

1403 case Stmt::ObjCForCollectionStmtClass:

1404 return cast(S)->getElement() == Cond;

1405 case Stmt::CXXForRangeStmtClass: {

1406 const auto *FRS = cast(S);

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

1408 }

1409 default:

1410 return false;

1411 }

1412}

1413

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

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

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

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

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

1420 return false;

1421}

1422

1424

1425

1426

1427

1428

1429

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

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

1434 Prev = I, ++I) {

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

1436

1437 if (!Piece)

1438 continue;

1439

1442

1444 const Stmt *InnerStmt = nullptr;

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

1446 SrcContexts.push_back(NextSrcContext);

1447 InnerStmt = NextSrcContext.asStmt();

1449 true);

1450 }

1451

1452

1453

1454

1455 while (true) {

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

1457

1458

1459

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

1463 break;

1464

1465

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

1467 break;

1468

1469

1470 Piece->setStartLocation(DstContext);

1471

1472

1473

1474 if (Prev != E) {

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

1476

1477 if (PrevPiece) {

1478 if (const Stmt *PrevSrc =

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

1481 if (PrevSrcParent ==

1483 PrevPiece->setEndLocation(DstContext);

1484 break;

1485 }

1486 }

1487 }

1488 }

1489

1490

1491

1492

1493 auto P =

1494 std::make_shared(SrcLoc, DstContext);

1495 Piece = P.get();

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

1497 }

1498 }

1499}

1500

1501

1502

1503

1504

1505

1506

1507

1508

1509

1510

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

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

1514

1515 if (!PieceI)

1516 continue;

1517

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

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

1520

1521 if (!s1Start || !s1End)

1522 continue;

1523

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

1525 if (NextI == E)

1526 break;

1527

1529

1530 while (true) {

1531 if (NextI == E)

1532 break;

1533

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

1535 if (EV) {

1536 StringRef S = EV->getString();

1539 ++NextI;

1540 continue;

1541 }

1542 break;

1543 }

1544

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

1546 break;

1547 }

1548

1549 if (!PieceNextI)

1550 continue;

1551

1554

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

1556 continue;

1557

1558

1559

1562 continue;

1563

1564

1566 continue;

1567

1568

1569

1571 I = pieces.erase(I);

1572 }

1573}

1574

1575

1576

1577

1578

1579

1580

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

1585

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

1588 return std::nullopt;

1589

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

1591 if (!Buffer)

1592 return std::nullopt;

1593

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

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

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

1597

1598

1599

1600

1601

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

1603 return std::nullopt;

1604

1605

1606 return Snippet.size();

1607}

1608

1609

1611 const Stmt *S) {

1613}

1614

1615

1616

1617

1618

1619

1620

1621

1622

1623

1624

1625

1626

1627

1628

1629

1630

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

1633

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

1635

1636 if (!PieceI) {

1637 ++I;

1638 continue;

1639 }

1640

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

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

1643

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

1645 if (NextI == E)

1646 break;

1647

1648 const auto *PieceNextI =

1649 dyn_cast(NextI->get());

1650

1651 if (!PieceNextI) {

1652 if (isa(NextI->get())) {

1653 ++NextI;

1654 if (NextI == E)

1655 break;

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

1657 }

1658

1659 if (!PieceNextI) {

1660 ++I;

1661 continue;

1662 }

1663 }

1664

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

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

1667

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

1669 const size_t MAX_SHORT_LINE_LENGTH = 80;

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

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

1674 Path.erase(I);

1675 I = Path.erase(NextI);

1676 continue;

1677 }

1678 }

1679 }

1680

1681 ++I;

1682 }

1683}

1684

1685

1687 while (X) {

1688 if (X == Y)

1689 return true;

1691 }

1692 return false;

1693}

1694

1695

1698 bool erased = false;

1699

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

1701 erased ? I : ++I) {

1702 erased = false;

1703

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

1705

1706 if (!PieceI)

1707 continue;

1708

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

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

1711

1712 if (!start || !end)

1713 continue;

1714

1716 if (!endParent)

1717 continue;

1718

1720 continue;

1721

1724

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

1726 continue;

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

1728 std::swap(SecondLoc, FirstLoc);

1729

1730 SourceRange EdgeRange(FirstLoc, SecondLoc);

1732

1733

1734 if (!ByteWidth)

1735 continue;

1736

1737 const size_t MAX_PUNY_EDGE_LENGTH = 2;

1738 if (*ByteWidth <= MAX_PUNY_EDGE_LENGTH) {

1739

1740

1741

1742 I = path.erase(I);

1743 erased = true;

1744 continue;

1745 }

1746 }

1747}

1748

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

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

1752

1753 if (!PieceI)

1754 continue;

1755

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

1757 if (NextI == E)

1758 return;

1759

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

1761

1762 if (!PieceNextI)

1763 continue;

1764

1765

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

1767 path.erase(NextI);

1768 }

1769 }

1770}

1771

1774 bool hasChanges = false;

1776 assert(LC);

1779

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

1781

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

1783

1784

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

1787 }

1788 OCS.insert(CallI);

1789 }

1790 ++I;

1791 continue;

1792 }

1793

1794

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

1796

1797 if (!PieceI) {

1798 ++I;

1799 continue;

1800 }

1801

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

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

1806

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

1808 if (NextI == E)

1809 break;

1810

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

1812

1813 if (!PieceNextI) {

1814 ++I;

1815 continue;

1816 }

1817

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

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

1822

1823

1824

1825

1826

1827

1828

1829

1830

1831

1832

1833

1834

1835

1836

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

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

1839 path.erase(NextI);

1840 hasChanges = true;

1841 continue;

1842 }

1843

1844

1845

1846

1847

1848

1849

1850

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

1852 bool removeEdge = false;

1853

1854

1855

1857 removeEdge = true;

1858

1859

1860

1862

1863

1864 if (isa(s1End) && PM.isConsumedExpr(cast(s1End))) {

1865 removeEdge = true;

1866 }

1867

1868

1869

1870

1871

1872

1873

1874

1875

1876

1877

1878 else if (s1Start && s2End &&

1881 removeEdge = true;

1882 }

1883

1884

1885

1886

1887

1888

1889

1890

1891 else if (s1Start && s2End &&

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

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

1896 removeEdge = true;

1897 }

1898 }

1899

1900 if (removeEdge) {

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

1902 path.erase(NextI);

1903 hasChanges = true;

1904 continue;

1905 }

1906 }

1907

1908

1909

1910

1911

1912

1913

1914

1915 if (s1End == s2Start) {

1916 const auto *FS = dyn_cast_or_null(level3);

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

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

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

1920 path.erase(NextI);

1921 hasChanges = true;

1922 continue;

1923 }

1924 }

1925

1926

1927 ++I;

1928 }

1929

1930 if (!hasChanges) {

1931

1932

1934

1936

1937

1939

1941

1943 }

1944

1945 return hasChanges;

1946}

1947

1948

1949

1950

1951

1952

1953

1956 const auto *FirstEdge =

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

1958 if (!FirstEdge)

1959 return;

1960

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

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

1965 return;

1966

1967 Path.pop_front();

1968}

1969

1970

1972

1975

1976 for (const auto &P : path) {

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

1979 unsigned LineNo = Loc.getLineNumber();

1981 ExecutedLines[FID].insert(LineNo);

1982 }

1983}

1984

1985PathDiagnosticConstruct::PathDiagnosticConstruct(

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

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

1991 AnalysisEntryPoint)) {

1993}

1994

1995PathDiagnosticBuilder::PathDiagnosticBuilder(

1998 std::unique_ptr VisitorsDiagnostics)

2000 ErrorNode(ErrorNode),

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

2002

2003std::unique_ptr

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

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

2007

2010

2013

2014

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

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

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

2019 LastPiece = EndNotes->second[0];

2020 } else {

2022 *getBugReport());

2023 }

2024 Construct.PD->setEndOfPath(LastPiece);

2025

2027

2028

2029 while (Construct.ascendToPrevNode()) {

2030 generatePathDiagnosticsForNode(Construct, PrevLoc);

2031

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

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

2034 continue;

2035

2036

2037

2038 std::setllvm::FoldingSetNodeID DeduplicationSet;

2039

2040

2042 llvm::FoldingSetNodeID ID;

2043 Note->Profile(ID);

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

2045 continue;

2046

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

2049 updateStackPiecesWithMessage(Note, Construct.CallStack);

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

2051 }

2052 }

2053

2055

2056

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

2060 addEdgeToPath(Construct.getActivePath(), PrevLoc,

2062 }

2063

2064

2065

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

2068 bool stillHasNotes =

2070 assert(stillHasNotes);

2071 (void)stillHasNotes;

2072 }

2073

2074

2075 if (!Opts.ShouldAddPopUpNotes)

2077

2078

2081

2083

2084

2085

2086

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

2089 }

2090

2091

2092

2094 }

2095

2096

2097

2098

2101 }

2102

2103 if (Opts.ShouldDisplayMacroExpansions)

2105

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

2107}

2108

2109

2110

2111

2112

2113void BugType::anchor() {}

2114

2115

2116

2117

2118

2119LLVM_ATTRIBUTE_USED static bool

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

2122 if (Pair.second == CheckerName)

2123 return true;

2124 }

2125 return false;

2126}

2127

2129 StringRef CheckerName) {

2131 if (Checker.FullName == CheckerName)

2132 return Checker.IsHidden;

2133 }

2134 llvm_unreachable(

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

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

2137}

2138

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

2142 const Decl *DeclToUnique)

2143 : BugReport(Kind::PathSensitive, bt, shortDesc, desc), ErrorNode(errorNode),

2144 ErrorNodeRange(getStmt() ? getStmt()->getSourceRange() : SourceRange()),

2145 UniqueingLocation(LocationToUnique), UniqueingDecl(DeclToUnique) {

2147 ->getAnalysisManager()

2148 .getCheckerManager()

2149 ->getCheckerRegistryData(),

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

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

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

2154

2157 ->getAnalysisManager()

2158 .getCheckerManager()

2159 ->getCheckerRegistryData(),

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

2162 "non-user facing!");

2163}

2164

2166 std::unique_ptr visitor) {

2167 if (!visitor)

2168 return;

2169

2170 llvm::FoldingSetNodeID ID;

2171 visitor->Profile(ID);

2172

2173 void *InsertPos = nullptr;

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

2175 return;

2176 }

2177

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

2179}

2180

2183}

2184

2187 if (!N)

2188 return nullptr;

2189

2192}

2193

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

2196 hash.AddPointer(&BT);

2198 assert(Location.isValid());

2200

2202 if (!range.isValid())

2203 continue;

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

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

2206 }

2207}

2208

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

2211 hash.AddPointer(&BT);

2216 } else {

2217

2218

2219

2220

2222 }

2223

2225 if (!range.isValid())

2226 continue;

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

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

2229 }

2230}

2231

2232template

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

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

2237

2239 return;

2240

2241

2242

2243

2244

2245

2246

2247 switch (TKind) {

2250 return;

2252 return;

2253 }

2254

2255 llvm_unreachable(

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

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

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

2259}

2260

2263 if (!sym)

2264 return;

2265

2267

2268

2269

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

2272}

2273

2275 if (!sym)

2276 return;

2278

2279

2280

2281

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

2284}

2285

2288 if (!R)

2289 return;

2290

2293

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

2296}

2297

2299 if (!R)

2300 return;

2301

2304

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

2307}

2308

2313}

2314

2316 if (!LC)

2317 return;

2319}

2320

2321std::optionalbugreporter::TrackingKind

2325 if (!RKind)

2326 return SKind;

2327 if (!SKind)

2328 return RKind;

2329

2330

2331

2332 switch(*RKind) {

2334 return RKind;

2336 return SKind;

2337 }

2338

2339 llvm_unreachable(

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

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

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

2343 return std::nullopt;

2344}

2345

2346std::optionalbugreporter::TrackingKind

2348 if (!sym)

2349 return std::nullopt;

2350

2351

2354 return std::nullopt;

2355 return It->getSecond();

2356}

2357

2358std::optionalbugreporter::TrackingKind

2360 if (!R)

2361 return std::nullopt;

2362

2366 return It->getSecond();

2367

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

2370 return std::nullopt;

2371}

2372

2375}

2376

2379}

2380

2383}

2384

2386 if (!LC)

2387 return false;

2389}

2390

2393 return nullptr;

2394

2396 const Stmt *S = nullptr;

2397

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

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

2402 }

2403 if (!S)

2405

2406 return S;

2407}

2408

2411

2412

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

2415

2417}

2418

2420

2421

2424 }

2426}

2427

2428static const Stmt *

2431

2432

2434 return S;

2435

2436

2437 }

2439}

2440

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

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

2449

2450 if (!S) {

2451

2452 if (std::optional PIE = P.getAs<PreImplicitCall>())

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

2457

2459 }

2460 if (!S)

2462 }

2463

2464 if (S) {

2465

2466

2467

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

2469 S = AS->getSubStmt();

2470

2471

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

2474

2475

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

2478

2481

2482 if (S->getBeginLoc().isValid())

2484

2487 }

2488

2490 SM);

2491}

2492

2493

2494

2495

2496

2499}

2500

2503}

2504

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

2507

2509

2510 assert(StrBugTypes.empty() &&

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

2512

2513

2514 for (const auto I : EQClassesVector)

2515 delete I;

2516}

2517

2519

2520

2521 for (const auto EQ : EQClassesVector)

2522 FlushReport(*EQ);

2523

2524

2525

2526

2527

2528 StrBugTypes.clear();

2529}

2530

2531

2532

2533

2534

2535namespace {

2536

2537

2538

2539class BugPathInfo {

2540public:

2541 std::unique_ptr BugPath;

2544};

2545

2546

2547

2548class BugPathGetter {

2549 std::unique_ptr TrimmedGraph;

2550

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

2552

2553

2554 PriorityMapTy PriorityMap;

2555

2556

2557

2558 using ReportNewNodePair =

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

2561

2562 BugPathInfo CurrentBugPath;

2563

2564

2565 template

2566 class PriorityCompare {

2567 const PriorityMapTy &PriorityMap;

2568

2569 public:

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

2571

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

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

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

2576

2577 if (LI == E)

2578 return Descending;

2579 if (RI == E)

2580 return !Descending;

2581

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

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

2584 }

2585

2586 bool operator()(const ReportNewNodePair &LHS,

2587 const ReportNewNodePair &RHS) const {

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

2589 }

2590 };

2591

2592public:

2593 BugPathGetter(const ExplodedGraph *OriginalGraph,

2595

2596 BugPathInfo *getNextBugPath();

2597};

2598

2599}

2600

2601BugPathGetter::BugPathGetter(const ExplodedGraph *OriginalGraph,

2604 for (const auto I : bugReports) {

2605 assert(I->isValid() &&

2606 "We only allow BugReporterVisitors and BugReporter itself to "

2607 "invalidate reports!");

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

2609 }

2610

2611

2612

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

2615

2616

2617

2618

2620

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

2623 assert(NewNode &&

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

2625 "node!");

2626 ReportNodes.emplace_back(Report, NewNode);

2627 RemainingNodes.insert(NewNode);

2628 }

2629

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

2631

2632

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

2634

2635 assert(TrimmedGraph->num_roots() == 1);

2636 WS.push(*TrimmedGraph->roots_begin());

2638

2639 while (!WS.empty()) {

2641 WS.pop();

2642

2643 PriorityMapTy::iterator PriorityEntry;

2644 bool IsNew;

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

2647

2648 if (!IsNew) {

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

2650 continue;

2651 }

2652

2653 if (RemainingNodes.erase(Node))

2654 if (RemainingNodes.empty())

2655 break;

2656

2658 WS.push(Succ);

2659 }

2660

2661

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

2663}

2664

2665BugPathInfo *BugPathGetter::getNextBugPath() {

2666 if (ReportNodes.empty())

2667 return nullptr;

2668

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

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

2672

2673

2674

2675 auto GNew = std::make_unique();

2676

2677

2678

2680 while (true) {

2681

2682

2683 ExplodedNode *NewN = GNew->createUncachedNode(

2686

2687

2688 if (Succ)

2690 else

2691 CurrentBugPath.ErrorNode = NewN;

2692

2693 Succ = NewN;

2694

2695

2697 GNew->addRoot(NewN);

2698 break;

2699 }

2700

2701

2702

2704 PriorityCompare(PriorityMap));

2705 }

2706

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

2708

2709 return &CurrentBugPath;

2710}

2711

2712

2713

2716 using MacroStackTy = std::vector<

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

2718

2719 using PiecesTy = std::vector;

2720

2721 MacroStackTy MacroStack;

2722 PiecesTy Pieces;

2723

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

2725 I != E; ++I) {

2726 const auto &piece = *I;

2727

2728

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

2731 }

2732

2733

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

2735

2736

2737

2739 SM.getExpansionLoc(Loc) :

2741

2742 if (Loc.isFileID()) {

2743 MacroStack.clear();

2744 Pieces.push_back(piece);

2745 continue;

2746 }

2747

2748 assert(Loc.isMacroID());

2749

2750

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

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

2753 continue;

2754 }

2755

2756

2757

2758 std::shared_ptr MacroGroup;

2759

2761 SM.getExpansionLoc(Loc) :

2763

2764

2765 while (!MacroStack.empty()) {

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

2767 MacroGroup = MacroStack.back().first;

2768 break;

2769 }

2770

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

2772 MacroGroup = MacroStack.back().first;

2773 break;

2774 }

2775

2776 MacroStack.pop_back();

2777 }

2778

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

2780

2781 auto NewGroup = std::make_shared(

2783

2784 if (MacroGroup)

2785 MacroGroup->subPieces.push_back(NewGroup);

2786 else {

2787 assert(InstantiationLoc.isFileID());

2788 Pieces.push_back(NewGroup);

2789 }

2790

2791 MacroGroup = NewGroup;

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

2793 }

2794

2795

2796 MacroGroup->subPieces.push_back(piece);

2797 }

2798

2799

2800 path.clear();

2801

2802 path.insert(path.end(), Pieces.begin(), Pieces.end());

2803}

2804

2805

2806

2807

2808static std::unique_ptr

2812 std::unique_ptr Notes =

2813 std::make_unique();

2815

2816

2817

2819 while (NextNode) {

2820

2821

2822

2823

2824

2825

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

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

2828

2830

2832 if (!Pred) {

2834 for (auto &V : visitors) {

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

2836

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

2838 assert(!LastPiece &&

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

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

2842 LastPiece = std::move(Piece);

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

2844 }

2845 }

2846 break;

2847 }

2848

2849 for (auto &V : visitors) {

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

2851 if (P)

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

2853 }

2854

2856 break;

2857

2858 NextNode = Pred;

2859 }

2860

2861 return Notes;

2862}

2863

2864std::optional PathDiagnosticBuilder::findValidReport(

2868

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

2870

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

2872

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

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

2876 const ExplodedNode *ErrorNode = BugPath->ErrorNode;

2877

2878

2879

2881

2882

2886

2888

2889

2890 std::unique_ptr visitorNotes =

2892

2895

2896

2901

2902

2903

2905 switch (Z3Oracle.interpretQueryResult(CrosscheckResult)) {

2907 ++NumTimesReportRefuted;

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

2909 continue;

2911 ++NumTimesReportEQClassAborted;

2912 return {};

2914 ++NumTimesReportPassesZ3;

2915 break;

2916 }

2917 }

2918

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

2921 BugPath->Report, BugPath->ErrorNode,

2922 std::move(visitorNotes));

2923 }

2924 }

2925

2926 ++NumTimesReportEQClassWasExhausted;

2927 return {};

2928}

2929

2930std::unique_ptr

2934 assert(!bugReports.empty());

2935

2936 auto Out = std::make_unique();

2937

2938 std::optional PDB =

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

2940

2941 if (PDB) {

2943 if (std::unique_ptr PD = PDB->generate(PC)) {

2944 (*Out)[PC] = std::move(PD);

2945 }

2946 }

2947 }

2948

2949 return Out;

2950}

2951

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

2954 assert(ValidSourceLoc);

2955

2956

2957 if (!ValidSourceLoc)

2958 return;

2959

2960

2962 return;

2963

2964

2965 llvm::FoldingSetNodeID ID;

2966 R->Profile(ID);

2967

2968

2969 void *InsertPos;

2971

2972 if (!EQ) {

2974 EQClasses.InsertNode(EQ, InsertPos);

2975 EQClassesVector.push_back(EQ);

2976 } else

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

2978}

2979

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

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

2983

2984

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

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

2987

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

2990

2991

2992

2993

2996 return;

2997 }

2998

3000}

3001

3002

3003

3004

3005

3006namespace {

3007

3008struct FRIEC_WLItem {

3011

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

3014};

3015

3016}

3017

3018BugReport *PathSensitiveBugReporter::findReportInEquivalenceClass(

3020

3021

3022

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

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

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

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

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

3029 R = PR;

3030 bugReports.push_back(PR);

3031 }

3032 }

3033 return R;

3034 }

3035

3036

3037

3038

3039

3040

3041

3042 BugReport *exampleReport = nullptr;

3043

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

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

3046 if (!R)

3047 continue;

3048

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

3050 if (errorNode->isSink()) {

3051 llvm_unreachable(

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

3053 }

3054

3056 bugReports.push_back(R);

3057 if (!exampleReport)

3058 exampleReport = R;

3059 continue;

3060 }

3061

3062

3063

3064

3065

3067 if (ErrorB->isInevitablySinking())

3068 continue;

3069

3070

3071

3072 using WLItem = FRIEC_WLItem;

3074

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

3076

3077 DFSWorkList WL;

3078 WL.push_back(errorNode);

3080

3081 while (!WL.empty()) {

3082 WLItem &WI = WL.back();

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

3084

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

3087

3089

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

3091 bugReports.push_back(R);

3092 if (!exampleReport)

3093 exampleReport = R;

3094 WL.clear();

3095 break;

3096 }

3097

3098 continue;

3099 }

3100

3101

3102 unsigned &mark = Visited[Succ];

3103 if (!mark) {

3104 mark = 1;

3105 WL.push_back(Succ);

3106 break;

3107 }

3108 }

3109

3110

3111

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

3113 WL.pop_back();

3114 }

3115 }

3116

3117

3118

3119 return exampleReport;

3120}

3121

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

3125 if (!report)

3126 return;

3127

3128

3129 for (const std::string &CheckerOrPackage :

3132 return;

3133 }

3134

3136 std::unique_ptr Diagnostics =

3138

3139 for (auto &P : *Diagnostics) {

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

3142

3143

3144

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

3147 auto piece = std::make_unique(

3150 piece->addRange(Range);

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

3152 }

3153

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

3156

3157

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

3160 auto ConvertedPiece = std::make_shared(

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

3163 ConvertedPiece->addRange(R);

3164

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

3166 }

3167 } else {

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

3169 Pieces.push_front(I);

3170 }

3171

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

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

3174

3176

3177

3181 Pieces.push_front(std::make_shared(

3183 "[debug] analyzing from " +

3185 }

3187 }

3188}

3189

3190

3191

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

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

3198 SignatureSourceRange = FD->getSourceRange();

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

3200 SignatureSourceRange = OD->getSourceRange();

3201 } else {

3202 return;

3203 }

3206 : SignatureSourceRange.getEnd();

3207 if (!Start.isValid() || !End.isValid())

3208 return;

3209 unsigned StartLine = SM.getExpansionLineNumber(Start);

3210 unsigned EndLine = SM.getExpansionLineNumber(End);

3211

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

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

3214 ExecutedLines[FID].insert(Line);

3215}

3216

3222 return;

3224 FileID FID = SM.getFileID(ExpansionLoc);

3225 unsigned LineNo = SM.getExpansionLineNumber(ExpansionLoc);

3226 ExecutedLines[FID].insert(LineNo);

3227}

3228

3229

3230

3231static std::unique_ptr

3233 auto ExecutedLines = std::make_unique();

3234

3235 while (N) {

3237

3241

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

3246

3247

3249

3250

3251

3252

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

3256 }

3257

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

3260 }

3261

3263 }

3264 return ExecutedLines;

3265}

3266

3267std::unique_ptr

3271 auto *basicReport = cast(exampleReport);

3272 auto Out = std::make_unique();

3273 for (auto *Consumer : consumers)

3274 (*Out)[Consumer] =

3276 return Out;

3277}

3278

3283

3284

3286 return nullptr;

3287

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

3290

3291

3293 return CP;

3294

3296 if (Path.empty())

3297 return nullptr;

3298

3299

3300

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

3303

3304

3305 return nullptr;

3306}

3307

3309 if (PD.path.empty())

3310 return;

3311

3313 assert(LastP);

3315

3316

3317

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

3320 if (CP) {

3321

3323

3324

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

3326 if (ND) {

3328 llvm::raw_svector_ostream os(buf);

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

3331 }

3332

3333

3336

3337 return;

3338 }

3339 }

3340}

3341

3342

3343

3344std::unique_ptr

3345PathSensitiveBugReporter::generateDiagnosticForConsumerMap(

3348 std::vector<BasicBugReport *> BasicBugReports;

3349 std::vector<PathSensitiveBugReport *> PathSensitiveBugReports;

3350 if (isa(exampleReport))

3352 consumers, bugReports);

3353

3354

3355

3356

3357

3358 assert(!bugReports.empty());

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

3360

3361

3366 consumers, convertedArrayOfReports);

3367

3368 if (Out->empty())

3369 return Out;

3370

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

3372

3373

3374

3376 for (auto const &P : *Out)

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

3379

3380 return Out;

3381}

3382

3385 StringRef Category, StringRef Str,

3390 Loc, Ranges, Fixits);

3391}

3392

3395 StringRef name, StringRef category,

3399

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

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

3402 R->setDeclWithIssue(DeclWithIssue);

3403 for (const auto &SR : Ranges)

3405 for (const auto &FH : Fixits)

3408}

3409

3411 StringRef name, StringRef category) {

3413 llvm::raw_svector_ostream(fullDesc) << CheckName.getName() << ":" << name

3414 << ":" << category;

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

3416 if (!BT)

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

3418 return BT.get();

3419}

BoundNodesTreeBuilder Nodes

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.

constexpr llvm::StringLiteral StrLoopRangeEmpty

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

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

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

static void updateExecutedLinesWithDiagnosticPieces(PathDiagnostic &PD)

Populate executes lines with lines containing at least one diagnostics.

static void removeRedundantMsgs(PathPieces &path)

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

constexpr llvm::StringLiteral StrLoopCollectionEmpty

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

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

static void removeIdenticalEvents(PathPieces &path)

static const Stmt * getTerminatorCondition(const CFGBlock *B)

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

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

Generate notes from all visitors.

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.

static const Stmt * findReasonableStmtCloseToFunctionExit(const ExplodedNode *N)

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

static bool isJumpToFalseBranch(const BlockEdge *BE)

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

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

static bool isLoop(const Stmt *Term)

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

constexpr llvm::StringLiteral StrEnteringLoop

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

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

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

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

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

Eliminate two-edge cycles created by addContextEdges().

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

Return true if X is contained by Y.

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

static void removePopUpNotes(PathPieces &Path)

Same logic as above to remove extra pieces.

STATISTIC(MaxBugClassSize, "The maximum number of bug reports in the same equivalence class")

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

constexpr llvm::StringLiteral StrLoopBodyZero

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

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

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

static bool exitingDestructor(const ExplodedNode *N)

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

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

static void simplifySimpleBranches(PathPieces &pieces)

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

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

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

static void resetDiagnosticLocationToMainFile(PathDiagnostic &PD)

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

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...

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

llvm::DenseSet< const PathDiagnosticCallPiece * > OptimizedCallsSet

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

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

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

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

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

static void removeEdgesToDefaultInitializers(PathPieces &Pieces)

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

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

static void removePiecesWithInvalidLocations(PathPieces &Pieces)

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

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

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

llvm::DenseSet< const void * > Visited

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

Stores options for the analyzer from the command line.

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

Stmt * getTerminatorCondition(bool StripParens=true)

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, SmallVectorImpl< PartialDiagnosticAt > *Diag=nullptr) const

EvaluateKnownConstInt - Call EvaluateAsRValue and return the folded integer.

Expr * IgnoreParenImpCasts() LLVM_READONLY

Skip past any parentheses and implicit casts which might surround this expression until reaching a fi...

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.

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.

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.

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()

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()

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

Generate the diagnostics for the given bug report.

void FlushReports()

Generate and flush diagnostics for all bug reports.

BugReporter(BugReporterData &d)

const SourceManager & getSourceManager()

const Decl * getAnalysisEntryPoint() const

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

const AnalyzerOptions & getAnalyzerOptions()

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

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

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

ArrayRef< PathDiagnosticConsumer * > getPathDiagnosticConsumers()

bool isSuppressed(const BugReport &)

Return true if the given bug report was explicitly suppressed by the user.

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

CheckerNameRef getCheckerName() const

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

StringRef getName() const

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 &

const Stmt * getCurrentOrPreviousStmtForDiagnostics() const

Find the statement that was executed at or immediately before this node.

ExplodedNode * getFirstPred()

const ExplodedNode *const * const_succ_iterator

ProgramStateManager & getStateManager()

ExplodedGraph & getGraph()

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

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

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

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

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

Marks a symbol as interesting.

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

PathDiagnosticLocation getLocation() const override

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

const Decl * getDeclWithIssue() const override

The smallest declaration that contains the bug location.

bool shouldPrunePath() const

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

ArrayRef< SourceRange > getRanges() const override

Get the SourceRanges associated with the report.

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.

void clearVisitors()

Remove all visitors attached to this bug report.

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

Add custom or predefined bug report visitors to this report.

bool isValid() const

Returns whether or not this report should be considered valid.

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

void markNotInteresting(SymbolRef sym)

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

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.

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.

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

bugReports A set of bug reports within a single equivalence class

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

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

ProgramStateManager & getStateManager() const

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

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...

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'.

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

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

File IDs mapped to sets of line numbers.

@ CF

Indicates that the tracked object is a CF object.

std::shared_ptr< PathDiagnosticPiece > PathDiagnosticPieceRef

bool EQ(InterpState &S, CodePtr OpPC)

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

bool isa(CodeGen::Address addr)

@ Result

The result type of a method or function.

const FunctionProtoType * T

Diagnostic wrappers for TextAPI types for error reporting.

llvm::SmallVector< std::pair< StringRef, StringRef >, 0 > Dependencies