clang: lib/StaticAnalyzer/Core/BugReporterVisitors.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
13
48#include "llvm/ADT/ArrayRef.h"
49#include "llvm/ADT/STLExtras.h"
50#include "llvm/ADT/SmallPtrSet.h"
51#include "llvm/ADT/SmallString.h"
52#include "llvm/ADT/SmallVector.h"
53#include "llvm/ADT/StringExtras.h"
54#include "llvm/ADT/StringRef.h"
55#include "llvm/Support/Casting.h"
56#include "llvm/Support/ErrorHandling.h"
57#include "llvm/Support/raw_ostream.h"
58#include
59#include
60#include
61#include
62#include
63#include
64#include
65
66using namespace clang;
67using namespace ento;
68using namespace bugreporter;
69
70
71
72
73
80 }
81 }
82 return nullptr;
83}
84
85
86
88
89
90
91
92
93
94
95
96
97
98
99
100
102 const auto *E = dyn_cast(S);
103 if ()
104 return nullptr;
105
106 while (true) {
107 if (const auto *CE = dyn_cast(E)) {
108 if (CE->getCastKind() == CK_LValueToRValue) {
109
110 break;
111 }
112 E = CE->getSubExpr();
113 } else if (const auto *B = dyn_cast(E)) {
114
116 E = Inner;
117 } else if (B->isAssignmentOp()) {
118
119 E = B->getLHS();
120 } else {
121
122
123 break;
124 }
125 } else if (const auto *U = dyn_cast(E)) {
126 if (U->getOpcode() == UO_Deref || U->getOpcode() == UO_AddrOf ||
127 (U->isIncrementDecrementOp() && U->getType()->isPointerType())) {
128
129
131 } else {
132
133
134 break;
135 }
136 }
137
138 else if (const auto *ME = dyn_cast(E)) {
139
140
141
142
143
144
145
146
147 if (ME->getMemberDecl()->getType()->isReferenceType())
148 break;
149 E = ME->getBase();
150 } else if (const auto *IvarRef = dyn_cast(E)) {
151 E = IvarRef->getBase();
152 } else if (const auto *AE = dyn_cast(E)) {
153 E = AE->getBase();
154 } else if (const auto *PE = dyn_cast(E)) {
155 E = PE->getSubExpr();
156 } else if (const auto *FE = dyn_cast(E)) {
157 E = FE->getSubExpr();
158 } else {
159
160 break;
161 }
162 }
163
164
165
166
167 if (const auto *CE = dyn_cast(E))
168 if (CE->getCastKind() == CK_LValueToRValue)
169 E = CE->getSubExpr();
170
171 return E;
172}
173
175 if (const auto *DR = dyn_cast(E))
176 return dyn_cast(DR->getDecl());
177 return nullptr;
178}
179
182 bool LookingForReference = true) {
183 if (const auto *ME = dyn_cast(E)) {
184
185
186
187
188 const Expr *Base = ME->getBase();
190 if (!VD)
191 return nullptr;
192
193 const auto *FD = dyn_cast(ME->getMemberDecl());
194 if (!FD)
195 return nullptr;
196
197 if (FD->getType()->isReferenceType()) {
199 return N->getState()->getLValue(FD, StructSVal).getAsRegion();
200 }
201 return nullptr;
202 }
203
205 if (!VD)
206 return nullptr;
208 return nullptr;
210}
211
212
213
214
215
216
217
218
219
222 if (LeftVal == RightVal)
223 return true;
224
226 if (!LLCV)
227 return false;
228
230 if (!RLCV)
231 return false;
232
233 return LLCV->getRegion() == RLCV->getRegion() &&
234 LLCV->getStore() == LeftNode->getState()->getStore() &&
235 RLCV->getStore() == RightNode->getState()->getStore();
236}
237
242
243 assert(CondVarExpr);
245
246
247
248
249
250 if (const auto *DRE = dyn_cast(CondVarExpr))
251 if (const auto *VD = dyn_cast(DRE->getDecl()))
252 return State->getSVal(State->getLValue(VD, LCtx));
253
254 if (const auto *ME = dyn_cast(CondVarExpr))
255 if (const auto *FD = dyn_cast(ME->getMemberDecl()))
256 if (auto FieldL = State->getSVal(ME, LCtx).getAs<Loc>())
257 return State->getRawSVal(*FieldL, FD->getType());
258
259 return std::nullopt;
260}
261
262static std::optional<const llvm::APSInt *>
264
265 if (std::optional V = getSValForVar(CondVarExpr, N))
267 return CI->getValue().get();
268 return std::nullopt;
269}
270
274
275
276
278 return false;
279
280 if (std::optional V = getSValForVar(CondVarExpr, N))
281 if (std::optionalbugreporter::TrackingKind K =
283 return *K == bugreporter::TrackingKind::Condition;
284
285 return false;
286}
287
292 return false;
293}
294
295
302}
303
304
305
308 if (.isMacroID())
309 return false;
310 while (SM.isMacroArgExpansion(Loc))
311 Loc = SM.getImmediateExpansionRange(Loc).getBegin();
312 std::pair<FileID, unsigned> TLInfo = SM.getDecomposedLoc(Loc);
316}
317
318
319
320
323 SVal ValueAfter) {
326
329 return false;
330
331
334 if (BO->isAssignmentOp() && RegionOfInterest->isSubRegionOf(
336 return true;
337
338
339 SVal ValueAtN = N->getState()->getSVal(RegionOfInterest);
341 .areEqual(State, ValueAtN, ValueAfter)
344 return true;
345
346 return false;
347}
348
349
350
351
352
356 return nullptr;
357}
358
362
368 const auto &Ranges = BR.getRanges();
369
370
371
372 auto P = std::make_shared(
373 L, BR.getDescription(), Ranges.begin() == Ranges.end());
376
377 return P;
378}
379
380
381
382
383
384bool NoStateChangeFuncVisitor::isModifiedInFrame(const ExplodedNode *N) {
387 if (!FramesModifyingCalculated.count(SCtx))
388 findModifyingFrames(N);
389 return FramesModifying.count(SCtx);
390}
391
392void NoStateChangeFuncVisitor::markFrameAsModifying(
395 auto p = FramesModifying.insert(SCtx);
396 if (!p.second)
397 break;
398
400 }
401}
402
405
406
408
409
410
411 auto IsMatchingCallExitEnd = [OrigSCtx](const ExplodedNode *N) {
414 };
415 while (N && !IsMatchingCallExitEnd(N)) {
417 "This function is to be used on the trimmed ExplodedGraph!");
419 }
420 return N;
421}
422
423void NoStateChangeFuncVisitor::findModifyingFrames(
425
427
430
431 const ExplodedNode *CurrCallExitBeginN = CallExitBeginN;
433
434 for (const ExplodedNode *CurrN = CallExitBeginN; CurrN;
436
438 CurrCallExitBeginN = CurrN;
440 FramesModifyingCalculated.insert(CurrentSCtx);
441
442 continue;
443 }
444
445 if (auto CE = CurrN->getLocationAs<CallEnter>()) {
448 markFrameAsModifying(CurrentSCtx);
449
450
452
453
454
455
456
457
458
459 if (CE->getCalleeContext() == OriginalSCtx) {
460 markFrameAsModifying(CurrentSCtx);
461 break;
462 }
463 }
464
466 markFrameAsModifying(CurrentSCtx);
467 }
468}
469
472
477
478
479 if (!CallExitLoc || isModifiedInFrame(N))
480 return nullptr;
481
484
485
486
487
488
489
490
491
492
493
494 if (Call->isInSystemHeader()) {
495
496
497
498
499
500
501
503 static int i = 0;
505 }
506 return nullptr;
507 }
508
509 if (const auto *MC = dyn_cast(Call)) {
510
511
513 return Piece;
514 }
515
516 if (const auto *CCall = dyn_cast(Call)) {
517
518
520 }
521
523}
524
525
526
529 using namespace ast_matchers;
530 const char *IvarBind = "Ivar";
532 return false;
534 hasOperatorName("="),
535 hasLHS(ignoringParenImpCasts(
538 auto Matches = match(ParentM, *Parent->getBody(), Parent->getASTContext());
540 auto IvarRef = Match.getNodeAs<ObjCIvarRefExpr>(IvarBind);
541 if (IvarRef->isFreeIvar())
542 return true;
543
544 const Expr *Base = IvarRef->getBase();
545 if (const auto *ICE = dyn_cast(Base))
546 Base = ICE->getSubExpr();
547
548 if (const auto *DRE = dyn_cast(Base))
549 if (const auto *ID = dyn_cast(DRE->getDecl()))
551 return true;
552
553 return false;
554 }
555 return false;
556}
557
558
559
560
561
562
563
564const std::optionalNoStoreFuncVisitor::RegionVector
565NoStoreFuncVisitor::findRegionOfInterestInRecord(
568 int depth ) {
569
570 if (depth == DEREFERENCE_LIMIT)
571 return std::nullopt;
572
573 if (const auto *RDX = dyn_cast(RD))
574 if (!RDX->hasDefinition())
575 return std::nullopt;
576
577
578
579 if (const auto *RDX = dyn_cast(RD))
580 for (const auto &II : RDX->bases())
581 if (const RecordDecl *RRD = II.getType()->getAsRecordDecl())
582 if (std::optional Out =
583 findRegionOfInterestInRecord(RRD, State, R, Vec, depth))
584 return Out;
585
589 const SVal V = State->getSVal(FR);
590 const MemRegion *VR = V.getAsRegion();
591
592 RegionVector VecF = Vec;
593 VecF.push_back(FR);
594
595 if (RegionOfInterest == VR)
596 return VecF;
597
599 if (auto Out =
600 findRegionOfInterestInRecord(RRD, State, FR, VecF, depth + 1))
601 return Out;
602
605 continue;
606
608 if (std::optional Out =
609 findRegionOfInterestInRecord(RRD, State, VR, VecF, depth + 1))
610 return Out;
611 }
612
613 return std::nullopt;
614}
615
620 if (const auto *IvarR = dyn_cast(RegionOfInterest)) {
621 const MemRegion *SelfRegion = Call.getReceiverSVal().getAsRegion();
622 if (RegionOfInterest->isSubRegionOf(SelfRegion) &&
624 IvarR->getDecl()))
625 return maybeEmitNote(R, Call, N, {}, SelfRegion, "self",
626 false, 1);
627 }
628 return nullptr;
629}
630
635 const MemRegion *ThisR = Call.getCXXThisVal().getAsRegion();
636 if (RegionOfInterest->isSubRegionOf(ThisR) && .getDecl()->isImplicit())
637 return maybeEmitNote(R, Call, N, {}, ThisR, "this",
638 false, 1);
639
640
641
642 return nullptr;
643}
644
645
649}
650
654 for (unsigned I = 0; I < Call.getNumArgs() && I < Parameters.size(); ++I) {
659
660 unsigned IndirectionLevel = 1;
662 while (const MemRegion *MR = V.getAsRegion()) {
664 return maybeEmitNote(R, Call, N, {}, MR, ParamName,
665 ParamIsReferenceType, IndirectionLevel);
666
668 if (PT.isNull() || PT->isVoidType())
669 break;
670
672
673 if (const RecordDecl *RD = PT->getAsRecordDecl())
674 if (std::optional P =
675 findRegionOfInterestInRecord(RD, State, MR))
676 return maybeEmitNote(R, Call, N, *P, RegionOfInterest, ParamName,
677 ParamIsReferenceType, IndirectionLevel);
678
679 V = State->getSVal(MR, PT);
680 T = PT;
681 IndirectionLevel++;
682 }
683 }
684
685 return nullptr;
686}
687
688bool NoStoreFuncVisitor::wasModifiedBeforeCallExit(
690 return ::wasRegionOfInterestModifiedAt(
691 RegionOfInterest, CurrN,
692 CallExitBeginN->getState()->getSVal(RegionOfInterest));
693}
694
696 ", which participates in a condition later";
697
700 const RegionVector &FieldChain, const MemRegion *MatchedRegion,
701 StringRef FirstElement, bool FirstIsReferenceType,
702 unsigned IndirectionLevel) {
703
706
707
708
709
711 return nullptr;
712
714 llvm::raw_svector_ostream os(sbuf);
715 os << "Returning without writing to '";
716
717
718 if (!prettyPrintRegionName(FieldChain, MatchedRegion, FirstElement,
719 FirstIsReferenceType, IndirectionLevel, os))
720 return nullptr;
721
722 os << "'";
725 return std::make_shared(L, os.str());
726}
727
728bool NoStoreFuncVisitor::prettyPrintRegionName(const RegionVector &FieldChain,
730 StringRef FirstElement,
731 bool FirstIsReferenceType,
732 unsigned IndirectionLevel,
733 llvm::raw_svector_ostream &os) {
734
735 if (FirstIsReferenceType)
736 IndirectionLevel--;
737
738 RegionVector RegionSequence;
739
740
741 assert(RegionOfInterest->isSubRegionOf(MatchedRegion));
742 const MemRegion *R = RegionOfInterest;
743 while (R != MatchedRegion) {
744 RegionSequence.push_back(R);
745 R = cast(R)->getSuperRegion();
746 }
747 std::reverse(RegionSequence.begin(), RegionSequence.end());
748 RegionSequence.append(FieldChain.begin(), FieldChain.end());
749
750 StringRef Sep;
751 for (const MemRegion *R : RegionSequence) {
752
753
754
755 if (isa<CXXBaseObjectRegion, CXXTempObjectRegion>(R))
756 continue;
757
758 if (Sep.empty())
759 Sep = prettyPrintFirstElement(FirstElement,
760 true,
761 IndirectionLevel, os);
762
763 os << Sep;
764
765
766 if (!isa(R))
767 return false;
768
769 const auto *DR = cast(R);
770 Sep = DR->getValueType()->isAnyPointerType() ? "->" : ".";
771 DR->getDecl()->getDeclName().print(os, PP);
772 }
773
774 if (Sep.empty())
775 prettyPrintFirstElement(FirstElement,
776 false, IndirectionLevel, os);
777 return true;
778}
779
780StringRef NoStoreFuncVisitor::prettyPrintFirstElement(
781 StringRef FirstElement, bool MoreItemsExpected, int IndirectionLevel,
782 llvm::raw_svector_ostream &os) {
783 StringRef Out = ".";
784
785 if (IndirectionLevel > 0 && MoreItemsExpected) {
786 IndirectionLevel--;
787 Out = "->";
788 }
789
790 if (IndirectionLevel > 0 && MoreItemsExpected)
791 os << "(";
792
793 for (int i = 0; i < IndirectionLevel; i++)
794 os << "*";
795 os << FirstElement;
796
797 if (IndirectionLevel > 0 && MoreItemsExpected)
798 os << ")";
799
800 return Out;
801}
802
803
804
805
806
807namespace {
808
809
810
811class MacroNullReturnSuppressionVisitor final : public BugReporterVisitor {
812 const SubRegion *RegionOfInterest;
813 const SVal ValueAtDereference;
814
815
816
817 bool WasModified = false;
818
819public:
820 MacroNullReturnSuppressionVisitor(const SubRegion *R, const SVal V)
821 : RegionOfInterest(R), ValueAtDereference(V) {}
822
826 if (WasModified)
827 return nullptr;
828
830 if (!BugPoint)
831 return nullptr;
832
834 if (auto Loc = matchAssignment(N)) {
836 std::string MacroName = std::string(getMacroName(*Loc, BRC));
837 SourceLocation BugLoc = BugPoint->getStmt()->getBeginLoc();
839 BR.markInvalid(getTag(), MacroName.c_str());
840 }
841 }
842
844 WasModified = true;
845
846 return nullptr;
847 }
848
849 static void addMacroVisitorIfNecessary(
854 if (EnableNullFPSuppression && Options.ShouldSuppressNullReturnPaths &&
855 isa(V))
857 V);
858 }
859
860 void* getTag() const {
861 static int Tag = 0;
862 return static_cast<void *>(&Tag);
863 }
864
865 void Profile(llvm::FoldingSetNodeID &ID) const override {
866 ID.AddPointer(getTag());
867 }
868
869private:
870
871
872 std::optional matchAssignment(const ExplodedNode *N) {
876 if (!S)
877 return std::nullopt;
878
879 if (const auto *DS = dyn_cast(S)) {
880 if (const auto *VD = dyn_cast(DS->getSingleDecl()))
881 if (const Expr *RHS = VD->getInit())
882 if (RegionOfInterest->isSubRegionOf(
883 State->getLValue(VD, LCtx).getAsRegion()))
884 return RHS->getBeginLoc();
885 } else if (const auto *BO = dyn_cast(S)) {
887 const Expr *RHS = BO->getRHS();
888 if (BO->isAssignmentOp() && RegionOfInterest->isSubRegionOf(R)) {
890 }
891 }
892 return std::nullopt;
893 }
894};
895
896}
897
898namespace {
899
900
901
902
903
904
905
906
909 enum {
910 Initial,
911 MaybeUnsuppress,
912 Satisfied
913 } Mode = Initial;
914
915 bool EnableNullFPSuppression;
916 bool ShouldInvalidate = true;
919
920public:
925 EnableNullFPSuppression(Suppressed), Options(Options), TKind(TKind) {}
926
927 static void *getTag() {
928 static int Tag = 0;
929 return static_cast<void *>(&Tag);
930 }
931
932 void Profile(llvm::FoldingSetNodeID &ID) const override {
933 ID.AddPointer(ReturnVisitor::getTag());
934 ID.AddPointer(CalleeSFC);
935 ID.AddBoolean(EnableNullFPSuppression);
936 }
937
941
943 return nullptr;
944
946 if (!SP)
947 return nullptr;
948
949 const auto *Ret = dyn_cast(SP->getStmt());
950 if (!Ret)
951 return nullptr;
952
953
954
956 SVal V = State->getSVal(Ret, CalleeSFC);
957 if (V.isUnknownOrUndef())
958 return nullptr;
959
960
961 Mode = Satisfied;
962
963 const Expr *RetE = Ret->getRetValue();
964 assert(RetE && "Tracking a return value for a void function");
965
966
967 std::optional LValue;
969 if ((LValue = V.getAs<Loc>())) {
970 SVal RValue = State->getRawSVal(*LValue, RetE->getType());
971 if (isa(RValue))
972 V = RValue;
973 }
974 }
975
976
977 if (isa<nonloc::LazyCompoundVal, nonloc::CompoundVal>(V))
978 return nullptr;
979
981
982
983 getParentTracker().track(RetE, N, {TKind, EnableNullFPSuppression});
984
985
987 llvm::raw_svector_ostream Out(Msg);
988
989 bool WouldEventBeMeaningless = false;
990
991 if (State->isNull(V).isConstrainedTrue()) {
992 if (isa(V)) {
993
994
995
996
997 if (EnableNullFPSuppression &&
998 Options.ShouldAvoidSuppressingNullArgumentPaths)
999 Mode = MaybeUnsuppress;
1000
1002 Out << "Returning nil";
1003 } else {
1004 Out << "Returning null pointer";
1005 }
1006 } else {
1007 Out << "Returning zero";
1008 }
1009
1010 } else {
1012 Out << "Returning the value " << CI->getValue();
1013 } else {
1014
1015
1016
1017
1018
1020 WouldEventBeMeaningless = true;
1021
1022 Out << (isa(V) ? "Returning pointer" : "Returning value");
1023 }
1024 }
1025
1026 if (LValue) {
1027 if (const MemRegion *MR = LValue->getAsRegion()) {
1028 if (MR->canPrintPretty()) {
1029 Out << " (reference to ";
1030 MR->printPretty(Out);
1031 Out << ")";
1032 }
1033 }
1034 } else {
1035
1036 if (const auto *DR = dyn_cast(RetE))
1037 if (const auto *DD = dyn_cast(DR->getDecl()))
1038 Out << " (loaded from '" << *DD << "')";
1039 }
1040
1042 if (!L.isValid() || !L.asLocation().isValid())
1043 return nullptr;
1044
1045 if (TKind == bugreporter::TrackingKind::Condition)
1047
1048 auto EventPiece = std::make_shared(L, Out.str());
1049
1050
1051
1052 if (WouldEventBeMeaningless)
1053 EventPiece->setPrunable(true);
1054 else
1056
1057 return EventPiece;
1058 }
1059
1063 assert(Options.ShouldAvoidSuppressingNullArgumentPaths);
1064
1065
1067 if (!CE)
1068 return nullptr;
1069
1070 if (CE->getCalleeContext() != CalleeSFC)
1071 return nullptr;
1072
1073 Mode = Satisfied;
1074
1075
1076
1077
1080
1083 for (unsigned I = 0, E = Call->getNumArgs(); I != E; ++I) {
1084 std::optional ArgV = Call->getArgSVal(I).getAs<Loc>();
1085 if (!ArgV)
1086 continue;
1087
1088 const Expr *ArgE = Call->getArgExpr(I);
1089 if (!ArgE)
1090 continue;
1091
1092
1093 if (!State->isNull(*ArgV).isConstrainedTrue())
1094 continue;
1095
1096 if (getParentTracker()
1097 .track(ArgE, N, {TKind, EnableNullFPSuppression})
1098 .FoundSomethingToTrack)
1099 ShouldInvalidate = false;
1100
1101
1102
1103
1104 }
1105
1106 return nullptr;
1107 }
1108
1112 switch (Mode) {
1113 case Initial:
1114 return visitNodeInitial(N, BRC, BR);
1115 case MaybeUnsuppress:
1116 return visitNodeMaybeUnsuppress(N, BRC, BR);
1117 case Satisfied:
1118 return nullptr;
1119 }
1120
1121 llvm_unreachable("Invalid visit mode!");
1122 }
1123
1126 if (EnableNullFPSuppression && ShouldInvalidate)
1127 BR.markInvalid(ReturnVisitor::getTag(), CalleeSFC);
1128 }
1129};
1130
1131
1132
1133
1134
1135
1136
1140 bool Satisfied = false;
1141
1144
1145public:
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1160 OriginSFC(OriginSFC) {
1161 assert(R);
1162 }
1163
1164 void Profile(llvm::FoldingSetNodeID &ID) const override;
1165
1169};
1170}
1171
1172void StoreSiteFinder::Profile(llvm::FoldingSetNodeID &ID) const {
1173 static int tag = 0;
1174 ID.AddPointer(&tag);
1175 ID.AddPointer(R);
1177 ID.AddInteger(static_cast<int>(Options.Kind));
1178 ID.AddBoolean(Options.EnableNullFPSuppression);
1179}
1180
1181
1182
1185 if ()
1186 return false;
1187
1189 if (!DS)
1190 return false;
1191
1193 return false;
1194
1196 const auto *FrameSpace = dyn_cast(VarSpace);
1197 if (!FrameSpace) {
1198
1199
1200
1202 return true;
1203 }
1204
1208}
1209
1212 if (const auto *TR = dyn_cast(R))
1213 return TR->getValueType()->isObjCObjectPointerType();
1214
1215 return false;
1216}
1217
1219 return D->getType()->isObjCObjectPointerType();
1220}
1221
1222
1225
1226 if (HasPrefix) {
1228 OS << " ";
1229 }
1230
1231 const char *Action = nullptr;
1232
1235 Action = HasPrefix ? "initialized to " : "Initializing to ";
1236 break;
1238 Action = HasPrefix ? "captured by block as " : "Captured by block as ";
1239 break;
1240 default:
1241 llvm_unreachable("Unexpected store kind");
1242 }
1243
1244 if (isaloc::ConcreteInt(SI.Value)) {
1245 OS << Action << (isObjCPointer(SI.Dest) ? "nil" : "a null pointer value");
1246
1248 OS << Action << CVal->getValue();
1249
1251 OS << Action << "the value of ";
1253
1255
1256
1257
1258 const auto *DS =
1260
1262 if (isa(SI.Dest)) {
1263 const auto *VD = cast(DS->getSingleDecl());
1264
1265 if (VD->getInit()) {
1266 OS << (HasPrefix ? "initialized" : "Initializing")
1267 << " to a garbage value";
1268 } else {
1269 OS << (HasPrefix ? "declared" : "Declaring")
1270 << " without an initial value";
1271 }
1272 }
1273 } else {
1274 OS << (HasPrefix ? "initialized" : "Initialized") << " here";
1275 }
1276 }
1277}
1278
1279
1282 const auto *VR = cast(SI.Dest);
1283 const auto *D = VR->getDecl();
1284
1285 OS << "Passing ";
1286
1287 if (isaloc::ConcreteInt(SI.Value)) {
1288 OS << (isObjCPointer(D) ? "nil object reference" : "null pointer value");
1289
1291 OS << "uninitialized value";
1292
1294 OS << "the value " << CI->getValue();
1295
1298
1299 } else {
1300 OS << "value";
1301 }
1302
1303 if (const auto *Param = dyn_cast(VR->getDecl())) {
1304
1305 unsigned Idx = Param->getFunctionScopeIndex() + 1;
1306 OS << " via " << Idx << llvm::getOrdinalSuffix(Idx) << " parameter";
1308 OS << " ";
1310 }
1311 } else if (const auto *ImplParam = dyn_cast(D)) {
1313 OS << " via implicit parameter 'self'";
1314 }
1315 }
1316}
1317
1318
1322
1323 if (isaloc::ConcreteInt(SI.Value)) {
1325 : (HasSuffix ? "Null pointer value stored"
1326 : "Storing null pointer value"));
1327
1329 OS << (HasSuffix ? "Uninitialized value stored"
1330 : "Storing uninitialized value");
1331
1333 if (HasSuffix)
1334 OS << "The value " << CV->getValue() << " is assigned";
1335 else
1336 OS << "Assigning " << CV->getValue();
1337
1339 if (HasSuffix) {
1340 OS << "The value of ";
1342 OS << " is assigned";
1343 } else {
1344 OS << "Assigning the value of ";
1346 }
1347
1348 } else {
1349 OS << (HasSuffix ? "Value assigned" : "Assigning value");
1350 }
1351
1352 if (HasSuffix) {
1353 OS << " to ";
1355 }
1356}
1357
1359 if (!CE)
1360 return false;
1361
1363
1365}
1366
1369
1370 const auto *TVR = dyn_cast_or_null(R);
1371
1372 if (!TVR)
1373 return nullptr;
1374
1376
1377
1378 std::stack<const TypedValueRegion *> TVRStack;
1379 while (isa(TVR) || isa(TVR)) {
1380
1381
1382
1383
1384 if (ITy == TVR->getValueType().getCanonicalType())
1385 break;
1386
1387 TVRStack.push(TVR);
1388 TVR = cast(TVR->getSuperRegion());
1389 }
1390
1391
1392
1393 if (ITy != TVR->getValueType().getCanonicalType())
1394 return nullptr;
1395
1397 while (!TVRStack.empty()) {
1398 TVR = TVRStack.top();
1399 TVRStack.pop();
1400
1401
1402
1403 if (!isa(Init))
1404 return nullptr;
1405
1406 ILE = cast(Init);
1408
1409 if (const auto *FR = dyn_cast(TVR)) {
1410 const auto *FD = FR->getDecl();
1411
1412 if (FD->getFieldIndex() >= NumInits)
1413 return nullptr;
1414
1415 Init = ILE->getInit(FD->getFieldIndex());
1416 } else if (const auto *ER = dyn_cast(TVR)) {
1417 const auto Ind = ER->getIndex();
1418
1419
1420
1421 if (!Ind.isConstant())
1422 return nullptr;
1423
1424 const auto IndVal = Ind.getAsInteger()->getLimitedValue();
1425 if (IndVal >= NumInits)
1426 return nullptr;
1427
1429 }
1430 }
1431
1432 return Init;
1433}
1434
1438 if (Satisfied)
1439 return nullptr;
1440
1443 const Expr *InitE = nullptr;
1444 bool IsParam = false;
1445
1446
1447 if (const auto *VR = dyn_cast(R)) {
1449 StoreSite = Pred;
1450 InitE = VR->getDecl()->getInit();
1451 }
1452 }
1453
1454
1455
1456 if (std::optional PIP =
1458 const MemRegion *FieldReg = (const MemRegion *)PIP->getLocationValue();
1459 if (FieldReg == R) {
1460 StoreSite = Pred;
1461 InitE = PIP->getInitializer()->getInit();
1462 }
1463 }
1464
1465
1466
1467
1468
1469
1470 if (!StoreSite) {
1471 if (Succ->getState()->getSVal(R) != V)
1472 return nullptr;
1473
1476 if (!PS || PS->getLocationValue() != R)
1477 return nullptr;
1478 }
1479
1480 StoreSite = Succ;
1481
1483
1484
1486 if (BO->isAssignmentOp())
1487 InitE = BO->getRHS();
1488 }
1489
1490
1491 else if (const auto *DS = P->getStmtAs<DeclStmt>()) {
1492 const auto *Decl = DS->getSingleDecl();
1493 if (isa(Decl)) {
1494 const auto *VD = cast(Decl);
1495
1496
1497
1498
1499
1500
1501
1502 if (const auto *ILE = dyn_cast(VD->getInit()))
1504 }
1506
1507 const auto State = Succ->getState();
1508
1510
1511
1512
1513
1514
1515
1516
1517
1518 std::stack<const SubRegion *> SRStack;
1519 const SubRegion *SR = cast(R);
1520 while (isa(SR) || isa(SR)) {
1521 SRStack.push(SR);
1523 }
1524
1525
1526 const auto *OriginEx = CE->getArg(0);
1527 const auto OriginVal =
1529
1530
1531
1532
1533 SVal OriginField = OriginVal;
1534 while (!SRStack.empty()) {
1535 const auto *TopR = SRStack.top();
1536 SRStack.pop();
1537
1538 if (const auto *FR = dyn_cast(TopR)) {
1539 OriginField = State->getLValue(FR->getDecl(), OriginField);
1540 } else if (const auto *ER = dyn_cast(TopR)) {
1541 OriginField = State->getLValue(ER->getElementType(),
1542 ER->getIndex(), OriginField);
1543 } else {
1544
1545 }
1546 }
1547
1548
1549 getParentTracker().track(V, OriginField.getAsRegion(), Options);
1550 InitE = OriginEx;
1551 }
1552 }
1553
1554 else if (const auto *ILE = P->getStmtAs<InitListExpr>()) {
1555
1556
1557
1558
1559
1560
1562 }
1563 }
1564
1565
1566
1567
1568
1570 if (const auto *VR = dyn_cast(R)) {
1571
1572 if (const auto *Param = dyn_cast(VR->getDecl())) {
1575
1578 InitE = Call->getArgExpr(Param->getFunctionScopeIndex());
1579 } else {
1580
1581 assert(isa(VR->getDecl()));
1582 InitE = cast(CE->getCalleeContext()->getCallSite())
1584 }
1585 IsParam = true;
1586 }
1587 }
1588
1589
1590
1591 if (const auto *TmpR = dyn_cast(R))
1592 InitE = TmpR->getExpr();
1593 }
1594
1595 if (!StoreSite)
1596 return nullptr;
1597
1598 Satisfied = true;
1599
1600
1601
1602 if (InitE) {
1603 if (!IsParam)
1605
1606 getParentTracker().track(InitE, StoreSite, Options);
1607 }
1608
1609
1610 const MemRegion *OldRegion = nullptr;
1611
1612
1613
1614 if (InitE) {
1615
1616
1617
1618
1619
1620
1621
1622
1623 if (const MemRegion *Candidate =
1626
1627
1628
1630 if (SM.includedInBindings(N->getState()->getStore(), Candidate)) {
1631
1632 if (N->getState()->getSVal(Candidate) == V) {
1633 OldRegion = Candidate;
1634 }
1635 break;
1636 }
1637 }
1638 }
1639 }
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652 if (!OldRegion && StoreSite->getState()->getSVal(R) == V) {
1653
1654
1656 for (;
1657 NodeWithoutBinding && NodeWithoutBinding->getState()->getSVal(R) == V;
1658 NodeWithoutBinding = NodeWithoutBinding->getFirstPred()) {
1659 }
1660
1661 if (NodeWithoutBinding) {
1662
1663
1664
1665
1666
1667
1668
1669
1672 if (FB)
1673 OldRegion = FB.getRegion();
1674 }
1675 }
1676
1677 if (Options.Kind == TrackingKind::Condition && OriginSFC &&
1678 !OriginSFC->isParentOf(StoreSite->getStackFrame()))
1679 return nullptr;
1680
1681
1683 llvm::raw_svector_ostream os(sbuf);
1684
1686 StoreSite,
1687 InitE,
1688 V,
1689 R,
1690 OldRegion};
1691
1693 const Stmt *S = PS->getStmt();
1694 const auto *DS = dyn_cast(S);
1695 const auto *VR = dyn_cast(R);
1696
1697 if (DS) {
1699 } else if (isa(S)) {
1701 if (VR) {
1702
1705 if (const auto *BDR =
1706 dyn_cast_or_null(V.getAsRegion())) {
1707 if (const VarRegion *OriginalR = BDR->getOriginalRegion(VR)) {
1708 getParentTracker().track(State->getSVal(OriginalR), OriginalR,
1709 Options, OriginSFC);
1710 }
1711 }
1712 }
1713 }
1715 isa(SI.Dest)) {
1717 }
1718
1719 return getParentTracker().handle(SI, BRC, Options);
1720}
1721
1722
1723
1724
1725
1727 static int tag = 0;
1728 ID.AddPointer(&tag);
1729 ID.AddString(Message);
1730 ID.AddBoolean(Assumption);
1731 ID.Add(Constraint);
1732}
1733
1734
1735
1737 return "TrackConstraintBRVisitor";
1738}
1739
1740bool TrackConstraintBRVisitor::isZeroCheck() const {
1741 return !Assumption && Constraint.getAs<Loc>();
1742}
1743
1744bool TrackConstraintBRVisitor::isUnderconstrained(const ExplodedNode *N) const {
1745 if (isZeroCheck())
1746 return N->getState()->isNull(Constraint).isUnderconstrained();
1747 return (bool)N->getState()->assume(Constraint, !Assumption);
1748}
1749
1753 if (IsSatisfied)
1754 return nullptr;
1755
1756
1757
1758 if (!IsTrackingTurnedOn)
1759 if (!isUnderconstrained(N))
1760 IsTrackingTurnedOn = true;
1761 if (!IsTrackingTurnedOn)
1762 return nullptr;
1763
1764
1765
1766 if (isUnderconstrained(PrevN)) {
1767 IsSatisfied = true;
1768
1769
1770
1771
1772
1773 assert(!isUnderconstrained(N));
1774
1775
1777
1778
1779
1780
1781 if (isa_and_nonnull(P.getTag()))
1782 return nullptr;
1783
1787 return nullptr;
1788
1789 auto X = std::make_shared(L, Message);
1791 return std::move(X);
1792 }
1793
1794 return nullptr;
1795}
1796
1797
1798
1799
1800
1804
1806 if (!Options.ShouldSuppressInlinedDefensiveChecks)
1807 IsSatisfied = true;
1808}
1809
1811 llvm::FoldingSetNodeID &ID) const {
1812 static int id = 0;
1813 ID.AddPointer(&id);
1814 ID.Add(V);
1815}
1816
1818 return "IDCVisitor";
1819}
1820
1826 if (IsSatisfied)
1827 return nullptr;
1828
1829
1830 if (!IsTrackingTurnedOn)
1831 if (Succ->getState()->isNull(V).isConstrainedTrue())
1832 IsTrackingTurnedOn = true;
1833 if (!IsTrackingTurnedOn)
1834 return nullptr;
1835
1836
1837
1838 if (!Pred->getState()->isNull(V).isConstrainedTrue() &&
1839 Succ->getState()->isNull(V).isConstrainedTrue()) {
1840 IsSatisfied = true;
1841
1842
1845 if (CurLC != ReportLC && !CurLC->isParentOf(ReportLC)) {
1847 return nullptr;
1848 }
1849
1850
1851
1852
1853
1855
1856 if (!BugPoint)
1857 return nullptr;
1858
1860 const Stmt *CurTerminatorStmt = nullptr;
1862 CurTerminatorStmt = BE->getSrc()->getTerminator().getStmt();
1864 const Stmt *CurStmt = SP->getStmt();
1866 return nullptr;
1867
1870 } else {
1871 return nullptr;
1872 }
1873
1874 if (!CurTerminatorStmt)
1875 return nullptr;
1876
1878 if (TerminatorLoc.isMacroID()) {
1879 SourceLocation BugLoc = BugPoint->getStmt()->getBeginLoc();
1880
1881
1884 BR.markInvalid("Suppress Macro IDC", CurLC);
1885 }
1886 return nullptr;
1887 }
1888 }
1889 return nullptr;
1890}
1891
1892
1893
1894
1895
1896namespace {
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908class TrackControlDependencyCondBRVisitor final
1912 llvm::SmallSet<const CFGBlock *, 32> VisitedBlocks;
1913
1914public:
1915 TrackControlDependencyCondBRVisitor(TrackerRef ParentTracker,
1918 ControlDeps(&O->getCFG()) {}
1919
1920 void Profile(llvm::FoldingSetNodeID &ID) const override {
1921 static int x = 0;
1922 ID.AddPointer(&x);
1923 }
1924
1928};
1929}
1930
1931static std::shared_ptr
1935
1938 return nullptr;
1939
1943
1944 return std::make_shared(
1947 (Twine() + "Tracking condition '" + ConditionText + "'").str());
1948}
1949
1952 return false;
1953
1956
1957 if (!Then || !Else)
1958 return false;
1959
1961 return true;
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1975 if (const auto *BinOp = dyn_cast(ElseCond))
1976 if (BinOp->isLogicalOp())
1978
1979 return false;
1980}
1981
1983TrackControlDependencyCondBRVisitor::VisitNode(const ExplodedNode *N,
1986
1987 if (Origin->getStackFrame() != N->getStackFrame())
1988 return nullptr;
1989
1991
1992
1993 if (!VisitedBlocks.insert(NB).second)
1994 return nullptr;
1995
1996 CFGBlock *OriginB = const_cast<CFGBlock *>(Origin->getCFGBlock());
1997
1998
1999 if (!OriginB || !NB)
2000 return nullptr;
2001
2003 return nullptr;
2004
2005 if (ControlDeps.isControlDependent(OriginB, NB)) {
2006
2007
2008 if (llvm::isa_and_nonnull(NB->getTerminatorStmt()))
2009 return nullptr;
2010
2012
2013
2015 if (!InnerExpr)
2016 return nullptr;
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031 if (isa(InnerExpr))
2032 return nullptr;
2033
2034
2035
2036
2038 getParentTracker().track(InnerExpr, N,
2040 false});
2042 }
2043 }
2044 }
2045
2046 return nullptr;
2047}
2048
2049
2050
2051
2052
2054
2056 if (const auto *FE = dyn_cast(Ex))
2058 if (const auto *OVE = dyn_cast(Ex))
2060 if (const auto *POE = dyn_cast(Ex)) {
2061 const auto *PropRef = dyn_cast(POE->getSyntacticForm());
2062 if (PropRef && PropRef->isMessagingGetter()) {
2063 const Expr *GetterMessageSend =
2064 POE->getSemanticExpr(POE->getNumSemanticExprs() - 1);
2065 assert(isa(GetterMessageSend->IgnoreParenCasts()));
2067 }
2068 }
2069
2070
2071 if (const auto *CO = dyn_cast(Ex)) {
2072
2073
2075 do {
2077 if (std::optional BE = ProgPoint.getAs<BlockEdge>()) {
2078 const CFGBlock *srcBlk = BE->getSrc();
2080 if (term == CO) {
2081 bool TookTrueBranch = (*(srcBlk->succ_begin()) == BE->getDst());
2082 if (TookTrueBranch)
2084 else
2086 }
2087 }
2088 }
2090 } while (NI);
2091 }
2092
2093 if (auto *BO = dyn_cast(Ex))
2096
2097 if (auto *UO = dyn_cast(Ex)) {
2098 if (UO->getOpcode() == UO_LNot)
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109 if (UO->getOpcode() == UO_AddrOf && UO->getSubExpr()->isLValue())
2112 }
2113
2114 return Ex;
2115}
2116
2117
2118
2120 const Expr *Inner) {
2121 while (N) {
2123 return N;
2125 }
2126 return N;
2127}
2128
2129
2130
2131
2132
2135 StringRef NodeText) {
2136
2141 P.getLocationContext());
2142
2145
2147 return nullptr;
2148
2149 return std::make_shared(L, NodeText);
2150}
2151
2152namespace {
2153class DefaultStoreHandler final : public StoreHandler {
2154public:
2156
2159
2161 llvm::raw_svector_ostream OS(Buffer);
2162
2167 break;
2170 break;
2173 break;
2174 }
2175
2176 if (Opts.Kind == bugreporter::TrackingKind::Condition)
2178
2179 return constructNote(SI, BRC, OS.str());
2180 }
2181};
2182
2183class ControlDependencyHandler final : public ExpressionHandler {
2184public:
2186
2191
2192
2193
2194
2195
2196
2197
2199 ->getAnalysisManager()
2200 .getAnalyzerOptions()
2201 .ShouldTrackConditions) {
2202 Report.addVisitor(
2203 &getParentTracker(), InputNode);
2204 return {true};
2205 }
2206
2207 return {};
2208 }
2209};
2210
2212public:
2214
2218
2219
2220
2221 if (const Expr *Receiver =
2223 return getParentTracker().track(Receiver, LVNode, Opts);
2224
2225 return {};
2226 }
2227};
2228
2230public:
2232
2236
2237 if (const auto *Arr = dyn_cast(Inner))
2238 return getParentTracker().track(
2239 Arr->getIdx(), LVNode,
2240 {Opts.Kind, false});
2241
2242 return {};
2243 }
2244};
2245
2246
2247class InterestingLValueHandler final : public ExpressionHandler {
2248public:
2250
2258
2259
2260
2263
2265 bool LVIsNull = LVState->isNull(LVal).isConstrainedTrue();
2266
2267
2268
2269
2270 if (RR && !LVIsNull)
2271 Result.combineWith(getParentTracker().track(LVal, RR, Opts, SFC));
2272
2273
2274
2275
2276
2279
2280 if (R) {
2281
2282
2285
2286
2287
2288 Result.FoundSomethingToTrack = true;
2289 Result.WasInterrupted = true;
2290
2291 MacroNullReturnSuppressionVisitor::addMacroVisitorIfNecessary(
2293
2296
2297
2298
2299 if (V.getAsLocSymbol(true))
2300 if (LVState->isNull(V).isConstrainedTrue())
2303 false, "Assuming pointer value is null");
2304
2305
2308
2309
2310
2311
2312
2313
2315 InputNode);
2316 getParentTracker().track(V, R, Opts, SFC);
2317 }
2318 }
2319
2320 return Result;
2321 }
2322};
2323
2324
2325
2326
2327
2328
2329
2330
2331class InlinedFunctionCallHandler final : public ExpressionHandler {
2333
2338 return {};
2339
2340
2341
2342
2343
2344 const bool BypassCXXNewExprEval = isa(E);
2345
2346
2348
2349 do {
2350
2351 if (std::optional CEE =
2353 if (CEE->getCalleeContext()->getCallSite() == E)
2354 break;
2355
2356
2358 if (!ExprNode)
2359 break;
2360
2362
2363
2364
2365
2366 if (!BypassCXXNewExprEval)
2368
2369 if (SP->getStmt() == E && CurrentSFC == PredSFC)
2370 break;
2371
2372 CurrentSFC = PredSFC;
2373 } while (ExprNode->getStackFrame() == CurrentSFC);
2374
2375
2378 if (!ExprNode)
2379 return {};
2380
2381
2383 if (!CEE)
2384 return {};
2385
2386 const StackFrameContext *CalleeContext = CEE->getCalleeContext();
2388 return {};
2389
2390
2393
2394
2395 if (cast(E)->isGLValue())
2396 if (std::optional LValue = RetVal.getAs<Loc>())
2397 RetVal = State->getSVal(*LValue);
2398
2399
2400 AnalyzerOptions &Options = State->getAnalysisManager().options;
2401
2402 bool EnableNullFPSuppression = false;
2404 if (std::optional RetLoc = RetVal.getAs<Loc>())
2405 EnableNullFPSuppression = State->isNull(*RetLoc).isConstrainedTrue();
2406
2408 Report.addVisitor(&getParentTracker(), CalleeContext,
2409 EnableNullFPSuppression, Options,
2411 return {true};
2412 }
2413};
2414
2415class DefaultExpressionHandler final : public ExpressionHandler {
2416public:
2418
2426
2427
2428
2430
2431
2433
2434
2435
2436
2437 bool CanDereference = true;
2438 if (const auto *SR = L->getRegionAs<SymbolicRegion>()) {
2439 if (SR->getPointeeStaticType()->isVoidType())
2440 CanDereference = false;
2442 CanDereference = false;
2443
2444
2445
2446
2449 RVal = LVState->getRawSVal(*L, Inner->getType());
2450 else if (CanDereference)
2451 RVal = LVState->getSVal(L->getRegion());
2452
2453 if (CanDereference) {
2455 Result.FoundSomethingToTrack = true;
2456
2458 Result.combineWith(
2459 getParentTracker().track(RVal, L->getRegion(), Opts, SFC));
2460 }
2461
2463 if (isa_and_nonnull(RegionRVal)) {
2464 Report.markInteresting(RegionRVal, Opts.Kind);
2467 false, "Assuming pointer value is null");
2468 Result.FoundSomethingToTrack = true;
2469 }
2470 }
2471
2472 return Result;
2473 }
2474};
2475
2476
2477
2479public:
2481
2486 return {};
2487
2489 if (!RVNode)
2490 return {};
2491
2494
2495 const auto track = [&CombinedResult, &Parent, ExprNode,
2496 Opts](const Expr *Inner) {
2497 CombinedResult.combineWith(Parent.track(Inner, ExprNode, Opts));
2498 };
2499
2500
2501
2502
2503
2504
2505 if (const auto *ILE = dyn_cast(E)) {
2506 if (ILE->getNumInits() == 1) {
2507 track(ILE->getInit(0));
2508
2509 return CombinedResult;
2510 }
2511
2512 return {};
2513 }
2514
2517 const auto *BO = dyn_cast(E);
2518
2519 if (!BO || !BO->isMultiplicativeOp() || .isZeroConstant())
2520 return {};
2521
2524
2525
2526 if (BO->getOpcode() == BO_Mul) {
2528 track(BO->getLHS());
2530 track(BO->getRHS());
2531 } else {
2533 track(BO->getLHS());
2534 }
2535
2536 return CombinedResult;
2537 }
2538};
2539}
2540
2542
2543 addLowPriorityHandler();
2544 addLowPriorityHandler();
2545 addLowPriorityHandler();
2546 addLowPriorityHandler();
2547 addLowPriorityHandler();
2548 addLowPriorityHandler();
2549 addLowPriorityHandler();
2550
2551 addHighPriorityHandler();
2552}
2553
2556 if ( || !N)
2557 return {};
2558
2561 if (!LVNode)
2562 return {};
2563
2564 Result CombinedResult;
2565
2566 for (ExpressionHandlerPtr &Handler : ExpressionHandlers) {
2567 CombinedResult.combineWith(Handler->handle(Inner, N, LVNode, Opts));
2569
2570
2572 break;
2573 }
2574 }
2575
2576 return CombinedResult;
2577}
2578
2581 if (.isUnknown()) {
2582 Report.addVisitor(this, V, R, Opts, Origin);
2583 return {true};
2584 }
2585 return {};
2586}
2587
2590
2591 for (StoreHandlerPtr &Handler : StoreHandlers) {
2593
2594
2596 }
2597 return {};
2598}
2599
2602
2606 ->track(E, InputNode, Opts)
2607 .FoundSomethingToTrack;
2608}
2609
2615}
2616
2617
2618
2619
2620
2623 const auto *ME = dyn_cast(S);
2624 if (!ME)
2625 return nullptr;
2626 if (const Expr *Receiver = ME->getInstanceReceiver()) {
2629 if (state->isNull(V).isConstrainedTrue())
2630 return Receiver;
2631 }
2632 return nullptr;
2633}
2634
2639 if ()
2640 return nullptr;
2641
2642 const Stmt *S = P->getStmt();
2643 const Expr *Receiver = getNilReceiver(S, N);
2644 if (!Receiver)
2645 return nullptr;
2646
2648 llvm::raw_svector_ostream OS(Buf);
2649
2650 if (const auto *ME = dyn_cast(S)) {
2651 OS << "'";
2652 ME->getSelector().print(OS);
2653 OS << "' not called";
2654 }
2655 else {
2656 OS << "No method is called";
2657 }
2658 OS << " because the receiver is nil";
2659
2660
2661
2662
2665 false});
2666
2669 return std::make_shared(L, OS.str());
2670}
2671
2672
2673
2674
2675
2676
2677
2679
2683 auto piece = VisitNodeImpl(N, BRC, BR);
2684 if (piece) {
2685 piece->setTag(getTag());
2686 if (auto *ev = dyn_cast(piece.get()))
2687 ev->setPrunable(true, false);
2688 }
2689 return piece;
2690}
2691
2697 const std::pair<const ProgramPointTag *, const ProgramPointTag *> &Tags =
2699
2700
2701
2702 if (std::optional BE = ProgPoint.getAs<BlockEdge>()) {
2703 const CFGBlock *SrcBlock = BE->getSrc();
2705
2706
2707
2708
2711 if (PreviousNodeTag == Tags.first || PreviousNodeTag == Tags.second)
2712 return nullptr;
2713
2714 return VisitTerminator(Term, N, SrcBlock, BE->getDst(), BR, BRC);
2715 }
2716 return nullptr;
2717 }
2718
2719 if (std::optional PS = ProgPoint.getAs<PostStmt>()) {
2721 if (CurrentNodeTag != Tags.first && CurrentNodeTag != Tags.second)
2722 return nullptr;
2723
2724 bool TookTrue = CurrentNodeTag == Tags.first;
2725 return VisitTrueTest(cast(PS->getStmt()), BRC, BR, N, TookTrue);
2726 }
2727
2728 return nullptr;
2729}
2730
2735 const Expr *Cond = nullptr;
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2751
2752
2753 default:
2754 return nullptr;
2755 case Stmt::IfStmtClass:
2756 Cond = cast(Term)->getCond();
2757 break;
2758 case Stmt::ConditionalOperatorClass:
2759 Cond = cast(Term)->getCond();
2760 break;
2761 case Stmt::BinaryOperatorClass:
2762
2763
2764
2765 const auto *BO = cast(Term);
2766 assert(BO->isLogicalOp() &&
2767 "CFG terminator is not a short-circuit operator!");
2768 Cond = BO->getLHS();
2769 break;
2770 }
2771
2773
2774
2775
2776
2777 while (const auto *InnerBO = dyn_cast(Cond)) {
2778 if (!InnerBO->isLogicalOp())
2779 break;
2781 }
2782
2783 assert(Cond);
2784 assert(srcBlk->succ_size() == 2);
2785 const bool TookTrue = *(srcBlk->succ_begin()) == dstBlk;
2786 return VisitTrueTest(Cond, BRC, R, N, TookTrue);
2787}
2788
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811 bool IsAssuming =
2813 CurrentState->getSVal(Cond, LCtx).isUnknownOrUndef();
2814
2815
2816
2817 const Expr *CondTmp = Cond;
2818 bool TookTrueTmp = TookTrue;
2819
2820 while (true) {
2823 default:
2824 break;
2825 case Stmt::BinaryOperatorClass:
2826 if (auto P = VisitTrueTest(Cond, cast(CondTmp),
2827 BRC, R, N, TookTrueTmp, IsAssuming))
2828 return P;
2829 break;
2830 case Stmt::DeclRefExprClass:
2831 if (auto P = VisitTrueTest(Cond, cast(CondTmp),
2832 BRC, R, N, TookTrueTmp, IsAssuming))
2833 return P;
2834 break;
2835 case Stmt::MemberExprClass:
2836 if (auto P = VisitTrueTest(Cond, cast(CondTmp),
2837 BRC, R, N, TookTrueTmp, IsAssuming))
2838 return P;
2839 break;
2840 case Stmt::UnaryOperatorClass: {
2841 const auto *UO = cast(CondTmp);
2842 if (UO->getOpcode() == UO_LNot) {
2843 TookTrueTmp = !TookTrueTmp;
2844 CondTmp = UO->getSubExpr();
2845 continue;
2846 }
2847 break;
2848 }
2849 }
2850 break;
2851 }
2852
2853
2854
2855
2856
2857 if (!IsAssuming)
2858 return nullptr;
2859
2862 return nullptr;
2863
2864 return std::make_shared(
2865 Loc, TookTrue ? GenericTrueMessage : GenericFalseMessage);
2866}
2867
2872 std::optional &prunable,
2873 bool IsSameFieldName) {
2874 const Expr *OriginalExpr = Ex;
2876
2879
2880
2890 return false;
2891 }
2892 }
2893 }
2894
2895 if (const auto *DR = dyn_cast(Ex)) {
2896 const bool quotes = isa(DR->getDecl());
2897 if (quotes) {
2898 Out << '\'';
2901 if (const MemRegion *R = state->getLValue(cast(DR->getDecl()),
2904 prunable = false;
2905 else {
2909 prunable = false;
2910 }
2911 }
2912 }
2913 Out << DR->getDecl()->getDeclName().getAsString();
2914 if (quotes)
2915 Out << '\'';
2916 return quotes;
2917 }
2918
2919 if (const auto *IL = dyn_cast(Ex)) {
2922 if (IL->getValue() == 0) {
2923 Out << "null";
2924 return false;
2925 }
2926 }
2928 if (IL->getValue() == 0) {
2929 Out << "nil";
2930 return false;
2931 }
2932 }
2933
2934 Out << IL->getValue();
2935 return false;
2936 }
2937
2938 if (const auto *ME = dyn_cast(Ex)) {
2939 if (!IsSameFieldName)
2940 Out << "field '" << ME->getMemberDecl()->getName() << '\'';
2941 else
2942 Out << '\''
2946 nullptr)
2947 << '\'';
2948 }
2949
2950 return false;
2951}
2952
2956 bool IsAssuming) {
2957 bool shouldInvert = false;
2958 std::optional shouldPrune;
2959
2960
2961
2962 bool IsSameFieldName = false;
2965
2966 if (LhsME && RhsME)
2967 IsSameFieldName =
2968 LhsME->getMemberDecl()->getName() == RhsME->getMemberDecl()->getName();
2969
2971 {
2972 llvm::raw_svector_ostream OutLHS(LhsString), OutRHS(RhsString);
2973 const bool isVarLHS = patternMatch(BExpr->getLHS(), BExpr, OutLHS, BRC, R,
2974 N, shouldPrune, IsSameFieldName);
2975 const bool isVarRHS = patternMatch(BExpr->getRHS(), BExpr, OutRHS, BRC, R,
2976 N, shouldPrune, IsSameFieldName);
2977
2978 shouldInvert = !isVarLHS && isVarRHS;
2979 }
2980
2982
2984
2985
2986 return VisitConditionVariable(LhsString, BExpr->getLHS(), BRC, R, N,
2987 TookTrue);
2988 }
2989
2990
2991
2992 if (LhsString.empty() || RhsString.empty() ||
2994 return nullptr;
2995
2996
2998 llvm::raw_svector_ostream Out(buf);
2999 Out << (IsAssuming ? "Assuming " : "")
3000 << (shouldInvert ? RhsString : LhsString) << " is ";
3001
3002
3003 if (shouldInvert)
3004 switch (Op) {
3005 default: break;
3006 case BO_LT: Op = BO_GT; break;
3007 case BO_GT: Op = BO_LT; break;
3008 case BO_LE: Op = BO_GE; break;
3009 case BO_GE: Op = BO_LE; break;
3010 }
3011
3012 if (!TookTrue)
3013 switch (Op) {
3014 case BO_EQ: Op = BO_NE; break;
3015 case BO_NE: Op = BO_EQ; break;
3016 case BO_LT: Op = BO_GE; break;
3017 case BO_GT: Op = BO_LE; break;
3018 case BO_LE: Op = BO_GT; break;
3019 case BO_GE: Op = BO_LT; break;
3020 default:
3021 return nullptr;
3022 }
3023
3024 switch (Op) {
3025 case BO_EQ:
3026 Out << "equal to ";
3027 break;
3028 case BO_NE:
3029 Out << "not equal to ";
3030 break;
3031 default:
3033 break;
3034 }
3035
3036 Out << (shouldInvert ? LhsString : RhsString);
3039
3043
3044
3045 std::string Message = std::string(Out.str());
3046 Message[0] = toupper(Message[0]);
3047
3048
3049 if (!IsAssuming) {
3051 if (!shouldInvert) {
3052 if (LhsME && LhsME->getMemberLoc().isValid())
3054 else
3056 } else {
3057 if (RhsME && RhsME->getMemberLoc().isValid())
3059 else
3061 }
3062
3063 return std::make_shared(Loc, Message);
3064 }
3065
3067 auto event = std::make_shared(Loc, Message);
3068 if (shouldPrune)
3069 event->setPrunable(*shouldPrune);
3070 return event;
3071}
3072
3076
3077
3078
3080 llvm::raw_svector_ostream Out(buf);
3081 Out << "Assuming " << LhsString << " is ";
3082
3083 if (!printValue(CondVarExpr, Out, N, TookTrue, true))
3084 return nullptr;
3085
3088
3091
3092 auto event = std::make_shared(Loc, Out.str());
3093
3095 event->setPrunable(false);
3096
3097 return event;
3098}
3099
3103 bool IsAssuming) {
3104 const auto *VD = dyn_cast(DRE->getDecl());
3105 if (!VD)
3106 return nullptr;
3107
3109 llvm::raw_svector_ostream Out(Buf);
3110
3111 Out << (IsAssuming ? "Assuming '" : "'") << VD->getDeclName() << "' is ";
3112
3113 if (!printValue(DRE, Out, N, TookTrue, IsAssuming))
3114 return nullptr;
3115
3117
3120
3121
3122 if (!IsAssuming) {
3124 return std::make_shared(Loc, Out.str());
3125 }
3126
3128 auto event = std::make_shared(Loc, Out.str());
3129
3131 event->setPrunable(false);
3132
3133 return std::move(event);
3134}
3135
3139 bool IsAssuming) {
3141 llvm::raw_svector_ostream Out(Buf);
3142
3143 Out << (IsAssuming ? "Assuming field '" : "Field '")
3145
3146 if (!printValue(ME, Out, N, TookTrue, IsAssuming))
3147 return nullptr;
3148
3151
3152
3155 else
3157
3159 return nullptr;
3160
3163
3164
3165 if (!IsAssuming)
3166 return std::make_shared(Loc, Out.str());
3167
3168 auto event = std::make_shared(Loc, Out.str());
3170 event->setPrunable(false);
3171 return event;
3172}
3173
3176 bool IsAssuming) {
3178
3180 Out << (TookTrue ? "non-null" : "null");
3181 return true;
3182 }
3183
3185 Out << (TookTrue ? "non-nil" : "nil");
3186 return true;
3187 }
3188
3190 return false;
3191
3192 std::optional<const llvm::APSInt *> IntValue;
3193 if (!IsAssuming)
3195
3196 if (IsAssuming || !IntValue) {
3198 Out << (TookTrue ? "true" : "false");
3199 else
3200 Out << (TookTrue ? "not equal to 0" : "0");
3201 } else {
3203 Out << ((*IntValue)->getBoolValue() ? "true" : "false");
3204 else
3205 Out << **IntValue;
3206 }
3207
3208 return true;
3209}
3210
3211constexpr llvm::StringLiteral ConditionBRVisitor::GenericTrueMessage;
3212constexpr llvm::StringLiteral ConditionBRVisitor::GenericFalseMessage;
3213
3216 return Piece->getString() == GenericTrueMessage ||
3217 Piece->getString() == GenericFalseMessage;
3218}
3219
3220
3221
3222
3223
3227
3228
3231
3233
3234
3235
3236
3237 if (Options.ShouldSuppressFromCXXStandardLibrary) {
3239 return;
3240 } else {
3241
3242
3243
3244
3245
3246
3247 if (const auto *MD = dyn_cast(D)) {
3249 if (CD->getName() == "list") {
3251 return;
3252 }
3253 }
3254
3255
3256
3257 if (const auto *MD = dyn_cast(D)) {
3259 if (CD->getName() == "__independent_bits_engine") {
3261 return;
3262 }
3263 }
3264
3267 const auto *MD = dyn_cast(LCtx->getDecl());
3268 if (!MD)
3269 continue;
3270
3272
3273
3274
3275
3276
3277
3278 if (CD->getName() == "basic_string") {
3280 return;
3281 }
3282
3283
3284
3285
3286 if (CD->getName() == "shared_ptr") {
3288 return;
3289 }
3290 }
3291 }
3292 }
3293
3294
3295
3298 while (Loc.isMacroID()) {
3299 Loc = Loc.getSpellingLoc();
3300 if (SM.getFilename(Loc).ends_with("sys/queue.h")) {
3302 return;
3303 }
3304 }
3305}
3306
3307
3308
3309
3310
3316
3317
3318 std::optional CEnter = ProgLoc.getAs<CallEnter>();
3319 if (!CEnter)
3320 return nullptr;
3321
3322
3325 unsigned Idx = 0;
3327
3328 for (const auto ParamDecl : parms) {
3329 const MemRegion *ArgReg = Call->getArgSVal(Idx).getAsRegion();
3330 ++Idx;
3331
3332
3334 continue;
3335
3336
3337 assert(ParamDecl && "Formal parameter has no decl?");
3338 QualType T = ParamDecl->getType();
3339
3341
3342 continue;
3343 }
3344
3345
3346
3348 continue;
3349
3350
3351
3352 SVal BoundVal = State->getSVal(R);
3355 return nullptr;
3356 }
3357 }
3358 return nullptr;
3359}
3360
3361
3362
3363
3364
3365int NoteTag::Kind = 0;
3366
3368 static int Tag = 0;
3369 ID.AddPointer(&Tag);
3370}
3371
3376 const NoteTag *T = dyn_cast_or_null(PP.getTag());
3377 if ()
3378 return nullptr;
3379
3380 if (std::optionalstd::string Msg = T->generateMessage(BRC, R)) {
3383 auto Piece = std::make_shared(Loc, *Msg);
3384 Piece->setPrunable(T->isPrunable());
3385 return Piece;
3386 }
3387
3388 return nullptr;
3389}
Defines the clang::ASTContext interface.
This file defines AnalysisDeclContext, a class that manages the analysis context data for context sen...
static bool isInterestingExpr(const Expr *E, const ExplodedNode *N, const PathSensitiveBugReport *B)
static const ExplodedNode * findNodeForExpression(const ExplodedNode *N, const Expr *Inner)
Find the ExplodedNode where the lvalue (the value of 'Ex') was computed.
static void showBRParamDiagnostics(llvm::raw_svector_ostream &OS, StoreInfo SI)
Display diagnostics for passing bad region as a parameter.
static const Expr * peelOffPointerArithmetic(const BinaryOperator *B)
static const Expr * tryExtractInitializerFromList(const InitListExpr *ILE, const MemRegion *R)
static bool wasRegionOfInterestModifiedAt(const SubRegion *RegionOfInterest, const ExplodedNode *N, SVal ValueAfter)
static llvm::StringLiteral WillBeUsedForACondition
static bool isFunctionMacroExpansion(SourceLocation Loc, const SourceManager &SM)
static std::shared_ptr< PathDiagnosticEventPiece > constructDebugPieceForTrackedCondition(const Expr *Cond, const ExplodedNode *N, BugReporterContext &BRC)
static const MemRegion * getLocationRegionIfReference(const Expr *E, const ExplodedNode *N, bool LookingForReference=true)
static bool hasVisibleUpdate(const ExplodedNode *LeftNode, SVal LeftVal, const ExplodedNode *RightNode, SVal RightVal)
Comparing internal representations of symbolic values (via SVal::operator==()) is a valid way to chec...
static bool potentiallyWritesIntoIvar(const Decl *Parent, const ObjCIvarDecl *Ivar)
static std::optional< const llvm::APSInt * > getConcreteIntegerValue(const Expr *CondVarExpr, const ExplodedNode *N)
static bool isVarAnInterestingCondition(const Expr *CondVarExpr, const ExplodedNode *N, const PathSensitiveBugReport *B)
static void showBRDefaultDiagnostics(llvm::raw_svector_ostream &OS, StoreInfo SI)
Show default diagnostics for storing bad region.
static std::optional< SVal > getSValForVar(const Expr *CondVarExpr, const ExplodedNode *N)
static const Expr * peelOffOuterExpr(const Expr *Ex, const ExplodedNode *N)
static const VarDecl * getVarDeclForExpression(const Expr *E)
static bool isTrivialCopyOrMoveCtor(const CXXConstructExpr *CE)
static StringRef getMacroName(SourceLocation Loc, BugReporterContext &BRC)
static bool isObjCPointer(const MemRegion *R)
static bool isAssertlikeBlock(const CFGBlock *B, ASTContext &Context)
static bool isInitializationOfVar(const ExplodedNode *N, const VarRegion *VR)
Returns true if N represents the DeclStmt declaring and initializing VR.
static const ExplodedNode * getMatchingCallExitEnd(const ExplodedNode *N)
static void showBRDiagnostics(llvm::raw_svector_ostream &OS, StoreInfo SI)
Show diagnostics for initializing or declaring a region R with a bad value.
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
Defines the clang::Expr interface and subclasses for C++ expressions.
Defines the clang::IdentifierInfo, clang::IdentifierTable, and clang::Selector interfaces.
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
Defines the clang::SourceLocation class and associated facilities.
Defines the SourceManager interface.
C Language Family Type Representation.
static bool isPointerToConst(const QualType &QT)
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
const LangOptions & getLangOpts() const
CFGStmtMap * getCFGStmtMap()
static bool isInStdNamespace(const Decl *D)
Stores options for the analyzer from the command line.
AnalysisDiagClients AnalysisDiagOpt
A builtin binary operation expression such as "x + y" or "x <= y".
bool isComparisonOp() const
StringRef getOpcodeStr() const
static bool isAdditiveOp(Opcode Opc)
bool isAssignmentOp() const
Represents a single basic block in a source-level CFG.
bool isInevitablySinking() const
Returns true if the block would eventually end with a sink (a noreturn node).
succ_iterator succ_begin()
Stmt * getTerminatorStmt()
const Expr * getLastCondition() const
Stmt * getTerminatorCondition(bool StripParens=true)
unsigned succ_size() const
CFGBlock * getBlock(Stmt *S)
Returns the CFGBlock the specified Stmt* appears in.
unsigned size() const
Return the total number of CFGBlocks within the CFG This is simply a renaming of the getNumBlockIDs()...
bool isLinear() const
Returns true if the CFG has no branches.
A boolean literal, per ([C++ lex.bool] Boolean literals).
Represents a call to a C++ constructor.
CXXConstructorDecl * getConstructor() const
Get the constructor that this expression will (ultimately) call.
bool isCopyOrMoveConstructor(unsigned &TypeQuals) const
Determine whether this is a copy or move constructor.
Represents a C++ struct/union/class.
Represents a point when we begin processing an inlined call.
Represents a point when we start the call exit sequence (for inlined call).
Represents a point when we finish the call exit sequence (for inlined call).
Represents a character-granular source range.
static CharSourceRange getTokenRange(SourceRange R)
DeclContext * getParent()
getParent - Returns the containing DeclContext.
A reference to a declared variable, function, enum, etc.
DeclStmt - Adaptor class for mixing declarations with statements and expressions.
const Decl * getSingleDecl() const
Decl - This represents one declaration (or definition), e.g.
This represents one expression.
Expr * IgnoreParenCasts() LLVM_READONLY
Skip past any parentheses and casts which might surround this expression until reaching a fixed point...
Expr * IgnoreParens() LLVM_READONLY
Skip past any parentheses which might surround this expression until reaching a fixed point.
Expr * IgnoreImpCasts() LLVM_READONLY
Skip past any implicit casts which might surround this expression until reaching a fixed point.
Represents a member of a struct/union/class.
A SourceLocation and its associated SourceManager.
GNUNullExpr - Implements the GNU __null extension, which is a name for a null pointer constant that h...
Describes an C or C++ initializer list.
unsigned getNumInits() const
const Expr * getInit(unsigned Init) const
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
static StringRef getSourceText(CharSourceRange Range, const SourceManager &SM, const LangOptions &LangOpts, bool *Invalid=nullptr)
Returns a string for the source that the range encompasses.
static StringRef getImmediateMacroName(SourceLocation Loc, const SourceManager &SM, const LangOptions &LangOpts)
Retrieve the name of the immediate macro expansion.
static CharSourceRange getAsCharRange(SourceRange Range, const SourceManager &SM, const LangOptions &LangOpts)
Given a token range, produce a corresponding CharSourceRange that is not a token range.
static bool isAtStartOfMacroExpansion(SourceLocation loc, const SourceManager &SM, const LangOptions &LangOpts, SourceLocation *MacroBegin=nullptr)
Returns true if the given MacroID location points at the first token of the macro expansion.
static bool isAtEndOfMacroExpansion(SourceLocation loc, const SourceManager &SM, const LangOptions &LangOpts, SourceLocation *MacroEnd=nullptr)
Returns true if the given MacroID location points at the last token of the macro expansion.
It wraps the AnalysisDeclContext to represent both the call stack with the help of StackFrameContext ...
bool isParentOf(const LocationContext *LC) const
const Decl * getDecl() const
LLVM_ATTRIBUTE_RETURNS_NONNULL AnalysisDeclContext * getAnalysisDeclContext() const
const LocationContext * getParent() const
It might return null.
const StackFrameContext * getStackFrame() const
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
SourceLocation getMemberLoc() const
getMemberLoc - Return the location of the "member", in X->F, it is the location of 'F'.
ValueDecl * getMemberDecl() const
Retrieve the member declaration to which this expression refers.
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
std::string getNameAsString() const
Get a human-readable name for the declaration, even if it is one of the special kinds of names (C++ c...
ObjCBoolLiteralExpr - Objective-C Boolean Literal.
ObjCIvarDecl - Represents an ObjC instance variable.
ObjCIvarRefExpr - A reference to an ObjC instance variable.
Represents a parameter to a function.
Represents a program point after a store evaluation.
ProgramPoints can be "tagged" as representing points specific to a given analysis entity.
const ProgramPointTag * getTag() const
std::optional< T > getAs() const
Convert to the specified ProgramPoint type, returning std::nullopt if this ProgramPoint is not of the...
A (possibly-)qualified type.
bool isNull() const
Return true if this QualType doesn't point to a type yet.
QualType getCanonicalType() const
bool isConstQualified() const
Determine whether this type is const-qualified.
Represents a struct/union/class.
field_range fields() const
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
This class handles loading and caching of source files into memory.
A trivial tuple used to represent a source range.
Each ExpansionInfo encodes the expansion location - where the token was ultimately expanded,...
bool isFunctionMacroExpansion() const
This is a discriminated union of FileInfo and ExpansionInfo.
const ExpansionInfo & getExpansion() const
It represents a stack frame of the call stack (based on CallEvent).
const Stmt * getCallSite() const
bool inTopFrame() const override
const Stmt * getStmt() const
Stmt - This represents one statement.
SourceLocation getEndLoc() const LLVM_READONLY
StmtClass getStmtClass() const
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
SourceLocation getBeginLoc() const LLVM_READONLY
bool isBooleanType() const
bool isPointerType() const
bool isReferenceType() const
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
bool isIntegralOrEnumerationType() const
Determine whether this type is an integral or enumeration type.
bool isObjCObjectPointerType() const
bool isAnyPointerType() const
RecordDecl * getAsRecordDecl() const
Retrieves the RecordDecl this type refers to.
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Represents a variable declaration or definition.
bool isStaticLocal() const
Returns true if a variable with function scope is a static local variable.
bool hasLocalStorage() const
Returns true if a variable with function scope is a non-static local variable.
Maps string IDs to AST nodes matched by parts of a matcher.
AllocaRegion - A region that represents an untyped blob of bytes created by a call to 'alloca'.
StringRef getDescription() const
A verbose warning message that is appropriate for displaying next to the source code that introduces ...
ASTContext & getASTContext() const
ProgramStateManager & getStateManager() const
const SourceManager & getSourceManager() const
const AnalyzerOptions & getAnalyzerOptions() const
BugReporterVisitors are used to add custom diagnostics along a path.
static PathDiagnosticPieceRef getDefaultEndPath(const BugReporterContext &BRC, const ExplodedNode *N, const PathSensitiveBugReport &BR)
Generates the default final diagnostic piece.
virtual PathDiagnosticPieceRef getEndPath(BugReporterContext &BRC, const ExplodedNode *N, PathSensitiveBugReport &BR)
Provide custom definition for the final diagnostic piece on the path - the piece, which is displayed ...
virtual void finalizeVisitor(BugReporterContext &BRC, const ExplodedNode *EndPathNode, PathSensitiveBugReport &BR)
Last function called on the visitor, no further calls to VisitNode would follow.
Represents a call to a C++ constructor.
Manages the lifetime of CallEvent objects.
CallEventRef getCaller(const StackFrameContext *CalleeCtx, ProgramStateRef State)
Gets an outside caller given a callee context.
Represents an abstract call to a function or method along a particular path.
static bool isCallStmt(const Stmt *S)
Returns true if this is a statement is a function or method call of some kind.
PathDiagnosticPieceRef VisitTerminator(const Stmt *Term, const ExplodedNode *N, const CFGBlock *SrcBlk, const CFGBlock *DstBlk, PathSensitiveBugReport &R, BugReporterContext &BRC)
bool printValue(const Expr *CondVarExpr, raw_ostream &Out, const ExplodedNode *N, bool TookTrue, bool IsAssuming)
Tries to print the value of the given expression.
PathDiagnosticPieceRef VisitNode(const ExplodedNode *N, BugReporterContext &BRC, PathSensitiveBugReport &BR) override
Return a diagnostic piece which should be associated with the given node.
bool patternMatch(const Expr *Ex, const Expr *ParentEx, raw_ostream &Out, BugReporterContext &BRC, PathSensitiveBugReport &R, const ExplodedNode *N, std::optional< bool > &prunable, bool IsSameFieldName)
static bool isPieceMessageGeneric(const PathDiagnosticPiece *Piece)
PathDiagnosticPieceRef VisitConditionVariable(StringRef LhsString, const Expr *CondVarExpr, BugReporterContext &BRC, PathSensitiveBugReport &R, const ExplodedNode *N, bool TookTrue)
PathDiagnosticPieceRef VisitTrueTest(const Expr *Cond, BugReporterContext &BRC, PathSensitiveBugReport &R, const ExplodedNode *N, bool TookTrue)
static const char * getTag()
Return the tag associated with this visitor.
PathDiagnosticPieceRef VisitNodeImpl(const ExplodedNode *N, BugReporterContext &BRC, PathSensitiveBugReport &BR)
bool isConstrainedTrue() const
Return true if the constraint is perfectly constrained to 'true'.
bool isValid() const =delete
static bool isInterestingLValueExpr(const Expr *Ex)
Returns true if nodes for the given expression kind are always kept around.
const CFGBlock * getCFGBlock() const
const ProgramStateRef & getState() const
const Stmt * getStmtForDiagnostics() const
If the node's program point corresponds to a statement, retrieve that statement.
ProgramPoint getLocation() const
getLocation - Returns the edge associated with the given node.
ExplodedNode * getFirstSucc()
const StackFrameContext * getStackFrame() const
SVal getSVal(const Stmt *S) const
Get the value of an arbitrary expression at this node.
const LocationContext * getLocationContext() const
std::optional< T > getLocationAs() const &
ExplodedNode * getFirstPred()
unsigned succ_size() const
static std::pair< const ProgramPointTag *, const ProgramPointTag * > getEagerlyAssumeBifurcationTags()
LLVM_ATTRIBUTE_RETURNS_NONNULL const FieldDecl * getDecl() const override
void finalizeVisitor(BugReporterContext &BRC, const ExplodedNode *N, PathSensitiveBugReport &BR) override
Last function called on the visitor, no further calls to VisitNode would follow.
const FieldRegion * getFieldRegion(const FieldDecl *fd, const SubRegion *superRegion)
getFieldRegion - Retrieve or create the memory region associated with a specified FieldDecl.
MemRegion - The root abstract class for all memory regions.
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemSpaceRegion * getMemorySpace() const
virtual bool isBoundable() const
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * StripCasts(bool StripBaseAndDerivedCasts=true) const
virtual bool isSubRegionOf(const MemRegion *R) const
Check if the region is a subregion of the given region.
virtual void printPretty(raw_ostream &os) const
Print the region for use in diagnostics.
const RegionTy * getAs() const
virtual bool canPrintPretty() const
Returns true if this region can be printed in a user-friendly way.
MemSpaceRegion - A memory region that represents a "memory space"; for example, the set of global var...
PathDiagnosticPieceRef VisitNode(const ExplodedNode *N, BugReporterContext &BRC, PathSensitiveBugReport &BR) override
Return a diagnostic piece which should be associated with the given node.
static const Expr * getNilReceiver(const Stmt *S, const ExplodedNode *N)
If the statement is a message send expression with nil receiver, returns the receiver expression.
virtual bool wasModifiedBeforeCallExit(const ExplodedNode *CurrN, const ExplodedNode *CallExitBeginN)
virtual PathDiagnosticPieceRef maybeEmitNoteForObjCSelf(PathSensitiveBugReport &R, const ObjCMethodCall &Call, const ExplodedNode *N)=0
Consume the information on the non-modifying stack frame in order to either emit a note or not.
virtual PathDiagnosticPieceRef maybeEmitNoteForCXXThis(PathSensitiveBugReport &R, const CXXConstructorCall &Call, const ExplodedNode *N)=0
Consume the information on the non-modifying stack frame in order to either emit a note or not.
bugreporter::TrackingKind TKind
virtual bool wasModifiedInFunction(const ExplodedNode *CallEnterN, const ExplodedNode *CallExitEndN)
PathDiagnosticPieceRef VisitNode(const ExplodedNode *N, BugReporterContext &BR, PathSensitiveBugReport &R) final
Return a diagnostic piece which should be associated with the given node.
virtual PathDiagnosticPieceRef maybeEmitNoteForParameters(PathSensitiveBugReport &R, const CallEvent &Call, const ExplodedNode *N)=0
Consume the information on the non-modifying stack frame in order to either emit a note or not.
Put a diagnostic on return statement of all inlined functions for which the region of interest Region...
The tag upon which the TagVisitor reacts.
Represents any expression that calls an Objective-C method.
static PathDiagnosticLocation createBegin(const Decl *D, const SourceManager &SM)
Create a location for the beginning of the declaration.
FullSourceLoc asLocation() const
static PathDiagnosticLocation create(const Decl *D, const SourceManager &SM)
Create a location corresponding to the given declaration.
bool hasValidLocation() const
StringRef getString() const
void markInteresting(SymbolRef sym, bugreporter::TrackingKind TKind=bugreporter::TrackingKind::Thorough)
Marks a symbol as interesting.
PathDiagnosticLocation getLocation() const override
The primary location of the bug report that points at the undesirable behavior in the code.
ArrayRef< SourceRange > getRanges() const override
Get the SourceRanges associated with the report.
const ExplodedNode * getErrorNode() const
bool addTrackedCondition(const ExplodedNode *Cond)
Notes that the condition of the CFGBlock associated with Cond is being tracked.
void markInvalid(const void *Tag, const void *Data)
Marks the current report as invalid, meaning that it is probably a false positive and should not be r...
void addVisitor(std::unique_ptr< BugReporterVisitor > visitor)
Add custom or predefined bug report visitors to this report.
std::optional< bugreporter::TrackingKind > getInterestingnessKind(SymbolRef sym) const
bool isInteresting(SymbolRef sym) const
SValBuilder & getSValBuilder()
CallEventManager & getCallEventManager()
bool haveEqualConstraints(ProgramStateRef S1, ProgramStateRef S2) const
void iterBindings(ProgramStateRef state, StoreManager::BindingsHandler &F)
StoreManager & getStoreManager()
ProgramState - This class encapsulates:
Loc getLValue(const CXXBaseSpecifier &BaseSpec, const SubRegion *Super) const
Get the lvalue for a base class object reference.
SVal getSVal(const Stmt *S, const LocationContext *LCtx) const
Returns the SVal bound to the statement 'S' in the state's environment.
A Range represents the closed range [from, to].
ConditionTruthVal areEqual(ProgramStateRef state, SVal lhs, SVal rhs)
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
bool isZeroConstant() const
std::optional< T > getAs() const
Convert to the specified SVal type, returning std::nullopt if this SVal is not of the desired type.
const MemRegion * getAsRegion() const
SubRegion - A region that subsets another larger region.
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * getSuperRegion() const
bool isSubRegionOf(const MemRegion *R) const override
Check if the region is a subregion of the given region.
PathDiagnosticPieceRef VisitNode(const ExplodedNode *Succ, BugReporterContext &BRC, PathSensitiveBugReport &BR) override
Return a diagnostic piece which should be associated with the given node.
SuppressInlineDefensiveChecksVisitor(DefinedSVal Val, const ExplodedNode *N)
static const char * getTag()
Return the tag associated with this visitor.
void Profile(llvm::FoldingSetNodeID &ID) const override
SymbolicRegion - A special, "non-concrete" region.
void Profile(llvm::FoldingSetNodeID &ID) const override
PathDiagnosticPieceRef VisitNode(const ExplodedNode *N, BugReporterContext &BRC, PathSensitiveBugReport &R) override
Return a diagnostic piece which should be associated with the given node.
void Profile(llvm::FoldingSetNodeID &ID) const override
static const char * getTag()
Return the tag associated with this visitor.
PathDiagnosticPieceRef VisitNode(const ExplodedNode *N, BugReporterContext &BRC, PathSensitiveBugReport &BR) override
Return a diagnostic piece which should be associated with the given node.
When a region containing undefined value or '0' value is passed as an argument in a call,...
PathDiagnosticPieceRef VisitNode(const ExplodedNode *N, BugReporterContext &BRC, PathSensitiveBugReport &BR) override
Return a diagnostic piece which should be associated with the given node.
const VarDecl * getDecl() const override=0
Handles expressions during the tracking.
ExpressionHandler(Tracker &ParentTracker)
Handles stores during the tracking.
StoreHandler(Tracker &ParentTracker)
PathDiagnosticPieceRef constructNote(StoreInfo SI, BugReporterContext &BRC, StringRef NodeText)
A generalized component for tracking expressions, values, and stores.
static TrackerRef create(PathSensitiveBugReport &Report)
virtual PathDiagnosticPieceRef handle(StoreInfo SI, BugReporterContext &BRC, TrackingOptions Opts)
Handle the store operation and produce the note.
Tracker(PathSensitiveBugReport &Report)
virtual Result track(const Expr *E, const ExplodedNode *N, TrackingOptions Opts={})
Track expression value back to its point of origin.
Visitor that tracks expressions and values.
Value representing integer constant.
While nonloc::CompoundVal covers a few simple use cases, nonloc::LazyCompoundVal is a more performant...
LLVM_ATTRIBUTE_RETURNS_NONNULL const TypedValueRegion * getRegion() const
This function itself is immaterial.
const internal::VariadicDynCastAllOfMatcher< Stmt, ObjCIvarRefExpr > objcIvarRefExpr
Matches a reference to an ObjCIvar.
const internal::ArgumentAdaptingMatcherFunc< internal::HasDescendantMatcher > hasDescendant
Matches AST nodes that have descendant AST nodes that match the provided matcher.
SmallVector< BoundNodes, 1 > match(MatcherT Matcher, const NodeT &Node, ASTContext &Context)
Returns the results of matching Matcher on Node.
const internal::VariadicDynCastAllOfMatcher< Stmt, BinaryOperator > binaryOperator
Matches binary operator expressions.
internal::Matcher< Stmt > StatementMatcher
static std::string getMacroName(MacroType Macro, GtestCmp Cmp)
internal::PolymorphicMatcher< internal::HasDeclarationMatcher, void(internal::HasDeclarationSupportedTypes), internal::Matcher< Decl > > hasDeclaration(const internal::Matcher< Decl > &InnerMatcher)
Matches a node if the declaration associated with that node matches the given matcher.
const internal::VariadicAllOfMatcher< Stmt > stmt
Matches statements.
const Expr * getDerefExpr(const Stmt *S)
Given that expression S represents a pointer that would be dereferenced, try to find a sub-expression...
bool trackExpressionValue(const ExplodedNode *N, const Expr *E, PathSensitiveBugReport &R, TrackingOptions Opts={})
Attempts to add visitors to track expression value back to its point of origin.
void trackStoredValue(SVal V, const MemRegion *R, PathSensitiveBugReport &Report, TrackingOptions Opts={}, const StackFrameContext *Origin=nullptr)
Track how the value got stored into the given region and where it came from.
TrackingKind
Specifies the type of tracking for an expression.
@ Thorough
Default tracking kind – specifies that as much information should be gathered about the tracked expre...
@ Condition
Specifies that a more moderate tracking should be used for the expression value.
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
std::shared_ptr< PathDiagnosticPiece > PathDiagnosticPieceRef
bool Ret(InterpState &S, CodePtr &PC)
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
const FunctionProtoType * T
@ ObjCSelf
Parameter for Objective-C 'self' argument.
Describes an event when the value got stored into a memory region.
@ Assignment
The value got stored into the region during assignment: int x; x = 42;.
@ CallArgument
The value got stored into the parameter region as the result of a call.
@ BlockCapture
The value got stored into the region as block capture.
@ Initialization
The value got stored into the region during initialization: int x = 42;.
const Expr * SourceOfTheValue
The expression where the value comes from.
const ExplodedNode * StoreSite
The node where the store happened.
Kind StoreKind
The type of store operation.
SVal Value
Symbolic value that is being stored.
const MemRegion * Dest
Memory regions involved in the store operation.
Describes a tracking result with the most basic information of what was actually done (or not done).
void combineWith(const Result &Other)
Combines the current result with the given result.
bool WasInterrupted
Signifies that the tracking was interrupted at some point.
Defines a set of options altering tracking behavior.
bool EnableNullFPSuppression
Specifies whether we should employ false positive suppression (inlined defensive checks,...
TrackingKind Kind
Specifies the kind of tracking.