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

1

2

3

4

5

6

7

8

9

10

11

12

13

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

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

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

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

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

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

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

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

55#include

56#include

57#include

58#include

59#include

60#include

61

62using namespace clang;

63using namespace ento;

65

66

67

68

69

76 }

77 }

78 return nullptr;

79}

80

81

82

84

85

86

87

88

89

90

91

92

93

94

95

96

98 const auto *E = dyn_cast(S);

99 if (!E)

100 return nullptr;

101

102 while (true) {

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

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

105

106 break;

107 }

108 E = CE->getSubExpr();

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

110

112 E = Inner;

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

114

115 E = B->getLHS();

116 } else {

117

118

119 break;

120 }

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

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

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

124

125

126 E = U->getSubExpr();

127 } else {

128

129

130 break;

131 }

132 }

133

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

135

136

137

138

139

140

141

142

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

144 break;

145 E = ME->getBase();

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

147 E = IvarRef->getBase();

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

149 E = AE->getBase();

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

151 E = PE->getSubExpr();

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

153 E = FE->getSubExpr();

154 } else {

155

156 break;

157 }

158 }

159

160

161

162

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

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

165 E = CE->getSubExpr();

166

167 return E;

168}

169

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

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

173 return nullptr;

174}

175

178 bool LookingForReference = true) {

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

180

181

182

183

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

186 if (!VD)

187 return nullptr;

188

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

190 if (!FD)

191 return nullptr;

192

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

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

196 }

197 return nullptr;

198 }

199

201 if (!VD)

202 return nullptr;

204 return nullptr;

206}

207

208

209

210

211

212

213

214

215

218 if (LeftVal == RightVal)

219 return true;

220

222 if (!LLCV)

223 return false;

224

226 if (!RLCV)

227 return false;

228

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

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

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

232}

233

238

239 assert(CondVarExpr);

241

242

243

244

245

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

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

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

249

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

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

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

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

254

255 return std::nullopt;

256}

257

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

260

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

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

264 return std::nullopt;

265}

266

270

271

272

274 return false;

275

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

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

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

280

281 return false;

282}

283

290

291

299

300

301

304 if (Loc.isMacroID())

305 return false;

306 while (SM.isMacroArgExpansion(Loc))

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

312}

313

314

315

316

319 SVal ValueAfter) {

322

325 return false;

326

327

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

332 return true;

333

334

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

337 .areEqual(State, ValueAtN, ValueAfter)

340 return true;

341

342 return false;

343}

344

345

346

347

348

354

358

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

365

366

367

368 auto P = std::make_shared(

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

371 P->addRange(Range);

372

373 return P;

374}

375

376

377

378

379

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

383 if (!FramesModifyingCalculated.count(SCtx))

384 findModifyingFrames(N);

385 return FramesModifying.count(SCtx);

386}

387

388void NoStateChangeFuncVisitor::markFrameAsModifying(

391 auto p = FramesModifying.insert(SCtx);

392 if (!p.second)

393 break;

394

396 }

397}

398

401

402

404

405

406

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

410 };

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

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

415 }

416 return N;

417}

418

419void NoStateChangeFuncVisitor::findModifyingFrames(

421

422 assert(CallExitBeginN->getLocationAs());

423

424 const StackFrameContext *const OriginalSCtx =

426

427 const ExplodedNode *CurrCallExitBeginN = CallExitBeginN;

428 const StackFrameContext *CurrentSCtx = OriginalSCtx;

429

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

431 CurrN = CurrN->getFirstPred()) {

432

433 if (CurrN->getLocationAs()) {

434 CurrCallExitBeginN = CurrN;

436 FramesModifyingCalculated.insert(CurrentSCtx);

437

438 continue;

439 }

440

441 if (auto CE = CurrN->getLocationAs()) {

444 markFrameAsModifying(CurrentSCtx);

445

446

448

449

450

451

452

453

454

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

456 markFrameAsModifying(CurrentSCtx);

457 break;

458 }

459 }

460

462 markFrameAsModifying(CurrentSCtx);

463 }

464}

465

468

473

474

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

476 return nullptr;

477

480

481

482

483

484

485

486

487

488

489

490 if (Call->isInSystemHeader()) {

491

492

493

494

495

496

497

499 static int i = 0;

501 }

502 return nullptr;

503 }

504

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

506

507

509 return Piece;

510 }

511

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

513

514

516 }

517

519}

520

521

522

526 const char *IvarBind = "Ivar";

527 if (!Parent || !Parent->hasBody())

528 return false;

530 hasOperatorName("="),

531 hasLHS(ignoringParenImpCasts(

537 if (IvarRef->isFreeIvar())

538 return true;

539

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

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

542 Base = ICE->getSubExpr();

543

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

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

547 return true;

548

549 return false;

550 }

551 return false;

552}

553

554

555

556

557

558

559

560const std::optionalNoStoreFuncVisitor::RegionVector

561NoStoreFuncVisitor::findRegionOfInterestInRecord(

563 const NoStoreFuncVisitor::RegionVector &Vec ,

564 int depth ) {

565

566 if (depth == DEREFERENCE_LIMIT)

567 return std::nullopt;

568

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

570 if (!RDX->hasDefinition())

571 return std::nullopt;

572

573

574

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

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

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

578 if (std::optional Out =

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

580 return Out;

581

582 for (const FieldDecl *I : RD->fields()) {

583 QualType FT = I->getType();

584 const FieldRegion *FR = MmrMgr.getFieldRegion(I, cast(R));

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

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

587

588 RegionVector VecF = Vec;

589 VecF.push_back(FR);

590

591 if (RegionOfInterest == VR)

592 return VecF;

593

595 if (auto Out =

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

597 return Out;

598

601 continue;

602

604 if (std::optional Out =

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

606 return Out;

607 }

608

609 return std::nullopt;

610}

611

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

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

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

620 IvarR->getDecl()))

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

622 false, 1);

623 }

624 return nullptr;

625}

626

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

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

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

634 false, 1);

635

636

637

638 return nullptr;

639}

640

641

646

649 ArrayRef<ParmVarDecl *> Parameters = Call.parameters();

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

651 const ParmVarDecl *PVD = Parameters[I];

652 SVal V = Call.getArgSVal(I);

655

656 unsigned IndirectionLevel = 1;

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

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

661 ParamIsReferenceType, IndirectionLevel);

662

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

665 break;

666

668

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

670 if (std::optional P =

671 findRegionOfInterestInRecord(RD, State, MR))

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

673 ParamIsReferenceType, IndirectionLevel);

674

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

676 T = PT;

677 IndirectionLevel++;

678 }

679 }

680

681 return nullptr;

682}

683

684bool NoStoreFuncVisitor::wasModifiedBeforeCallExit(

686 return ::wasRegionOfInterestModifiedAt(

687 RegionOfInterest, CurrN,

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

689}

690

692 ", which participates in a condition later";

693

696 const RegionVector &FieldChain, const MemRegion *MatchedRegion,

697 StringRef FirstElement, bool FirstIsReferenceType,

698 unsigned IndirectionLevel) {

699

702

703

704

705

707 return nullptr;

708

710 llvm::raw_svector_ostream os(sbuf);

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

712

713

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

715 FirstIsReferenceType, IndirectionLevel, os))

716 return nullptr;

717

718 os << "'";

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

722}

723

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

726 StringRef FirstElement,

727 bool FirstIsReferenceType,

728 unsigned IndirectionLevel,

729 llvm::raw_svector_ostream &os) {

730

731 if (FirstIsReferenceType)

732 IndirectionLevel--;

733

734 RegionVector RegionSequence;

735

736

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

738 const MemRegion *R = RegionOfInterest;

739 while (R != MatchedRegion) {

740 RegionSequence.push_back(R);

742 }

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

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

745

746 StringRef Sep;

747 for (const MemRegion *R : RegionSequence) {

748

749

750

752 continue;

753

754 if (Sep.empty())

755 Sep = prettyPrintFirstElement(FirstElement,

756 true,

757 IndirectionLevel, os);

758

759 os << Sep;

760

761

763 return false;

764

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

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

768 }

769

770 if (Sep.empty())

771 prettyPrintFirstElement(FirstElement,

772 false, IndirectionLevel, os);

773 return true;

774}

775

776StringRef NoStoreFuncVisitor::prettyPrintFirstElement(

777 StringRef FirstElement, bool MoreItemsExpected, int IndirectionLevel,

778 llvm::raw_svector_ostream &os) {

779 StringRef Out = ".";

780

781 if (IndirectionLevel > 0 && MoreItemsExpected) {

782 IndirectionLevel--;

783 Out = "->";

784 }

785

786 if (IndirectionLevel > 0 && MoreItemsExpected)

787 os << "(";

788

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

790 os << "*";

791 os << FirstElement;

792

793 if (IndirectionLevel > 0 && MoreItemsExpected)

794 os << ")";

795

796 return Out;

797}

798

799

800

801

802

803namespace {

804

805

806

807class MacroNullReturnSuppressionVisitor final : public BugReporterVisitor {

808 const SubRegion *RegionOfInterest;

809 const SVal ValueAtDereference;

810

811

812

813 bool WasModified = false;

814

815public:

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

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

818

820 BugReporterContext &BRC,

821 PathSensitiveBugReport &BR) override {

822 if (WasModified)

823 return nullptr;

824

826 if (!BugPoint)

827 return nullptr;

828

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

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

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

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

836 }

837 }

838

840 WasModified = true;

841

842 return nullptr;

843 }

844

845 static void addMacroVisitorIfNecessary(

846 const ExplodedNode *N, const MemRegion *R,

847 bool EnableNullFPSuppression, PathSensitiveBugReport &BR,

848 const SVal V) {

849 AnalyzerOptions &Options = N->getState()->getAnalysisManager().options;

850 if (EnableNullFPSuppression && Options.ShouldSuppressNullReturnPaths &&

852 BR.addVisitor(R->getAs(),

853 V);

854 }

855

856 void* getTag() const {

857 static int Tag = 0;

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

859 }

860

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

862 ID.AddPointer(getTag());

863 }

864

865private:

866

867

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

872 if (!S)

873 return std::nullopt;

874

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

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

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

878 if (RegionOfInterest->isSubRegionOf(

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

880 return RHS->getBeginLoc();

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

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

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

886 }

887 }

888 return std::nullopt;

889 }

890};

891

892}

893

894namespace {

895

896

897

898

899

900

901

902

903class ReturnVisitor : public TrackingBugReporterVisitor {

904 const StackFrameContext *CalleeSFC;

905 enum {

906 Initial,

907 MaybeUnsuppress,

908 Satisfied

909 } Mode = Initial;

910

911 bool EnableNullFPSuppression;

912 bool ShouldInvalidate = true;

913 AnalyzerOptions& Options;

915

916public:

917 ReturnVisitor(TrackerRef ParentTracker, const StackFrameContext *Frame,

918 bool Suppressed, AnalyzerOptions &Options,

920 : TrackingBugReporterVisitor(ParentTracker), CalleeSFC(Frame),

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

922

923 static void *getTag() {

924 static int Tag = 0;

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

926 }

927

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

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

930 ID.AddPointer(CalleeSFC);

931 ID.AddBoolean(EnableNullFPSuppression);

932 }

933

935 BugReporterContext &BRC,

936 PathSensitiveBugReport &BR) {

937

939 return nullptr;

940

941 std::optional SP = N->getLocationAs();

942 if (!SP)

943 return nullptr;

944

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

946 if (!Ret)

947 return nullptr;

948

949

950

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

953 if (V.isUnknownOrUndef())

954 return nullptr;

955

956

957 Mode = Satisfied;

958

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

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

961

962

963 std::optional LValue;

965 if ((LValue = V.getAs())) {

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

968 V = RValue;

969 }

970 }

971

972

974 return nullptr;

975

977

978

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

980

981

982 SmallString<64> Msg;

983 llvm::raw_svector_ostream Out(Msg);

984

985 bool WouldEventBeMeaningless = false;

986

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

989

990

991

992

993 if (EnableNullFPSuppression &&

994 Options.ShouldAvoidSuppressingNullArgumentPaths)

995 Mode = MaybeUnsuppress;

996

998 Out << "Returning nil";

999 } else {

1000 Out << "Returning null pointer";

1001 }

1002 } else {

1003 Out << "Returning zero";

1004 }

1005

1006 } else {

1007 if (auto CI = V.getAsnonloc::ConcreteInt()) {

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

1009 } else {

1010

1011

1012

1013

1014

1016 WouldEventBeMeaningless = true;

1017

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

1019 }

1020 }

1021

1022 if (LValue) {

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

1024 if (MR->canPrintPretty()) {

1025 Out << " (reference to ";

1026 MR->printPretty(Out);

1027 Out << ")";

1028 }

1029 }

1030 } else {

1031

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

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

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

1035 }

1036

1037 PathDiagnosticLocation L(Ret, BRC.getSourceManager(), CalleeSFC);

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

1039 return nullptr;

1040

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

1043

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

1045

1046

1047

1048 if (WouldEventBeMeaningless)

1049 EventPiece->setPrunable(true);

1050 else

1052

1053 return EventPiece;

1054 }

1055

1057 BugReporterContext &BRC,

1058 PathSensitiveBugReport &BR) {

1059 assert(Options.ShouldAvoidSuppressingNullArgumentPaths);

1060

1061

1062 std::optional CE = N->getLocationAs();

1063 if (!CE)

1064 return nullptr;

1065

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

1067 return nullptr;

1068

1069 Mode = Satisfied;

1070

1071

1072

1073

1076

1078 CallEventRef<> Call = CallMgr.getCaller(CalleeSFC, State);

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

1080 std::optional ArgV = Call->getArgSVal(I).getAs();

1081 if (!ArgV)

1082 continue;

1083

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

1085 if (!ArgE)

1086 continue;

1087

1088

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

1090 continue;

1091

1092 if (getParentTracker()

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

1094 .FoundSomethingToTrack)

1095 ShouldInvalidate = false;

1096

1097

1098

1099

1100 }

1101

1102 return nullptr;

1103 }

1104

1106 BugReporterContext &BRC,

1107 PathSensitiveBugReport &BR) override {

1108 switch (Mode) {

1109 case Initial:

1110 return visitNodeInitial(N, BRC, BR);

1111 case MaybeUnsuppress:

1112 return visitNodeMaybeUnsuppress(N, BRC, BR);

1113 case Satisfied:

1114 return nullptr;

1115 }

1116

1117 llvm_unreachable("Invalid visit mode!");

1118 }

1119

1120 void finalizeVisitor(BugReporterContext &, const ExplodedNode *,

1121 PathSensitiveBugReport &BR) override {

1122 if (EnableNullFPSuppression && ShouldInvalidate)

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

1124 }

1125};

1126

1127

1128

1129

1130

1131

1132

1133class StoreSiteFinder final : public TrackingBugReporterVisitor {

1134 const MemRegion *R;

1135 SVal V;

1136 bool Satisfied = false;

1137

1138 TrackingOptions Options;

1139 const StackFrameContext *OriginSFC;

1140

1141public:

1142

1143

1144

1145

1146

1147

1148

1149

1150

1151

1153 const MemRegion *R, TrackingOptions Options,

1154 const StackFrameContext *OriginSFC = nullptr)

1155 : TrackingBugReporterVisitor(ParentTracker), R(R), V(V), Options(Options),

1156 OriginSFC(OriginSFC) {

1157 assert(R);

1158 }

1159

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

1161

1163 BugReporterContext &BRC,

1164 PathSensitiveBugReport &BR) override;

1165};

1166}

1167

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

1169 static int tag = 0;

1170 ID.AddPointer(&tag);

1171 ID.AddPointer(R);

1172 ID.Add(V);

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

1174 ID.AddBoolean(Options.EnableNullFPSuppression);

1175}

1176

1177

1178

1181 if (!P)

1182 return false;

1183

1185 if (!DS)

1186 return false;

1187

1189 return false;

1190

1191 const auto *FrameSpace =

1193

1194 if (!FrameSpace) {

1195

1196

1197

1198 [[maybe_unused]] bool IsLocalStaticOrLocalExtern =

1200 assert(IsLocalStaticOrLocalExtern &&

1201 "Declared a variable on the stack without Stack memspace?");

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

1221

1222namespace {

1223using DestTypeValue = std::pair<const StoreInfo &, loc::ConcreteInt>;

1224

1225llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const DestTypeValue &Val) {

1226 if (auto *TyR = Val.first.Dest->getAs<TypedRegion>()) {

1227 QualType LocTy = TyR->getLocationType();

1228 if (!LocTy.isNull()) {

1229 if (auto *PtrTy = LocTy->getAs()) {

1230 std::string PStr = PtrTy->getPointeeType().getAsString();

1231 if (!PStr.empty())

1232 OS << "(" << PStr << ")";

1233 }

1234 }

1235 }

1236 SmallString<16> ValStr;

1237 Val.second.getValue()->toString(ValStr, 10, true);

1238 OS << ValStr;

1239 return OS;

1240}

1241}

1242

1243

1246

1247 if (HasPrefix) {

1249 OS << " ";

1250 }

1251

1252 const char *Action = nullptr;

1253

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

1257 break;

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

1260 break;

1261 default:

1262 llvm_unreachable("Unexpected store kind");

1263 }

1264

1266 if (!*CVal->getValue())

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

1268 else

1269 OS << Action << DestTypeValue(SI, *CVal);

1270

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

1273

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

1277

1279

1280

1281

1282 const auto *DS =

1284

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

1288

1289 if (VD->getInit()) {

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

1291 << " to a garbage value";

1292 } else {

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

1294 << " without an initial value";

1295 }

1296 }

1297 } else {

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

1299 }

1300 }

1301}

1302

1303

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

1308

1309 OS << "Passing ";

1310

1312 if (!*CI->getValue())

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

1314 else

1315 OS << (isObjCPointer(D) ? "object reference of value " : "pointer value ")

1316 << DestTypeValue(SI, *CI);

1317

1319 OS << "uninitialized value";

1320

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

1323

1326

1327 } else {

1328 OS << "value";

1329 }

1330

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

1332

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

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

1336 OS << " ";

1338 }

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

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

1342 }

1343 }

1344}

1345

1346

1350

1353 if (!*V)

1355 ? "nil object reference stored"

1356 : (HasSuffix ? "Null pointer value stored"

1357 : "Storing null pointer value"));

1358 else {

1360 OS << "object reference of value " << DestTypeValue(SI, *CV)

1361 << " stored";

1362 } else {

1363 if (HasSuffix)

1364 OS << "Pointer value of " << DestTypeValue(SI, *CV) << " stored";

1365 else

1366 OS << "Storing pointer value of " << DestTypeValue(SI, *CV);

1367 }

1368 }

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

1371 : "Storing uninitialized value");

1372

1374 if (HasSuffix)

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

1376 else

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

1378

1380 if (HasSuffix) {

1381 OS << "The value of ";

1383 OS << " is assigned";

1384 } else {

1385 OS << "Assigning the value of ";

1387 }

1388

1389 } else {

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

1391 }

1392

1393 if (HasSuffix) {

1394 OS << " to ";

1396 }

1397}

1398

1400 if (!CE)

1401 return false;

1402

1404

1406}

1407

1410

1411 const auto *TVR = dyn_cast_or_null(R);

1412

1413 if (!TVR)

1414 return nullptr;

1415

1417

1418

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

1421

1422

1423

1424

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

1426 break;

1427

1428 TVRStack.push(TVR);

1430 }

1431

1432

1433

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

1435 return nullptr;

1436

1438 while (!TVRStack.empty()) {

1439 TVR = TVRStack.top();

1440 TVRStack.pop();

1441

1442

1443

1445 return nullptr;

1446

1449

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

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

1452

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

1454 return nullptr;

1455

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

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

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

1459

1460

1461

1462 if (!Ind.isConstant())

1463 return nullptr;

1464

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

1466 if (IndVal >= NumInits)

1467 return nullptr;

1468

1470 }

1471 }

1472

1473 return Init;

1474}

1475

1479 if (Satisfied)

1480 return nullptr;

1481

1484 const Expr *InitE = nullptr;

1485 bool IsParam = false;

1486

1487

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

1490 StoreSite = Pred;

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

1492 }

1493 }

1494

1495

1496

1497 if (std::optional PIP =

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

1500 if (FieldReg == R) {

1501 StoreSite = Pred;

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

1503 }

1504 }

1505

1506

1507

1508

1509

1510

1511 if (!StoreSite) {

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

1513 return nullptr;

1514

1516 std::optional PS = Succ->getLocationAs();

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

1518 return nullptr;

1519 }

1520

1521 StoreSite = Succ;

1522

1523 if (std::optional P = Succ->getLocationAs()) {

1524

1525

1526 if (const BinaryOperator *BO = P->getStmtAs()) {

1527 if (BO->isAssignmentOp())

1528 InitE = BO->getRHS();

1529 }

1530

1531

1532 else if (const auto *DS = P->getStmtAs()) {

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

1536

1537

1538

1539

1540

1541

1542

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

1545 }

1546 } else if (const auto *CE = P->getStmtAs()) {

1547

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

1549

1551

1552

1553

1554

1555

1556

1557

1558

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

1562 SRStack.push(SR);

1564 }

1565

1566

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

1568 const auto OriginVal =

1570

1571

1572

1573

1574 SVal OriginField = OriginVal;

1575 while (!SRStack.empty()) {

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

1577 SRStack.pop();

1578

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

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

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

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

1583 ER->getIndex(), OriginField);

1584 } else {

1585

1586 }

1587 }

1588

1589

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

1591 InitE = OriginEx;

1592 }

1593 }

1594

1595 else if (const auto *ILE = P->getStmtAs()) {

1596

1597

1598

1599

1600

1601

1603 }

1604 }

1605

1606

1607

1608

1609

1610 if (std::optional CE = Succ->getLocationAs()) {

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

1612

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

1616

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

1620 } else {

1621

1624 ->getInstanceReceiver()->IgnoreParenCasts();

1625 }

1626 IsParam = true;

1627 }

1628 }

1629

1630

1631

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

1633 InitE = TmpR->getExpr();

1634 }

1635

1636 if (!StoreSite)

1637 return nullptr;

1638

1639 Satisfied = true;

1640

1641

1642

1643 if (InitE) {

1644 if (!IsParam)

1646

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

1648 }

1649

1650

1651 const MemRegion *OldRegion = nullptr;

1652

1653

1654

1655 if (InitE) {

1656

1657

1658

1659

1660

1661

1662

1663

1664 if (const MemRegion *Candidate =

1667

1668

1669

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

1672

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

1674 OldRegion = Candidate;

1675 }

1676 break;

1677 }

1678 }

1679 }

1680 }

1681

1682

1683

1684

1685

1686

1687

1688

1689

1690

1691

1692

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

1694

1695

1697 for (;

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

1699 NodeWithoutBinding = NodeWithoutBinding->getFirstPred()) {

1700 }

1701

1702 if (NodeWithoutBinding) {

1703

1704

1705

1706

1707

1708

1709

1710

1713 if (FB)

1714 OldRegion = FB.getRegion();

1715 }

1716 }

1717

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

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

1720 return nullptr;

1721

1722

1723 SmallString<256> sbuf;

1724 llvm::raw_svector_ostream os(sbuf);

1725

1727 StoreSite,

1728 InitE,

1729 V,

1730 R,

1731 OldRegion};

1732

1733 if (std::optional PS = StoreSite->getLocationAs()) {

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

1735 const auto *DS = dyn_cast(S);

1736 const auto *VR = dyn_cast(R);

1737

1738 if (DS) {

1742 if (VR) {

1743

1746 if (const auto *BDR =

1747 dyn_cast_or_null(V.getAsRegion())) {

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

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

1750 Options, OriginSFC);

1751 }

1752 }

1753 }

1754 }

1758 }

1759

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

1761}

1762

1763

1764

1765

1766

1768 static int tag = 0;

1769 ID.AddPointer(&tag);

1770 ID.AddString(Message);

1771 ID.AddBoolean(Assumption);

1772 ID.Add(Constraint);

1773}

1774

1775

1776

1778 return "TrackConstraintBRVisitor";

1779}

1780

1781bool TrackConstraintBRVisitor::isZeroCheck() const {

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

1783}

1784

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

1786 if (isZeroCheck())

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

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

1789}

1790

1794 if (IsSatisfied)

1795 return nullptr;

1796

1797

1798

1799 if (!IsTrackingTurnedOn)

1800 if (!isUnderconstrained(N))

1801 IsTrackingTurnedOn = true;

1802 if (!IsTrackingTurnedOn)

1803 return nullptr;

1804

1805

1806

1807 if (isUnderconstrained(PrevN)) {

1808 IsSatisfied = true;

1809

1810

1811

1812

1813

1814 assert(!isUnderconstrained(N));

1815

1816

1818

1819

1820

1821

1822 if (isa_and_nonnull(P.getTag()))

1823 return nullptr;

1824

1828 return nullptr;

1829

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

1832 return std::move(X);

1833 }

1834

1835 return nullptr;

1836}

1837

1838

1839

1840

1841

1845

1847 if (!Options.ShouldSuppressInlinedDefensiveChecks)

1848 IsSatisfied = true;

1849}

1850

1852 llvm::FoldingSetNodeID &ID) const {

1853 static int id = 0;

1854 ID.AddPointer(&id);

1855 ID.Add(V);

1856}

1857

1859 return "IDCVisitor";

1860}

1861

1867 if (IsSatisfied)

1868 return nullptr;

1869

1870

1871 if (!IsTrackingTurnedOn)

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

1873 IsTrackingTurnedOn = true;

1874 if (!IsTrackingTurnedOn)

1875 return nullptr;

1876

1877

1878

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

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

1881 IsSatisfied = true;

1882

1883

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

1888 return nullptr;

1889 }

1890

1891

1892

1893

1894

1896

1897 if (!BugPoint)

1898 return nullptr;

1899

1901 const Stmt *CurTerminatorStmt = nullptr;

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

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

1907 return nullptr;

1908

1911 } else {

1912 return nullptr;

1913 }

1914

1915 if (!CurTerminatorStmt)

1916 return nullptr;

1917

1919 if (TerminatorLoc.isMacroID()) {

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

1921

1922

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

1926 }

1927 return nullptr;

1928 }

1929 }

1930 return nullptr;

1931}

1932

1933

1934

1935

1936

1937namespace {

1938

1939

1940

1941

1942

1943

1944

1945

1946

1947

1948

1949class TrackControlDependencyCondBRVisitor final

1954

1955public:

1956 TrackControlDependencyCondBRVisitor(TrackerRef ParentTracker,

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

1960

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

1962 static int x = 0;

1963 ID.AddPointer(&x);

1964 }

1965

1969};

1970}

1971

1972static std::shared_ptr

1976

1979 return nullptr;

1980

1984

1985 return std::make_shared(

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

1989}

1990

1993 return false;

1994

1997

1998 if (!Then || !Else)

1999 return false;

2000

2002 return true;

2003

2004

2005

2006

2007

2008

2009

2010

2011

2012

2013

2014

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

2017 if (BinOp->isLogicalOp())

2019

2020 return false;

2021}

2022

2024TrackControlDependencyCondBRVisitor::VisitNode(const ExplodedNode *N,

2027

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

2029 return nullptr;

2030

2031 CFGBlock *NB = const_cast<CFGBlock *>(N->getCFGBlock());

2032

2033

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

2035 return nullptr;

2036

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

2038

2039

2040 if (!OriginB || !NB)

2041 return nullptr;

2042

2044 return nullptr;

2045

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

2047

2048

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

2050 return nullptr;

2051

2053

2054

2056 if (!InnerExpr)

2057 return nullptr;

2058

2059

2060

2061

2062

2063

2064

2065

2066

2067

2068

2069

2070

2071

2073 return nullptr;

2074

2075

2076

2077

2079 getParentTracker().track(InnerExpr, N,

2081 false});

2083 }

2084 }

2085 }

2086

2087 return nullptr;

2088}

2089

2090

2091

2092

2093

2095

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

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

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

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

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

2104 const Expr *GetterMessageSend =

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

2108 }

2109 }

2110

2111

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

2113

2114

2116 do {

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

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

2121 if (term == CO) {

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

2123 if (TookTrueBranch)

2125 else

2127 }

2128 }

2129 }

2131 } while (NI);

2132 }

2133

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

2137

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

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

2141

2142

2143

2144

2145

2146

2147

2148

2149

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

2153 }

2154

2155 return Ex;

2156}

2157

2158

2159

2161 const Expr *Inner) {

2162 while (N) {

2164 return N;

2166 }

2167 return N;

2168}

2169

2170

2171

2172

2173

2176 StringRef NodeText) {

2177

2183

2186

2188 return nullptr;

2189

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

2191}

2192

2193namespace {

2194class DefaultStoreHandler final : public StoreHandler {

2195public:

2197

2200

2202 llvm::raw_svector_ostream OS(Buffer);

2203

2208 break;

2211 break;

2214 break;

2215 }

2216

2219

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

2221 }

2222};

2223

2224class ControlDependencyHandler final : public ExpressionHandler {

2225public:

2227

2232

2233

2234

2235

2236

2237

2238

2240 ->getAnalysisManager()

2241 .getAnalyzerOptions()

2242 .ShouldTrackConditions) {

2243 Report.addVisitor(

2244 &getParentTracker(), InputNode);

2245 return {true};

2246 }

2247

2248 return {};

2249 }

2250};

2251

2252class NilReceiverHandler final : public ExpressionHandler {

2253public:

2255

2256 Tracker::Result handle(const Expr *Inner, const ExplodedNode *InputNode,

2257 const ExplodedNode *LVNode,

2258 TrackingOptions Opts) override {

2259

2260

2261

2262 if (const Expr *Receiver =

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

2265

2266 return {};

2267 }

2268};

2269

2270class ArrayIndexHandler final : public ExpressionHandler {

2271public:

2273

2274 Tracker::Result handle(const Expr *Inner, const ExplodedNode *InputNode,

2275 const ExplodedNode *LVNode,

2276 TrackingOptions Opts) override {

2277

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

2279 return getParentTracker().track(

2280 Arr->getIdx(), LVNode,

2281 {Opts.Kind, false});

2282

2283 return {};

2284 }

2285};

2286

2287

2288class InterestingLValueHandler final : public ExpressionHandler {

2289public:

2291

2292 Tracker::Result handle(const Expr *Inner, const ExplodedNode *InputNode,

2293 const ExplodedNode *LVNode,

2294 TrackingOptions Opts) override {

2296 const StackFrameContext *SFC = LVNode->getStackFrame();

2297 PathSensitiveBugReport &Report = getParentTracker().getReport();

2298 Tracker::Result Result;

2299

2300

2301

2303 SVal LVal = LVNode->getSVal(Inner);

2304

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

2307

2308

2309

2310

2311 if (RR && !LVIsNull)

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

2313

2314

2315

2316

2317

2318 const MemRegion *R =

2319 (RR && LVIsNull) ? RR : LVNode->getSVal(Inner).getAsRegion();

2320

2321 if (R) {

2322

2323

2324 SVal V = LVState->getRawSVal(loc::MemRegionVal(R));

2326

2327

2328

2329 Result.FoundSomethingToTrack = true;

2330 Result.WasInterrupted = true;

2331

2332 MacroNullReturnSuppressionVisitor::addMacroVisitorIfNecessary(

2334

2336 Report.addVisitor(R);

2337

2338

2339

2340 if (V.getAsLocSymbol(true))

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

2342 Report.addVisitor(

2343 V.castAs(),

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

2345

2346

2347 if (auto DV = V.getAs())

2349

2350

2351

2352

2353

2354

2355 Report.addVisitor(*DV,

2356 InputNode);

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

2358 }

2359 }

2360

2362 }

2363};

2364

2365

2366

2367

2368

2369

2370

2371

2372class InlinedFunctionCallHandler final : public ExpressionHandler {

2374

2375 Tracker::Result handle(const Expr *E, const ExplodedNode *InputNode,

2376 const ExplodedNode *ExprNode,

2377 TrackingOptions Opts) override {

2379 return {};

2380

2381

2382

2383

2384

2386

2387

2388 const StackFrameContext *CurrentSFC = ExprNode->getStackFrame();

2389

2390 do {

2391

2392 if (std::optional CEE =

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

2395 break;

2396

2397

2399 if (!ExprNode)

2400 break;

2401

2402 const StackFrameContext *PredSFC = ExprNode->getStackFrame();

2403

2404

2405

2406

2407 if (!BypassCXXNewExprEval)

2408 if (std::optional SP = ExprNode->getLocationAs())

2409

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

2411 break;

2412

2413 CurrentSFC = PredSFC;

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

2415

2416

2417 while (ExprNode && ExprNode->getLocation().getAs())

2419 if (!ExprNode)

2420 return {};

2421

2422

2423 std::optional CEE = ExprNode->getLocationAs();

2424 if (!CEE)

2425 return {};

2426

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

2429 return {};

2430

2431

2433 SVal RetVal = ExprNode->getSVal(E);

2434

2435

2437 if (std::optional LValue = RetVal.getAs())

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

2439

2440

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

2442

2443 bool EnableNullFPSuppression = false;

2445 if (std::optional RetLoc = RetVal.getAs())

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

2447

2448 PathSensitiveBugReport &Report = getParentTracker().getReport();

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

2450 EnableNullFPSuppression, Options,

2452 return {true};

2453 }

2454};

2455

2456class DefaultExpressionHandler final : public ExpressionHandler {

2457public:

2459

2460 Tracker::Result handle(const Expr *Inner, const ExplodedNode *InputNode,

2461 const ExplodedNode *LVNode,

2462 TrackingOptions Opts) override {

2464 const StackFrameContext *SFC = LVNode->getStackFrame();

2465 PathSensitiveBugReport &Report = getParentTracker().getReport();

2466 Tracker::Result Result;

2467

2468

2469

2470 SVal V = LVState->getSValAsScalarOrLoc(Inner, LVNode->getLocationContext());

2471

2472

2473 if (auto L = V.getAsloc::MemRegionVal()) {

2474

2475

2476

2477

2478 bool CanDereference = true;

2479 if (const auto *SR = L->getRegionAs()) {

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

2481 CanDereference = false;

2482 } else if (L->getRegionAs())

2483 CanDereference = false;

2484

2485

2486

2487

2488 SVal RVal;

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

2491 else if (CanDereference)

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

2493

2494 if (CanDereference) {

2495 Report.addVisitor(L->getRegion());

2496 Result.FoundSomethingToTrack = true;

2497

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

2501 }

2502

2503 const MemRegion *RegionRVal = RVal.getAsRegion();

2504 if (isa_and_nonnull(RegionRVal)) {

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

2506 Report.addVisitor(

2507 loc::MemRegionVal(RegionRVal),

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

2509 Result.FoundSomethingToTrack = true;

2510 }

2511 }

2512

2514 }

2515};

2516

2517

2518

2519class PRValueHandler final : public ExpressionHandler {

2520public:

2522

2523 Tracker::Result handle(const Expr *E, const ExplodedNode *InputNode,

2524 const ExplodedNode *ExprNode,

2525 TrackingOptions Opts) override {

2527 return {};

2528

2530 if (!RVNode)

2531 return {};

2532

2533 Tracker::Result CombinedResult;

2534 Tracker &Parent = getParentTracker();

2535

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

2537 Opts](const Expr *Inner) {

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

2539 };

2540

2541

2542

2543

2544

2545

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

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

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

2549

2550 return CombinedResult;

2551 }

2552

2553 return {};

2554 }

2555

2557 SVal V = RVState->getSValAsScalarOrLoc(E, RVNode->getLocationContext());

2558 const auto *BO = dyn_cast(E);

2559

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

2561 return {};

2562

2563 SVal RHSV = RVState->getSVal(BO->getRHS(), RVNode->getLocationContext());

2564 SVal LHSV = RVState->getSVal(BO->getLHS(), RVNode->getLocationContext());

2565

2566

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

2569 track(BO->getLHS());

2571 track(BO->getRHS());

2572 } else {

2574 track(BO->getLHS());

2575 }

2576

2577 return CombinedResult;

2578 }

2579};

2580}

2581

2594

2597 if (!E || !N)

2598 return {};

2599

2602 if (!LVNode)

2603 return {};

2604

2605 Result CombinedResult;

2606

2607 for (ExpressionHandlerPtr &Handler : ExpressionHandlers) {

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

2610

2611

2613 break;

2614 }

2615 }

2616

2617 return CombinedResult;

2618}

2619

2622 if (V.isUnknown()) {

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

2624 return {true};

2625 }

2626 return {};

2627}

2628

2631

2632 for (StoreHandlerPtr &Handler : StoreHandlers) {

2634

2635

2637 }

2638 return {};

2639}

2640

2642 const Expr *E,

2643

2647 ->track(E, InputNode, Opts)

2648 .FoundSomethingToTrack;

2649}

2650

2657

2658

2659

2660

2661

2664 const auto *ME = dyn_cast(S);

2665 if (!ME)

2666 return nullptr;

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

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

2671 return Receiver;

2672 }

2673 return nullptr;

2674}

2675

2680 if (!P)

2681 return nullptr;

2682

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

2685 if (!Receiver)

2686 return nullptr;

2687

2689 llvm::raw_svector_ostream OS(Buf);

2690

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

2692 OS << "'";

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

2694 OS << "' not called";

2695 }

2696 else {

2697 OS << "No method is called";

2698 }

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

2700

2701

2702

2703

2706 false});

2707

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

2711}

2712

2713

2714

2715

2716

2717

2718

2720

2725 if (piece) {

2726 piece->setTag(getTag());

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

2728 ev->setPrunable(true, false);

2729 }

2730 return piece;

2731}

2732

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

2740

2741

2742

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

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

2746

2747

2748

2749

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

2753 return nullptr;

2754

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

2756 }

2757 return nullptr;

2758 }

2759

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

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

2763 return nullptr;

2764

2765 bool TookTrue = CurrentNodeTag == Tags.first;

2767 }

2768

2769 return nullptr;

2770}

2771

2777

2778

2779

2780

2781

2782

2783

2784

2785

2786

2787

2788

2789

2790

2792

2793

2794 default:

2795 return nullptr;

2796 case Stmt::IfStmtClass: {

2797 const auto *IfStatement = cast(Term);

2798

2799 if (IfStatement->isConsteval())

2800 return nullptr;

2801 Cond = IfStatement->getCond();

2802 break;

2803 }

2804 case Stmt::ConditionalOperatorClass:

2806 break;

2807 case Stmt::BinaryOperatorClass:

2808

2809

2810

2812 assert(BO->isLogicalOp() &&

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

2814 Cond = BO->getLHS();

2815 break;

2816 }

2817

2818 Cond = Cond->IgnoreParens();

2819

2820

2821

2822

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

2824 if (!InnerBO->isLogicalOp())

2825 break;

2826 Cond = InnerBO->getRHS()->IgnoreParens();

2827 }

2828

2829 assert(Cond);

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

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

2833}

2834

2842

2843

2844

2845

2846

2847

2848

2849

2850

2851

2852

2853

2854

2855

2856

2857 bool IsAssuming =

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

2860

2861

2862

2864 bool TookTrueTmp = TookTrue;

2865

2866 while (true) {

2869 default:

2870 break;

2871 case Stmt::BinaryOperatorClass:

2873 BRC, R, N, TookTrueTmp, IsAssuming))

2874 return P;

2875 break;

2876 case Stmt::DeclRefExprClass:

2878 BRC, R, N, TookTrueTmp, IsAssuming))

2879 return P;

2880 break;

2881 case Stmt::MemberExprClass:

2883 BRC, R, N, TookTrueTmp, IsAssuming))

2884 return P;

2885 break;

2886 case Stmt::UnaryOperatorClass: {

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

2889 TookTrueTmp = !TookTrueTmp;

2890 CondTmp = UO->getSubExpr();

2891 continue;

2892 }

2893 break;

2894 }

2895 }

2896 break;

2897 }

2898

2899

2900

2901

2902

2903 if (!IsAssuming)

2904 return nullptr;

2905

2908 return nullptr;

2909

2910 return std::make_shared(

2911 Loc, TookTrue ? GenericTrueMessage : GenericFalseMessage);

2912}

2913

2918 std::optional &prunable,

2919 bool IsSameFieldName) {

2920 const Expr *OriginalExpr = Ex;

2922

2925

2926

2936 return false;

2937 }

2938 }

2939 }

2940

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

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

2943 if (quotes) {

2944 Out << '\'';

2950 prunable = false;

2951 else {

2955 prunable = false;

2956 }

2957 }

2958 }

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

2960 if (quotes)

2961 Out << '\'';

2962 return quotes;

2963 }

2964

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

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

2969 Out << "null";

2970 return false;

2971 }

2972 }

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

2975 Out << "nil";

2976 return false;

2977 }

2978 }

2979

2980 Out << IL->getValue();

2981 return false;

2982 }

2983

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

2985 if (!IsSameFieldName)

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

2987 else

2988 Out << '\''

2992 nullptr)

2993 << '\'';

2994 }

2995

2996 return false;

2997}

2998

3002 bool IsAssuming) {

3003 bool shouldInvert = false;

3004 std::optional shouldPrune;

3005

3006

3007

3008 bool IsSameFieldName = false;

3011

3012 if (LhsME && RhsME)

3013 IsSameFieldName =

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

3015

3017 {

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

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

3020 N, shouldPrune, IsSameFieldName);

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

3022 N, shouldPrune, IsSameFieldName);

3023

3024 shouldInvert = !isVarLHS && isVarRHS;

3025 }

3026

3028

3030

3031

3033 TookTrue);

3034 }

3035

3036

3037

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

3040 return nullptr;

3041

3042

3044 llvm::raw_svector_ostream Out(buf);

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

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

3047

3048

3049 if (shouldInvert)

3050 switch (Op) {

3051 default: break;

3052 case BO_LT: Op = BO_GT; break;

3053 case BO_GT: Op = BO_LT; break;

3054 case BO_LE: Op = BO_GE; break;

3055 case BO_GE: Op = BO_LE; break;

3056 }

3057

3058 if (!TookTrue)

3059 switch (Op) {

3060 case BO_EQ: Op = BO_NE; break;

3061 case BO_NE: Op = BO_EQ; break;

3062 case BO_LT: Op = BO_GE; break;

3063 case BO_GT: Op = BO_LE; break;

3064 case BO_LE: Op = BO_GT; break;

3065 case BO_GE: Op = BO_LT; break;

3066 default:

3067 return nullptr;

3068 }

3069

3070 switch (Op) {

3071 case BO_EQ:

3072 Out << "equal to ";

3073 break;

3074 case BO_NE:

3075 Out << "not equal to ";

3076 break;

3077 default:

3079 break;

3080 }

3081

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

3085

3089

3090

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

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

3093

3094

3095 if (!IsAssuming) {

3097 if (!shouldInvert) {

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

3100 else

3102 } else {

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

3105 else

3107 }

3108

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

3110 }

3111

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

3114 if (shouldPrune)

3115 event->setPrunable(*shouldPrune);

3116 return event;

3117}

3118

3122

3123

3124

3126 llvm::raw_svector_ostream Out(buf);

3127 Out << "Assuming " << LhsString << " is ";

3128

3129 if (printValue(CondVarExpr, Out, N, TookTrue, true))

3130 return nullptr;

3131

3134

3137

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

3139

3141 event->setPrunable(false);

3142

3143 return event;

3144}

3145

3149 bool IsAssuming) {

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

3151 if (!VD)

3152 return nullptr;

3153

3155 llvm::raw_svector_ostream Out(Buf);

3156

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

3158

3159 if (printValue(DRE, Out, N, TookTrue, IsAssuming))

3160 return nullptr;

3161

3163

3166

3167

3168 if (!IsAssuming) {

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

3171 }

3172

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

3175

3177 event->setPrunable(false);

3178

3179 return std::move(event);

3180}

3181

3185 bool IsAssuming) {

3187 llvm::raw_svector_ostream Out(Buf);

3188

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

3191

3192 if (printValue(ME, Out, N, TookTrue, IsAssuming))

3193 return nullptr;

3194

3197

3198

3201 else

3203

3205 return nullptr;

3206

3209

3210

3211 if (!IsAssuming)

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

3213

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

3216 event->setPrunable(false);

3217 return event;

3218}

3219

3222 bool IsAssuming) {

3224

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

3227 return true;

3228 }

3229

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

3232 return true;

3233 }

3234

3236 return false;

3237

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

3239 if (!IsAssuming)

3241

3242 if (IsAssuming || !IntValue) {

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

3245 else

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

3247 } else {

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

3250 else

3251 Out << **IntValue;

3252 }

3253

3254 return true;

3255}

3256

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

3260 Piece->getString() == GenericFalseMessage;

3261}

3262

3263

3264

3265

3266

3270

3271

3274

3276

3277

3278

3279

3280 if (Options.ShouldSuppressFromCXXStandardLibrary) {

3282 return;

3283 } else {

3284

3285

3286

3287

3288

3289

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

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

3294 return;

3295 }

3296 }

3297

3298

3299

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

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

3304 return;

3305 }

3306 }

3307

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

3311 if (!MD)

3312 continue;

3313

3315

3316

3317

3318

3319

3320

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

3323 return;

3324 }

3325

3326

3327

3328

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

3331 return;

3332 }

3333 }

3334 }

3335 }

3336

3337

3338

3341 while (Loc.isMacroID()) {

3342 Loc = Loc.getSpellingLoc();

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

3345 return;

3346 }

3347 }

3348}

3349

3350

3351

3352

3353

3359

3360

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

3362 if (!CEnter)

3363 return nullptr;

3364

3365

3368 unsigned Idx = 0;

3370

3371 for (const auto ParamDecl : parms) {

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

3373 ++Idx;

3374

3375

3377 continue;

3378

3379

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

3381 QualType T = ParamDecl->getType();

3382

3383 if (!(T->isAnyPointerType() || T->isReferenceType())) {

3384

3385 continue;

3386 }

3387

3388

3389

3390 if (T->getPointeeType().isConstQualified())

3391 continue;

3392

3393

3394

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

3398 return nullptr;

3399 }

3400 }

3401 return nullptr;

3402}

3403

3404

3405

3406

3407

3408int NoteTag::Kind = 0;

3409

3411 static int Tag = 0;

3412 ID.AddPointer(&Tag);

3413}

3414

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

3420 if (T)

3421 return nullptr;

3422

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

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

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

3428 return Piece;

3429 }

3430

3431 return nullptr;

3432}

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)

Definition BugReporterVisitors.cpp:284

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

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

Definition BugReporterVisitors.cpp:2160

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

Display diagnostics for passing bad region as a parameter.

Definition BugReporterVisitors.cpp:1304

static const Expr * peelOffPointerArithmetic(const BinaryOperator *B)

Definition BugReporterVisitors.cpp:70

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

Definition BugReporterVisitors.cpp:1408

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

Definition BugReporterVisitors.cpp:317

static llvm::StringLiteral WillBeUsedForACondition

Definition BugReporterVisitors.cpp:691

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

Definition BugReporterVisitors.cpp:302

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

Definition BugReporterVisitors.cpp:1973

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

Definition BugReporterVisitors.cpp:177

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

Definition BugReporterVisitors.cpp:216

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

Definition BugReporterVisitors.cpp:523

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

Definition BugReporterVisitors.cpp:259

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

Definition BugReporterVisitors.cpp:267

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

Show default diagnostics for storing bad region.

Definition BugReporterVisitors.cpp:1347

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

Definition BugReporterVisitors.cpp:234

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

Definition BugReporterVisitors.cpp:2094

static const VarDecl * getVarDeclForExpression(const Expr *E)

Definition BugReporterVisitors.cpp:170

static bool isTrivialCopyOrMoveCtor(const CXXConstructExpr *CE)

Definition BugReporterVisitors.cpp:1399

static StringRef getMacroName(SourceLocation Loc, BugReporterContext &BRC)

Definition BugReporterVisitors.cpp:292

static bool isObjCPointer(const MemRegion *R)

Definition BugReporterVisitors.cpp:1210

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

Definition BugReporterVisitors.cpp:1991

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

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

Definition BugReporterVisitors.cpp:1179

static const ExplodedNode * getMatchingCallExitEnd(const ExplodedNode *N)

Definition BugReporterVisitors.cpp:399

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

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

Definition BugReporterVisitors.cpp:1244

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

static bool isComparisonOp(Opcode Opc)

StringRef getOpcodeStr() const

static bool isAdditiveOp(Opcode Opc)

static bool isAssignmentOp(Opcode Opc)

BinaryOperatorKind Opcode

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.

ASTContext & getASTContext() const LLVM_READONLY

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

bool isLocalExternDecl() const

Determine whether this is a block-scope declaration with linkage.

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 * IgnoreImpCasts() LLVM_READONLY

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

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

const LocationContext * getLocationContext() const

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.

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

RecordDecl * getAsRecordDecl() const

Retrieves the RecordDecl this type refers to.

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

const T * getAs() const

Member-template getAs'.

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.

A safe wrapper around APSInt objects allocated and owned by BasicValueFactory.

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.

Definition BugReporterVisitors.cpp:360

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

Definition BugReporterVisitors.cpp:349

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

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

Definition BugReporterVisitors.cpp:355

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)

Definition BugReporterVisitors.cpp:2772

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

Tries to print the value of the given expression.

Definition BugReporterVisitors.cpp:3220

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

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

Definition BugReporterVisitors.cpp:2722

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

Definition BugReporterVisitors.cpp:2914

static bool isPieceMessageGeneric(const PathDiagnosticPiece *Piece)

Definition BugReporterVisitors.cpp:3257

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

Definition BugReporterVisitors.cpp:3119

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

Definition BugReporterVisitors.cpp:2836

static const char * getTag()

Return the tag associated with this visitor.

Definition BugReporterVisitors.cpp:2719

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

Definition BugReporterVisitors.cpp:2734

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.

Definition BugReporterVisitors.cpp:3267

MemRegion - The root abstract class for all memory regions.

const MemSpace * getMemorySpaceAs(ProgramStateRef State) 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.

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

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

Definition BugReporterVisitors.cpp:2677

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.

Definition BugReporterVisitors.cpp:2662

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.

Definition BugReporterVisitors.cpp:466

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.

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.

Definition BugReporterVisitors.cpp:1863

SuppressInlineDefensiveChecksVisitor(DefinedSVal Val, const ExplodedNode *N)

Definition BugReporterVisitors.cpp:1843

static const char * getTag()

Return the tag associated with this visitor.

Definition BugReporterVisitors.cpp:1858

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

Definition BugReporterVisitors.cpp:1851

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

Definition BugReporterVisitors.cpp:3410

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

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

Definition BugReporterVisitors.cpp:3415

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

Definition BugReporterVisitors.cpp:1767

static const char * getTag()

Return the tag associated with this visitor.

Definition BugReporterVisitors.cpp:1777

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

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

Definition BugReporterVisitors.cpp:1791

TypedRegion - An abstract class representing regions that are typed.

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

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

Definition BugReporterVisitors.cpp:3355

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)

Definition BugReporterVisitors.cpp:2174

void addLowPriorityHandler(ExpressionHandlerPtr SH)

Add custom expression handler with the lowest priority.

static TrackerRef create(PathSensitiveBugReport &Report)

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

Handle the store operation and produce the note.

Definition BugReporterVisitors.cpp:2629

void addHighPriorityHandler(ExpressionHandlerPtr SH)

Add custom expression handler with the highest priority.

Tracker(PathSensitiveBugReport &Report)

Definition BugReporterVisitors.cpp:2582

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

Track expression value back to its point of origin.

Definition BugReporterVisitors.cpp:2595

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.

internal::Matcher< Stmt > StatementMatcher

const internal::VariadicDynCastAllOfMatcher< Stmt, BinaryOperator > binaryOperator

Matches binary operator expressions.

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.

llvm::IntrusiveRefCntPtr< Tracker > TrackerRef

const Expr * getDerefExpr(const Stmt *S)

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

Definition BugReporterVisitors.cpp:97

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.

Definition BugReporterVisitors.cpp:2641

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.

Definition BugReporterVisitors.cpp:2651

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.

IntrusiveRefCntPtr< const ProgramState > ProgramStateRef

@ OS

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

raw_ostream & operator<<(raw_ostream &os, const MemRegion *R)

std::shared_ptr< PathDiagnosticPiece > PathDiagnosticPieceRef

bool Ret(InterpState &S, CodePtr &PC)

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

All declarations that can appear in a module declaration.

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

@ Match

This is not an overload because the signature exactly matches an existing declaration.

bool isa(CodeGen::Address addr)

std::pair< FileID, unsigned > FileIDAndOffset

@ Result

The result type of a method or function.

const FunctionProtoType * T

U cast(CodeGen::Address addr)

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