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 (.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) && .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);
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() || .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 (.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 ((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 ((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 ((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 ()
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.