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"
98 const auto *E = dyn_cast<Expr>(S);
103 if (
const auto *CE = dyn_cast<CastExpr>(E)) {
104 if (CE->getCastKind() == CK_LValueToRValue) {
108 E = CE->getSubExpr();
109 }
else if (
const auto *B = dyn_cast<BinaryOperator>(E)) {
113 }
else if (B->isAssignmentOp()) {
121 }
else if (
const auto *
U = dyn_cast<UnaryOperator>(E)) {
122 if (
U->getOpcode() == UO_Deref ||
U->getOpcode() == UO_AddrOf ||
123 (
U->isIncrementDecrementOp() &&
U->getType()->isPointerType())) {
134 else if (
const auto *ME = dyn_cast<MemberExpr>(E)) {
143 if (ME->getMemberDecl()->getType()->isReferenceType())
146 }
else if (
const auto *IvarRef = dyn_cast<ObjCIvarRefExpr>(E)) {
147 E = IvarRef->getBase();
148 }
else if (
const auto *AE = dyn_cast<ArraySubscriptExpr>(E)) {
150 }
else if (
const auto *PE = dyn_cast<ParenExpr>(E)) {
151 E = PE->getSubExpr();
152 }
else if (
const auto *FE = dyn_cast<FullExpr>(E)) {
153 E = FE->getSubExpr();
163 if (
const auto *CE = dyn_cast<ImplicitCastExpr>(E))
164 if (CE->getCastKind() == CK_LValueToRValue)
165 E = CE->getSubExpr();
171 if (
const auto *DR = dyn_cast<DeclRefExpr>(E))
172 return dyn_cast<VarDecl>(DR->getDecl());
178 bool LookingForReference =
true) {
179 if (
const auto *ME = dyn_cast<MemberExpr>(E)) {
189 const auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl());
193 if (FD->getType()->isReferenceType()) {
195 return N->
getState()->getLValue(FD, StructSVal).getAsRegion();
218 if (LeftVal == RightVal)
229 return LLCV->
getRegion() == RLCV->getRegion() &&
230 LLCV->getStore() == LeftNode->
getState()->getStore() &&
231 RLCV->getStore() == RightNode->
getState()->getStore();
246 if (
const auto *DRE = dyn_cast<DeclRefExpr>(CondVarExpr))
247 if (
const auto *VD = dyn_cast<VarDecl>(DRE->getDecl()))
248 return State->getSVal(State->getLValue(VD, SF));
250 if (
const auto *ME = dyn_cast<MemberExpr>(CondVarExpr))
251 if (
const auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl()))
252 if (
auto FieldL = State->getSVal(ME, SF).getAs<
Loc>())
253 return State->getRawSVal(*FieldL, FD->getType());
258static std::optional<const llvm::APSInt *>
263 return CI->getValue().get();
277 if (std::optional<bugreporter::TrackingKind> K =
279 return *K == bugreporter::TrackingKind::Condition;
304 if (!
Loc.isMacroID())
335 SVal ValueAtN = N->
getState()->getSVal(RegionOfInterest);
337 .
areEqual(State, ValueAtN, ValueAfter)
368 auto P = std::make_shared<PathDiagnosticEventPiece>(
380bool NoStateChangeFuncVisitor::isModifiedInFrame(
const ExplodedNode *N) {
382 if (!FramesModifyingCalculated.count(SF))
383 findModifyingFrames(N);
384 return FramesModifying.count(SF);
387void NoStateChangeFuncVisitor::markFrameAsModifying(
const StackFrame *SF) {
389 auto p = FramesModifying.insert(SF);
405 auto IsMatchingCallExitEnd = [OrigSF](
const ExplodedNode *N) {
409 while (N && !IsMatchingCallExitEnd(N)) {
411 "This function is to be used on the trimmed ExplodedGraph!");
417void NoStateChangeFuncVisitor::findModifyingFrames(
422 const StackFrame *
const OriginalSF = CallExitBeginN->
getStackFrame();
424 const ExplodedNode *CurrCallExitBeginN = CallExitBeginN;
425 const StackFrame *CurrentSF = OriginalSF;
427 for (
const ExplodedNode *CurrN = CallExitBeginN; CurrN;
428 CurrN = CurrN->getFirstPred()) {
430 if (CurrN->getLocationAs<CallExitBegin>()) {
431 CurrCallExitBeginN = CurrN;
432 CurrentSF = CurrN->getStackFrame();
433 FramesModifyingCalculated.insert(CurrentSF);
438 if (
auto CE = CurrN->getLocationAs<CallEnter>()) {
441 markFrameAsModifying(CurrentSF);
444 CurrentSF = CurrN->getStackFrame();
452 if (CE->getCalleeStackFrame() == OriginalSF) {
453 markFrameAsModifying(CurrentSF);
459 markFrameAsModifying(CurrentSF);
471 if (!CallExitLoc || isModifiedInFrame(N))
486 if (
Call->isInSystemHeader()) {
496 R.markInvalid(&i,
nullptr);
501 if (
const auto *MC = dyn_cast<ObjCMethodCall>(
Call)) {
508 if (
const auto *CCall = dyn_cast<CXXConstructorCall>(
Call)) {
522 const char *IvarBind =
"Ivar";
529 hasOperatorName(
"="),
530 hasLHS(ignoringParenImpCasts(
536 if (IvarRef->isFreeIvar())
539 const Expr *
Base = IvarRef->getBase();
540 if (
const auto *ICE = dyn_cast<ImplicitCastExpr>(
Base))
541 Base = ICE->getSubExpr();
543 if (
const auto *DRE = dyn_cast<DeclRefExpr>(
Base))
544 if (
const auto *ID = dyn_cast<ImplicitParamDecl>(DRE->getDecl()))
559const std::optional<NoStoreFuncVisitor::RegionVector>
560NoStoreFuncVisitor::findRegionOfInterestInRecord(
562 const NoStoreFuncVisitor::RegionVector &Vec ,
565 if (depth == DEREFERENCE_LIMIT)
568 if (
const auto *RDX = dyn_cast<CXXRecordDecl>(RD))
569 if (!RDX->hasDefinition())
574 if (
const auto *RDX = dyn_cast<CXXRecordDecl>(RD))
575 for (
const auto &II : RDX->bases())
576 if (
const RecordDecl *RRD = II.getType()->getAsRecordDecl())
577 if (std::optional<RegionVector> Out =
578 findRegionOfInterestInRecord(RRD, State, R, Vec, depth))
581 for (
const FieldDecl *I : RD->
fields()) {
582 QualType FT = I->getType();
584 const SVal
V = State->getSVal(FR);
585 const MemRegion *VR =
V.getAsRegion();
587 RegionVector VecF = Vec;
590 if (RegionOfInterest == VR)
595 findRegionOfInterestInRecord(RRD, State, FR, VecF, depth + 1))
603 if (std::optional<RegionVector> Out =
604 findRegionOfInterestInRecord(RRD, State, VR, VecF, depth + 1))
615 if (
const auto *IvarR = dyn_cast<ObjCIvarRegion>(RegionOfInterest)) {
616 const MemRegion *SelfRegion =
Call.getReceiverSVal().getAsRegion();
617 if (RegionOfInterest->isSubRegionOf(SelfRegion) &&
620 return maybeEmitNote(R,
Call, N, {}, SelfRegion,
"self",
630 const MemRegion *ThisR =
Call.getCXXThisVal().getAsRegion();
631 if (RegionOfInterest->isSubRegionOf(ThisR) && !
Call.getDecl()->isImplicit())
632 return maybeEmitNote(R,
Call, N, {}, ThisR,
"this",
649 for (
unsigned I = 0; I <
Call.getNumArgs() && I <
Parameters.size(); ++I) {
651 SVal
V =
Call.getArgSVal(I);
655 unsigned IndirectionLevel = 1;
657 while (
const MemRegion *MR =
V.getAsRegion()) {
659 return maybeEmitNote(R,
Call, N, {}, MR, ParamName,
660 ParamIsReferenceType, IndirectionLevel);
663 if (PT.isNull() || PT->isVoidType())
668 if (
const RecordDecl *RD = PT->getAsRecordDecl())
669 if (std::optional<RegionVector> P =
670 findRegionOfInterestInRecord(RD, State, MR))
671 return maybeEmitNote(R,
Call, N, *P, RegionOfInterest, ParamName,
672 ParamIsReferenceType, IndirectionLevel);
674 V = State->getSVal(MR, PT);
683bool NoStoreFuncVisitor::wasModifiedBeforeCallExit(
685 return ::wasRegionOfInterestModifiedAt(
686 RegionOfInterest, CurrN,
687 CallExitBeginN->
getState()->getSVal(RegionOfInterest));
691 ", which participates in a condition later";
695 const RegionVector &FieldChain,
const MemRegion *MatchedRegion,
696 StringRef FirstElement,
bool FirstIsReferenceType,
697 unsigned IndirectionLevel) {
709 llvm::raw_svector_ostream os(sbuf);
710 os <<
"Returning without writing to '";
713 if (!prettyPrintRegionName(FieldChain, MatchedRegion, FirstElement,
714 FirstIsReferenceType, IndirectionLevel, os))
720 return std::make_shared<PathDiagnosticEventPiece>(L, os.str());
723bool NoStoreFuncVisitor::prettyPrintRegionName(
const RegionVector &FieldChain,
725 StringRef FirstElement,
726 bool FirstIsReferenceType,
727 unsigned IndirectionLevel,
728 llvm::raw_svector_ostream &os) {
730 if (FirstIsReferenceType)
733 RegionVector RegionSequence;
736 assert(RegionOfInterest->isSubRegionOf(MatchedRegion));
737 const MemRegion *
R = RegionOfInterest;
738 while (R != MatchedRegion) {
739 RegionSequence.push_back(R);
742 std::reverse(RegionSequence.begin(), RegionSequence.end());
743 RegionSequence.append(FieldChain.begin(), FieldChain.end());
746 for (
const MemRegion *R : RegionSequence) {
754 Sep = prettyPrintFirstElement(FirstElement,
756 IndirectionLevel, os);
765 Sep = DR->getValueType()->isAnyPointerType() ?
"->" :
".";
766 DR->getDecl()->getDeclName().print(os, PP);
770 prettyPrintFirstElement(FirstElement,
771 false, IndirectionLevel, os);
775StringRef NoStoreFuncVisitor::prettyPrintFirstElement(
776 StringRef FirstElement,
bool MoreItemsExpected,
int IndirectionLevel,
777 llvm::raw_svector_ostream &os) {
780 if (IndirectionLevel > 0 && MoreItemsExpected) {
785 if (IndirectionLevel > 0 && MoreItemsExpected)
788 for (
int i = 0; i < IndirectionLevel; i++)
792 if (IndirectionLevel > 0 && MoreItemsExpected)
807 const SubRegion *RegionOfInterest;
808 const SVal ValueAtDereference;
812 bool WasModified =
false;
815 MacroNullReturnSuppressionVisitor(
const SubRegion *R,
const SVal
V)
816 : RegionOfInterest(
R), ValueAtDereference(
V) {}
819 BugReporterContext &BRC,
820 PathSensitiveBugReport &BR)
override {
829 if (
auto Loc = matchAssignment(N)) {
831 std::string MacroName = std::string(
getMacroName(*Loc, BRC));
832 SourceLocation BugLoc = BugPoint->getStmt()->getBeginLoc();
844 static void addMacroVisitorIfNecessary(
845 const ExplodedNode *N,
const MemRegion *R,
846 bool EnableNullFPSuppression, PathSensitiveBugReport &BR,
848 AnalyzerOptions &Options = N->
getState()->getAnalysisManager().options;
849 if (EnableNullFPSuppression && Options.ShouldSuppressNullReturnPaths &&
851 BR.
addVisitor<MacroNullReturnSuppressionVisitor>(
R->getAs<SubRegion>(),
855 void* getTag()
const {
857 return static_cast<void *
>(&
Tag);
860 void Profile(llvm::FoldingSetNodeID &ID)
const override {
861 ID.AddPointer(getTag());
867 std::optional<SourceLocation> matchAssignment(
const ExplodedNode *N) {
873 if (
const auto *DS = dyn_cast<DeclStmt>(S)) {
874 if (
const auto *VD = dyn_cast<VarDecl>(DS->getSingleDecl()))
875 if (
const Expr *RHS = VD->getInit())
876 if (RegionOfInterest->isSubRegionOf(
878 return RHS->getBeginLoc();
879 }
else if (
const auto *BO = dyn_cast<BinaryOperator>(S)) {
881 const Expr *RHS = BO->getRHS();
882 if (BO->isAssignmentOp() && RegionOfInterest->isSubRegionOf(R)) {
901class ReturnVisitor :
public TrackingBugReporterVisitor {
902 const StackFrame *CalleeSF;
909 bool EnableNullFPSuppression;
910 bool ShouldInvalidate =
true;
911 AnalyzerOptions& Options;
915 ReturnVisitor(
TrackerRef ParentTracker,
const StackFrame *Frame,
916 bool Suppressed, AnalyzerOptions &Options,
918 : TrackingBugReporterVisitor(ParentTracker), CalleeSF(Frame),
919 EnableNullFPSuppression(Suppressed), Options(Options), TKind(TKind) {}
921 static void *getTag() {
923 return static_cast<void *
>(&
Tag);
926 void Profile(llvm::FoldingSetNodeID &ID)
const override {
927 ID.AddPointer(ReturnVisitor::getTag());
928 ID.AddPointer(CalleeSF);
929 ID.AddBoolean(EnableNullFPSuppression);
933 BugReporterContext &BRC,
934 PathSensitiveBugReport &BR) {
943 const auto *
Ret = dyn_cast<ReturnStmt>(SP->getStmt());
950 const Expr *RV =
Ret->getRetValue();
953 SVal
V = State->getSVal(RV, CalleeSF);
954 if (
V.isUnknownOrUndef())
960 const Expr *RetE =
Ret->getRetValue();
961 assert(RetE &&
"Tracking a return value for a void function");
964 std::optional<Loc> LValue;
966 if ((LValue =
V.getAs<Loc>())) {
967 SVal RValue = State->getRawSVal(*LValue, RetE->
getType());
980 getParentTracker().track(RetE, N, {TKind, EnableNullFPSuppression});
984 llvm::raw_svector_ostream
Out(Msg);
986 bool WouldEventBeMeaningless =
false;
988 if (State->isNull(
V).isConstrainedTrue()) {
994 if (EnableNullFPSuppression &&
995 Options.ShouldAvoidSuppressingNullArgumentPaths)
996 Mode = MaybeUnsuppress;
999 Out <<
"Returning nil";
1001 Out <<
"Returning null pointer";
1004 Out <<
"Returning zero";
1008 if (
auto CI =
V.getAs<nonloc::ConcreteInt>()) {
1009 Out <<
"Returning the value " << CI->getValue();
1017 WouldEventBeMeaningless =
true;
1019 Out << (isa<Loc>(
V) ?
"Returning pointer" :
"Returning value");
1024 if (
const MemRegion *MR = LValue->getAsRegion()) {
1025 if (MR->canPrintPretty()) {
1026 Out <<
" (reference to ";
1027 MR->printPretty(Out);
1033 if (
const auto *DR = dyn_cast<DeclRefExpr>(RetE))
1034 if (
const auto *DD = dyn_cast<DeclaratorDecl>(DR->getDecl()))
1035 Out <<
" (loaded from '" << *DD <<
"')";
1039 if (!L.isValid() || !L.asLocation().isValid())
1042 if (TKind == bugreporter::TrackingKind::Condition)
1045 auto EventPiece = std::make_shared<PathDiagnosticEventPiece>(L,
Out.str());
1049 if (WouldEventBeMeaningless)
1050 EventPiece->setPrunable(
true);
1058 BugReporterContext &BRC,
1059 PathSensitiveBugReport &BR) {
1060 assert(Options.ShouldAvoidSuppressingNullArgumentPaths);
1063 std::optional<CallEnter> CE = N->
getLocationAs<CallEnter>();
1067 if (CE->getCalleeStackFrame() != CalleeSF)
1080 for (
unsigned I = 0, E =
Call->getNumArgs(); I != E; ++I) {
1081 std::optional<Loc> ArgV =
Call->getArgSVal(I).getAs<Loc>();
1085 const Expr *ArgE =
Call->getArgExpr(I);
1090 if (!State->isNull(*ArgV).isConstrainedTrue())
1093 if (getParentTracker()
1094 .track(ArgE, N, {TKind, EnableNullFPSuppression})
1095 .FoundSomethingToTrack)
1096 ShouldInvalidate =
false;
1107 BugReporterContext &BRC,
1108 PathSensitiveBugReport &BR)
override {
1111 return visitNodeInitial(N, BRC, BR);
1112 case MaybeUnsuppress:
1113 return visitNodeMaybeUnsuppress(N, BRC, BR);
1118 llvm_unreachable(
"Invalid visit mode!");
1121 void finalizeVisitor(
const ExplodedNode *, BugReporterContext &,
1122 PathSensitiveBugReport &BR)
override {
1123 if (EnableNullFPSuppression && ShouldInvalidate)
1124 BR.
markInvalid(ReturnVisitor::getTag(), CalleeSF);
1134class StoreSiteFinder final :
public TrackingBugReporterVisitor {
1137 bool Satisfied =
false;
1139 TrackingOptions Options;
1140 const StackFrame *OriginSF;
1154 const MemRegion *R, TrackingOptions Options,
1155 const StackFrame *OriginSF =
nullptr)
1156 : TrackingBugReporterVisitor(ParentTracker),
R(
R),
V(
V), Options(Options),
1157 OriginSF(OriginSF) {
1161 void Profile(llvm::FoldingSetNodeID &ID)
const override;
1164 BugReporterContext &BRC,
1165 PathSensitiveBugReport &BR)
override;
1169void StoreSiteFinder::Profile(llvm::FoldingSetNodeID &ID)
const {
1171 ID.AddPointer(&tag);
1174 ID.AddInteger(
static_cast<int>(Options.Kind));
1175 ID.AddBoolean(Options.EnableNullFPSuppression);
1192 const auto *FrameSpace =
1199 [[maybe_unused]]
bool IsLocalStaticOrLocalExtern =
1201 assert(IsLocalStaticOrLocalExtern &&
1202 "Declared a variable on the stack without Stack memspace?");
1211 if (R->isBoundable())
1212 if (
const auto *TR = dyn_cast<TypedValueRegion>(R))
1213 return TR->getValueType()->isObjCObjectPointerType();
1223using DestTypeValue = std::pair<const StoreInfo &, loc::ConcreteInt>;
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();
1229 if (
auto *PtrTy = LocTy->
getAs<PointerType>()) {
1230 std::string PStr = PtrTy->getPointeeType().getAsString();
1232 OS <<
"(" << PStr <<
")";
1236 SmallString<16> ValStr;
1237 Val.second.getValue()->toString(ValStr, 10,
true);
1252 const char *Action =
nullptr;
1256 Action = HasPrefix ?
"initialized to " :
"Initializing to ";
1259 Action = HasPrefix ?
"captured by block as " :
"Captured by block as ";
1262 llvm_unreachable(
"Unexpected store kind");
1266 if (!*CVal->getValue())
1269 OS << Action << DestTypeValue(SI, *CVal);
1272 OS << Action << CVal->getValue();
1275 OS << Action <<
"the value of ";
1279 if (
const auto *VR = dyn_cast<VarRegion>(SI.
Dest)) {
1280 const VarDecl *VD = VR->getDecl();
1282 OS << (HasPrefix ?
"declared" :
"Declared")
1283 <<
" without an initial value";
1287 OS << (HasPrefix ?
"initialized" :
"Initialized") <<
" here";
1295 const auto *D = VR->getDecl();
1300 if (!*CI->getValue())
1301 OS << (
isObjCPointer(D) ?
"nil object reference" :
"null pointer value");
1303 OS << (
isObjCPointer(D) ?
"object reference of value " :
"pointer value ")
1304 << DestTypeValue(SI, *CI);
1307 OS <<
"uninitialized value";
1310 OS <<
"the value " << CI->getValue();
1319 if (
const auto *Param = dyn_cast<ParmVarDecl>(VR->getDecl())) {
1321 unsigned Idx = Param->getFunctionScopeIndex() + 1;
1322 OS <<
" via " << Idx << llvm::getOrdinalSuffix(Idx) <<
" parameter";
1327 }
else if (
const auto *ImplParam = dyn_cast<ImplicitParamDecl>(D)) {
1329 OS <<
" via implicit parameter 'self'";
1343 ?
"nil object reference stored"
1344 : (HasSuffix ?
"Null pointer value stored"
1345 :
"Storing null pointer value"));
1348 OS <<
"object reference of value " << DestTypeValue(SI, *CV)
1352 OS <<
"Pointer value of " << DestTypeValue(SI, *CV) <<
" stored";
1354 OS <<
"Storing pointer value of " << DestTypeValue(SI, *CV);
1358 OS << (HasSuffix ?
"Uninitialized value stored"
1359 :
"Storing uninitialized value");
1363 OS <<
"The value " << CV->getValue() <<
" is assigned";
1365 OS <<
"Assigning " << CV->getValue();
1369 OS <<
"The value of ";
1371 OS <<
" is assigned";
1373 OS <<
"Assigning the value of ";
1378 OS << (HasSuffix ?
"Value assigned" :
"Assigning value");
1399 const auto *TVR = dyn_cast_or_null<TypedValueRegion>(R);
1407 std::stack<const TypedValueRegion *> TVRStack;
1413 if (ITy == TVR->getValueType().getCanonicalType())
1422 if (ITy != TVR->getValueType().getCanonicalType())
1426 while (!TVRStack.empty()) {
1427 TVR = TVRStack.top();
1438 if (
const auto *FR = dyn_cast<FieldRegion>(TVR)) {
1439 const auto *FD = FR->
getDecl();
1441 if (FD->getFieldIndex() >= NumInits)
1445 }
else if (
const auto *ER = dyn_cast<ElementRegion>(TVR)) {
1446 const auto Ind = ER->getIndex();
1450 if (!Ind.isConstant())
1453 const auto IndVal = Ind.getAsInteger()->getLimitedValue();
1454 if (IndVal >= NumInits)
1472 const Expr *InitE =
nullptr;
1473 bool IsParam =
false;
1476 if (
const auto *VR = dyn_cast<VarRegion>(R)) {
1479 InitE = VR->getDecl()->getInit();
1485 if (std::optional<PostInitializer> PIP =
1488 if (FieldReg == R) {
1490 InitE = PIP->getInitializer()->getInit();
1504 std::optional<PostStore> PS = Succ->
getLocationAs<PostStore>();
1505 if (!PS || PS->getLocationValue() != R)
1511 if (std::optional<PostStmt> P = Succ->
getLocationAs<PostStmt>()) {
1514 if (
const BinaryOperator *BO = P->getStmtAs<BinaryOperator>()) {
1515 if (BO->isAssignmentOp())
1516 InitE = BO->getRHS();
1520 else if (
const auto *DS = P->getStmtAs<DeclStmt>()) {
1521 const auto *
Decl = DS->getSingleDecl();
1531 if (
const auto *ILE = dyn_cast<InitListExpr>(VD->getInit()))
1534 }
else if (
const auto *CE = P->getStmtAs<CXXConstructExpr>()) {
1536 const auto State = Succ->
getState();
1547 std::stack<const SubRegion *> SRStack;
1555 const auto *OriginEx = CE->getArg(0);
1556 const auto OriginVal =
1562 SVal OriginField = OriginVal;
1563 while (!SRStack.empty()) {
1564 const auto *TopR = SRStack.top();
1567 if (
const auto *FR = dyn_cast<FieldRegion>(TopR)) {
1568 OriginField = State->getLValue(FR->
getDecl(), OriginField);
1569 }
else if (
const auto *ER = dyn_cast<ElementRegion>(TopR)) {
1570 OriginField = State->getLValue(ER->getElementType(),
1571 ER->getIndex(), OriginField);
1578 getParentTracker().track(
V, OriginField.
getAsRegion(), Options);
1583 else if (
const auto *ILE = P->getStmtAs<InitListExpr>()) {
1598 if (std::optional<CallEnter> CE = Succ->
getLocationAs<CallEnter>()) {
1599 if (
const auto *VR = dyn_cast<VarRegion>(R)) {
1601 if (
const auto *Param = dyn_cast<ParmVarDecl>(VR->getDecl())) {
1607 InitE =
Call->getArgExpr(Param->getFunctionScopeIndex());
1613 ->getInstanceReceiver()
1614 ->IgnoreParenCasts();
1622 if (
const auto *TmpR = dyn_cast<CXXTempObjectRegion>(R))
1623 InitE = TmpR->getExpr();
1637 getParentTracker().track(InitE, StoreSite, Options);
1663 if (N->
getState()->getSVal(Candidate) ==
V) {
1664 OldRegion = Candidate;
1683 if (!OldRegion && StoreSite->
getState()->getSVal(R) ==
V) {
1688 NodeWithoutBinding && NodeWithoutBinding->
getState()->getSVal(R) ==
V;
1689 NodeWithoutBinding = NodeWithoutBinding->
getFirstPred()) {
1692 if (NodeWithoutBinding) {
1704 OldRegion = FB.getRegion();
1708 if (Options.Kind == TrackingKind::Condition && OriginSF &&
1713 SmallString<256> sbuf;
1714 llvm::raw_svector_ostream os(sbuf);
1723 if (std::optional<PostStmt> PS = StoreSite->
getLocationAs<PostStmt>()) {
1724 const Stmt *S = PS->getStmt();
1725 const auto *DS = dyn_cast<DeclStmt>(S);
1726 const auto *VR = dyn_cast<VarRegion>(R);
1730 }
else if (
const auto *BExpr = dyn_cast<BlockExpr>(S)) {
1736 if (
const auto *BDR =
1737 dyn_cast_or_null<BlockDataRegion>(
V.getAsRegion())) {
1738 if (
const VarRegion *OriginalR = BDR->getOriginalRegion(VR)) {
1739 getParentTracker().track(State->getSVal(OriginalR), OriginalR,
1750 return getParentTracker().handle(SI, BRC, Options);
1759 ID.AddPointer(&tag);
1760 ID.AddString(Message);
1761 ID.AddBoolean(Assumption);
1768 return "TrackConstraintBRVisitor";
1771bool TrackConstraintBRVisitor::isZeroCheck()
const {
1772 return !Assumption && Constraint.
getAs<
Loc>();
1775bool TrackConstraintBRVisitor::isUnderconstrained(
const ExplodedNode *N)
const {
1777 return N->
getState()->isNull(Constraint).isUnderconstrained();
1778 return (
bool)N->
getState()->assume(Constraint, !Assumption);
1789 if (!IsTrackingTurnedOn)
1790 if (!isUnderconstrained(N))
1791 IsTrackingTurnedOn =
true;
1792 if (!IsTrackingTurnedOn)
1797 if (isUnderconstrained(PrevN)) {
1804 assert(!isUnderconstrained(N));
1812 if (isa_and_nonnull<NoteTag>(P.
getTag()))
1820 auto X = std::make_shared<PathDiagnosticEventPiece>(L, Message);
1822 return std::move(
X);
1837 if (!Options.ShouldSuppressInlinedDefensiveChecks)
1842 llvm::FoldingSetNodeID &ID)
const {
1849 return "IDCVisitor";
1861 if (!IsTrackingTurnedOn)
1862 if (Succ->
getState()->isNull(V).isConstrainedTrue())
1863 IsTrackingTurnedOn =
true;
1864 if (!IsTrackingTurnedOn)
1869 if (!Pred->
getState()->isNull(V).isConstrainedTrue() &&
1870 Succ->
getState()->isNull(V).isConstrainedTrue()) {
1876 if (CurSF != ReportSF && !CurSF->
isParentOf(ReportSF)) {
1891 const Stmt *CurTerminatorStmt =
nullptr;
1893 CurTerminatorStmt = BE->getSrc()->getTerminator().getStmt();
1895 const Stmt *CurStmt = SP->getStmt();
1905 if (!CurTerminatorStmt)
1939class TrackControlDependencyCondBRVisitor final
1946 TrackControlDependencyCondBRVisitor(
TrackerRef ParentTracker,
1949 ControlDeps(&O->getCFG()) {}
1951 void Profile(llvm::FoldingSetNodeID &ID)
const override {
1962static std::shared_ptr<PathDiagnosticEventPiece>
1975 return std::make_shared<PathDiagnosticEventPiece>(
1978 (Twine() +
"Tracking condition '" + ConditionText +
"'").str());
2006 if (
const auto *BinOp = dyn_cast<BinaryOperator>(ElseCond))
2007 if (BinOp->isLogicalOp())
2014TrackControlDependencyCondBRVisitor::VisitNode(
const ExplodedNode *N,
2021 CFGBlock *NB =
const_cast<CFGBlock *
>(N->
getCFGBlock());
2024 if (!VisitedBlocks.insert(NB).second)
2027 CFGBlock *OriginB =
const_cast<CFGBlock *
>(Origin->getCFGBlock());
2030 if (!OriginB || !NB)
2036 if (ControlDeps.isControlDependent(OriginB, NB)) {
2069 getParentTracker().track(InnerExpr, N,
2087 if (
const auto *FE = dyn_cast<FullExpr>(Ex))
2089 if (
const auto *OVE = dyn_cast<OpaqueValueExpr>(Ex))
2091 if (
const auto *POE = dyn_cast<PseudoObjectExpr>(Ex)) {
2092 const auto *PropRef = dyn_cast<ObjCPropertyRefExpr>(POE->getSyntacticForm());
2093 if (PropRef && PropRef->isMessagingGetter()) {
2094 const Expr *GetterMessageSend =
2095 POE->getSemanticExpr(POE->getNumSemanticExprs() - 1);
2102 if (
const auto *CO = dyn_cast<ConditionalOperator>(Ex)) {
2108 if (std::optional<BlockEdge> BE = ProgPoint.
getAs<
BlockEdge>()) {
2109 const CFGBlock *srcBlk = BE->getSrc();
2112 bool TookTrueBranch = (*(srcBlk->
succ_begin()) == BE->getDst());
2124 if (
auto *BO = dyn_cast<BinaryOperator>(Ex))
2128 if (
auto *UO = dyn_cast<UnaryOperator>(Ex)) {
2129 if (UO->getOpcode() == UO_LNot)
2140 if (UO->getOpcode() == UO_AddrOf && UO->getSubExpr()->isLValue())
2151 const Expr *Inner) {
2166 StringRef NodeText) {
2180 return std::make_shared<PathDiagnosticEventPiece>(L, NodeText);
2192 llvm::raw_svector_ostream
OS(Buffer);
2210 return constructNote(SI, BRC,
OS.str());
2230 ->getAnalysisManager()
2231 .getAnalyzerOptions()
2232 .ShouldTrackConditions) {
2233 Report.addVisitor<TrackControlDependencyCondBRVisitor>(
2234 &getParentTracker(), InputNode);
2242class NilReceiverHandler final :
public ExpressionHandler {
2246 Tracker::Result handle(
const Expr *Inner,
const ExplodedNode *InputNode,
2247 const ExplodedNode *LVNode,
2248 TrackingOptions Opts)
override {
2252 if (
const Expr *Receiver =
2254 return getParentTracker().track(Receiver, LVNode, Opts);
2260class ArrayIndexHandler final :
public ExpressionHandler {
2264 Tracker::Result handle(
const Expr *Inner,
const ExplodedNode *InputNode,
2265 const ExplodedNode *LVNode,
2266 TrackingOptions Opts)
override {
2268 if (
const auto *Arr = dyn_cast<ArraySubscriptExpr>(Inner))
2269 return getParentTracker().track(
2270 Arr->getIdx(), LVNode,
2271 {Opts.Kind, false});
2278class InterestingLValueHandler final :
public ExpressionHandler {
2282 Tracker::Result handle(
const Expr *Inner,
const ExplodedNode *InputNode,
2283 const ExplodedNode *LVNode,
2284 TrackingOptions Opts)
override {
2287 PathSensitiveBugReport &
Report = getParentTracker().getReport();
2293 SVal LVal = LVNode->
getSVal(Inner);
2296 bool LVIsNull = LVState->isNull(LVal).isConstrainedTrue();
2301 if (RR && !LVIsNull)
2302 Result.combineWith(getParentTracker().track(LVal, RR, Opts, SF));
2308 const MemRegion *
R =
2309 (RR && LVIsNull) ? RR : LVNode->getSVal(Inner).getAsRegion();
2314 SVal
V = LVState->getRawSVal(loc::MemRegionVal(R));
2319 Result.FoundSomethingToTrack =
true;
2320 Result.WasInterrupted =
true;
2322 MacroNullReturnSuppressionVisitor::addMacroVisitorIfNecessary(
2326 Report.addVisitor<UndefOrNullArgVisitor>(
R);
2330 if (
V.getAsLocSymbol(
true))
2331 if (LVState->isNull(
V).isConstrainedTrue())
2332 Report.addVisitor<TrackConstraintBRVisitor>(
2333 V.castAs<DefinedSVal>(),
2334 false,
"Assuming pointer value is null");
2337 if (
auto DV =
V.getAs<DefinedSVal>())
2345 Report.addVisitor<SuppressInlineDefensiveChecksVisitor>(*DV,
2347 getParentTracker().track(
V, R, Opts, SF);
2362class InlinedFunctionCallHandler final :
public ExpressionHandler {
2365 Tracker::Result handle(
const Expr *E,
const ExplodedNode *InputNode,
2366 const ExplodedNode *ExprNode,
2367 TrackingOptions Opts)
override {
2382 if (std::optional<CallExitEnd> CEE =
2384 if (CEE->getCalleeStackFrame()->getCallSite() == E)
2397 if (!BypassCXXNewExprEval)
2398 if (std::optional<StmtPoint> SP = ExprNode->
getLocationAs<StmtPoint>())
2400 if (SP->getStmt() == E && CurrentSF == PredSF)
2413 std::optional<CallExitEnd> CEE = ExprNode->
getLocationAs<CallExitEnd>();
2417 const StackFrame *CalleeSF = CEE->getCalleeStackFrame();
2423 SVal RetVal = ExprNode->
getSVal(E);
2427 if (std::optional<Loc> LValue = RetVal.
getAs<Loc>())
2428 RetVal = State->getSVal(*LValue);
2431 AnalyzerOptions &Options = State->getAnalysisManager().options;
2433 bool EnableNullFPSuppression =
false;
2435 if (std::optional<Loc> RetLoc = RetVal.
getAs<Loc>())
2436 EnableNullFPSuppression = State->isNull(*RetLoc).isConstrainedTrue();
2438 PathSensitiveBugReport &
Report = getParentTracker().getReport();
2439 Report.addVisitor<ReturnVisitor>(&getParentTracker(), CalleeSF,
2440 EnableNullFPSuppression, Options,
2446class DefaultExpressionHandler final :
public ExpressionHandler {
2450 Tracker::Result handle(
const Expr *Inner,
const ExplodedNode *InputNode,
2451 const ExplodedNode *LVNode,
2452 TrackingOptions Opts)
override {
2455 PathSensitiveBugReport &
Report = getParentTracker().getReport();
2460 SVal
V = LVState->getSValAsScalarOrLoc(Inner, LVNode->
getStackFrame());
2463 if (
auto L =
V.getAs<loc::MemRegionVal>()) {
2468 bool CanDereference =
true;
2469 if (
const auto *SR = L->getRegionAs<SymbolicRegion>()) {
2470 if (SR->getPointeeStaticType()->isVoidType())
2471 CanDereference =
false;
2472 }
else if (L->getRegionAs<AllocaRegion>())
2473 CanDereference =
false;
2480 RVal = LVState->getRawSVal(*L, Inner->
getType());
2481 else if (CanDereference)
2482 RVal = LVState->getSVal(L->getRegion());
2484 if (CanDereference) {
2485 Report.addVisitor<UndefOrNullArgVisitor>(L->getRegion());
2486 Result.FoundSomethingToTrack =
true;
2490 getParentTracker().track(RVal, L->getRegion(), Opts, SF));
2494 if (isa_and_nonnull<SymbolicRegion>(RegionRVal)) {
2495 Report.markInteresting(RegionRVal, Opts.
Kind);
2496 Report.addVisitor<TrackConstraintBRVisitor>(
2497 loc::MemRegionVal(RegionRVal),
2498 false,
"Assuming pointer value is null");
2499 Result.FoundSomethingToTrack =
true;
2509class PRValueHandler final :
public ExpressionHandler {
2513 Tracker::Result handle(
const Expr *E,
const ExplodedNode *InputNode,
2514 const ExplodedNode *ExprNode,
2515 TrackingOptions Opts)
override {
2523 Tracker::Result CombinedResult;
2524 Tracker &Parent = getParentTracker();
2526 const auto track = [&CombinedResult, &Parent, ExprNode,
2527 Opts](
const Expr *Inner) {
2536 if (
const auto *ILE = dyn_cast<InitListExpr>(E)) {
2537 if (ILE->getNumInits() == 1) {
2538 track(ILE->getInit(0));
2540 return CombinedResult;
2547 SVal
V = RVState->getSValAsScalarOrLoc(E, RVNode->
getStackFrame());
2548 const auto *BO = dyn_cast<BinaryOperator>(E);
2550 if (!BO || !BO->isMultiplicativeOp() || !
V.isZeroConstant())
2553 SVal RHSV = RVState->getSVal(BO->getRHS(), RVNode->
getStackFrame());
2554 SVal LHSV = RVState->getSVal(BO->getLHS(), RVNode->
getStackFrame());
2557 if (BO->getOpcode() == BO_Mul) {
2559 track(BO->getLHS());
2561 track(BO->getRHS());
2564 track(BO->getLHS());
2567 return CombinedResult;
2597 for (ExpressionHandlerPtr &Handler : ExpressionHandlers) {
2598 CombinedResult.
combineWith(Handler->handle(Inner, N, LVNode, Opts));
2607 return CombinedResult;
2612 if (!
V.isUnknown()) {
2613 Report.addVisitor<StoreSiteFinder>(
this,
V, R, Opts, Origin);
2622 for (StoreHandlerPtr &Handler : StoreHandlers) {
2637 ->track(E, InputNode, Opts)
2638 .FoundSomethingToTrack;
2654 const auto *ME = dyn_cast<ObjCMessageExpr>(S);
2657 if (
const Expr *Receiver = ME->getInstanceReceiver()) {
2660 if (state->isNull(
V).isConstrainedTrue())
2673 const Stmt *S = P->getStmt();
2679 llvm::raw_svector_ostream
OS(Buf);
2681 if (
const auto *ME = dyn_cast<ObjCMessageExpr>(S)) {
2683 ME->getSelector().print(
OS);
2684 OS <<
"' not called";
2687 OS <<
"No method is called";
2689 OS <<
" because the receiver is nil";
2700 return std::make_shared<PathDiagnosticEventPiece>(L,
OS.str());
2717 if (
auto *ev = dyn_cast<PathDiagnosticEventPiece>(piece.get()))
2718 ev->setPrunable(
true,
false);
2728 const std::pair<const ProgramPointTag *, const ProgramPointTag *> &Tags =
2733 if (std::optional<BlockEdge> BE = ProgPoint.
getAs<
BlockEdge>()) {
2734 const CFGBlock *SrcBlock = BE->getSrc();
2742 if (PreviousNodeTag == Tags.first || PreviousNodeTag == Tags.second)
2750 if (std::optional<PostStmt> PS = ProgPoint.
getAs<
PostStmt>()) {
2752 if (CurrentNodeTag != Tags.first && CurrentNodeTag != Tags.second)
2755 bool TookTrue = CurrentNodeTag == Tags.first;
2766 const Expr *Cond =
nullptr;
2786 case Stmt::IfStmtClass: {
2789 if (IfStatement->isConsteval())
2791 Cond = IfStatement->getCond();
2794 case Stmt::ConditionalOperatorClass:
2797 case Stmt::BinaryOperatorClass:
2802 assert(BO->isLogicalOp() &&
2803 "CFG terminator is not a short-circuit operator!");
2804 Cond = BO->getLHS();
2813 while (
const auto *InnerBO = dyn_cast<BinaryOperator>(Cond)) {
2814 if (!InnerBO->isLogicalOp())
2821 const bool TookTrue = *(srcBlk->
succ_begin()) == dstBlk;
2849 CurrentState->getSVal(Cond, SF).isUnknownOrUndef();
2853 const Expr *CondTmp = Cond;
2854 bool TookTrueTmp = TookTrue;
2861 case Stmt::BinaryOperatorClass:
2863 BRC, R, N, TookTrueTmp, IsAssuming))
2866 case Stmt::DeclRefExprClass:
2868 BRC, R, N, TookTrueTmp, IsAssuming))
2871 case Stmt::MemberExprClass:
2873 BRC, R, N, TookTrueTmp, IsAssuming))
2876 case Stmt::UnaryOperatorClass: {
2878 if (UO->getOpcode() == UO_LNot) {
2879 TookTrueTmp = !TookTrueTmp;
2880 CondTmp = UO->getSubExpr();
2900 return std::make_shared<PathDiagnosticEventPiece>(
2901 Loc, TookTrue ? GenericTrueMessage : GenericFalseMessage);
2905 const Expr *OtherEx, raw_ostream &Out,
2909 std::optional<bool> &Prunable,
2910 bool IsSameFieldName) {
2911 const Expr *OriginalExpr = Ex;
2933 if (
const auto *DR = dyn_cast<DeclRefExpr>(Ex)) {
2941 if (
Report.isInteresting(R))
2951 Out << DR->getDecl()->getDeclName().getAsString();
2957 if (
const auto *IL = dyn_cast<IntegerLiteral>(Ex)) {
2960 if (IL->getValue() == 0) {
2966 if (IL->getValue() == 0) {
2974 IL->getValue().print(Out, IsAnySigned);
2978 if (
const auto *ME = dyn_cast<MemberExpr>(Ex)) {
2979 if (!IsSameFieldName)
2980 Out <<
"field '" << ME->getMemberDecl()->getName() <<
'\'';
2997 bool shouldInvert =
false;
2998 std::optional<bool> shouldPrune;
3002 bool IsSameFieldName =
false;
3008 LhsME->getMemberDecl()->getName() == RhsME->getMemberDecl()->getName();
3012 llvm::raw_svector_ostream OutLHS(LhsString), OutRHS(RhsString);
3013 const bool isVarLHS =
3015 shouldPrune, IsSameFieldName);
3016 const bool isVarRHS =
3018 shouldPrune, IsSameFieldName);
3020 shouldInvert = !isVarLHS && isVarRHS;
3034 if (LhsString.empty() || RhsString.empty() ||
3040 llvm::raw_svector_ostream Out(buf);
3041 Out << (IsAssuming ?
"Assuming " :
"")
3042 << (shouldInvert ? RhsString : LhsString) <<
" is ";
3048 case BO_LT: Op = BO_GT;
break;
3049 case BO_GT: Op = BO_LT;
break;
3050 case BO_LE: Op = BO_GE;
break;
3051 case BO_GE: Op = BO_LE;
break;
3056 case BO_EQ: Op = BO_NE;
break;
3057 case BO_NE: Op = BO_EQ;
break;
3058 case BO_LT: Op = BO_GE;
break;
3059 case BO_GT: Op = BO_LE;
break;
3060 case BO_LE: Op = BO_GT;
break;
3061 case BO_GE: Op = BO_LT;
break;
3071 Out <<
"not equal to ";
3078 Out << (shouldInvert ? LhsString : RhsString);
3087 std::string Message = std::string(Out.str());
3088 Message[0] = toupper(Message[0]);
3093 if (!shouldInvert) {
3094 if (LhsME && LhsME->getMemberLoc().isValid())
3099 if (RhsME && RhsME->getMemberLoc().isValid())
3105 return std::make_shared<PathDiagnosticPopUpPiece>(
Loc, Message);
3109 auto event = std::make_shared<PathDiagnosticEventPiece>(
Loc, Message);
3111 event->setPrunable(*shouldPrune);
3122 llvm::raw_svector_ostream Out(buf);
3123 Out <<
"Assuming " << LhsString <<
" is ";
3125 if (!
printValue(CondVarExpr, Out, N, TookTrue,
true))
3134 auto event = std::make_shared<PathDiagnosticEventPiece>(
Loc, Out.str());
3137 event->setPrunable(
false);
3146 const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl());
3151 llvm::raw_svector_ostream Out(Buf);
3153 Out << (IsAssuming ?
"Assuming '" :
"'") << VD->getDeclName() <<
"' is ";
3155 if (!
printValue(DRE, Out, N, TookTrue, IsAssuming))
3166 return std::make_shared<PathDiagnosticPopUpPiece>(
Loc, Out.str());
3170 auto event = std::make_shared<PathDiagnosticEventPiece>(
Loc, Out.str());
3173 event->setPrunable(
false);
3175 return std::move(event);
3183 llvm::raw_svector_ostream Out(Buf);
3185 Out << (IsAssuming ?
"Assuming field '" :
"Field '")
3188 if (!
printValue(ME, Out, N, TookTrue, IsAssuming))
3208 return std::make_shared<PathDiagnosticPopUpPiece>(
Loc, Out.str());
3210 auto event = std::make_shared<PathDiagnosticEventPiece>(
Loc, Out.str());
3212 event->setPrunable(
false);
3222 Out << (TookTrue ?
"non-null" :
"null");
3227 Out << (TookTrue ?
"non-nil" :
"nil");
3234 std::optional<const llvm::APSInt *> IntValue;
3238 if (IsAssuming || !IntValue) {
3240 Out << (TookTrue ?
"true" :
"false");
3242 Out << (TookTrue ?
"not equal to 0" :
"0");
3245 Out << ((*IntValue)->getBoolValue() ?
"true" :
"false");
3255 return Piece->
getString() == GenericTrueMessage ||
3256 Piece->
getString() == GenericFalseMessage;
3276 if (Options.ShouldSuppressFromCXXStandardLibrary) {
3286 if (
const auto *MD = dyn_cast<CXXMethodDecl>(D)) {
3288 if (CD->
getName() ==
"list") {
3296 if (
const auto *MD = dyn_cast<CXXConstructorDecl>(D)) {
3298 if (CD->
getName() ==
"__independent_bits_engine") {
3305 const auto *MD = dyn_cast<CXXMethodDecl>(SF.
getDecl());
3316 if (CD->
getName() ==
"basic_string") {
3324 if (CD->
getName() ==
"shared_ptr") {
3336 while (
Loc.isMacroID()) {
3337 Loc =
Loc.getSpellingLoc();
3366 for (
const auto ParamDecl : parms) {
3367 const MemRegion *ArgReg =
Call->getArgSVal(Idx).getAsRegion();
3375 assert(ParamDecl &&
"Formal parameter has no decl?");
3378 if (!(
T->isAnyPointerType() ||
T->isReferenceType())) {
3385 if (
T->getPointeeType().isConstQualified())
3390 SVal BoundVal = State->getSVal(R);
3403int NoteTag::Kind = 0;
3407 ID.AddPointer(&Tag);
3418 if (std::optional<std::string> Msg =
T->generateMessage(BRC, R)) {
3421 auto Piece = std::make_shared<PathDiagnosticEventPiece>(
Loc, *Msg);
3422 Piece->setPrunable(
T->isPrunable());
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.
Result
Implement __builtin_bit_cast and related operations.
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
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 Stmt * getTerminatorCondition(bool StripParens=true) const
const Expr * getLastCondition() const
unsigned succ_size() const
const CFGBlock * getBlock(const Stmt *S) const
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 byte-granular source range.
static CharSourceRange getTokenRange(SourceRange R)
SourceLocation getBegin() const
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...
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 * 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.
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.
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
const StackFrame * getStackFrame() 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.
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.
FileIDAndOffset getDecomposedLoc(SourceLocation Loc) const
Decompose the specified location into a raw FileID + Offset pair.
bool isMacroArgExpansion(SourceLocation Loc, SourceLocation *StartLoc=nullptr) const
Tests whether the given source location represents a macro argument's expansion into the function-lik...
CharSourceRange getImmediateExpansionRange(SourceLocation Loc) const
Return the start/end of the expansion information for an expansion location.
StringRef getFilename(SourceLocation SpellingLoc) const
Return the filename of the file containing a SourceLocation.
const SrcMgr::SLocEntry & getSLocEntry(FileID FID, bool *Invalid=nullptr) const
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.
bool isParentOf(const StackFrame *SF) const
LLVM_ATTRIBUTE_RETURNS_NONNULL AnalysisDeclContext * getAnalysisDeclContext() const
const Expr * getCallSite() const
const Decl * getDecl() const
const StackFrame * getParent() const
It might return null.
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 isSignedIntegerOrEnumerationType() const
Determines whether this is an integer type that is signed or an enumeration types whose underlying ty...
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<specific type>'.
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 hasGlobalStorage() const
Returns true for all variables that do not have local storage.
bool isStaticLocal() const
Returns true if a variable with function scope is a static local variable.
const Expr * getInit() const
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.
virtual PathDiagnosticPieceRef getEndPath(const ExplodedNode *N, BugReporterContext &BRC, PathSensitiveBugReport &BR)
Provide custom definition for the final diagnostic piece on the path - the piece, which is displayed ...
static PathDiagnosticPieceRef getDefaultEndPath(const BugReporterContext &BRC, const ExplodedNode *N, const PathSensitiveBugReport &BR)
Generates the default final diagnostic piece.
virtual void finalizeVisitor(const ExplodedNode *EndPathNode, BugReporterContext &BRC, 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 StackFrame *CalleeSF, 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.
static bool isPieceMessageGeneric(const PathDiagnosticPiece *Piece)
PathDiagnosticPieceRef VisitConditionVariable(StringRef LhsString, const Expr *CondVarExpr, BugReporterContext &BRC, PathSensitiveBugReport &R, const ExplodedNode *N, bool TookTrue)
bool patternMatch(const Expr *Ex, const Expr *ParentEx, const Expr *OtherEx, raw_ostream &Out, BugReporterContext &BRC, PathSensitiveBugReport &R, const ExplodedNode *N, std::optional< bool > &prunable, bool IsSameFieldName)
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
SVal getSVal(const Expr *E) const
Get the value of an arbitrary expression at this node.
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()
std::optional< T > getLocationAs() const &
llvm::iterator_range< StackFrame::parent_iterator > stackframes() const
Iterates over the current stack frame and all of its ancestors.
ExplodedNode * getFirstPred()
unsigned succ_size() const
const StackFrame * getStackFrame() const
static std::pair< const ProgramPointTag *, const ProgramPointTag * > getEagerlyAssumeBifurcationTags()
LLVM_ATTRIBUTE_RETURNS_NONNULL const FieldDecl * getDecl() const override
void finalizeVisitor(const ExplodedNode *N, BugReporterContext &BRC, PathSensitiveBugReport &BR) override
Last function called on the visitor, no further calls to VisitNode would follow.
MemRegion - The root abstract class for all memory regions.
const MemSpace * getMemorySpaceAs(ProgramStateRef State) 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.
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.
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.
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
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 Expr *E, const StackFrame *SF) const
Returns the SVal bound to the expression E 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
virtual bool includedInBindings(Store store, const MemRegion *region) const =0
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
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.
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.
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)
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.
void addHighPriorityHandler(ExpressionHandlerPtr SH)
Add custom expression handler with the highest priority.
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.
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...
void trackStoredValue(SVal V, const MemRegion *R, PathSensitiveBugReport &Report, TrackingOptions Opts={}, const StackFrame *Origin=nullptr)
Track how the value got stored into the given region and where it came from.
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.
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
PRESERVE_NONE bool Ret(InterpState &S)
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.
Top level wrappers for InstallAPI frontend operations.
@ Match
This is not an overload because the signature exactly matches an existing declaration.
bool isa(CodeGen::Address addr)
std::pair< FileID, unsigned > FileIDAndOffset
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.