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"
67using namespace bugreporter;
101 const auto *E = dyn_cast<Expr>(S);
106 if (
const auto *CE = dyn_cast<CastExpr>(E)) {
107 if (CE->getCastKind() == CK_LValueToRValue) {
111 E = CE->getSubExpr();
112 }
else if (
const auto *B = dyn_cast<BinaryOperator>(E)) {
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, LCtx));
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, LCtx).getAs<
Loc>())
253 return State->getRawSVal(*FieldL, FD->getType());
258static std::optional<const llvm::APSInt *>
263 return &CI->getValue();
277 if (std::optional<bugreporter::TrackingKind> K =
279 return *K == bugreporter::TrackingKind::Condition;
304 if (!
Loc.isMacroID())
306 while (
SM.isMacroArgExpansion(
Loc))
307 Loc =
SM.getImmediateExpansionRange(
Loc).getBegin();
308 std::pair<FileID, unsigned> TLInfo =
SM.getDecomposedLoc(
Loc);
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) {
383 if (!FramesModifyingCalculated.count(SCtx))
384 findModifyingFrames(N);
385 return FramesModifying.count(SCtx);
388void NoStateChangeFuncVisitor::markFrameAsModifying(
391 auto p = FramesModifying.insert(SCtx);
407 auto IsMatchingCallExitEnd = [OrigSCtx](
const ExplodedNode *N) {
411 while (N && !IsMatchingCallExitEnd(N)) {
413 "This function is to be used on the trimmed ExplodedGraph!");
419void NoStateChangeFuncVisitor::findModifyingFrames(
427 const ExplodedNode *CurrCallExitBeginN = CallExitBeginN;
434 CurrCallExitBeginN = CurrN;
436 FramesModifyingCalculated.insert(CurrentSCtx);
441 if (
auto CE = CurrN->getLocationAs<
CallEnter>()) {
444 markFrameAsModifying(CurrentSCtx);
455 if (CE->getCalleeContext() == OriginalSCtx) {
456 markFrameAsModifying(CurrentSCtx);
462 markFrameAsModifying(CurrentSCtx);
475 if (!CallExitLoc || isModifiedInFrame(N))
490 if (
Call->isInSystemHeader()) {
505 if (
const auto *MC = dyn_cast<ObjCMethodCall>(
Call)) {
512 if (
const auto *CCall = dyn_cast<CXXConstructorCall>(
Call)) {
539 static const unsigned DEREFERENCE_LIMIT = 2;
546 MmrMgr(R->getMemRegionManager()),
547 SM(MmrMgr.getContext().getSourceManager()),
548 PP(MmrMgr.getContext().getPrintingPolicy()) {}
550 void Profile(llvm::FoldingSetNodeID &
ID)
const override {
553 ID.AddPointer(RegionOfInterest);
559 bool wasModifiedBeforeCallExit(
const ExplodedNode *CurrN,
568 const std::optional<RegionVector>
570 const MemRegion *R,
const RegionVector &Vec = {},
594 const MemRegion *MatchedRegion, StringRef FirstElement,
595 bool FirstIsReferenceType,
unsigned IndirectionLevel);
597 bool prettyPrintRegionName(
const RegionVector &FieldChain,
599 StringRef FirstElement,
bool FirstIsReferenceType,
600 unsigned IndirectionLevel,
601 llvm::raw_svector_ostream &os);
603 StringRef prettyPrintFirstElement(StringRef FirstElement,
604 bool MoreItemsExpected,
605 int IndirectionLevel,
606 llvm::raw_svector_ostream &os);
614 using namespace ast_matchers;
615 const char *IvarBind =
"Ivar";
619 hasOperatorName(
"="),
620 hasLHS(ignoringParenImpCasts(
626 if (IvarRef->isFreeIvar())
629 const Expr *
Base = IvarRef->getBase();
630 if (
const auto *ICE = dyn_cast<ImplicitCastExpr>(
Base))
631 Base = ICE->getSubExpr();
633 if (
const auto *DRE = dyn_cast<DeclRefExpr>(
Base))
634 if (
const auto *ID = dyn_cast<ImplicitParamDecl>(DRE->getDecl()))
649const std::optional<NoStoreFuncVisitor::RegionVector>
650NoStoreFuncVisitor::findRegionOfInterestInRecord(
655 if (depth == DEREFERENCE_LIMIT)
658 if (
const auto *RDX = dyn_cast<CXXRecordDecl>(RD))
659 if (!RDX->hasDefinition())
664 if (
const auto *RDX = dyn_cast<CXXRecordDecl>(RD))
665 for (
const auto &II : RDX->bases())
666 if (
const RecordDecl *RRD = II.getType()->getAsRecordDecl())
667 if (std::optional<RegionVector> Out =
668 findRegionOfInterestInRecord(RRD, State, R, Vec, depth))
674 const SVal V = State->getSVal(FR);
677 RegionVector VecF = Vec;
680 if (RegionOfInterest == VR)
685 findRegionOfInterestInRecord(RRD, State, FR, VecF, depth + 1))
693 if (std::optional<RegionVector> Out =
694 findRegionOfInterestInRecord(RRD, State, VR, VecF, depth + 1))
705 if (
const auto *IvarR = dyn_cast<ObjCIvarRegion>(RegionOfInterest)) {
706 const MemRegion *SelfRegion =
Call.getReceiverSVal().getAsRegion();
707 if (RegionOfInterest->isSubRegionOf(SelfRegion) &&
710 return maybeEmitNote(R,
Call, N, {}, SelfRegion,
"self",
721 if (RegionOfInterest->isSubRegionOf(ThisR) && !
Call.getDecl()->isImplicit())
722 return maybeEmitNote(R,
Call, N, {}, ThisR,
"this",
739 for (
unsigned I = 0; I <
Call.getNumArgs() && I <
Parameters.size(); ++I) {
745 unsigned IndirectionLevel = 1;
747 while (
const MemRegion *MR =
V.getAsRegion()) {
749 return maybeEmitNote(R,
Call, N, {}, MR, ParamName,
750 ParamIsReferenceType, IndirectionLevel);
753 if (PT.isNull() || PT->isVoidType())
758 if (
const RecordDecl *RD = PT->getAsRecordDecl())
759 if (std::optional<RegionVector>
P =
760 findRegionOfInterestInRecord(RD, State, MR))
761 return maybeEmitNote(R,
Call, N, *
P, RegionOfInterest, ParamName,
762 ParamIsReferenceType, IndirectionLevel);
764 V = State->getSVal(MR, PT);
773bool NoStoreFuncVisitor::wasModifiedBeforeCallExit(
775 return ::wasRegionOfInterestModifiedAt(
776 RegionOfInterest, CurrN,
777 CallExitBeginN->
getState()->getSVal(RegionOfInterest));
781 ", which participates in a condition later";
785 const RegionVector &FieldChain,
const MemRegion *MatchedRegion,
786 StringRef FirstElement,
bool FirstIsReferenceType,
787 unsigned IndirectionLevel) {
799 llvm::raw_svector_ostream os(sbuf);
800 os <<
"Returning without writing to '";
803 if (!prettyPrintRegionName(FieldChain, MatchedRegion, FirstElement,
804 FirstIsReferenceType, IndirectionLevel, os))
810 return std::make_shared<PathDiagnosticEventPiece>(L, os.str());
813bool NoStoreFuncVisitor::prettyPrintRegionName(
const RegionVector &FieldChain,
815 StringRef FirstElement,
816 bool FirstIsReferenceType,
817 unsigned IndirectionLevel,
818 llvm::raw_svector_ostream &os) {
820 if (FirstIsReferenceType)
823 RegionVector RegionSequence;
826 assert(RegionOfInterest->isSubRegionOf(MatchedRegion));
828 while (R != MatchedRegion) {
829 RegionSequence.push_back(R);
830 R = cast<SubRegion>(R)->getSuperRegion();
832 std::reverse(RegionSequence.begin(), RegionSequence.end());
833 RegionSequence.append(FieldChain.begin(), FieldChain.end());
836 for (
const MemRegion *R : RegionSequence) {
840 if (isa<CXXBaseObjectRegion, CXXTempObjectRegion>(R))
844 Sep = prettyPrintFirstElement(FirstElement,
846 IndirectionLevel, os);
851 if (!isa<DeclRegion>(R))
854 const auto *DR = cast<DeclRegion>(R);
855 Sep = DR->getValueType()->isAnyPointerType() ?
"->" :
".";
856 DR->getDecl()->getDeclName().print(os, PP);
860 prettyPrintFirstElement(FirstElement,
861 false, IndirectionLevel, os);
865StringRef NoStoreFuncVisitor::prettyPrintFirstElement(
866 StringRef FirstElement,
bool MoreItemsExpected,
int IndirectionLevel,
867 llvm::raw_svector_ostream &os) {
870 if (IndirectionLevel > 0 && MoreItemsExpected) {
875 if (IndirectionLevel > 0 && MoreItemsExpected)
878 for (
int i = 0; i < IndirectionLevel; i++)
882 if (IndirectionLevel > 0 && MoreItemsExpected)
898 const SVal ValueAtDereference;
902 bool WasModified =
false;
905 MacroNullReturnSuppressionVisitor(
const SubRegion *R,
const SVal V)
906 : RegionOfInterest(R), ValueAtDereference(
V) {}
919 if (
auto Loc = matchAssignment(N)) {
934 static void addMacroVisitorIfNecessary(
939 if (EnableNullFPSuppression && Options.ShouldSuppressNullReturnPaths &&
945 void* getTag()
const {
947 return static_cast<void *
>(&Tag);
950 void Profile(llvm::FoldingSetNodeID &
ID)
const override {
951 ID.AddPointer(getTag());
957 std::optional<SourceLocation> matchAssignment(
const ExplodedNode *N) {
964 if (
const auto *DS = dyn_cast<DeclStmt>(S)) {
965 if (
const auto *VD = dyn_cast<VarDecl>(DS->getSingleDecl()))
966 if (
const Expr *RHS = VD->getInit())
967 if (RegionOfInterest->isSubRegionOf(
968 State->getLValue(VD, LCtx).getAsRegion()))
969 return RHS->getBeginLoc();
970 }
else if (
const auto *BO = dyn_cast<BinaryOperator>(S)) {
972 const Expr *RHS = BO->getRHS();
973 if (BO->isAssignmentOp() && RegionOfInterest->isSubRegionOf(R)) {
1000 bool EnableNullFPSuppression;
1001 bool ShouldInvalidate =
true;
1010 EnableNullFPSuppression(Suppressed), Options(Options), TKind(TKind) {}
1012 static void *getTag() {
1014 return static_cast<void *
>(&Tag);
1017 void Profile(llvm::FoldingSetNodeID &
ID)
const override {
1018 ID.AddPointer(ReturnVisitor::getTag());
1019 ID.AddPointer(CalleeSFC);
1020 ID.AddBoolean(EnableNullFPSuppression);
1034 const auto *
Ret = dyn_cast<ReturnStmt>(SP->getStmt());
1041 SVal V = State->getSVal(Ret, CalleeSFC);
1042 if (
V.isUnknownOrUndef())
1048 const Expr *RetE =
Ret->getRetValue();
1049 assert(RetE &&
"Tracking a return value for a void function");
1052 std::optional<Loc> LValue;
1054 if ((LValue =
V.getAs<
Loc>())) {
1055 SVal RValue = State->getRawSVal(*LValue, RetE->
getType());
1056 if (isa<DefinedSVal>(RValue))
1062 if (isa<nonloc::LazyCompoundVal, nonloc::CompoundVal>(
V))
1068 getParentTracker().track(RetE, N, {TKind, EnableNullFPSuppression});
1072 llvm::raw_svector_ostream Out(Msg);
1074 bool WouldEventBeMeaningless =
false;
1076 if (State->isNull(
V).isConstrainedTrue()) {
1082 if (EnableNullFPSuppression &&
1083 Options.ShouldAvoidSuppressingNullArgumentPaths)
1084 Mode = MaybeUnsuppress;
1087 Out <<
"Returning nil";
1089 Out <<
"Returning null pointer";
1092 Out <<
"Returning zero";
1097 Out <<
"Returning the value " << CI->getValue();
1105 WouldEventBeMeaningless =
true;
1107 Out << (isa<Loc>(
V) ?
"Returning pointer" :
"Returning value");
1112 if (
const MemRegion *MR = LValue->getAsRegion()) {
1113 if (MR->canPrintPretty()) {
1114 Out <<
" (reference to ";
1115 MR->printPretty(Out);
1121 if (
const auto *DR = dyn_cast<DeclRefExpr>(RetE))
1122 if (
const auto *DD = dyn_cast<DeclaratorDecl>(DR->getDecl()))
1123 Out <<
" (loaded from '" << *DD <<
"')";
1127 if (!L.isValid() || !L.asLocation().isValid())
1130 if (TKind == bugreporter::TrackingKind::Condition)
1133 auto EventPiece = std::make_shared<PathDiagnosticEventPiece>(L, Out.str());
1137 if (WouldEventBeMeaningless)
1138 EventPiece->setPrunable(
true);
1148 assert(Options.ShouldAvoidSuppressingNullArgumentPaths);
1155 if (CE->getCalleeContext() != CalleeSFC)
1168 for (
unsigned I = 0, E =
Call->getNumArgs(); I != E; ++I) {
1169 std::optional<Loc> ArgV =
Call->getArgSVal(I).getAs<
Loc>();
1173 const Expr *ArgE =
Call->getArgExpr(I);
1178 if (!State->isNull(*ArgV).isConstrainedTrue())
1181 if (getParentTracker()
1182 .track(ArgE, N, {TKind, EnableNullFPSuppression})
1183 .FoundSomethingToTrack)
1184 ShouldInvalidate =
false;
1199 return visitNodeInitial(N, BRC, BR);
1200 case MaybeUnsuppress:
1201 return visitNodeMaybeUnsuppress(N, BRC, BR);
1206 llvm_unreachable(
"Invalid visit mode!");
1211 if (EnableNullFPSuppression && ShouldInvalidate)
1212 BR.
markInvalid(ReturnVisitor::getTag(), CalleeSFC);
1225 bool Satisfied =
false;
1245 OriginSFC(OriginSFC) {
1249 void Profile(llvm::FoldingSetNodeID &
ID)
const override;
1257void StoreSiteFinder::Profile(llvm::FoldingSetNodeID &ID)
const {
1259 ID.AddPointer(&tag);
1262 ID.AddInteger(
static_cast<int>(Options.Kind));
1263 ID.AddBoolean(Options.EnableNullFPSuppression);
1281 const auto *FrameSpace = dyn_cast<StackSpaceRegion>(VarSpace);
1297 if (
const auto *TR = dyn_cast<TypedValueRegion>(R))
1298 return TR->getValueType()->isObjCObjectPointerType();
1316 const char *Action =
nullptr;
1320 Action = HasPrefix ?
"initialized to " :
"Initializing to ";
1323 Action = HasPrefix ?
"captured by block as " :
"Captured by block as ";
1326 llvm_unreachable(
"Unexpected store kind");
1329 if (isa<loc::ConcreteInt>(SI.
Value)) {
1333 OS << Action << CVal->getValue();
1336 OS << Action <<
"the value of ";
1347 if (isa<VarRegion>(SI.
Dest)) {
1348 const auto *VD = cast<VarDecl>(DS->getSingleDecl());
1350 if (VD->getInit()) {
1351 OS << (HasPrefix ?
"initialized" :
"Initializing")
1352 <<
" to a garbage value";
1354 OS << (HasPrefix ?
"declared" :
"Declaring")
1355 <<
" without an initial value";
1359 OS << (HasPrefix ?
"initialized" :
"Initialized") <<
" here";
1367 const auto *VR = cast<VarRegion>(SI.
Dest);
1368 const auto *D = VR->getDecl();
1372 if (isa<loc::ConcreteInt>(SI.
Value)) {
1373 OS << (
isObjCPointer(D) ?
"nil object reference" :
"null pointer value");
1376 OS <<
"uninitialized value";
1379 OS <<
"the value " << CI->getValue();
1388 if (
const auto *Param = dyn_cast<ParmVarDecl>(VR->getDecl())) {
1390 unsigned Idx = Param->getFunctionScopeIndex() + 1;
1391 OS <<
" via " << Idx << llvm::getOrdinalSuffix(Idx) <<
" parameter";
1396 }
else if (
const auto *ImplParam = dyn_cast<ImplicitParamDecl>(D)) {
1398 OS <<
" via implicit parameter 'self'";
1408 if (isa<loc::ConcreteInt>(SI.
Value)) {
1410 : (HasSuffix ?
"Null pointer value stored"
1411 :
"Storing null pointer value"));
1414 OS << (HasSuffix ?
"Uninitialized value stored"
1415 :
"Storing uninitialized value");
1419 OS <<
"The value " << CV->getValue() <<
" is assigned";
1421 OS <<
"Assigning " << CV->getValue();
1425 OS <<
"The value of ";
1427 OS <<
" is assigned";
1429 OS <<
"Assigning the value of ";
1434 OS << (HasSuffix ?
"Value assigned" :
"Assigning value");
1455 const auto *TVR = dyn_cast_or_null<TypedValueRegion>(R);
1463 std::stack<const TypedValueRegion *> TVRStack;
1464 while (isa<FieldRegion>(TVR) || isa<ElementRegion>(TVR)) {
1469 if (ITy == TVR->getValueType().getCanonicalType())
1473 TVR = cast<TypedValueRegion>(TVR->getSuperRegion());
1478 if (ITy != TVR->getValueType().getCanonicalType())
1482 while (!TVRStack.empty()) {
1483 TVR = TVRStack.top();
1488 if (!isa<InitListExpr>(
Init))
1491 ILE = cast<InitListExpr>(
Init);
1494 if (
const auto *FR = dyn_cast<FieldRegion>(TVR)) {
1495 const auto *FD = FR->
getDecl();
1497 if (FD->getFieldIndex() >= NumInits)
1501 }
else if (
const auto *ER = dyn_cast<ElementRegion>(TVR)) {
1502 const auto Ind = ER->getIndex();
1506 if (!Ind.isConstant())
1509 const auto IndVal = Ind.getAsInteger()->getLimitedValue();
1510 if (IndVal >= NumInits)
1528 const Expr *InitE =
nullptr;
1529 bool IsParam =
false;
1532 if (
const auto *VR = dyn_cast<VarRegion>(R)) {
1535 InitE = VR->getDecl()->getInit();
1541 if (std::optional<PostInitializer> PIP =
1544 if (FieldReg == R) {
1546 InitE = PIP->getInitializer()->getInit();
1561 if (!PS || PS->getLocationValue() != R)
1571 if (BO->isAssignmentOp())
1572 InitE = BO->getRHS();
1576 else if (
const auto *DS =
P->getStmtAs<
DeclStmt>()) {
1577 const auto *
Decl = DS->getSingleDecl();
1578 if (isa<VarDecl>(
Decl)) {
1579 const auto *VD = cast<VarDecl>(
Decl);
1587 if (
const auto *ILE = dyn_cast<InitListExpr>(VD->getInit()))
1592 const auto State = Succ->
getState();
1603 std::stack<const SubRegion *> SRStack;
1604 const SubRegion *SR = cast<SubRegion>(R);
1605 while (isa<FieldRegion>(SR) || isa<ElementRegion>(SR)) {
1611 const auto *OriginEx = CE->getArg(0);
1612 const auto OriginVal =
1618 SVal OriginField = OriginVal;
1619 while (!SRStack.empty()) {
1620 const auto *TopR = SRStack.top();
1623 if (
const auto *FR = dyn_cast<FieldRegion>(TopR)) {
1624 OriginField = State->getLValue(FR->
getDecl(), OriginField);
1625 }
else if (
const auto *ER = dyn_cast<ElementRegion>(TopR)) {
1626 OriginField = State->getLValue(ER->getElementType(),
1627 ER->getIndex(), OriginField);
1634 getParentTracker().track(
V, OriginField.
getAsRegion(), Options);
1655 if (
const auto *VR = dyn_cast<VarRegion>(R)) {
1657 if (
const auto *Param = dyn_cast<ParmVarDecl>(VR->getDecl())) {
1663 InitE =
Call->getArgExpr(Param->getFunctionScopeIndex());
1666 assert(isa<ImplicitParamDecl>(VR->getDecl()));
1667 InitE = cast<ObjCMessageExpr>(CE->getCalleeContext()->getCallSite())
1676 if (
const auto *TmpR = dyn_cast<CXXTempObjectRegion>(R))
1677 InitE = TmpR->getExpr();
1691 getParentTracker().track(InitE, StoreSite, Options);
1715 if (
SM.includedInBindings(N->
getState()->getStore(), Candidate)) {
1717 if (N->
getState()->getSVal(Candidate) ==
V) {
1718 OldRegion = Candidate;
1737 if (!OldRegion && StoreSite->
getState()->getSVal(R) ==
V) {
1742 NodeWithoutBinding && NodeWithoutBinding->
getState()->getSVal(R) ==
V;
1743 NodeWithoutBinding = NodeWithoutBinding->
getFirstPred()) {
1746 if (NodeWithoutBinding) {
1758 OldRegion = FB.getRegion();
1762 if (Options.Kind == TrackingKind::Condition && OriginSFC &&
1768 llvm::raw_svector_ostream os(sbuf);
1778 const Stmt *S = PS->getStmt();
1779 const auto *DS = dyn_cast<DeclStmt>(S);
1780 const auto *VR = dyn_cast<VarRegion>(R);
1784 }
else if (isa<BlockExpr>(S)) {
1790 if (
const auto *BDR =
1791 dyn_cast_or_null<BlockDataRegion>(
V.getAsRegion())) {
1792 if (
const VarRegion *OriginalR = BDR->getOriginalRegion(VR)) {
1793 getParentTracker().track(State->getSVal(OriginalR), OriginalR,
1794 Options, OriginSFC);
1800 isa<VarRegion>(SI.
Dest)) {
1804 return getParentTracker().handle(SI, BRC, Options);
1813 ID.AddPointer(&tag);
1814 ID.AddString(Message);
1815 ID.AddBoolean(Assumption);
1822 return "TrackConstraintBRVisitor";
1825bool TrackConstraintBRVisitor::isZeroCheck()
const {
1826 return !Assumption && Constraint.
getAs<
Loc>();
1829bool TrackConstraintBRVisitor::isUnderconstrained(
const ExplodedNode *N)
const {
1831 return N->
getState()->isNull(Constraint).isUnderconstrained();
1832 return (
bool)N->
getState()->assume(Constraint, !Assumption);
1843 if (!IsTrackingTurnedOn)
1844 if (!isUnderconstrained(N))
1845 IsTrackingTurnedOn =
true;
1846 if (!IsTrackingTurnedOn)
1851 if (isUnderconstrained(PrevN)) {
1858 assert(!isUnderconstrained(N));
1866 if (isa_and_nonnull<NoteTag>(
P.getTag()))
1874 auto X = std::make_shared<PathDiagnosticEventPiece>(L, Message);
1876 return std::move(
X);
1891 if (!Options.ShouldSuppressInlinedDefensiveChecks)
1896 llvm::FoldingSetNodeID &ID)
const {
1903 return "IDCVisitor";
1915 if (!IsTrackingTurnedOn)
1916 if (Succ->
getState()->isNull(
V).isConstrainedTrue())
1917 IsTrackingTurnedOn =
true;
1918 if (!IsTrackingTurnedOn)
1923 if (!Pred->
getState()->isNull(
V).isConstrainedTrue() &&
1924 Succ->
getState()->isNull(
V).isConstrainedTrue()) {
1930 if (CurLC != ReportLC && !CurLC->
isParentOf(ReportLC)) {
1945 const Stmt *CurTerminatorStmt =
nullptr;
1947 CurTerminatorStmt = BE->getSrc()->getTerminator().getStmt();
1949 const Stmt *CurStmt = SP->getStmt();
1959 if (!CurTerminatorStmt)
1993class TrackControlDependencyCondBRVisitor final
1997 llvm::SmallSet<const CFGBlock *, 32> VisitedBlocks;
2000 TrackControlDependencyCondBRVisitor(
TrackerRef ParentTracker,
2003 ControlDeps(&O->getCFG()) {}
2005 void Profile(llvm::FoldingSetNodeID &
ID)
const override {
2016static std::shared_ptr<PathDiagnosticEventPiece>
2029 return std::make_shared<PathDiagnosticEventPiece>(
2032 (Twine() +
"Tracking condition '" + ConditionText +
"'").str());
2060 if (
const auto *BinOp = dyn_cast<BinaryOperator>(ElseCond))
2061 if (BinOp->isLogicalOp())
2068TrackControlDependencyCondBRVisitor::VisitNode(
const ExplodedNode *N,
2078 if (!VisitedBlocks.insert(NB).second)
2084 if (!OriginB || !NB)
2090 if (ControlDeps.isControlDependent(OriginB, NB)) {
2116 if (isa<CallExpr>(InnerExpr))
2123 getParentTracker().track(InnerExpr, N,
2141 if (
const auto *FE = dyn_cast<FullExpr>(Ex))
2143 if (
const auto *OVE = dyn_cast<OpaqueValueExpr>(Ex))
2145 if (
const auto *POE = dyn_cast<PseudoObjectExpr>(Ex)) {
2146 const auto *PropRef = dyn_cast<ObjCPropertyRefExpr>(POE->getSyntacticForm());
2147 if (PropRef && PropRef->isMessagingGetter()) {
2148 const Expr *GetterMessageSend =
2149 POE->getSemanticExpr(POE->getNumSemanticExprs() - 1);
2156 if (
const auto *CO = dyn_cast<ConditionalOperator>(Ex)) {
2162 if (std::optional<BlockEdge> BE = ProgPoint.
getAs<
BlockEdge>()) {
2163 const CFGBlock *srcBlk = BE->getSrc();
2166 bool TookTrueBranch = (*(srcBlk->
succ_begin()) == BE->getDst());
2178 if (
auto *BO = dyn_cast<BinaryOperator>(Ex))
2182 if (
auto *UO = dyn_cast<UnaryOperator>(Ex)) {
2183 if (UO->getOpcode() == UO_LNot)
2194 if (UO->getOpcode() == UO_AddrOf && UO->getSubExpr()->isLValue())
2205 const Expr *Inner) {
2220 StringRef NodeText) {
2226 P.getLocationContext());
2234 return std::make_shared<PathDiagnosticEventPiece>(L, NodeText);
2246 llvm::raw_svector_ostream OS(Buffer);
2261 if (Opts.
Kind == bugreporter::TrackingKind::Condition)
2264 return constructNote(SI, BRC, OS.str());
2284 ->getAnalysisManager()
2285 .getAnalyzerOptions()
2286 .ShouldTrackConditions) {
2287 Report.
addVisitor<TrackControlDependencyCondBRVisitor>(
2288 &getParentTracker(), InputNode);
2306 if (
const Expr *Receiver =
2308 return getParentTracker().track(Receiver, LVNode, Opts);
2322 if (
const auto *Arr = dyn_cast<ArraySubscriptExpr>(Inner))
2323 return getParentTracker().track(
2324 Arr->getIdx(), LVNode,
2325 {Opts.Kind, false});
2350 bool LVIsNull = LVState->isNull(LVal).isConstrainedTrue();
2355 if (RR && !LVIsNull)
2356 Result.combineWith(getParentTracker().track(LVal, RR, Opts, SFC));
2369 Report.
addVisitor<NoStoreFuncVisitor>(cast<SubRegion>(R), Opts.
Kind);
2373 Result.FoundSomethingToTrack =
true;
2374 Result.WasInterrupted =
true;
2376 MacroNullReturnSuppressionVisitor::addMacroVisitorIfNecessary(
2384 if (
V.getAsLocSymbol(
true))
2385 if (LVState->isNull(
V).isConstrainedTrue())
2388 false,
"Assuming pointer value is null");
2401 getParentTracker().track(
V, R, Opts, SFC);
2429 const bool BypassCXXNewExprEval = isa<CXXNewExpr>(E);
2436 if (std::optional<CallExitEnd> CEE =
2438 if (CEE->getCalleeContext()->getCallSite() == E)
2451 if (!BypassCXXNewExprEval)
2454 if (SP->getStmt() == E && CurrentSFC == PredSFC)
2457 CurrentSFC = PredSFC;
2480 if (cast<Expr>(E)->isGLValue())
2481 if (std::optional<Loc> LValue = RetVal.
getAs<
Loc>())
2482 RetVal = State->getSVal(*LValue);
2487 bool EnableNullFPSuppression =
false;
2489 if (std::optional<Loc> RetLoc = RetVal.
getAs<
Loc>())
2490 EnableNullFPSuppression = State->isNull(*RetLoc).isConstrainedTrue();
2493 Report.
addVisitor<ReturnVisitor>(&getParentTracker(), CalleeContext,
2494 EnableNullFPSuppression, Options,
2522 bool CanDereference =
true;
2524 if (SR->getPointeeStaticType()->isVoidType())
2525 CanDereference =
false;
2527 CanDereference =
false;
2534 RVal = LVState->getRawSVal(*L, Inner->getType());
2535 else if (CanDereference)
2536 RVal = LVState->getSVal(L->getRegion());
2538 if (CanDereference) {
2540 Result.FoundSomethingToTrack =
true;
2544 getParentTracker().track(RVal, L->getRegion(), Opts, SFC));
2548 if (isa_and_nonnull<SymbolicRegion>(RegionRVal)) {
2552 false,
"Assuming pointer value is null");
2553 Result.FoundSomethingToTrack =
true;
2580 const auto track = [&CombinedResult, &
Parent, ExprNode,
2581 Opts](
const Expr *Inner) {
2590 if (
const auto *ILE = dyn_cast<InitListExpr>(E)) {
2591 if (ILE->getNumInits() == 1) {
2592 track(ILE->getInit(0));
2594 return CombinedResult;
2602 const auto *BO = dyn_cast<BinaryOperator>(E);
2604 if (!BO || !BO->isMultiplicativeOp() || !
V.isZeroConstant())
2611 if (BO->getOpcode() == BO_Mul) {
2613 track(BO->getLHS());
2615 track(BO->getRHS());
2618 track(BO->getLHS());
2621 return CombinedResult;
2628 addLowPriorityHandler<ControlDependencyHandler>();
2629 addLowPriorityHandler<NilReceiverHandler>();
2630 addLowPriorityHandler<ArrayIndexHandler>();
2631 addLowPriorityHandler<InterestingLValueHandler>();
2632 addLowPriorityHandler<InlinedFunctionCallHandler>();
2633 addLowPriorityHandler<DefaultExpressionHandler>();
2634 addLowPriorityHandler<PRValueHandler>();
2636 addHighPriorityHandler<DefaultStoreHandler>();
2651 for (ExpressionHandlerPtr &Handler : ExpressionHandlers) {
2652 CombinedResult.
combineWith(Handler->handle(Inner, N, LVNode, Opts));
2661 return CombinedResult;
2666 if (!
V.isUnknown()) {
2667 Report.
addVisitor<StoreSiteFinder>(
this,
V, R, Opts, Origin);
2676 for (StoreHandlerPtr &Handler : StoreHandlers) {
2691 ->track(E, InputNode, Opts)
2692 .FoundSomethingToTrack;
2708 const auto *ME = dyn_cast<ObjCMessageExpr>(S);
2711 if (
const Expr *Receiver = ME->getInstanceReceiver()) {
2714 if (state->isNull(
V).isConstrainedTrue())
2727 const Stmt *S =
P->getStmt();
2728 const Expr *Receiver = getNilReceiver(S, N);
2733 llvm::raw_svector_ostream
OS(Buf);
2735 if (
const auto *ME = dyn_cast<ObjCMessageExpr>(S)) {
2737 ME->getSelector().print(
OS);
2738 OS <<
"' not called";
2741 OS <<
"No method is called";
2743 OS <<
" because the receiver is nil";
2754 return std::make_shared<PathDiagnosticEventPiece>(L,
OS.str());
2768 auto piece = VisitNodeImpl(N, BRC, BR);
2770 piece->setTag(getTag());
2771 if (
auto *ev = dyn_cast<PathDiagnosticEventPiece>(piece.get()))
2772 ev->setPrunable(
true,
false);
2782 const std::pair<const ProgramPointTag *, const ProgramPointTag *> &Tags =
2787 if (std::optional<BlockEdge> BE = ProgPoint.
getAs<
BlockEdge>()) {
2788 const CFGBlock *SrcBlock = BE->getSrc();
2796 if (PreviousNodeTag == Tags.first || PreviousNodeTag == Tags.second)
2799 return VisitTerminator(Term, N, SrcBlock, BE->getDst(), BR, BRC);
2804 if (std::optional<PostStmt> PS = ProgPoint.
getAs<
PostStmt>()) {
2806 if (CurrentNodeTag != Tags.first && CurrentNodeTag != Tags.second)
2809 bool TookTrue = CurrentNodeTag == Tags.first;
2810 return VisitTrueTest(cast<Expr>(PS->getStmt()), BRC, BR, N, TookTrue);
2820 const Expr *Cond =
nullptr;
2840 case Stmt::IfStmtClass:
2841 Cond = cast<IfStmt>(Term)->getCond();
2843 case Stmt::ConditionalOperatorClass:
2844 Cond = cast<ConditionalOperator>(Term)->getCond();
2846 case Stmt::BinaryOperatorClass:
2850 const auto *BO = cast<BinaryOperator>(Term);
2851 assert(BO->isLogicalOp() &&
2852 "CFG terminator is not a short-circuit operator!");
2853 Cond = BO->getLHS();
2862 while (
const auto *InnerBO = dyn_cast<BinaryOperator>(Cond)) {
2863 if (!InnerBO->isLogicalOp())
2870 const bool TookTrue = *(srcBlk->
succ_begin()) == dstBlk;
2871 return VisitTrueTest(Cond, BRC, R, N, TookTrue);
2898 CurrentState->getSVal(Cond, LCtx).isUnknownOrUndef();
2902 const Expr *CondTmp = Cond;
2903 bool TookTrueTmp = TookTrue;
2910 case Stmt::BinaryOperatorClass:
2911 if (
auto P = VisitTrueTest(Cond, cast<BinaryOperator>(CondTmp),
2912 BRC, R, N, TookTrueTmp, IsAssuming))
2915 case Stmt::DeclRefExprClass:
2916 if (
auto P = VisitTrueTest(Cond, cast<DeclRefExpr>(CondTmp),
2917 BRC, R, N, TookTrueTmp, IsAssuming))
2920 case Stmt::MemberExprClass:
2921 if (
auto P = VisitTrueTest(Cond, cast<MemberExpr>(CondTmp),
2922 BRC, R, N, TookTrueTmp, IsAssuming))
2925 case Stmt::UnaryOperatorClass: {
2926 const auto *UO = cast<UnaryOperator>(CondTmp);
2927 if (UO->getOpcode() == UO_LNot) {
2928 TookTrueTmp = !TookTrueTmp;
2929 CondTmp = UO->getSubExpr();
2949 return std::make_shared<PathDiagnosticEventPiece>(
2950 Loc, TookTrue ? GenericTrueMessage : GenericFalseMessage);
2957 std::optional<bool> &prunable,
2958 bool IsSameFieldName) {
2959 const Expr *OriginalExpr = Ex;
2980 if (
const auto *DR = dyn_cast<DeclRefExpr>(Ex)) {
2981 const bool quotes = isa<VarDecl>(DR->getDecl());
2998 Out << DR->getDecl()->getDeclName().getAsString();
3004 if (
const auto *IL = dyn_cast<IntegerLiteral>(Ex)) {
3007 if (IL->getValue() == 0) {
3013 if (IL->getValue() == 0) {
3019 Out << IL->getValue();
3023 if (
const auto *ME = dyn_cast<MemberExpr>(Ex)) {
3024 if (!IsSameFieldName)
3025 Out <<
"field '" << ME->getMemberDecl()->getName() <<
'\'';
3042 bool shouldInvert =
false;
3043 std::optional<bool> shouldPrune;
3047 bool IsSameFieldName =
false;
3053 LhsME->getMemberDecl()->getName() == RhsME->getMemberDecl()->getName();
3057 llvm::raw_svector_ostream OutLHS(LhsString), OutRHS(RhsString);
3058 const bool isVarLHS = patternMatch(BExpr->
getLHS(), BExpr, OutLHS, BRC, R,
3059 N, shouldPrune, IsSameFieldName);
3060 const bool isVarRHS = patternMatch(BExpr->
getRHS(), BExpr, OutRHS, BRC, R,
3061 N, shouldPrune, IsSameFieldName);
3063 shouldInvert = !isVarLHS && isVarRHS;
3071 return VisitConditionVariable(LhsString, BExpr->
getLHS(), BRC, R, N,
3077 if (LhsString.empty() || RhsString.empty() ||
3083 llvm::raw_svector_ostream Out(buf);
3084 Out << (IsAssuming ?
"Assuming " :
"")
3085 << (shouldInvert ? RhsString : LhsString) <<
" is ";
3091 case BO_LT: Op = BO_GT;
break;
3092 case BO_GT: Op = BO_LT;
break;
3093 case BO_LE: Op = BO_GE;
break;
3094 case BO_GE: Op = BO_LE;
break;
3099 case BO_EQ: Op = BO_NE;
break;
3100 case BO_NE: Op = BO_EQ;
break;
3101 case BO_LT: Op = BO_GE;
break;
3102 case BO_GT: Op = BO_LE;
break;
3103 case BO_LE: Op = BO_GT;
break;
3104 case BO_GE: Op = BO_LT;
break;
3114 Out <<
"not equal to ";
3121 Out << (shouldInvert ? LhsString : RhsString);
3130 std::string Message = std::string(Out.str());
3131 Message[0] = toupper(Message[0]);
3136 if (!shouldInvert) {
3137 if (LhsME && LhsME->getMemberLoc().isValid())
3142 if (RhsME && RhsME->getMemberLoc().isValid())
3148 return std::make_shared<PathDiagnosticPopUpPiece>(
Loc, Message);
3152 auto event = std::make_shared<PathDiagnosticEventPiece>(
Loc, Message);
3154 event->setPrunable(*shouldPrune);
3165 llvm::raw_svector_ostream Out(buf);
3166 Out <<
"Assuming " << LhsString <<
" is ";
3168 if (!printValue(CondVarExpr, Out, N, TookTrue,
true))
3177 auto event = std::make_shared<PathDiagnosticEventPiece>(
Loc, Out.str());
3180 event->setPrunable(
false);
3189 const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl());
3194 llvm::raw_svector_ostream Out(Buf);
3196 Out << (IsAssuming ?
"Assuming '" :
"'") << VD->getDeclName() <<
"' is ";
3198 if (!printValue(DRE, Out, N, TookTrue, IsAssuming))
3209 return std::make_shared<PathDiagnosticPopUpPiece>(
Loc, Out.str());
3213 auto event = std::make_shared<PathDiagnosticEventPiece>(
Loc, Out.str());
3216 event->setPrunable(
false);
3218 return std::move(event);
3226 llvm::raw_svector_ostream Out(Buf);
3228 Out << (IsAssuming ?
"Assuming field '" :
"Field '")
3231 if (!printValue(ME, Out, N, TookTrue, IsAssuming))
3251 return std::make_shared<PathDiagnosticPopUpPiece>(
Loc, Out.str());
3253 auto event = std::make_shared<PathDiagnosticEventPiece>(
Loc, Out.str());
3255 event->setPrunable(
false);
3265 Out << (TookTrue ?
"non-null" :
"null");
3270 Out << (TookTrue ?
"non-nil" :
"nil");
3277 std::optional<const llvm::APSInt *> IntValue;
3281 if (IsAssuming || !IntValue) {
3283 Out << (TookTrue ?
"true" :
"false");
3285 Out << (TookTrue ?
"not equal to 0" :
"0");
3288 Out << ((*IntValue)->getBoolValue() ?
"true" :
"false");
3296constexpr llvm::StringLiteral ConditionBRVisitor::GenericTrueMessage;
3297constexpr llvm::StringLiteral ConditionBRVisitor::GenericFalseMessage;
3301 return Piece->
getString() == GenericTrueMessage ||
3302 Piece->
getString() == GenericFalseMessage;
3322 if (Options.ShouldSuppressFromCXXStandardLibrary) {
3332 if (
const auto *MD = dyn_cast<CXXMethodDecl>(D)) {
3334 if (CD->
getName() ==
"list") {
3342 if (
const auto *MD = dyn_cast<CXXConstructorDecl>(D)) {
3344 if (CD->
getName() ==
"__independent_bits_engine") {
3352 const auto *MD = dyn_cast<CXXMethodDecl>(LCtx->getDecl());
3363 if (CD->
getName() ==
"basic_string") {
3371 if (CD->
getName() ==
"shared_ptr") {
3383 while (
Loc.isMacroID()) {
3384 Loc =
Loc.getSpellingLoc();
3385 if (
SM.getFilename(
Loc).ends_with(
"sys/queue.h")) {
3413 for (
const auto ParamDecl : parms) {
3414 const MemRegion *ArgReg =
Call->getArgSVal(Idx).getAsRegion();
3422 assert(ParamDecl &&
"Formal parameter has no decl?");
3437 SVal BoundVal = State->getSVal(R);
3460 llvm::SMTSolverRef RefutationSolver = llvm::CreateZ3Solver();
3464 for (
const auto &I : Constraints) {
3466 auto RangeIt = I.second.begin();
3469 RefutationSolver, Ctx, Sym, RangeIt->From(), RangeIt->To(),
3471 while ((++RangeIt) != I.second.end()) {
3472 SMTConstraints = RefutationSolver->mkOr(
3474 RangeIt->From(), RangeIt->To(),
3478 RefutationSolver->addConstraint(SMTConstraints);
3482 std::optional<bool> IsSAT = RefutationSolver->check();
3491 const ExplodedNode *N,
bool OverwriteConstraintsOnExistingSyms) {
3497 for (
auto const &
C : NewCs) {
3499 if (!Constraints.contains(Sym)) {
3501 Constraints =
CF.add(Constraints, Sym,
C.second);
3502 }
else if (OverwriteConstraintsOnExistingSyms) {
3504 Constraints =
CF.remove(Constraints, Sym);
3505 Constraints =
CF.add(Constraints, Sym,
C.second);
3517 llvm::FoldingSetNodeID &ID)
const {
3519 ID.AddPointer(&Tag);
3526int NoteTag::Kind = 0;
3530 ID.AddPointer(&Tag);
3541 if (std::optional<std::string> Msg =
T->generateMessage(BRC, R)) {
3544 auto Piece = std::make_shared<PathDiagnosticEventPiece>(
Loc, *Msg);
3545 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.
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 * > geteagerlyAssumeBinOpBifurcationTags()
PathDiagnosticPieceRef VisitNode(const ExplodedNode *N, BugReporterContext &BRC, PathSensitiveBugReport &BR) override
Return a diagnostic piece which should be associated with the given node.
void addConstraints(const ExplodedNode *N, bool OverwriteConstraintsOnExistingSyms)
void finalizeVisitor(BugReporterContext &BRC, const ExplodedNode *EndPathNode, PathSensitiveBugReport &BR) override
Last function called on the visitor, no further calls to VisitNode would follow.
FalsePositiveRefutationBRVisitor()
void Profile(llvm::FoldingSetNodeID &ID) const override
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.
Put a diagnostic on return statement (or on } in its absence) of all inlined functions for which some...
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.
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
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].
static llvm::SMTExprRef getRangeExpr(llvm::SMTSolverRef &Solver, ASTContext &Ctx, SymbolRef Sym, const llvm::APSInt &From, const llvm::APSInt &To, bool InRange)
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.
LLVM_ATTRIBUTE_RETURNS_NONNULL const TypedValueRegion * getRegion() const
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.
llvm::ImmutableMap< SymbolRef, RangeSet > ConstraintMap
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
@ CF
Indicates that the tracked object is a CF object.
std::shared_ptr< PathDiagnosticPiece > PathDiagnosticPieceRef
ConstraintMap getConstraintMap(ProgramStateRef State)
bool Ret(InterpState &S, CodePtr &PC, APValue &Result)
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 how types, statements, expressions, and declarations should be printed.
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.