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

1

2

3

4

5

6

7

8

9

10

11

12

13

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

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

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

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

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

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

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

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

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

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

58#include

59#include

60#include

61#include

62#include

63#include

64#include

65

66using namespace clang;

67using namespace ento;

68using namespace bugreporter;

69

70

71

72

73

80 }

81 }

82 return nullptr;

83}

84

85

86

88

89

90

91

92

93

94

95

96

97

98

99

100

102 const auto *E = dyn_cast(S);

103 if (E)

104 return nullptr;

105

106 while (true) {

107 if (const auto *CE = dyn_cast(E)) {

108 if (CE->getCastKind() == CK_LValueToRValue) {

109

110 break;

111 }

112 E = CE->getSubExpr();

113 } else if (const auto *B = dyn_cast(E)) {

114

116 E = Inner;

117 } else if (B->isAssignmentOp()) {

118

119 E = B->getLHS();

120 } else {

121

122

123 break;

124 }

125 } else if (const auto *U = dyn_cast(E)) {

126 if (U->getOpcode() == UO_Deref || U->getOpcode() == UO_AddrOf ||

127 (U->isIncrementDecrementOp() && U->getType()->isPointerType())) {

128

129

130 E = U->getSubExpr();

131 } else {

132

133

134 break;

135 }

136 }

137

138 else if (const auto *ME = dyn_cast(E)) {

139

140

141

142

143

144

145

146

147 if (ME->getMemberDecl()->getType()->isReferenceType())

148 break;

149 E = ME->getBase();

150 } else if (const auto *IvarRef = dyn_cast(E)) {

151 E = IvarRef->getBase();

152 } else if (const auto *AE = dyn_cast(E)) {

153 E = AE->getBase();

154 } else if (const auto *PE = dyn_cast(E)) {

155 E = PE->getSubExpr();

156 } else if (const auto *FE = dyn_cast(E)) {

157 E = FE->getSubExpr();

158 } else {

159

160 break;

161 }

162 }

163

164

165

166

167 if (const auto *CE = dyn_cast(E))

168 if (CE->getCastKind() == CK_LValueToRValue)

169 E = CE->getSubExpr();

170

171 return E;

172}

173

175 if (const auto *DR = dyn_cast(E))

176 return dyn_cast(DR->getDecl());

177 return nullptr;

178}

179

182 bool LookingForReference = true) {

183 if (const auto *ME = dyn_cast(E)) {

184

185

186

187

188 const Expr *Base = ME->getBase();

190 if (!VD)

191 return nullptr;

192

193 const auto *FD = dyn_cast(ME->getMemberDecl());

194 if (!FD)

195 return nullptr;

196

197 if (FD->getType()->isReferenceType()) {

199 return N->getState()->getLValue(FD, StructSVal).getAsRegion();

200 }

201 return nullptr;

202 }

203

205 if (!VD)

206 return nullptr;

208 return nullptr;

210}

211

212

213

214

215

216

217

218

219

222 if (LeftVal == RightVal)

223 return true;

224

226 if (!LLCV)

227 return false;

228

230 if (!RLCV)

231 return false;

232

233 return LLCV->getRegion() == RLCV->getRegion() &&

234 LLCV->getStore() == LeftNode->getState()->getStore() &&

235 RLCV->getStore() == RightNode->getState()->getStore();

236}

237

242

243 assert(CondVarExpr);

245

246

247

248

249

250 if (const auto *DRE = dyn_cast(CondVarExpr))

251 if (const auto *VD = dyn_cast(DRE->getDecl()))

252 return State->getSVal(State->getLValue(VD, LCtx));

253

254 if (const auto *ME = dyn_cast(CondVarExpr))

255 if (const auto *FD = dyn_cast(ME->getMemberDecl()))

256 if (auto FieldL = State->getSVal(ME, LCtx).getAs<Loc>())

257 return State->getRawSVal(*FieldL, FD->getType());

258

259 return std::nullopt;

260}

261

262static std::optional<const llvm::APSInt *>

264

265 if (std::optional V = getSValForVar(CondVarExpr, N))

267 return CI->getValue().get();

268 return std::nullopt;

269}

270

274

275

276

278 return false;

279

280 if (std::optional V = getSValForVar(CondVarExpr, N))

281 if (std::optionalbugreporter::TrackingKind K =

283 return *K == bugreporter::TrackingKind::Condition;

284

285 return false;

286}

287

292 return false;

293}

294

295

302}

303

304

305

308 if (Loc.isMacroID())

309 return false;

310 while (SM.isMacroArgExpansion(Loc))

311 Loc = SM.getImmediateExpansionRange(Loc).getBegin();

312 std::pair<FileID, unsigned> TLInfo = SM.getDecomposedLoc(Loc);

316}

317

318

319

320

323 SVal ValueAfter) {

326

329 return false;

330

331

334 if (BO->isAssignmentOp() && RegionOfInterest->isSubRegionOf(

336 return true;

337

338

339 SVal ValueAtN = N->getState()->getSVal(RegionOfInterest);

341 .areEqual(State, ValueAtN, ValueAfter)

344 return true;

345

346 return false;

347}

348

349

350

351

352

356 return nullptr;

357}

358

362

368 const auto &Ranges = BR.getRanges();

369

370

371

372 auto P = std::make_shared(

373 L, BR.getDescription(), Ranges.begin() == Ranges.end());

376

377 return P;

378}

379

380

381

382

383

384bool NoStateChangeFuncVisitor::isModifiedInFrame(const ExplodedNode *N) {

387 if (!FramesModifyingCalculated.count(SCtx))

388 findModifyingFrames(N);

389 return FramesModifying.count(SCtx);

390}

391

392void NoStateChangeFuncVisitor::markFrameAsModifying(

395 auto p = FramesModifying.insert(SCtx);

396 if (!p.second)

397 break;

398

400 }

401}

402

405

406

408

409

410

411 auto IsMatchingCallExitEnd = [OrigSCtx](const ExplodedNode *N) {

414 };

415 while (N && !IsMatchingCallExitEnd(N)) {

417 "This function is to be used on the trimmed ExplodedGraph!");

419 }

420 return N;

421}

422

423void NoStateChangeFuncVisitor::findModifyingFrames(

425

427

430

431 const ExplodedNode *CurrCallExitBeginN = CallExitBeginN;

433

434 for (const ExplodedNode *CurrN = CallExitBeginN; CurrN;

436

438 CurrCallExitBeginN = CurrN;

440 FramesModifyingCalculated.insert(CurrentSCtx);

441

442 continue;

443 }

444

445 if (auto CE = CurrN->getLocationAs<CallEnter>()) {

448 markFrameAsModifying(CurrentSCtx);

449

450

452

453

454

455

456

457

458

459 if (CE->getCalleeContext() == OriginalSCtx) {

460 markFrameAsModifying(CurrentSCtx);

461 break;

462 }

463 }

464

466 markFrameAsModifying(CurrentSCtx);

467 }

468}

469

472

477

478

479 if (!CallExitLoc || isModifiedInFrame(N))

480 return nullptr;

481

484

485

486

487

488

489

490

491

492

493

494 if (Call->isInSystemHeader()) {

495

496

497

498

499

500

501

503 static int i = 0;

505 }

506 return nullptr;

507 }

508

509 if (const auto *MC = dyn_cast(Call)) {

510

511

513 return Piece;

514 }

515

516 if (const auto *CCall = dyn_cast(Call)) {

517

518

520 }

521

523}

524

525

526

529 using namespace ast_matchers;

530 const char *IvarBind = "Ivar";

532 return false;

534 hasOperatorName("="),

535 hasLHS(ignoringParenImpCasts(

538 auto Matches = match(ParentM, *Parent->getBody(), Parent->getASTContext());

540 auto IvarRef = Match.getNodeAs<ObjCIvarRefExpr>(IvarBind);

541 if (IvarRef->isFreeIvar())

542 return true;

543

544 const Expr *Base = IvarRef->getBase();

545 if (const auto *ICE = dyn_cast(Base))

546 Base = ICE->getSubExpr();

547

548 if (const auto *DRE = dyn_cast(Base))

549 if (const auto *ID = dyn_cast(DRE->getDecl()))

551 return true;

552

553 return false;

554 }

555 return false;

556}

557

558

559

560

561

562

563

564const std::optionalNoStoreFuncVisitor::RegionVector

565NoStoreFuncVisitor::findRegionOfInterestInRecord(

568 int depth ) {

569

570 if (depth == DEREFERENCE_LIMIT)

571 return std::nullopt;

572

573 if (const auto *RDX = dyn_cast(RD))

574 if (!RDX->hasDefinition())

575 return std::nullopt;

576

577

578

579 if (const auto *RDX = dyn_cast(RD))

580 for (const auto &II : RDX->bases())

581 if (const RecordDecl *RRD = II.getType()->getAsRecordDecl())

582 if (std::optional Out =

583 findRegionOfInterestInRecord(RRD, State, R, Vec, depth))

584 return Out;

585

589 const SVal V = State->getSVal(FR);

590 const MemRegion *VR = V.getAsRegion();

591

592 RegionVector VecF = Vec;

593 VecF.push_back(FR);

594

595 if (RegionOfInterest == VR)

596 return VecF;

597

599 if (auto Out =

600 findRegionOfInterestInRecord(RRD, State, FR, VecF, depth + 1))

601 return Out;

602

605 continue;

606

608 if (std::optional Out =

609 findRegionOfInterestInRecord(RRD, State, VR, VecF, depth + 1))

610 return Out;

611 }

612

613 return std::nullopt;

614}

615

620 if (const auto *IvarR = dyn_cast(RegionOfInterest)) {

621 const MemRegion *SelfRegion = Call.getReceiverSVal().getAsRegion();

622 if (RegionOfInterest->isSubRegionOf(SelfRegion) &&

624 IvarR->getDecl()))

625 return maybeEmitNote(R, Call, N, {}, SelfRegion, "self",

626 false, 1);

627 }

628 return nullptr;

629}

630

635 const MemRegion *ThisR = Call.getCXXThisVal().getAsRegion();

636 if (RegionOfInterest->isSubRegionOf(ThisR) && Call.getDecl()->isImplicit())

637 return maybeEmitNote(R, Call, N, {}, ThisR, "this",

638 false, 1);

639

640

641

642 return nullptr;

643}

644

645

649}

650

654 for (unsigned I = 0; I < Call.getNumArgs() && I < Parameters.size(); ++I) {

659

660 unsigned IndirectionLevel = 1;

662 while (const MemRegion *MR = V.getAsRegion()) {

664 return maybeEmitNote(R, Call, N, {}, MR, ParamName,

665 ParamIsReferenceType, IndirectionLevel);

666

668 if (PT.isNull() || PT->isVoidType())

669 break;

670

672

673 if (const RecordDecl *RD = PT->getAsRecordDecl())

674 if (std::optional P =

675 findRegionOfInterestInRecord(RD, State, MR))

676 return maybeEmitNote(R, Call, N, *P, RegionOfInterest, ParamName,

677 ParamIsReferenceType, IndirectionLevel);

678

679 V = State->getSVal(MR, PT);

680 T = PT;

681 IndirectionLevel++;

682 }

683 }

684

685 return nullptr;

686}

687

688bool NoStoreFuncVisitor::wasModifiedBeforeCallExit(

690 return ::wasRegionOfInterestModifiedAt(

691 RegionOfInterest, CurrN,

692 CallExitBeginN->getState()->getSVal(RegionOfInterest));

693}

694

696 ", which participates in a condition later";

697

700 const RegionVector &FieldChain, const MemRegion *MatchedRegion,

701 StringRef FirstElement, bool FirstIsReferenceType,

702 unsigned IndirectionLevel) {

703

706

707

708

709

711 return nullptr;

712

714 llvm::raw_svector_ostream os(sbuf);

715 os << "Returning without writing to '";

716

717

718 if (!prettyPrintRegionName(FieldChain, MatchedRegion, FirstElement,

719 FirstIsReferenceType, IndirectionLevel, os))

720 return nullptr;

721

722 os << "'";

725 return std::make_shared(L, os.str());

726}

727

728bool NoStoreFuncVisitor::prettyPrintRegionName(const RegionVector &FieldChain,

730 StringRef FirstElement,

731 bool FirstIsReferenceType,

732 unsigned IndirectionLevel,

733 llvm::raw_svector_ostream &os) {

734

735 if (FirstIsReferenceType)

736 IndirectionLevel--;

737

738 RegionVector RegionSequence;

739

740

741 assert(RegionOfInterest->isSubRegionOf(MatchedRegion));

742 const MemRegion *R = RegionOfInterest;

743 while (R != MatchedRegion) {

744 RegionSequence.push_back(R);

745 R = cast(R)->getSuperRegion();

746 }

747 std::reverse(RegionSequence.begin(), RegionSequence.end());

748 RegionSequence.append(FieldChain.begin(), FieldChain.end());

749

750 StringRef Sep;

751 for (const MemRegion *R : RegionSequence) {

752

753

754

755 if (isa<CXXBaseObjectRegion, CXXTempObjectRegion>(R))

756 continue;

757

758 if (Sep.empty())

759 Sep = prettyPrintFirstElement(FirstElement,

760 true,

761 IndirectionLevel, os);

762

763 os << Sep;

764

765

766 if (!isa(R))

767 return false;

768

769 const auto *DR = cast(R);

770 Sep = DR->getValueType()->isAnyPointerType() ? "->" : ".";

771 DR->getDecl()->getDeclName().print(os, PP);

772 }

773

774 if (Sep.empty())

775 prettyPrintFirstElement(FirstElement,

776 false, IndirectionLevel, os);

777 return true;

778}

779

780StringRef NoStoreFuncVisitor::prettyPrintFirstElement(

781 StringRef FirstElement, bool MoreItemsExpected, int IndirectionLevel,

782 llvm::raw_svector_ostream &os) {

783 StringRef Out = ".";

784

785 if (IndirectionLevel > 0 && MoreItemsExpected) {

786 IndirectionLevel--;

787 Out = "->";

788 }

789

790 if (IndirectionLevel > 0 && MoreItemsExpected)

791 os << "(";

792

793 for (int i = 0; i < IndirectionLevel; i++)

794 os << "*";

795 os << FirstElement;

796

797 if (IndirectionLevel > 0 && MoreItemsExpected)

798 os << ")";

799

800 return Out;

801}

802

803

804

805

806

807namespace {

808

809

810

811class MacroNullReturnSuppressionVisitor final : public BugReporterVisitor {

812 const SubRegion *RegionOfInterest;

813 const SVal ValueAtDereference;

814

815

816

817 bool WasModified = false;

818

819public:

820 MacroNullReturnSuppressionVisitor(const SubRegion *R, const SVal V)

821 : RegionOfInterest(R), ValueAtDereference(V) {}

822

826 if (WasModified)

827 return nullptr;

828

830 if (!BugPoint)

831 return nullptr;

832

834 if (auto Loc = matchAssignment(N)) {

836 std::string MacroName = std::string(getMacroName(*Loc, BRC));

837 SourceLocation BugLoc = BugPoint->getStmt()->getBeginLoc();

839 BR.markInvalid(getTag(), MacroName.c_str());

840 }

841 }

842

844 WasModified = true;

845

846 return nullptr;

847 }

848

849 static void addMacroVisitorIfNecessary(

854 if (EnableNullFPSuppression && Options.ShouldSuppressNullReturnPaths &&

855 isa(V))

857 V);

858 }

859

860 void* getTag() const {

861 static int Tag = 0;

862 return static_cast<void *>(&Tag);

863 }

864

865 void Profile(llvm::FoldingSetNodeID &ID) const override {

866 ID.AddPointer(getTag());

867 }

868

869private:

870

871

872 std::optional matchAssignment(const ExplodedNode *N) {

876 if (!S)

877 return std::nullopt;

878

879 if (const auto *DS = dyn_cast(S)) {

880 if (const auto *VD = dyn_cast(DS->getSingleDecl()))

881 if (const Expr *RHS = VD->getInit())

882 if (RegionOfInterest->isSubRegionOf(

883 State->getLValue(VD, LCtx).getAsRegion()))

884 return RHS->getBeginLoc();

885 } else if (const auto *BO = dyn_cast(S)) {

887 const Expr *RHS = BO->getRHS();

888 if (BO->isAssignmentOp() && RegionOfInterest->isSubRegionOf(R)) {

890 }

891 }

892 return std::nullopt;

893 }

894};

895

896}

897

898namespace {

899

900

901

902

903

904

905

906

909 enum {

910 Initial,

911 MaybeUnsuppress,

912 Satisfied

913 } Mode = Initial;

914

915 bool EnableNullFPSuppression;

916 bool ShouldInvalidate = true;

919

920public:

925 EnableNullFPSuppression(Suppressed), Options(Options), TKind(TKind) {}

926

927 static void *getTag() {

928 static int Tag = 0;

929 return static_cast<void *>(&Tag);

930 }

931

932 void Profile(llvm::FoldingSetNodeID &ID) const override {

933 ID.AddPointer(ReturnVisitor::getTag());

934 ID.AddPointer(CalleeSFC);

935 ID.AddBoolean(EnableNullFPSuppression);

936 }

937

941

943 return nullptr;

944

946 if (!SP)

947 return nullptr;

948

949 const auto *Ret = dyn_cast(SP->getStmt());

950 if (!Ret)

951 return nullptr;

952

953

954

956 SVal V = State->getSVal(Ret, CalleeSFC);

957 if (V.isUnknownOrUndef())

958 return nullptr;

959

960

961 Mode = Satisfied;

962

963 const Expr *RetE = Ret->getRetValue();

964 assert(RetE && "Tracking a return value for a void function");

965

966

967 std::optional LValue;

969 if ((LValue = V.getAs<Loc>())) {

970 SVal RValue = State->getRawSVal(*LValue, RetE->getType());

971 if (isa(RValue))

972 V = RValue;

973 }

974 }

975

976

977 if (isa<nonloc::LazyCompoundVal, nonloc::CompoundVal>(V))

978 return nullptr;

979

981

982

983 getParentTracker().track(RetE, N, {TKind, EnableNullFPSuppression});

984

985

987 llvm::raw_svector_ostream Out(Msg);

988

989 bool WouldEventBeMeaningless = false;

990

991 if (State->isNull(V).isConstrainedTrue()) {

992 if (isa(V)) {

993

994

995

996

997 if (EnableNullFPSuppression &&

998 Options.ShouldAvoidSuppressingNullArgumentPaths)

999 Mode = MaybeUnsuppress;

1000

1002 Out << "Returning nil";

1003 } else {

1004 Out << "Returning null pointer";

1005 }

1006 } else {

1007 Out << "Returning zero";

1008 }

1009

1010 } else {

1012 Out << "Returning the value " << CI->getValue();

1013 } else {

1014

1015

1016

1017

1018

1020 WouldEventBeMeaningless = true;

1021

1022 Out << (isa(V) ? "Returning pointer" : "Returning value");

1023 }

1024 }

1025

1026 if (LValue) {

1027 if (const MemRegion *MR = LValue->getAsRegion()) {

1028 if (MR->canPrintPretty()) {

1029 Out << " (reference to ";

1030 MR->printPretty(Out);

1031 Out << ")";

1032 }

1033 }

1034 } else {

1035

1036 if (const auto *DR = dyn_cast(RetE))

1037 if (const auto *DD = dyn_cast(DR->getDecl()))

1038 Out << " (loaded from '" << *DD << "')";

1039 }

1040

1042 if (!L.isValid() || !L.asLocation().isValid())

1043 return nullptr;

1044

1045 if (TKind == bugreporter::TrackingKind::Condition)

1047

1048 auto EventPiece = std::make_shared(L, Out.str());

1049

1050

1051

1052 if (WouldEventBeMeaningless)

1053 EventPiece->setPrunable(true);

1054 else

1056

1057 return EventPiece;

1058 }

1059

1063 assert(Options.ShouldAvoidSuppressingNullArgumentPaths);

1064

1065

1067 if (!CE)

1068 return nullptr;

1069

1070 if (CE->getCalleeContext() != CalleeSFC)

1071 return nullptr;

1072

1073 Mode = Satisfied;

1074

1075

1076

1077

1080

1083 for (unsigned I = 0, E = Call->getNumArgs(); I != E; ++I) {

1084 std::optional ArgV = Call->getArgSVal(I).getAs<Loc>();

1085 if (!ArgV)

1086 continue;

1087

1088 const Expr *ArgE = Call->getArgExpr(I);

1089 if (!ArgE)

1090 continue;

1091

1092

1093 if (!State->isNull(*ArgV).isConstrainedTrue())

1094 continue;

1095

1096 if (getParentTracker()

1097 .track(ArgE, N, {TKind, EnableNullFPSuppression})

1098 .FoundSomethingToTrack)

1099 ShouldInvalidate = false;

1100

1101

1102

1103

1104 }

1105

1106 return nullptr;

1107 }

1108

1112 switch (Mode) {

1113 case Initial:

1114 return visitNodeInitial(N, BRC, BR);

1115 case MaybeUnsuppress:

1116 return visitNodeMaybeUnsuppress(N, BRC, BR);

1117 case Satisfied:

1118 return nullptr;

1119 }

1120

1121 llvm_unreachable("Invalid visit mode!");

1122 }

1123

1126 if (EnableNullFPSuppression && ShouldInvalidate)

1127 BR.markInvalid(ReturnVisitor::getTag(), CalleeSFC);

1128 }

1129};

1130

1131

1132

1133

1134

1135

1136

1140 bool Satisfied = false;

1141

1144

1145public:

1146

1147

1148

1149

1150

1151

1152

1153

1154

1155

1160 OriginSFC(OriginSFC) {

1161 assert(R);

1162 }

1163

1164 void Profile(llvm::FoldingSetNodeID &ID) const override;

1165

1169};

1170}

1171

1172void StoreSiteFinder::Profile(llvm::FoldingSetNodeID &ID) const {

1173 static int tag = 0;

1174 ID.AddPointer(&tag);

1175 ID.AddPointer(R);

1176 ID.Add(V);

1177 ID.AddInteger(static_cast<int>(Options.Kind));

1178 ID.AddBoolean(Options.EnableNullFPSuppression);

1179}

1180

1181

1182

1185 if (P)

1186 return false;

1187

1189 if (!DS)

1190 return false;

1191

1193 return false;

1194

1196 const auto *FrameSpace = dyn_cast(VarSpace);

1197 if (!FrameSpace) {

1198

1199

1200

1202 return true;

1203 }

1204

1208}

1209

1212 if (const auto *TR = dyn_cast(R))

1213 return TR->getValueType()->isObjCObjectPointerType();

1214

1215 return false;

1216}

1217

1219 return D->getType()->isObjCObjectPointerType();

1220}

1221

1222

1225

1226 if (HasPrefix) {

1228 OS << " ";

1229 }

1230

1231 const char *Action = nullptr;

1232

1235 Action = HasPrefix ? "initialized to " : "Initializing to ";

1236 break;

1238 Action = HasPrefix ? "captured by block as " : "Captured by block as ";

1239 break;

1240 default:

1241 llvm_unreachable("Unexpected store kind");

1242 }

1243

1244 if (isaloc::ConcreteInt(SI.Value)) {

1245 OS << Action << (isObjCPointer(SI.Dest) ? "nil" : "a null pointer value");

1246

1248 OS << Action << CVal->getValue();

1249

1251 OS << Action << "the value of ";

1253

1255

1256

1257

1258 const auto *DS =

1260

1262 if (isa(SI.Dest)) {

1263 const auto *VD = cast(DS->getSingleDecl());

1264

1265 if (VD->getInit()) {

1266 OS << (HasPrefix ? "initialized" : "Initializing")

1267 << " to a garbage value";

1268 } else {

1269 OS << (HasPrefix ? "declared" : "Declaring")

1270 << " without an initial value";

1271 }

1272 }

1273 } else {

1274 OS << (HasPrefix ? "initialized" : "Initialized") << " here";

1275 }

1276 }

1277}

1278

1279

1282 const auto *VR = cast(SI.Dest);

1283 const auto *D = VR->getDecl();

1284

1285 OS << "Passing ";

1286

1287 if (isaloc::ConcreteInt(SI.Value)) {

1288 OS << (isObjCPointer(D) ? "nil object reference" : "null pointer value");

1289

1291 OS << "uninitialized value";

1292

1294 OS << "the value " << CI->getValue();

1295

1298

1299 } else {

1300 OS << "value";

1301 }

1302

1303 if (const auto *Param = dyn_cast(VR->getDecl())) {

1304

1305 unsigned Idx = Param->getFunctionScopeIndex() + 1;

1306 OS << " via " << Idx << llvm::getOrdinalSuffix(Idx) << " parameter";

1308 OS << " ";

1310 }

1311 } else if (const auto *ImplParam = dyn_cast(D)) {

1313 OS << " via implicit parameter 'self'";

1314 }

1315 }

1316}

1317

1318

1322

1323 if (isaloc::ConcreteInt(SI.Value)) {

1325 : (HasSuffix ? "Null pointer value stored"

1326 : "Storing null pointer value"));

1327

1329 OS << (HasSuffix ? "Uninitialized value stored"

1330 : "Storing uninitialized value");

1331

1333 if (HasSuffix)

1334 OS << "The value " << CV->getValue() << " is assigned";

1335 else

1336 OS << "Assigning " << CV->getValue();

1337

1339 if (HasSuffix) {

1340 OS << "The value of ";

1342 OS << " is assigned";

1343 } else {

1344 OS << "Assigning the value of ";

1346 }

1347

1348 } else {

1349 OS << (HasSuffix ? "Value assigned" : "Assigning value");

1350 }

1351

1352 if (HasSuffix) {

1353 OS << " to ";

1355 }

1356}

1357

1359 if (!CE)

1360 return false;

1361

1363

1365}

1366

1369

1370 const auto *TVR = dyn_cast_or_null(R);

1371

1372 if (!TVR)

1373 return nullptr;

1374

1376

1377

1378 std::stack<const TypedValueRegion *> TVRStack;

1379 while (isa(TVR) || isa(TVR)) {

1380

1381

1382

1383

1384 if (ITy == TVR->getValueType().getCanonicalType())

1385 break;

1386

1387 TVRStack.push(TVR);

1388 TVR = cast(TVR->getSuperRegion());

1389 }

1390

1391

1392

1393 if (ITy != TVR->getValueType().getCanonicalType())

1394 return nullptr;

1395

1397 while (!TVRStack.empty()) {

1398 TVR = TVRStack.top();

1399 TVRStack.pop();

1400

1401

1402

1403 if (!isa(Init))

1404 return nullptr;

1405

1406 ILE = cast(Init);

1408

1409 if (const auto *FR = dyn_cast(TVR)) {

1410 const auto *FD = FR->getDecl();

1411

1412 if (FD->getFieldIndex() >= NumInits)

1413 return nullptr;

1414

1415 Init = ILE->getInit(FD->getFieldIndex());

1416 } else if (const auto *ER = dyn_cast(TVR)) {

1417 const auto Ind = ER->getIndex();

1418

1419

1420

1421 if (!Ind.isConstant())

1422 return nullptr;

1423

1424 const auto IndVal = Ind.getAsInteger()->getLimitedValue();

1425 if (IndVal >= NumInits)

1426 return nullptr;

1427

1429 }

1430 }

1431

1432 return Init;

1433}

1434

1438 if (Satisfied)

1439 return nullptr;

1440

1443 const Expr *InitE = nullptr;

1444 bool IsParam = false;

1445

1446

1447 if (const auto *VR = dyn_cast(R)) {

1449 StoreSite = Pred;

1450 InitE = VR->getDecl()->getInit();

1451 }

1452 }

1453

1454

1455

1456 if (std::optional PIP =

1458 const MemRegion *FieldReg = (const MemRegion *)PIP->getLocationValue();

1459 if (FieldReg == R) {

1460 StoreSite = Pred;

1461 InitE = PIP->getInitializer()->getInit();

1462 }

1463 }

1464

1465

1466

1467

1468

1469

1470 if (!StoreSite) {

1471 if (Succ->getState()->getSVal(R) != V)

1472 return nullptr;

1473

1476 if (!PS || PS->getLocationValue() != R)

1477 return nullptr;

1478 }

1479

1480 StoreSite = Succ;

1481

1483

1484

1486 if (BO->isAssignmentOp())

1487 InitE = BO->getRHS();

1488 }

1489

1490

1491 else if (const auto *DS = P->getStmtAs<DeclStmt>()) {

1492 const auto *Decl = DS->getSingleDecl();

1493 if (isa(Decl)) {

1494 const auto *VD = cast(Decl);

1495

1496

1497

1498

1499

1500

1501

1502 if (const auto *ILE = dyn_cast(VD->getInit()))

1504 }

1506

1507 const auto State = Succ->getState();

1508

1510

1511

1512

1513

1514

1515

1516

1517

1518 std::stack<const SubRegion *> SRStack;

1519 const SubRegion *SR = cast(R);

1520 while (isa(SR) || isa(SR)) {

1521 SRStack.push(SR);

1523 }

1524

1525

1526 const auto *OriginEx = CE->getArg(0);

1527 const auto OriginVal =

1529

1530

1531

1532

1533 SVal OriginField = OriginVal;

1534 while (!SRStack.empty()) {

1535 const auto *TopR = SRStack.top();

1536 SRStack.pop();

1537

1538 if (const auto *FR = dyn_cast(TopR)) {

1539 OriginField = State->getLValue(FR->getDecl(), OriginField);

1540 } else if (const auto *ER = dyn_cast(TopR)) {

1541 OriginField = State->getLValue(ER->getElementType(),

1542 ER->getIndex(), OriginField);

1543 } else {

1544

1545 }

1546 }

1547

1548

1549 getParentTracker().track(V, OriginField.getAsRegion(), Options);

1550 InitE = OriginEx;

1551 }

1552 }

1553

1554 else if (const auto *ILE = P->getStmtAs<InitListExpr>()) {

1555

1556

1557

1558

1559

1560

1562 }

1563 }

1564

1565

1566

1567

1568

1570 if (const auto *VR = dyn_cast(R)) {

1571

1572 if (const auto *Param = dyn_cast(VR->getDecl())) {

1575

1578 InitE = Call->getArgExpr(Param->getFunctionScopeIndex());

1579 } else {

1580

1581 assert(isa(VR->getDecl()));

1582 InitE = cast(CE->getCalleeContext()->getCallSite())

1584 }

1585 IsParam = true;

1586 }

1587 }

1588

1589

1590

1591 if (const auto *TmpR = dyn_cast(R))

1592 InitE = TmpR->getExpr();

1593 }

1594

1595 if (!StoreSite)

1596 return nullptr;

1597

1598 Satisfied = true;

1599

1600

1601

1602 if (InitE) {

1603 if (!IsParam)

1605

1606 getParentTracker().track(InitE, StoreSite, Options);

1607 }

1608

1609

1610 const MemRegion *OldRegion = nullptr;

1611

1612

1613

1614 if (InitE) {

1615

1616

1617

1618

1619

1620

1621

1622

1623 if (const MemRegion *Candidate =

1626

1627

1628

1630 if (SM.includedInBindings(N->getState()->getStore(), Candidate)) {

1631

1632 if (N->getState()->getSVal(Candidate) == V) {

1633 OldRegion = Candidate;

1634 }

1635 break;

1636 }

1637 }

1638 }

1639 }

1640

1641

1642

1643

1644

1645

1646

1647

1648

1649

1650

1651

1652 if (!OldRegion && StoreSite->getState()->getSVal(R) == V) {

1653

1654

1656 for (;

1657 NodeWithoutBinding && NodeWithoutBinding->getState()->getSVal(R) == V;

1658 NodeWithoutBinding = NodeWithoutBinding->getFirstPred()) {

1659 }

1660

1661 if (NodeWithoutBinding) {

1662

1663

1664

1665

1666

1667

1668

1669

1672 if (FB)

1673 OldRegion = FB.getRegion();

1674 }

1675 }

1676

1677 if (Options.Kind == TrackingKind::Condition && OriginSFC &&

1678 !OriginSFC->isParentOf(StoreSite->getStackFrame()))

1679 return nullptr;

1680

1681

1683 llvm::raw_svector_ostream os(sbuf);

1684

1686 StoreSite,

1687 InitE,

1688 V,

1689 R,

1690 OldRegion};

1691

1693 const Stmt *S = PS->getStmt();

1694 const auto *DS = dyn_cast(S);

1695 const auto *VR = dyn_cast(R);

1696

1697 if (DS) {

1699 } else if (isa(S)) {

1701 if (VR) {

1702

1705 if (const auto *BDR =

1706 dyn_cast_or_null(V.getAsRegion())) {

1707 if (const VarRegion *OriginalR = BDR->getOriginalRegion(VR)) {

1708 getParentTracker().track(State->getSVal(OriginalR), OriginalR,

1709 Options, OriginSFC);

1710 }

1711 }

1712 }

1713 }

1715 isa(SI.Dest)) {

1717 }

1718

1719 return getParentTracker().handle(SI, BRC, Options);

1720}

1721

1722

1723

1724

1725

1727 static int tag = 0;

1728 ID.AddPointer(&tag);

1729 ID.AddString(Message);

1730 ID.AddBoolean(Assumption);

1731 ID.Add(Constraint);

1732}

1733

1734

1735

1737 return "TrackConstraintBRVisitor";

1738}

1739

1740bool TrackConstraintBRVisitor::isZeroCheck() const {

1741 return !Assumption && Constraint.getAs<Loc>();

1742}

1743

1744bool TrackConstraintBRVisitor::isUnderconstrained(const ExplodedNode *N) const {

1745 if (isZeroCheck())

1746 return N->getState()->isNull(Constraint).isUnderconstrained();

1747 return (bool)N->getState()->assume(Constraint, !Assumption);

1748}

1749

1753 if (IsSatisfied)

1754 return nullptr;

1755

1756

1757

1758 if (!IsTrackingTurnedOn)

1759 if (!isUnderconstrained(N))

1760 IsTrackingTurnedOn = true;

1761 if (!IsTrackingTurnedOn)

1762 return nullptr;

1763

1764

1765

1766 if (isUnderconstrained(PrevN)) {

1767 IsSatisfied = true;

1768

1769

1770

1771

1772

1773 assert(!isUnderconstrained(N));

1774

1775

1777

1778

1779

1780

1781 if (isa_and_nonnull(P.getTag()))

1782 return nullptr;

1783

1787 return nullptr;

1788

1789 auto X = std::make_shared(L, Message);

1791 return std::move(X);

1792 }

1793

1794 return nullptr;

1795}

1796

1797

1798

1799

1800

1804

1806 if (!Options.ShouldSuppressInlinedDefensiveChecks)

1807 IsSatisfied = true;

1808}

1809

1811 llvm::FoldingSetNodeID &ID) const {

1812 static int id = 0;

1813 ID.AddPointer(&id);

1814 ID.Add(V);

1815}

1816

1818 return "IDCVisitor";

1819}

1820

1826 if (IsSatisfied)

1827 return nullptr;

1828

1829

1830 if (!IsTrackingTurnedOn)

1831 if (Succ->getState()->isNull(V).isConstrainedTrue())

1832 IsTrackingTurnedOn = true;

1833 if (!IsTrackingTurnedOn)

1834 return nullptr;

1835

1836

1837

1838 if (!Pred->getState()->isNull(V).isConstrainedTrue() &&

1839 Succ->getState()->isNull(V).isConstrainedTrue()) {

1840 IsSatisfied = true;

1841

1842

1845 if (CurLC != ReportLC && !CurLC->isParentOf(ReportLC)) {

1847 return nullptr;

1848 }

1849

1850

1851

1852

1853

1855

1856 if (!BugPoint)

1857 return nullptr;

1858

1860 const Stmt *CurTerminatorStmt = nullptr;

1862 CurTerminatorStmt = BE->getSrc()->getTerminator().getStmt();

1864 const Stmt *CurStmt = SP->getStmt();

1866 return nullptr;

1867

1870 } else {

1871 return nullptr;

1872 }

1873

1874 if (!CurTerminatorStmt)

1875 return nullptr;

1876

1878 if (TerminatorLoc.isMacroID()) {

1879 SourceLocation BugLoc = BugPoint->getStmt()->getBeginLoc();

1880

1881

1884 BR.markInvalid("Suppress Macro IDC", CurLC);

1885 }

1886 return nullptr;

1887 }

1888 }

1889 return nullptr;

1890}

1891

1892

1893

1894

1895

1896namespace {

1897

1898

1899

1900

1901

1902

1903

1904

1905

1906

1907

1908class TrackControlDependencyCondBRVisitor final

1912 llvm::SmallSet<const CFGBlock *, 32> VisitedBlocks;

1913

1914public:

1915 TrackControlDependencyCondBRVisitor(TrackerRef ParentTracker,

1918 ControlDeps(&O->getCFG()) {}

1919

1920 void Profile(llvm::FoldingSetNodeID &ID) const override {

1921 static int x = 0;

1922 ID.AddPointer(&x);

1923 }

1924

1928};

1929}

1930

1931static std::shared_ptr

1935

1938 return nullptr;

1939

1943

1944 return std::make_shared(

1947 (Twine() + "Tracking condition '" + ConditionText + "'").str());

1948}

1949

1952 return false;

1953

1956

1957 if (!Then || !Else)

1958 return false;

1959

1961 return true;

1962

1963

1964

1965

1966

1967

1968

1969

1970

1971

1972

1973

1975 if (const auto *BinOp = dyn_cast(ElseCond))

1976 if (BinOp->isLogicalOp())

1978

1979 return false;

1980}

1981

1983TrackControlDependencyCondBRVisitor::VisitNode(const ExplodedNode *N,

1986

1987 if (Origin->getStackFrame() != N->getStackFrame())

1988 return nullptr;

1989

1991

1992

1993 if (!VisitedBlocks.insert(NB).second)

1994 return nullptr;

1995

1996 CFGBlock *OriginB = const_cast<CFGBlock *>(Origin->getCFGBlock());

1997

1998

1999 if (!OriginB || !NB)

2000 return nullptr;

2001

2003 return nullptr;

2004

2005 if (ControlDeps.isControlDependent(OriginB, NB)) {

2006

2007

2008 if (llvm::isa_and_nonnull(NB->getTerminatorStmt()))

2009 return nullptr;

2010

2012

2013

2015 if (!InnerExpr)

2016 return nullptr;

2017

2018

2019

2020

2021

2022

2023

2024

2025

2026

2027

2028

2029

2030

2031 if (isa(InnerExpr))

2032 return nullptr;

2033

2034

2035

2036

2038 getParentTracker().track(InnerExpr, N,

2040 false});

2042 }

2043 }

2044 }

2045

2046 return nullptr;

2047}

2048

2049

2050

2051

2052

2054

2056 if (const auto *FE = dyn_cast(Ex))

2058 if (const auto *OVE = dyn_cast(Ex))

2060 if (const auto *POE = dyn_cast(Ex)) {

2061 const auto *PropRef = dyn_cast(POE->getSyntacticForm());

2062 if (PropRef && PropRef->isMessagingGetter()) {

2063 const Expr *GetterMessageSend =

2064 POE->getSemanticExpr(POE->getNumSemanticExprs() - 1);

2065 assert(isa(GetterMessageSend->IgnoreParenCasts()));

2067 }

2068 }

2069

2070

2071 if (const auto *CO = dyn_cast(Ex)) {

2072

2073

2075 do {

2077 if (std::optional BE = ProgPoint.getAs<BlockEdge>()) {

2078 const CFGBlock *srcBlk = BE->getSrc();

2080 if (term == CO) {

2081 bool TookTrueBranch = (*(srcBlk->succ_begin()) == BE->getDst());

2082 if (TookTrueBranch)

2084 else

2086 }

2087 }

2088 }

2090 } while (NI);

2091 }

2092

2093 if (auto *BO = dyn_cast(Ex))

2096

2097 if (auto *UO = dyn_cast(Ex)) {

2098 if (UO->getOpcode() == UO_LNot)

2100

2101

2102

2103

2104

2105

2106

2107

2108

2109 if (UO->getOpcode() == UO_AddrOf && UO->getSubExpr()->isLValue())

2112 }

2113

2114 return Ex;

2115}

2116

2117

2118

2120 const Expr *Inner) {

2121 while (N) {

2123 return N;

2125 }

2126 return N;

2127}

2128

2129

2130

2131

2132

2135 StringRef NodeText) {

2136

2141 P.getLocationContext());

2142

2145

2147 return nullptr;

2148

2149 return std::make_shared(L, NodeText);

2150}

2151

2152namespace {

2153class DefaultStoreHandler final : public StoreHandler {

2154public:

2156

2159

2161 llvm::raw_svector_ostream OS(Buffer);

2162

2167 break;

2170 break;

2173 break;

2174 }

2175

2176 if (Opts.Kind == bugreporter::TrackingKind::Condition)

2178

2179 return constructNote(SI, BRC, OS.str());

2180 }

2181};

2182

2183class ControlDependencyHandler final : public ExpressionHandler {

2184public:

2186

2191

2192

2193

2194

2195

2196

2197

2199 ->getAnalysisManager()

2200 .getAnalyzerOptions()

2201 .ShouldTrackConditions) {

2202 Report.addVisitor(

2203 &getParentTracker(), InputNode);

2204 return {true};

2205 }

2206

2207 return {};

2208 }

2209};

2210

2212public:

2214

2218

2219

2220

2221 if (const Expr *Receiver =

2223 return getParentTracker().track(Receiver, LVNode, Opts);

2224

2225 return {};

2226 }

2227};

2228

2230public:

2232

2236

2237 if (const auto *Arr = dyn_cast(Inner))

2238 return getParentTracker().track(

2239 Arr->getIdx(), LVNode,

2240 {Opts.Kind, false});

2241

2242 return {};

2243 }

2244};

2245

2246

2247class InterestingLValueHandler final : public ExpressionHandler {

2248public:

2250

2258

2259

2260

2263

2265 bool LVIsNull = LVState->isNull(LVal).isConstrainedTrue();

2266

2267

2268

2269

2270 if (RR && !LVIsNull)

2271 Result.combineWith(getParentTracker().track(LVal, RR, Opts, SFC));

2272

2273

2274

2275

2276

2279

2280 if (R) {

2281

2282

2285

2286

2287

2288 Result.FoundSomethingToTrack = true;

2289 Result.WasInterrupted = true;

2290

2291 MacroNullReturnSuppressionVisitor::addMacroVisitorIfNecessary(

2293

2296

2297

2298

2299 if (V.getAsLocSymbol(true))

2300 if (LVState->isNull(V).isConstrainedTrue())

2303 false, "Assuming pointer value is null");

2304

2305

2308

2309

2310

2311

2312

2313

2315 InputNode);

2316 getParentTracker().track(V, R, Opts, SFC);

2317 }

2318 }

2319

2320 return Result;

2321 }

2322};

2323

2324

2325

2326

2327

2328

2329

2330

2331class InlinedFunctionCallHandler final : public ExpressionHandler {

2333

2338 return {};

2339

2340

2341

2342

2343

2344 const bool BypassCXXNewExprEval = isa(E);

2345

2346

2348

2349 do {

2350

2351 if (std::optional CEE =

2353 if (CEE->getCalleeContext()->getCallSite() == E)

2354 break;

2355

2356

2358 if (!ExprNode)

2359 break;

2360

2362

2363

2364

2365

2366 if (!BypassCXXNewExprEval)

2368

2369 if (SP->getStmt() == E && CurrentSFC == PredSFC)

2370 break;

2371

2372 CurrentSFC = PredSFC;

2373 } while (ExprNode->getStackFrame() == CurrentSFC);

2374

2375

2378 if (!ExprNode)

2379 return {};

2380

2381

2383 if (!CEE)

2384 return {};

2385

2386 const StackFrameContext *CalleeContext = CEE->getCalleeContext();

2388 return {};

2389

2390

2393

2394

2395 if (cast(E)->isGLValue())

2396 if (std::optional LValue = RetVal.getAs<Loc>())

2397 RetVal = State->getSVal(*LValue);

2398

2399

2400 AnalyzerOptions &Options = State->getAnalysisManager().options;

2401

2402 bool EnableNullFPSuppression = false;

2404 if (std::optional RetLoc = RetVal.getAs<Loc>())

2405 EnableNullFPSuppression = State->isNull(*RetLoc).isConstrainedTrue();

2406

2408 Report.addVisitor(&getParentTracker(), CalleeContext,

2409 EnableNullFPSuppression, Options,

2411 return {true};

2412 }

2413};

2414

2415class DefaultExpressionHandler final : public ExpressionHandler {

2416public:

2418

2426

2427

2428

2430

2431

2433

2434

2435

2436

2437 bool CanDereference = true;

2438 if (const auto *SR = L->getRegionAs<SymbolicRegion>()) {

2439 if (SR->getPointeeStaticType()->isVoidType())

2440 CanDereference = false;

2442 CanDereference = false;

2443

2444

2445

2446

2449 RVal = LVState->getRawSVal(*L, Inner->getType());

2450 else if (CanDereference)

2451 RVal = LVState->getSVal(L->getRegion());

2452

2453 if (CanDereference) {

2455 Result.FoundSomethingToTrack = true;

2456

2458 Result.combineWith(

2459 getParentTracker().track(RVal, L->getRegion(), Opts, SFC));

2460 }

2461

2463 if (isa_and_nonnull(RegionRVal)) {

2464 Report.markInteresting(RegionRVal, Opts.Kind);

2467 false, "Assuming pointer value is null");

2468 Result.FoundSomethingToTrack = true;

2469 }

2470 }

2471

2472 return Result;

2473 }

2474};

2475

2476

2477

2479public:

2481

2486 return {};

2487

2489 if (!RVNode)

2490 return {};

2491

2494

2495 const auto track = [&CombinedResult, &Parent, ExprNode,

2496 Opts](const Expr *Inner) {

2497 CombinedResult.combineWith(Parent.track(Inner, ExprNode, Opts));

2498 };

2499

2500

2501

2502

2503

2504

2505 if (const auto *ILE = dyn_cast(E)) {

2506 if (ILE->getNumInits() == 1) {

2507 track(ILE->getInit(0));

2508

2509 return CombinedResult;

2510 }

2511

2512 return {};

2513 }

2514

2517 const auto *BO = dyn_cast(E);

2518

2519 if (!BO || !BO->isMultiplicativeOp() || V.isZeroConstant())

2520 return {};

2521

2524

2525

2526 if (BO->getOpcode() == BO_Mul) {

2528 track(BO->getLHS());

2530 track(BO->getRHS());

2531 } else {

2533 track(BO->getLHS());

2534 }

2535

2536 return CombinedResult;

2537 }

2538};

2539}

2540

2542

2543 addLowPriorityHandler();

2544 addLowPriorityHandler();

2545 addLowPriorityHandler();

2546 addLowPriorityHandler();

2547 addLowPriorityHandler();

2548 addLowPriorityHandler();

2549 addLowPriorityHandler();

2550

2551 addHighPriorityHandler();

2552}

2553

2556 if (E || !N)

2557 return {};

2558

2561 if (!LVNode)

2562 return {};

2563

2564 Result CombinedResult;

2565

2566 for (ExpressionHandlerPtr &Handler : ExpressionHandlers) {

2567 CombinedResult.combineWith(Handler->handle(Inner, N, LVNode, Opts));

2569

2570

2572 break;

2573 }

2574 }

2575

2576 return CombinedResult;

2577}

2578

2581 if (V.isUnknown()) {

2582 Report.addVisitor(this, V, R, Opts, Origin);

2583 return {true};

2584 }

2585 return {};

2586}

2587

2590

2591 for (StoreHandlerPtr &Handler : StoreHandlers) {

2593

2594

2596 }

2597 return {};

2598}

2599

2602

2606 ->track(E, InputNode, Opts)

2607 .FoundSomethingToTrack;

2608}

2609

2615}

2616

2617

2618

2619

2620

2623 const auto *ME = dyn_cast(S);

2624 if (!ME)

2625 return nullptr;

2626 if (const Expr *Receiver = ME->getInstanceReceiver()) {

2629 if (state->isNull(V).isConstrainedTrue())

2630 return Receiver;

2631 }

2632 return nullptr;

2633}

2634

2639 if (P)

2640 return nullptr;

2641

2642 const Stmt *S = P->getStmt();

2643 const Expr *Receiver = getNilReceiver(S, N);

2644 if (!Receiver)

2645 return nullptr;

2646

2648 llvm::raw_svector_ostream OS(Buf);

2649

2650 if (const auto *ME = dyn_cast(S)) {

2651 OS << "'";

2652 ME->getSelector().print(OS);

2653 OS << "' not called";

2654 }

2655 else {

2656 OS << "No method is called";

2657 }

2658 OS << " because the receiver is nil";

2659

2660

2661

2662

2665 false});

2666

2669 return std::make_shared(L, OS.str());

2670}

2671

2672

2673

2674

2675

2676

2677

2679

2683 auto piece = VisitNodeImpl(N, BRC, BR);

2684 if (piece) {

2685 piece->setTag(getTag());

2686 if (auto *ev = dyn_cast(piece.get()))

2687 ev->setPrunable(true, false);

2688 }

2689 return piece;

2690}

2691

2697 const std::pair<const ProgramPointTag *, const ProgramPointTag *> &Tags =

2699

2700

2701

2702 if (std::optional BE = ProgPoint.getAs<BlockEdge>()) {

2703 const CFGBlock *SrcBlock = BE->getSrc();

2705

2706

2707

2708

2711 if (PreviousNodeTag == Tags.first || PreviousNodeTag == Tags.second)

2712 return nullptr;

2713

2714 return VisitTerminator(Term, N, SrcBlock, BE->getDst(), BR, BRC);

2715 }

2716 return nullptr;

2717 }

2718

2719 if (std::optional PS = ProgPoint.getAs<PostStmt>()) {

2721 if (CurrentNodeTag != Tags.first && CurrentNodeTag != Tags.second)

2722 return nullptr;

2723

2724 bool TookTrue = CurrentNodeTag == Tags.first;

2725 return VisitTrueTest(cast(PS->getStmt()), BRC, BR, N, TookTrue);

2726 }

2727

2728 return nullptr;

2729}

2730

2735 const Expr *Cond = nullptr;

2736

2737

2738

2739

2740

2741

2742

2743

2744

2745

2746

2747

2748

2749

2751

2752

2753 default:

2754 return nullptr;

2755 case Stmt::IfStmtClass:

2756 Cond = cast(Term)->getCond();

2757 break;

2758 case Stmt::ConditionalOperatorClass:

2759 Cond = cast(Term)->getCond();

2760 break;

2761 case Stmt::BinaryOperatorClass:

2762

2763

2764

2765 const auto *BO = cast(Term);

2766 assert(BO->isLogicalOp() &&

2767 "CFG terminator is not a short-circuit operator!");

2768 Cond = BO->getLHS();

2769 break;

2770 }

2771

2773

2774

2775

2776

2777 while (const auto *InnerBO = dyn_cast(Cond)) {

2778 if (!InnerBO->isLogicalOp())

2779 break;

2781 }

2782

2783 assert(Cond);

2784 assert(srcBlk->succ_size() == 2);

2785 const bool TookTrue = *(srcBlk->succ_begin()) == dstBlk;

2786 return VisitTrueTest(Cond, BRC, R, N, TookTrue);

2787}

2788

2796

2797

2798

2799

2800

2801

2802

2803

2804

2805

2806

2807

2808

2809

2810

2811 bool IsAssuming =

2813 CurrentState->getSVal(Cond, LCtx).isUnknownOrUndef();

2814

2815

2816

2817 const Expr *CondTmp = Cond;

2818 bool TookTrueTmp = TookTrue;

2819

2820 while (true) {

2823 default:

2824 break;

2825 case Stmt::BinaryOperatorClass:

2826 if (auto P = VisitTrueTest(Cond, cast(CondTmp),

2827 BRC, R, N, TookTrueTmp, IsAssuming))

2828 return P;

2829 break;

2830 case Stmt::DeclRefExprClass:

2831 if (auto P = VisitTrueTest(Cond, cast(CondTmp),

2832 BRC, R, N, TookTrueTmp, IsAssuming))

2833 return P;

2834 break;

2835 case Stmt::MemberExprClass:

2836 if (auto P = VisitTrueTest(Cond, cast(CondTmp),

2837 BRC, R, N, TookTrueTmp, IsAssuming))

2838 return P;

2839 break;

2840 case Stmt::UnaryOperatorClass: {

2841 const auto *UO = cast(CondTmp);

2842 if (UO->getOpcode() == UO_LNot) {

2843 TookTrueTmp = !TookTrueTmp;

2844 CondTmp = UO->getSubExpr();

2845 continue;

2846 }

2847 break;

2848 }

2849 }

2850 break;

2851 }

2852

2853

2854

2855

2856

2857 if (!IsAssuming)

2858 return nullptr;

2859

2862 return nullptr;

2863

2864 return std::make_shared(

2865 Loc, TookTrue ? GenericTrueMessage : GenericFalseMessage);

2866}

2867

2872 std::optional &prunable,

2873 bool IsSameFieldName) {

2874 const Expr *OriginalExpr = Ex;

2876

2879

2880

2890 return false;

2891 }

2892 }

2893 }

2894

2895 if (const auto *DR = dyn_cast(Ex)) {

2896 const bool quotes = isa(DR->getDecl());

2897 if (quotes) {

2898 Out << '\'';

2901 if (const MemRegion *R = state->getLValue(cast(DR->getDecl()),

2904 prunable = false;

2905 else {

2909 prunable = false;

2910 }

2911 }

2912 }

2913 Out << DR->getDecl()->getDeclName().getAsString();

2914 if (quotes)

2915 Out << '\'';

2916 return quotes;

2917 }

2918

2919 if (const auto *IL = dyn_cast(Ex)) {

2922 if (IL->getValue() == 0) {

2923 Out << "null";

2924 return false;

2925 }

2926 }

2928 if (IL->getValue() == 0) {

2929 Out << "nil";

2930 return false;

2931 }

2932 }

2933

2934 Out << IL->getValue();

2935 return false;

2936 }

2937

2938 if (const auto *ME = dyn_cast(Ex)) {

2939 if (!IsSameFieldName)

2940 Out << "field '" << ME->getMemberDecl()->getName() << '\'';

2941 else

2942 Out << '\''

2946 nullptr)

2947 << '\'';

2948 }

2949

2950 return false;

2951}

2952

2956 bool IsAssuming) {

2957 bool shouldInvert = false;

2958 std::optional shouldPrune;

2959

2960

2961

2962 bool IsSameFieldName = false;

2965

2966 if (LhsME && RhsME)

2967 IsSameFieldName =

2968 LhsME->getMemberDecl()->getName() == RhsME->getMemberDecl()->getName();

2969

2971 {

2972 llvm::raw_svector_ostream OutLHS(LhsString), OutRHS(RhsString);

2973 const bool isVarLHS = patternMatch(BExpr->getLHS(), BExpr, OutLHS, BRC, R,

2974 N, shouldPrune, IsSameFieldName);

2975 const bool isVarRHS = patternMatch(BExpr->getRHS(), BExpr, OutRHS, BRC, R,

2976 N, shouldPrune, IsSameFieldName);

2977

2978 shouldInvert = !isVarLHS && isVarRHS;

2979 }

2980

2982

2984

2985

2986 return VisitConditionVariable(LhsString, BExpr->getLHS(), BRC, R, N,

2987 TookTrue);

2988 }

2989

2990

2991

2992 if (LhsString.empty() || RhsString.empty() ||

2994 return nullptr;

2995

2996

2998 llvm::raw_svector_ostream Out(buf);

2999 Out << (IsAssuming ? "Assuming " : "")

3000 << (shouldInvert ? RhsString : LhsString) << " is ";

3001

3002

3003 if (shouldInvert)

3004 switch (Op) {

3005 default: break;

3006 case BO_LT: Op = BO_GT; break;

3007 case BO_GT: Op = BO_LT; break;

3008 case BO_LE: Op = BO_GE; break;

3009 case BO_GE: Op = BO_LE; break;

3010 }

3011

3012 if (!TookTrue)

3013 switch (Op) {

3014 case BO_EQ: Op = BO_NE; break;

3015 case BO_NE: Op = BO_EQ; break;

3016 case BO_LT: Op = BO_GE; break;

3017 case BO_GT: Op = BO_LE; break;

3018 case BO_LE: Op = BO_GT; break;

3019 case BO_GE: Op = BO_LT; break;

3020 default:

3021 return nullptr;

3022 }

3023

3024 switch (Op) {

3025 case BO_EQ:

3026 Out << "equal to ";

3027 break;

3028 case BO_NE:

3029 Out << "not equal to ";

3030 break;

3031 default:

3033 break;

3034 }

3035

3036 Out << (shouldInvert ? LhsString : RhsString);

3039

3043

3044

3045 std::string Message = std::string(Out.str());

3046 Message[0] = toupper(Message[0]);

3047

3048

3049 if (!IsAssuming) {

3051 if (!shouldInvert) {

3052 if (LhsME && LhsME->getMemberLoc().isValid())

3054 else

3056 } else {

3057 if (RhsME && RhsME->getMemberLoc().isValid())

3059 else

3061 }

3062

3063 return std::make_shared(Loc, Message);

3064 }

3065

3067 auto event = std::make_shared(Loc, Message);

3068 if (shouldPrune)

3069 event->setPrunable(*shouldPrune);

3070 return event;

3071}

3072

3076

3077

3078

3080 llvm::raw_svector_ostream Out(buf);

3081 Out << "Assuming " << LhsString << " is ";

3082

3083 if (!printValue(CondVarExpr, Out, N, TookTrue, true))

3084 return nullptr;

3085

3088

3091

3092 auto event = std::make_shared(Loc, Out.str());

3093

3095 event->setPrunable(false);

3096

3097 return event;

3098}

3099

3103 bool IsAssuming) {

3104 const auto *VD = dyn_cast(DRE->getDecl());

3105 if (!VD)

3106 return nullptr;

3107

3109 llvm::raw_svector_ostream Out(Buf);

3110

3111 Out << (IsAssuming ? "Assuming '" : "'") << VD->getDeclName() << "' is ";

3112

3113 if (!printValue(DRE, Out, N, TookTrue, IsAssuming))

3114 return nullptr;

3115

3117

3120

3121

3122 if (!IsAssuming) {

3124 return std::make_shared(Loc, Out.str());

3125 }

3126

3128 auto event = std::make_shared(Loc, Out.str());

3129

3131 event->setPrunable(false);

3132

3133 return std::move(event);

3134}

3135

3139 bool IsAssuming) {

3141 llvm::raw_svector_ostream Out(Buf);

3142

3143 Out << (IsAssuming ? "Assuming field '" : "Field '")

3145

3146 if (!printValue(ME, Out, N, TookTrue, IsAssuming))

3147 return nullptr;

3148

3151

3152

3155 else

3157

3159 return nullptr;

3160

3163

3164

3165 if (!IsAssuming)

3166 return std::make_shared(Loc, Out.str());

3167

3168 auto event = std::make_shared(Loc, Out.str());

3170 event->setPrunable(false);

3171 return event;

3172}

3173

3176 bool IsAssuming) {

3178

3180 Out << (TookTrue ? "non-null" : "null");

3181 return true;

3182 }

3183

3185 Out << (TookTrue ? "non-nil" : "nil");

3186 return true;

3187 }

3188

3190 return false;

3191

3192 std::optional<const llvm::APSInt *> IntValue;

3193 if (!IsAssuming)

3195

3196 if (IsAssuming || !IntValue) {

3198 Out << (TookTrue ? "true" : "false");

3199 else

3200 Out << (TookTrue ? "not equal to 0" : "0");

3201 } else {

3203 Out << ((*IntValue)->getBoolValue() ? "true" : "false");

3204 else

3205 Out << **IntValue;

3206 }

3207

3208 return true;

3209}

3210

3211constexpr llvm::StringLiteral ConditionBRVisitor::GenericTrueMessage;

3212constexpr llvm::StringLiteral ConditionBRVisitor::GenericFalseMessage;

3213

3216 return Piece->getString() == GenericTrueMessage ||

3217 Piece->getString() == GenericFalseMessage;

3218}

3219

3220

3221

3222

3223

3227

3228

3231

3233

3234

3235

3236

3237 if (Options.ShouldSuppressFromCXXStandardLibrary) {

3239 return;

3240 } else {

3241

3242

3243

3244

3245

3246

3247 if (const auto *MD = dyn_cast(D)) {

3249 if (CD->getName() == "list") {

3251 return;

3252 }

3253 }

3254

3255

3256

3257 if (const auto *MD = dyn_cast(D)) {

3259 if (CD->getName() == "__independent_bits_engine") {

3261 return;

3262 }

3263 }

3264

3267 const auto *MD = dyn_cast(LCtx->getDecl());

3268 if (!MD)

3269 continue;

3270

3272

3273

3274

3275

3276

3277

3278 if (CD->getName() == "basic_string") {

3280 return;

3281 }

3282

3283

3284

3285

3286 if (CD->getName() == "shared_ptr") {

3288 return;

3289 }

3290 }

3291 }

3292 }

3293

3294

3295

3298 while (Loc.isMacroID()) {

3299 Loc = Loc.getSpellingLoc();

3300 if (SM.getFilename(Loc).ends_with("sys/queue.h")) {

3302 return;

3303 }

3304 }

3305}

3306

3307

3308

3309

3310

3316

3317

3318 std::optional CEnter = ProgLoc.getAs<CallEnter>();

3319 if (!CEnter)

3320 return nullptr;

3321

3322

3325 unsigned Idx = 0;

3327

3328 for (const auto ParamDecl : parms) {

3329 const MemRegion *ArgReg = Call->getArgSVal(Idx).getAsRegion();

3330 ++Idx;

3331

3332

3334 continue;

3335

3336

3337 assert(ParamDecl && "Formal parameter has no decl?");

3338 QualType T = ParamDecl->getType();

3339

3341

3342 continue;

3343 }

3344

3345

3346

3348 continue;

3349

3350

3351

3352 SVal BoundVal = State->getSVal(R);

3355 return nullptr;

3356 }

3357 }

3358 return nullptr;

3359}

3360

3361

3362

3363

3364

3365int NoteTag::Kind = 0;

3366

3368 static int Tag = 0;

3369 ID.AddPointer(&Tag);

3370}

3371

3376 const NoteTag *T = dyn_cast_or_null(PP.getTag());

3377 if (T)

3378 return nullptr;

3379

3380 if (std::optionalstd::string Msg = T->generateMessage(BRC, R)) {

3383 auto Piece = std::make_shared(Loc, *Msg);

3384 Piece->setPrunable(T->isPrunable());

3385 return Piece;

3386 }

3387

3388 return nullptr;

3389}

Defines the clang::ASTContext interface.

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

static bool isInterestingExpr(const Expr *E, const ExplodedNode *N, const PathSensitiveBugReport *B)

static const ExplodedNode * findNodeForExpression(const ExplodedNode *N, const Expr *Inner)

Find the ExplodedNode where the lvalue (the value of 'Ex') was computed.

static void showBRParamDiagnostics(llvm::raw_svector_ostream &OS, StoreInfo SI)

Display diagnostics for passing bad region as a parameter.

static const Expr * peelOffPointerArithmetic(const BinaryOperator *B)

static const Expr * tryExtractInitializerFromList(const InitListExpr *ILE, const MemRegion *R)

static bool wasRegionOfInterestModifiedAt(const SubRegion *RegionOfInterest, const ExplodedNode *N, SVal ValueAfter)

static llvm::StringLiteral WillBeUsedForACondition

static bool isFunctionMacroExpansion(SourceLocation Loc, const SourceManager &SM)

static std::shared_ptr< PathDiagnosticEventPiece > constructDebugPieceForTrackedCondition(const Expr *Cond, const ExplodedNode *N, BugReporterContext &BRC)

static const MemRegion * getLocationRegionIfReference(const Expr *E, const ExplodedNode *N, bool LookingForReference=true)

static bool hasVisibleUpdate(const ExplodedNode *LeftNode, SVal LeftVal, const ExplodedNode *RightNode, SVal RightVal)

Comparing internal representations of symbolic values (via SVal::operator==()) is a valid way to chec...

static bool potentiallyWritesIntoIvar(const Decl *Parent, const ObjCIvarDecl *Ivar)

static std::optional< const llvm::APSInt * > getConcreteIntegerValue(const Expr *CondVarExpr, const ExplodedNode *N)

static bool isVarAnInterestingCondition(const Expr *CondVarExpr, const ExplodedNode *N, const PathSensitiveBugReport *B)

static void showBRDefaultDiagnostics(llvm::raw_svector_ostream &OS, StoreInfo SI)

Show default diagnostics for storing bad region.

static std::optional< SVal > getSValForVar(const Expr *CondVarExpr, const ExplodedNode *N)

static const Expr * peelOffOuterExpr(const Expr *Ex, const ExplodedNode *N)

static const VarDecl * getVarDeclForExpression(const Expr *E)

static bool isTrivialCopyOrMoveCtor(const CXXConstructExpr *CE)

static StringRef getMacroName(SourceLocation Loc, BugReporterContext &BRC)

static bool isObjCPointer(const MemRegion *R)

static bool isAssertlikeBlock(const CFGBlock *B, ASTContext &Context)

static bool isInitializationOfVar(const ExplodedNode *N, const VarRegion *VR)

Returns true if N represents the DeclStmt declaring and initializing VR.

static const ExplodedNode * getMatchingCallExitEnd(const ExplodedNode *N)

static void showBRDiagnostics(llvm::raw_svector_ostream &OS, StoreInfo SI)

Show diagnostics for initializing or declaring a region R with a bad value.

Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....

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

Defines the clang::IdentifierInfo, clang::IdentifierTable, and clang::Selector interfaces.

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.

C Language Family Type Representation.

static bool isPointerToConst(const QualType &QT)

Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...

const LangOptions & getLangOpts() const

CFGStmtMap * getCFGStmtMap()

static bool isInStdNamespace(const Decl *D)

Stores options for the analyzer from the command line.

AnalysisDiagClients AnalysisDiagOpt

A builtin binary operation expression such as "x + y" or "x <= y".

bool isComparisonOp() const

StringRef getOpcodeStr() const

static bool isAdditiveOp(Opcode Opc)

bool isAssignmentOp() const

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

bool isInevitablySinking() const

Returns true if the block would eventually end with a sink (a noreturn node).

succ_iterator succ_begin()

Stmt * getTerminatorStmt()

const Expr * getLastCondition() const

Stmt * getTerminatorCondition(bool StripParens=true)

unsigned succ_size() const

CFGBlock * getBlock(Stmt *S)

Returns the CFGBlock the specified Stmt* appears in.

unsigned size() const

Return the total number of CFGBlocks within the CFG This is simply a renaming of the getNumBlockIDs()...

bool isLinear() const

Returns true if the CFG has no branches.

A boolean literal, per ([C++ lex.bool] Boolean literals).

Represents a call to a C++ constructor.

CXXConstructorDecl * getConstructor() const

Get the constructor that this expression will (ultimately) call.

bool isCopyOrMoveConstructor(unsigned &TypeQuals) const

Determine whether this is a copy or move constructor.

Represents a C++ struct/union/class.

Represents a point when we begin processing an inlined call.

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

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

Represents a character-granular source range.

static CharSourceRange getTokenRange(SourceRange R)

DeclContext * getParent()

getParent - Returns the containing DeclContext.

A reference to a declared variable, function, enum, etc.

DeclStmt - Adaptor class for mixing declarations with statements and expressions.

const Decl * getSingleDecl() const

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

This represents one expression.

Expr * IgnoreParenCasts() LLVM_READONLY

Skip past any parentheses and casts which might surround this expression until reaching a fixed point...

Expr * IgnoreParens() LLVM_READONLY

Skip past any parentheses which might surround this expression until reaching a fixed point.

Expr * IgnoreImpCasts() LLVM_READONLY

Skip past any implicit casts which might surround this expression until reaching a fixed point.

Represents a member of a struct/union/class.

A SourceLocation and its associated SourceManager.

GNUNullExpr - Implements the GNU __null extension, which is a name for a null pointer constant that h...

Describes an C or C++ initializer list.

unsigned getNumInits() const

const Expr * getInit(unsigned Init) const

Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...

static StringRef getSourceText(CharSourceRange Range, const SourceManager &SM, const LangOptions &LangOpts, bool *Invalid=nullptr)

Returns a string for the source that the range encompasses.

static StringRef getImmediateMacroName(SourceLocation Loc, const SourceManager &SM, const LangOptions &LangOpts)

Retrieve the name of the immediate macro expansion.

static CharSourceRange getAsCharRange(SourceRange Range, const SourceManager &SM, const LangOptions &LangOpts)

Given a token range, produce a corresponding CharSourceRange that is not a token range.

static bool isAtStartOfMacroExpansion(SourceLocation loc, const SourceManager &SM, const LangOptions &LangOpts, SourceLocation *MacroBegin=nullptr)

Returns true if the given MacroID location points at the first token of the macro expansion.

static bool isAtEndOfMacroExpansion(SourceLocation loc, const SourceManager &SM, const LangOptions &LangOpts, SourceLocation *MacroEnd=nullptr)

Returns true if the given MacroID location points at the last token of the macro expansion.

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

bool isParentOf(const LocationContext *LC) const

const Decl * getDecl() const

LLVM_ATTRIBUTE_RETURNS_NONNULL AnalysisDeclContext * getAnalysisDeclContext() const

const LocationContext * getParent() const

It might return null.

const StackFrameContext * getStackFrame() const

MemberExpr - [C99 6.5.2.3] Structure and Union Members.

SourceLocation getMemberLoc() const

getMemberLoc - Return the location of the "member", in X->F, it is the location of 'F'.

ValueDecl * getMemberDecl() const

Retrieve the member declaration to which this expression refers.

StringRef getName() const

Get the name of identifier for this declaration as a StringRef.

std::string getNameAsString() const

Get a human-readable name for the declaration, even if it is one of the special kinds of names (C++ c...

ObjCBoolLiteralExpr - Objective-C Boolean Literal.

ObjCIvarDecl - Represents an ObjC instance variable.

ObjCIvarRefExpr - A reference to an ObjC instance variable.

Represents a parameter to a function.

Represents a program point after a store evaluation.

ProgramPoints can be "tagged" as representing points specific to a given analysis entity.

const ProgramPointTag * getTag() const

std::optional< T > getAs() const

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

A (possibly-)qualified type.

bool isNull() const

Return true if this QualType doesn't point to a type yet.

QualType getCanonicalType() const

bool isConstQualified() const

Determine whether this type is const-qualified.

Represents a struct/union/class.

field_range fields() const

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.

Each ExpansionInfo encodes the expansion location - where the token was ultimately expanded,...

bool isFunctionMacroExpansion() const

This is a discriminated union of FileInfo and ExpansionInfo.

const ExpansionInfo & getExpansion() const

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

const Stmt * getCallSite() const

bool inTopFrame() const override

const Stmt * getStmt() const

Stmt - This represents one statement.

SourceLocation getEndLoc() const LLVM_READONLY

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

bool isBooleanType() const

bool isPointerType() const

bool isReferenceType() const

QualType getPointeeType() const

If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.

bool isIntegralOrEnumerationType() const

Determine whether this type is an integral or enumeration type.

bool isObjCObjectPointerType() const

bool isAnyPointerType() const

RecordDecl * getAsRecordDecl() const

Retrieves the RecordDecl this type refers to.

Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...

Represents a variable declaration or definition.

bool isStaticLocal() const

Returns true if a variable with function scope is a static local variable.

bool hasLocalStorage() const

Returns true if a variable with function scope is a non-static local variable.

Maps string IDs to AST nodes matched by parts of a matcher.

AllocaRegion - A region that represents an untyped blob of bytes created by a call to 'alloca'.

StringRef getDescription() const

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

ASTContext & getASTContext() const

ProgramStateManager & getStateManager() const

const SourceManager & getSourceManager() const

const AnalyzerOptions & getAnalyzerOptions() const

BugReporterVisitors are used to add custom diagnostics along a path.

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

Generates the default final diagnostic piece.

virtual PathDiagnosticPieceRef getEndPath(BugReporterContext &BRC, const ExplodedNode *N, PathSensitiveBugReport &BR)

Provide custom definition for the final diagnostic piece on the path - the piece, which is displayed ...

virtual void finalizeVisitor(BugReporterContext &BRC, const ExplodedNode *EndPathNode, PathSensitiveBugReport &BR)

Last function called on the visitor, no further calls to VisitNode would follow.

Represents a call to a C++ constructor.

Manages the lifetime of CallEvent objects.

CallEventRef getCaller(const StackFrameContext *CalleeCtx, ProgramStateRef State)

Gets an outside caller given a callee context.

Represents an abstract call to a function or method along a particular path.

static bool isCallStmt(const Stmt *S)

Returns true if this is a statement is a function or method call of some kind.

PathDiagnosticPieceRef VisitTerminator(const Stmt *Term, const ExplodedNode *N, const CFGBlock *SrcBlk, const CFGBlock *DstBlk, PathSensitiveBugReport &R, BugReporterContext &BRC)

bool printValue(const Expr *CondVarExpr, raw_ostream &Out, const ExplodedNode *N, bool TookTrue, bool IsAssuming)

Tries to print the value of the given expression.

PathDiagnosticPieceRef VisitNode(const ExplodedNode *N, BugReporterContext &BRC, PathSensitiveBugReport &BR) override

Return a diagnostic piece which should be associated with the given node.

bool patternMatch(const Expr *Ex, const Expr *ParentEx, raw_ostream &Out, BugReporterContext &BRC, PathSensitiveBugReport &R, const ExplodedNode *N, std::optional< bool > &prunable, bool IsSameFieldName)

static bool isPieceMessageGeneric(const PathDiagnosticPiece *Piece)

PathDiagnosticPieceRef VisitConditionVariable(StringRef LhsString, const Expr *CondVarExpr, BugReporterContext &BRC, PathSensitiveBugReport &R, const ExplodedNode *N, bool TookTrue)

PathDiagnosticPieceRef VisitTrueTest(const Expr *Cond, BugReporterContext &BRC, PathSensitiveBugReport &R, const ExplodedNode *N, bool TookTrue)

static const char * getTag()

Return the tag associated with this visitor.

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

bool isConstrainedTrue() const

Return true if the constraint is perfectly constrained to 'true'.

bool isValid() const =delete

static bool isInterestingLValueExpr(const Expr *Ex)

Returns true if nodes for the given expression kind are always kept around.

const CFGBlock * getCFGBlock() const

const ProgramStateRef & getState() const

const Stmt * getStmtForDiagnostics() const

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

ProgramPoint getLocation() const

getLocation - Returns the edge associated with the given node.

ExplodedNode * getFirstSucc()

const StackFrameContext * getStackFrame() 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()

unsigned succ_size() const

static std::pair< const ProgramPointTag *, const ProgramPointTag * > getEagerlyAssumeBifurcationTags()

LLVM_ATTRIBUTE_RETURNS_NONNULL const FieldDecl * getDecl() const override

void finalizeVisitor(BugReporterContext &BRC, const ExplodedNode *N, PathSensitiveBugReport &BR) override

Last function called on the visitor, no further calls to VisitNode would follow.

const FieldRegion * getFieldRegion(const FieldDecl *fd, const SubRegion *superRegion)

getFieldRegion - Retrieve or create the memory region associated with a specified FieldDecl.

MemRegion - The root abstract class for all memory regions.

LLVM_ATTRIBUTE_RETURNS_NONNULL const MemSpaceRegion * getMemorySpace() const

virtual bool isBoundable() const

LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * StripCasts(bool StripBaseAndDerivedCasts=true) const

virtual bool isSubRegionOf(const MemRegion *R) const

Check if the region is a subregion of the given region.

virtual void printPretty(raw_ostream &os) const

Print the region for use in diagnostics.

const RegionTy * getAs() const

virtual bool canPrintPretty() const

Returns true if this region can be printed in a user-friendly way.

MemSpaceRegion - A memory region that represents a "memory space"; for example, the set of global var...

PathDiagnosticPieceRef VisitNode(const ExplodedNode *N, BugReporterContext &BRC, PathSensitiveBugReport &BR) override

Return a diagnostic piece which should be associated with the given node.

static const Expr * getNilReceiver(const Stmt *S, const ExplodedNode *N)

If the statement is a message send expression with nil receiver, returns the receiver expression.

virtual bool wasModifiedBeforeCallExit(const ExplodedNode *CurrN, const ExplodedNode *CallExitBeginN)

virtual PathDiagnosticPieceRef maybeEmitNoteForObjCSelf(PathSensitiveBugReport &R, const ObjCMethodCall &Call, const ExplodedNode *N)=0

Consume the information on the non-modifying stack frame in order to either emit a note or not.

virtual PathDiagnosticPieceRef maybeEmitNoteForCXXThis(PathSensitiveBugReport &R, const CXXConstructorCall &Call, const ExplodedNode *N)=0

Consume the information on the non-modifying stack frame in order to either emit a note or not.

bugreporter::TrackingKind TKind

virtual bool wasModifiedInFunction(const ExplodedNode *CallEnterN, const ExplodedNode *CallExitEndN)

PathDiagnosticPieceRef VisitNode(const ExplodedNode *N, BugReporterContext &BR, PathSensitiveBugReport &R) final

Return a diagnostic piece which should be associated with the given node.

virtual PathDiagnosticPieceRef maybeEmitNoteForParameters(PathSensitiveBugReport &R, const CallEvent &Call, const ExplodedNode *N)=0

Consume the information on the non-modifying stack frame in order to either emit a note or not.

Put a diagnostic on return statement of all inlined functions for which the region of interest Region...

The tag upon which the TagVisitor reacts.

Represents any expression that calls an Objective-C method.

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

Create a location for the beginning of the declaration.

FullSourceLoc asLocation() const

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

Create a location corresponding to the given declaration.

bool hasValidLocation() const

StringRef getString() const

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

Marks a symbol as interesting.

PathDiagnosticLocation getLocation() const override

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

ArrayRef< SourceRange > getRanges() const override

Get the SourceRanges associated with the report.

const ExplodedNode * getErrorNode() const

bool addTrackedCondition(const ExplodedNode *Cond)

Notes that the condition of the CFGBlock associated with Cond is being tracked.

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 addVisitor(std::unique_ptr< BugReporterVisitor > visitor)

Add custom or predefined bug report visitors to this report.

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

bool isInteresting(SymbolRef sym) const

SValBuilder & getSValBuilder()

CallEventManager & getCallEventManager()

bool haveEqualConstraints(ProgramStateRef S1, ProgramStateRef S2) const

void iterBindings(ProgramStateRef state, StoreManager::BindingsHandler &F)

StoreManager & getStoreManager()

ProgramState - This class encapsulates:

Loc getLValue(const CXXBaseSpecifier &BaseSpec, const SubRegion *Super) const

Get the lvalue for a base class object reference.

SVal getSVal(const Stmt *S, const LocationContext *LCtx) const

Returns the SVal bound to the statement 'S' in the state's environment.

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

ConditionTruthVal areEqual(ProgramStateRef state, SVal lhs, SVal rhs)

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

bool isZeroConstant() const

std::optional< T > getAs() const

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

const MemRegion * getAsRegion() const

SubRegion - A region that subsets another larger region.

LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * getSuperRegion() const

bool isSubRegionOf(const MemRegion *R) const override

Check if the region is a subregion of the given region.

PathDiagnosticPieceRef VisitNode(const ExplodedNode *Succ, BugReporterContext &BRC, PathSensitiveBugReport &BR) override

Return a diagnostic piece which should be associated with the given node.

SuppressInlineDefensiveChecksVisitor(DefinedSVal Val, const ExplodedNode *N)

static const char * getTag()

Return the tag associated with this visitor.

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

SymbolicRegion - A special, "non-concrete" region.

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

PathDiagnosticPieceRef VisitNode(const ExplodedNode *N, BugReporterContext &BRC, PathSensitiveBugReport &R) override

Return a diagnostic piece which should be associated with the given node.

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

static const char * getTag()

Return the tag associated with this visitor.

PathDiagnosticPieceRef VisitNode(const ExplodedNode *N, BugReporterContext &BRC, PathSensitiveBugReport &BR) override

Return a diagnostic piece which should be associated with the given node.

When a region containing undefined value or '0' value is passed as an argument in a call,...

PathDiagnosticPieceRef VisitNode(const ExplodedNode *N, BugReporterContext &BRC, PathSensitiveBugReport &BR) override

Return a diagnostic piece which should be associated with the given node.

const VarDecl * getDecl() const override=0

Handles expressions during the tracking.

ExpressionHandler(Tracker &ParentTracker)

Handles stores during the tracking.

StoreHandler(Tracker &ParentTracker)

PathDiagnosticPieceRef constructNote(StoreInfo SI, BugReporterContext &BRC, StringRef NodeText)

A generalized component for tracking expressions, values, and stores.

static TrackerRef create(PathSensitiveBugReport &Report)

virtual PathDiagnosticPieceRef handle(StoreInfo SI, BugReporterContext &BRC, TrackingOptions Opts)

Handle the store operation and produce the note.

Tracker(PathSensitiveBugReport &Report)

virtual Result track(const Expr *E, const ExplodedNode *N, TrackingOptions Opts={})

Track expression value back to its point of origin.

Visitor that tracks expressions and values.

Value representing integer constant.

While nonloc::CompoundVal covers a few simple use cases, nonloc::LazyCompoundVal is a more performant...

LLVM_ATTRIBUTE_RETURNS_NONNULL const TypedValueRegion * getRegion() const

This function itself is immaterial.

const internal::VariadicDynCastAllOfMatcher< Stmt, ObjCIvarRefExpr > objcIvarRefExpr

Matches a reference to an ObjCIvar.

const internal::ArgumentAdaptingMatcherFunc< internal::HasDescendantMatcher > hasDescendant

Matches AST nodes that have descendant AST nodes that match the provided matcher.

SmallVector< BoundNodes, 1 > match(MatcherT Matcher, const NodeT &Node, ASTContext &Context)

Returns the results of matching Matcher on Node.

const internal::VariadicDynCastAllOfMatcher< Stmt, BinaryOperator > binaryOperator

Matches binary operator expressions.

internal::Matcher< Stmt > StatementMatcher

static std::string getMacroName(MacroType Macro, GtestCmp Cmp)

internal::PolymorphicMatcher< internal::HasDeclarationMatcher, void(internal::HasDeclarationSupportedTypes), internal::Matcher< Decl > > hasDeclaration(const internal::Matcher< Decl > &InnerMatcher)

Matches a node if the declaration associated with that node matches the given matcher.

const internal::VariadicAllOfMatcher< Stmt > stmt

Matches statements.

const Expr * getDerefExpr(const Stmt *S)

Given that expression S represents a pointer that would be dereferenced, try to find a sub-expression...

bool trackExpressionValue(const ExplodedNode *N, const Expr *E, PathSensitiveBugReport &R, TrackingOptions Opts={})

Attempts to add visitors to track expression value back to its point of origin.

void trackStoredValue(SVal V, const MemRegion *R, PathSensitiveBugReport &Report, TrackingOptions Opts={}, const StackFrameContext *Origin=nullptr)

Track how the value got stored into the given region and where it came from.

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.

@ OS

Indicates that the tracking object is a descendant of a referenced-counted OSObject,...

std::shared_ptr< PathDiagnosticPiece > PathDiagnosticPieceRef

bool Ret(InterpState &S, CodePtr &PC)

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

bool isa(CodeGen::Address addr)

const FunctionProtoType * T

@ ObjCSelf

Parameter for Objective-C 'self' argument.

Describes an event when the value got stored into a memory region.

@ Assignment

The value got stored into the region during assignment: int x; x = 42;.

@ CallArgument

The value got stored into the parameter region as the result of a call.

@ BlockCapture

The value got stored into the region as block capture.

@ Initialization

The value got stored into the region during initialization: int x = 42;.

const Expr * SourceOfTheValue

The expression where the value comes from.

const ExplodedNode * StoreSite

The node where the store happened.

Kind StoreKind

The type of store operation.

SVal Value

Symbolic value that is being stored.

const MemRegion * Dest

Memory regions involved in the store operation.

Describes a tracking result with the most basic information of what was actually done (or not done).

void combineWith(const Result &Other)

Combines the current result with the given result.

bool WasInterrupted

Signifies that the tracking was interrupted at some point.

Defines a set of options altering tracking behavior.

bool EnableNullFPSuppression

Specifies whether we should employ false positive suppression (inlined defensive checks,...

TrackingKind Kind

Specifies the kind of tracking.