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"
68using namespace bugreporter;
102 const auto *
E = dyn_cast<Expr>(S);
107 if (
const auto *CE = dyn_cast<CastExpr>(
E)) {
108 if (CE->getCastKind() == CK_LValueToRValue) {
112 E = CE->getSubExpr();
113 }
else if (
const auto *B = dyn_cast<BinaryOperator>(
E)) {
117 }
else if (B->isAssignmentOp()) {
125 }
else if (
const auto *
U = dyn_cast<UnaryOperator>(
E)) {
126 if (
U->getOpcode() == UO_Deref ||
U->getOpcode() == UO_AddrOf ||
127 (
U->isIncrementDecrementOp() &&
U->getType()->isPointerType())) {
138 else if (
const auto *ME = dyn_cast<MemberExpr>(
E)) {
147 if (ME->getMemberDecl()->getType()->isReferenceType())
150 }
else if (
const auto *IvarRef = dyn_cast<ObjCIvarRefExpr>(
E)) {
151 E = IvarRef->getBase();
152 }
else if (
const auto *AE = dyn_cast<ArraySubscriptExpr>(
E)) {
154 }
else if (
const auto *PE = dyn_cast<ParenExpr>(
E)) {
155 E = PE->getSubExpr();
156 }
else if (
const auto *FE = dyn_cast<FullExpr>(
E)) {
157 E = FE->getSubExpr();
167 if (
const auto *CE = dyn_cast<ImplicitCastExpr>(
E))
168 if (CE->getCastKind() == CK_LValueToRValue)
169 E = CE->getSubExpr();
175 if (
const auto *DR = dyn_cast<DeclRefExpr>(
E))
176 return dyn_cast<VarDecl>(DR->getDecl());
182 bool LookingForReference =
true) {
183 if (
const auto *ME = dyn_cast<MemberExpr>(
E)) {
193 const auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl());
197 if (FD->getType()->isReferenceType()) {
199 return N->
getState()->getLValue(FD, StructSVal).getAsRegion();
222 if (LeftVal == RightVal)
233 return LLCV->
getRegion() == RLCV->getRegion() &&
234 LLCV->getStore() == LeftNode->
getState()->getStore() &&
235 RLCV->getStore() == RightNode->
getState()->getStore();
250 if (
const auto *DRE = dyn_cast<DeclRefExpr>(CondVarExpr))
251 if (
const auto *VD = dyn_cast<VarDecl>(DRE->getDecl()))
252 return State->getSVal(State->getLValue(VD, LCtx));
254 if (
const auto *ME = dyn_cast<MemberExpr>(CondVarExpr))
255 if (
const auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl()))
256 if (
auto FieldL = State->getSVal(ME, LCtx).getAs<
Loc>())
257 return State->getRawSVal(*FieldL, FD->getType());
262static std::optional<const llvm::APSInt *>
267 return &CI->getValue();
281 if (std::optional<bugreporter::TrackingKind> K =
283 return *K == bugreporter::TrackingKind::Condition;
308 if (!
Loc.isMacroID())
310 while (
SM.isMacroArgExpansion(
Loc))
311 Loc =
SM.getImmediateExpansionRange(
Loc).getBegin();
312 std::pair<FileID, unsigned> TLInfo =
SM.getDecomposedLoc(
Loc);
339 SVal ValueAtN = N->
getState()->getSVal(RegionOfInterest);
341 .
areEqual(State, ValueAtN, ValueAfter)
372 auto P = std::make_shared<PathDiagnosticEventPiece>(
384bool NoStateChangeFuncVisitor::isModifiedInFrame(
const ExplodedNode *N) {
387 if (!FramesModifyingCalculated.count(SCtx))
388 findModifyingFrames(N);
389 return FramesModifying.count(SCtx);
392void NoStateChangeFuncVisitor::markFrameAsModifying(
395 auto p = FramesModifying.insert(SCtx);
411 auto IsMatchingCallExitEnd = [OrigSCtx](
const ExplodedNode *N) {
415 while (N && !IsMatchingCallExitEnd(N)) {
417 "This function is to be used on the trimmed ExplodedGraph!");
423void NoStateChangeFuncVisitor::findModifyingFrames(
431 const ExplodedNode *CurrCallExitBeginN = CallExitBeginN;
438 CurrCallExitBeginN = CurrN;
440 FramesModifyingCalculated.insert(CurrentSCtx);
445 if (
auto CE = CurrN->getLocationAs<
CallEnter>()) {
448 markFrameAsModifying(CurrentSCtx);
459 if (CE->getCalleeContext() == OriginalSCtx) {
460 markFrameAsModifying(CurrentSCtx);
466 markFrameAsModifying(CurrentSCtx);
479 if (!CallExitLoc || isModifiedInFrame(N))
494 if (
Call->isInSystemHeader()) {
509 if (
const auto *MC = dyn_cast<ObjCMethodCall>(
Call)) {
516 if (
const auto *CCall = dyn_cast<CXXConstructorCall>(
Call)) {
543 static const unsigned DEREFERENCE_LIMIT = 2;
550 MmrMgr(R->getMemRegionManager()),
551 SM(MmrMgr.getContext().getSourceManager()),
552 PP(MmrMgr.getContext().getPrintingPolicy()) {}
554 void Profile(llvm::FoldingSetNodeID &
ID)
const override {
557 ID.AddPointer(RegionOfInterest);
563 bool wasModifiedBeforeCallExit(
const ExplodedNode *CurrN,
572 const std::optional<RegionVector>
574 const MemRegion *R,
const RegionVector &Vec = {},
598 const MemRegion *MatchedRegion, StringRef FirstElement,
599 bool FirstIsReferenceType,
unsigned IndirectionLevel);
601 bool prettyPrintRegionName(
const RegionVector &FieldChain,
603 StringRef FirstElement,
bool FirstIsReferenceType,
604 unsigned IndirectionLevel,
605 llvm::raw_svector_ostream &os);
607 StringRef prettyPrintFirstElement(StringRef FirstElement,
608 bool MoreItemsExpected,
609 int IndirectionLevel,
610 llvm::raw_svector_ostream &os);
618 using namespace ast_matchers;
619 const char *IvarBind =
"Ivar";
623 hasOperatorName(
"="),
624 hasLHS(ignoringParenImpCasts(
630 if (IvarRef->isFreeIvar())
633 const Expr *
Base = IvarRef->getBase();
634 if (
const auto *ICE = dyn_cast<ImplicitCastExpr>(
Base))
635 Base = ICE->getSubExpr();
637 if (
const auto *DRE = dyn_cast<DeclRefExpr>(
Base))
638 if (
const auto *ID = dyn_cast<ImplicitParamDecl>(DRE->getDecl()))
653const std::optional<NoStoreFuncVisitor::RegionVector>
654NoStoreFuncVisitor::findRegionOfInterestInRecord(
659 if (depth == DEREFERENCE_LIMIT)
662 if (
const auto *RDX = dyn_cast<CXXRecordDecl>(RD))
663 if (!RDX->hasDefinition())
668 if (
const auto *RDX = dyn_cast<CXXRecordDecl>(RD))
669 for (
const auto &II : RDX->bases())
670 if (
const RecordDecl *RRD = II.getType()->getAsRecordDecl())
671 if (std::optional<RegionVector> Out =
672 findRegionOfInterestInRecord(RRD, State, R, Vec, depth))
678 const SVal V = State->getSVal(FR);
681 RegionVector VecF = Vec;
684 if (RegionOfInterest == VR)
689 findRegionOfInterestInRecord(RRD, State, FR, VecF, depth + 1))
697 if (std::optional<RegionVector> Out =
698 findRegionOfInterestInRecord(RRD, State, VR, VecF, depth + 1))
709 if (
const auto *IvarR = dyn_cast<ObjCIvarRegion>(RegionOfInterest)) {
710 const MemRegion *SelfRegion =
Call.getReceiverSVal().getAsRegion();
711 if (RegionOfInterest->isSubRegionOf(SelfRegion) &&
714 return maybeEmitNote(R,
Call, N, {}, SelfRegion,
"self",
725 if (RegionOfInterest->isSubRegionOf(ThisR) && !
Call.getDecl()->isImplicit())
726 return maybeEmitNote(R,
Call, N, {}, ThisR,
"this",
743 for (
unsigned I = 0; I <
Call.getNumArgs() && I <
Parameters.size(); ++I) {
749 unsigned IndirectionLevel = 1;
751 while (
const MemRegion *MR =
V.getAsRegion()) {
753 return maybeEmitNote(R,
Call, N, {}, MR, ParamName,
754 ParamIsReferenceType, IndirectionLevel);
757 if (PT.isNull() || PT->isVoidType())
762 if (
const RecordDecl *RD = PT->getAsRecordDecl())
763 if (std::optional<RegionVector>
P =
764 findRegionOfInterestInRecord(RD, State, MR))
765 return maybeEmitNote(R,
Call, N, *
P, RegionOfInterest, ParamName,
766 ParamIsReferenceType, IndirectionLevel);
768 V = State->getSVal(MR, PT);
777bool NoStoreFuncVisitor::wasModifiedBeforeCallExit(
779 return ::wasRegionOfInterestModifiedAt(
780 RegionOfInterest, CurrN,
781 CallExitBeginN->
getState()->getSVal(RegionOfInterest));
785 ", which participates in a condition later";
789 const RegionVector &FieldChain,
const MemRegion *MatchedRegion,
790 StringRef FirstElement,
bool FirstIsReferenceType,
791 unsigned IndirectionLevel) {
803 llvm::raw_svector_ostream os(sbuf);
804 os <<
"Returning without writing to '";
807 if (!prettyPrintRegionName(FieldChain, MatchedRegion, FirstElement,
808 FirstIsReferenceType, IndirectionLevel, os))
814 return std::make_shared<PathDiagnosticEventPiece>(L, os.str());
817bool NoStoreFuncVisitor::prettyPrintRegionName(
const RegionVector &FieldChain,
819 StringRef FirstElement,
820 bool FirstIsReferenceType,
821 unsigned IndirectionLevel,
822 llvm::raw_svector_ostream &os) {
824 if (FirstIsReferenceType)
827 RegionVector RegionSequence;
830 assert(RegionOfInterest->isSubRegionOf(MatchedRegion));
832 while (R != MatchedRegion) {
833 RegionSequence.push_back(R);
834 R = cast<SubRegion>(R)->getSuperRegion();
836 std::reverse(RegionSequence.begin(), RegionSequence.end());
837 RegionSequence.append(FieldChain.begin(), FieldChain.end());
840 for (
const MemRegion *R : RegionSequence) {
844 if (isa<CXXBaseObjectRegion, CXXTempObjectRegion>(R))
848 Sep = prettyPrintFirstElement(FirstElement,
850 IndirectionLevel, os);
855 if (!isa<DeclRegion>(R))
858 const auto *DR = cast<DeclRegion>(R);
859 Sep = DR->getValueType()->isAnyPointerType() ?
"->" :
".";
860 DR->getDecl()->getDeclName().print(os, PP);
864 prettyPrintFirstElement(FirstElement,
865 false, IndirectionLevel, os);
869StringRef NoStoreFuncVisitor::prettyPrintFirstElement(
870 StringRef FirstElement,
bool MoreItemsExpected,
int IndirectionLevel,
871 llvm::raw_svector_ostream &os) {
874 if (IndirectionLevel > 0 && MoreItemsExpected) {
879 if (IndirectionLevel > 0 && MoreItemsExpected)
882 for (
int i = 0; i < IndirectionLevel; i++)
886 if (IndirectionLevel > 0 && MoreItemsExpected)
902 const SVal ValueAtDereference;
906 bool WasModified =
false;
909 MacroNullReturnSuppressionVisitor(
const SubRegion *R,
const SVal V)
910 : RegionOfInterest(R), ValueAtDereference(
V) {}
923 if (
auto Loc = matchAssignment(N)) {
938 static void addMacroVisitorIfNecessary(
943 if (EnableNullFPSuppression && Options.ShouldSuppressNullReturnPaths &&
949 void* getTag()
const {
951 return static_cast<void *
>(&
Tag);
954 void Profile(llvm::FoldingSetNodeID &
ID)
const override {
955 ID.AddPointer(getTag());
961 std::optional<SourceLocation> matchAssignment(
const ExplodedNode *N) {
968 if (
const auto *DS = dyn_cast<DeclStmt>(S)) {
969 if (
const auto *VD = dyn_cast<VarDecl>(DS->getSingleDecl()))
970 if (
const Expr *RHS = VD->getInit())
971 if (RegionOfInterest->isSubRegionOf(
972 State->getLValue(VD, LCtx).getAsRegion()))
973 return RHS->getBeginLoc();
974 }
else if (
const auto *BO = dyn_cast<BinaryOperator>(S)) {
976 const Expr *RHS = BO->getRHS();
977 if (BO->isAssignmentOp() && RegionOfInterest->isSubRegionOf(R)) {
1004 bool EnableNullFPSuppression;
1005 bool ShouldInvalidate =
true;
1014 EnableNullFPSuppression(Suppressed), Options(Options), TKind(TKind) {}
1016 static void *getTag() {
1018 return static_cast<void *
>(&
Tag);
1021 void Profile(llvm::FoldingSetNodeID &
ID)
const override {
1022 ID.AddPointer(ReturnVisitor::getTag());
1023 ID.AddPointer(CalleeSFC);
1024 ID.AddBoolean(EnableNullFPSuppression);
1038 const auto *
Ret = dyn_cast<ReturnStmt>(SP->getStmt());
1045 SVal V = State->getSVal(Ret, CalleeSFC);
1046 if (
V.isUnknownOrUndef())
1052 const Expr *RetE =
Ret->getRetValue();
1053 assert(RetE &&
"Tracking a return value for a void function");
1056 std::optional<Loc> LValue;
1058 if ((LValue =
V.getAs<
Loc>())) {
1059 SVal RValue = State->getRawSVal(*LValue, RetE->
getType());
1060 if (isa<DefinedSVal>(RValue))
1066 if (isa<nonloc::LazyCompoundVal, nonloc::CompoundVal>(
V))
1072 getParentTracker().track(RetE, N, {TKind, EnableNullFPSuppression});
1076 llvm::raw_svector_ostream Out(Msg);
1078 bool WouldEventBeMeaningless =
false;
1080 if (State->isNull(
V).isConstrainedTrue()) {
1086 if (EnableNullFPSuppression &&
1087 Options.ShouldAvoidSuppressingNullArgumentPaths)
1088 Mode = MaybeUnsuppress;
1091 Out <<
"Returning nil";
1093 Out <<
"Returning null pointer";
1096 Out <<
"Returning zero";
1101 Out <<
"Returning the value " << CI->getValue();
1109 WouldEventBeMeaningless =
true;
1111 Out << (isa<Loc>(
V) ?
"Returning pointer" :
"Returning value");
1116 if (
const MemRegion *MR = LValue->getAsRegion()) {
1117 if (MR->canPrintPretty()) {
1118 Out <<
" (reference to ";
1119 MR->printPretty(Out);
1125 if (
const auto *DR = dyn_cast<DeclRefExpr>(RetE))
1126 if (
const auto *DD = dyn_cast<DeclaratorDecl>(DR->getDecl()))
1127 Out <<
" (loaded from '" << *DD <<
"')";
1131 if (!L.isValid() || !L.asLocation().isValid())
1134 if (TKind == bugreporter::TrackingKind::Condition)
1137 auto EventPiece = std::make_shared<PathDiagnosticEventPiece>(L, Out.str());
1141 if (WouldEventBeMeaningless)
1142 EventPiece->setPrunable(
true);
1152 assert(Options.ShouldAvoidSuppressingNullArgumentPaths);
1159 if (CE->getCalleeContext() != CalleeSFC)
1172 for (
unsigned I = 0,
E =
Call->getNumArgs(); I !=
E; ++I) {
1173 std::optional<Loc> ArgV =
Call->getArgSVal(I).getAs<
Loc>();
1177 const Expr *ArgE =
Call->getArgExpr(I);
1182 if (!State->isNull(*ArgV).isConstrainedTrue())
1185 if (getParentTracker()
1186 .track(ArgE, N, {TKind, EnableNullFPSuppression})
1187 .FoundSomethingToTrack)
1188 ShouldInvalidate =
false;
1203 return visitNodeInitial(N, BRC, BR);
1204 case MaybeUnsuppress:
1205 return visitNodeMaybeUnsuppress(N, BRC, BR);
1210 llvm_unreachable(
"Invalid visit mode!");
1215 if (EnableNullFPSuppression && ShouldInvalidate)
1216 BR.
markInvalid(ReturnVisitor::getTag(), CalleeSFC);
1229 bool Satisfied =
false;
1249 OriginSFC(OriginSFC) {
1253 void Profile(llvm::FoldingSetNodeID &
ID)
const override;
1261void StoreSiteFinder::Profile(llvm::FoldingSetNodeID &ID)
const {
1263 ID.AddPointer(&tag);
1266 ID.AddInteger(
static_cast<int>(Options.Kind));
1267 ID.AddBoolean(Options.EnableNullFPSuppression);
1285 const auto *FrameSpace = dyn_cast<StackSpaceRegion>(VarSpace);
1301 if (
const auto *TR = dyn_cast<TypedValueRegion>(R))
1302 return TR->getValueType()->isObjCObjectPointerType();
1308 return D->getType()->isObjCObjectPointerType();
1320 const char *Action =
nullptr;
1324 Action = HasPrefix ?
"initialized to " :
"Initializing to ";
1327 Action = HasPrefix ?
"captured by block as " :
"Captured by block as ";
1330 llvm_unreachable(
"Unexpected store kind");
1333 if (isa<loc::ConcreteInt>(SI.
Value)) {
1337 OS << Action << CVal->getValue();
1340 OS << Action <<
"the value of ";
1351 if (isa<VarRegion>(SI.
Dest)) {
1352 const auto *VD = cast<VarDecl>(DS->getSingleDecl());
1354 if (VD->getInit()) {
1355 OS << (HasPrefix ?
"initialized" :
"Initializing")
1356 <<
" to a garbage value";
1358 OS << (HasPrefix ?
"declared" :
"Declaring")
1359 <<
" without an initial value";
1363 OS << (HasPrefix ?
"initialized" :
"Initialized") <<
" here";
1371 const auto *VR = cast<VarRegion>(SI.
Dest);
1372 const auto *
D = VR->getDecl();
1376 if (isa<loc::ConcreteInt>(SI.
Value)) {
1380 OS <<
"uninitialized value";
1383 OS <<
"the value " << CI->getValue();
1392 if (
const auto *Param = dyn_cast<ParmVarDecl>(VR->getDecl())) {
1394 unsigned Idx = Param->getFunctionScopeIndex() + 1;
1395 OS <<
" via " << Idx << llvm::getOrdinalSuffix(Idx) <<
" parameter";
1400 }
else if (
const auto *ImplParam = dyn_cast<ImplicitParamDecl>(
D)) {
1402 OS <<
" via implicit parameter 'self'";
1412 if (isa<loc::ConcreteInt>(SI.
Value)) {
1414 : (HasSuffix ?
"Null pointer value stored"
1415 :
"Storing null pointer value"));
1418 OS << (HasSuffix ?
"Uninitialized value stored"
1419 :
"Storing uninitialized value");
1423 OS <<
"The value " << CV->getValue() <<
" is assigned";
1425 OS <<
"Assigning " << CV->getValue();
1429 OS <<
"The value of ";
1431 OS <<
" is assigned";
1433 OS <<
"Assigning the value of ";
1438 OS << (HasSuffix ?
"Value assigned" :
"Assigning value");
1459 const auto *TVR = dyn_cast_or_null<TypedValueRegion>(R);
1467 std::stack<const TypedValueRegion *> TVRStack;
1468 while (isa<FieldRegion>(TVR) || isa<ElementRegion>(TVR)) {
1473 if (ITy == TVR->getValueType().getCanonicalType())
1477 TVR = cast<TypedValueRegion>(TVR->getSuperRegion());
1482 if (ITy != TVR->getValueType().getCanonicalType())
1486 while (!TVRStack.empty()) {
1487 TVR = TVRStack.top();
1492 if (!isa<InitListExpr>(
Init))
1495 ILE = cast<InitListExpr>(
Init);
1498 if (
const auto *FR = dyn_cast<FieldRegion>(TVR)) {
1499 const auto *FD = FR->
getDecl();
1501 if (FD->getFieldIndex() >= NumInits)
1505 }
else if (
const auto *ER = dyn_cast<ElementRegion>(TVR)) {
1506 const auto Ind = ER->getIndex();
1510 if (!Ind.isConstant())
1513 const auto IndVal = Ind.getAsInteger()->getLimitedValue();
1514 if (IndVal >= NumInits)
1532 const Expr *InitE =
nullptr;
1533 bool IsParam =
false;
1536 if (
const auto *VR = dyn_cast<VarRegion>(R)) {
1539 InitE = VR->getDecl()->getInit();
1545 if (std::optional<PostInitializer> PIP =
1548 if (FieldReg == R) {
1550 InitE = PIP->getInitializer()->getInit();
1565 if (!PS || PS->getLocationValue() != R)
1575 if (BO->isAssignmentOp())
1576 InitE = BO->getRHS();
1580 else if (
const auto *DS =
P->getStmtAs<
DeclStmt>()) {
1581 const auto *
Decl = DS->getSingleDecl();
1582 if (isa<VarDecl>(
Decl)) {
1583 const auto *VD = cast<VarDecl>(
Decl);
1591 if (
const auto *ILE = dyn_cast<InitListExpr>(VD->getInit()))
1596 const auto State = Succ->
getState();
1607 std::stack<const SubRegion *> SRStack;
1608 const SubRegion *SR = cast<SubRegion>(R);
1609 while (isa<FieldRegion>(SR) || isa<ElementRegion>(SR)) {
1615 const auto *OriginEx = CE->getArg(0);
1616 const auto OriginVal =
1622 SVal OriginField = OriginVal;
1623 while (!SRStack.empty()) {
1624 const auto *TopR = SRStack.top();
1627 if (
const auto *FR = dyn_cast<FieldRegion>(TopR)) {
1628 OriginField = State->getLValue(FR->
getDecl(), OriginField);
1629 }
else if (
const auto *ER = dyn_cast<ElementRegion>(TopR)) {
1630 OriginField = State->getLValue(ER->getElementType(),
1631 ER->getIndex(), OriginField);
1638 getParentTracker().track(
V, OriginField.
getAsRegion(), Options);
1659 if (
const auto *VR = dyn_cast<VarRegion>(R)) {
1661 if (
const auto *Param = dyn_cast<ParmVarDecl>(VR->getDecl())) {
1667 InitE =
Call->getArgExpr(Param->getFunctionScopeIndex());
1670 assert(isa<ImplicitParamDecl>(VR->getDecl()));
1671 InitE = cast<ObjCMessageExpr>(CE->getCalleeContext()->getCallSite())
1680 if (
const auto *TmpR = dyn_cast<CXXTempObjectRegion>(R))
1681 InitE = TmpR->getExpr();
1695 getParentTracker().track(InitE, StoreSite, Options);
1719 if (
SM.includedInBindings(N->
getState()->getStore(), Candidate)) {
1721 if (N->
getState()->getSVal(Candidate) ==
V) {
1722 OldRegion = Candidate;
1741 if (!OldRegion && StoreSite->
getState()->getSVal(R) ==
V) {
1746 NodeWithoutBinding && NodeWithoutBinding->
getState()->getSVal(R) ==
V;
1747 NodeWithoutBinding = NodeWithoutBinding->
getFirstPred()) {
1750 if (NodeWithoutBinding) {
1762 OldRegion = FB.getRegion();
1766 if (Options.Kind == TrackingKind::Condition && OriginSFC &&
1772 llvm::raw_svector_ostream os(sbuf);
1782 const Stmt *S = PS->getStmt();
1783 const auto *DS = dyn_cast<DeclStmt>(S);
1784 const auto *VR = dyn_cast<VarRegion>(R);
1788 }
else if (isa<BlockExpr>(S)) {
1794 if (
const auto *BDR =
1795 dyn_cast_or_null<BlockDataRegion>(
V.getAsRegion())) {
1796 if (
const VarRegion *OriginalR = BDR->getOriginalRegion(VR)) {
1797 getParentTracker().track(State->getSVal(OriginalR), OriginalR,
1798 Options, OriginSFC);
1804 isa<VarRegion>(SI.
Dest)) {
1808 return getParentTracker().handle(SI, BRC, Options);
1817 ID.AddPointer(&tag);
1818 ID.AddString(Message);
1819 ID.AddBoolean(Assumption);
1826 return "TrackConstraintBRVisitor";
1829bool TrackConstraintBRVisitor::isZeroCheck()
const {
1830 return !Assumption && Constraint.
getAs<
Loc>();
1833bool TrackConstraintBRVisitor::isUnderconstrained(
const ExplodedNode *N)
const {
1835 return N->
getState()->isNull(Constraint).isUnderconstrained();
1836 return (
bool)N->
getState()->assume(Constraint, !Assumption);
1847 if (!IsTrackingTurnedOn)
1848 if (!isUnderconstrained(N))
1849 IsTrackingTurnedOn =
true;
1850 if (!IsTrackingTurnedOn)
1855 if (isUnderconstrained(PrevN)) {
1862 assert(!isUnderconstrained(N));
1870 if (isa_and_nonnull<NoteTag>(
P.getTag()))
1878 auto X = std::make_shared<PathDiagnosticEventPiece>(L, Message);
1880 return std::move(
X);
1895 if (!Options.ShouldSuppressInlinedDefensiveChecks)
1900 llvm::FoldingSetNodeID &ID)
const {
1907 return "IDCVisitor";
1919 if (!IsTrackingTurnedOn)
1920 if (Succ->
getState()->isNull(
V).isConstrainedTrue())
1921 IsTrackingTurnedOn =
true;
1922 if (!IsTrackingTurnedOn)
1927 if (!Pred->
getState()->isNull(
V).isConstrainedTrue() &&
1928 Succ->
getState()->isNull(
V).isConstrainedTrue()) {
1934 if (CurLC != ReportLC && !CurLC->
isParentOf(ReportLC)) {
1949 const Stmt *CurTerminatorStmt =
nullptr;
1951 CurTerminatorStmt = BE->getSrc()->getTerminator().getStmt();
1953 const Stmt *CurStmt = SP->getStmt();
1963 if (!CurTerminatorStmt)
1997class TrackControlDependencyCondBRVisitor final
2001 llvm::SmallSet<const CFGBlock *, 32> VisitedBlocks;
2004 TrackControlDependencyCondBRVisitor(
TrackerRef ParentTracker,
2007 ControlDeps(&O->getCFG()) {}
2009 void Profile(llvm::FoldingSetNodeID &
ID)
const override {
2020static std::shared_ptr<PathDiagnosticEventPiece>
2033 return std::make_shared<PathDiagnosticEventPiece>(
2036 (Twine() +
"Tracking condition '" + ConditionText +
"'").str());
2064 if (
const auto *BinOp = dyn_cast<BinaryOperator>(ElseCond))
2065 if (BinOp->isLogicalOp())
2072TrackControlDependencyCondBRVisitor::VisitNode(
const ExplodedNode *N,
2082 if (!VisitedBlocks.insert(NB).second)
2088 if (!OriginB || !NB)
2094 if (ControlDeps.isControlDependent(OriginB, NB)) {
2120 if (isa<CallExpr>(InnerExpr))
2127 getParentTracker().track(InnerExpr, N,
2145 if (
const auto *FE = dyn_cast<FullExpr>(Ex))
2147 if (
const auto *OVE = dyn_cast<OpaqueValueExpr>(Ex))
2149 if (
const auto *POE = dyn_cast<PseudoObjectExpr>(Ex)) {
2150 const auto *PropRef = dyn_cast<ObjCPropertyRefExpr>(POE->getSyntacticForm());
2151 if (PropRef && PropRef->isMessagingGetter()) {
2152 const Expr *GetterMessageSend =
2153 POE->getSemanticExpr(POE->getNumSemanticExprs() - 1);
2160 if (
const auto *CO = dyn_cast<ConditionalOperator>(Ex)) {
2166 if (std::optional<BlockEdge> BE = ProgPoint.
getAs<
BlockEdge>()) {
2167 const CFGBlock *srcBlk = BE->getSrc();
2170 bool TookTrueBranch = (*(srcBlk->
succ_begin()) == BE->getDst());
2182 if (
auto *BO = dyn_cast<BinaryOperator>(Ex))
2186 if (
auto *UO = dyn_cast<UnaryOperator>(Ex)) {
2187 if (UO->getOpcode() == UO_LNot)
2198 if (UO->getOpcode() == UO_AddrOf && UO->getSubExpr()->isLValue())
2209 const Expr *Inner) {
2224 StringRef NodeText) {
2230 P.getLocationContext());
2238 return std::make_shared<PathDiagnosticEventPiece>(L, NodeText);
2250 llvm::raw_svector_ostream OS(Buffer);
2265 if (Opts.
Kind == bugreporter::TrackingKind::Condition)
2268 return constructNote(SI, BRC, OS.str());
2288 ->getAnalysisManager()
2289 .getAnalyzerOptions()
2290 .ShouldTrackConditions) {
2291 Report.
addVisitor<TrackControlDependencyCondBRVisitor>(
2292 &getParentTracker(), InputNode);
2310 if (
const Expr *Receiver =
2312 return getParentTracker().track(Receiver, LVNode, Opts);
2326 if (
const auto *Arr = dyn_cast<ArraySubscriptExpr>(Inner))
2327 return getParentTracker().track(
2328 Arr->getIdx(), LVNode,
2329 {Opts.Kind, false});
2354 bool LVIsNull = LVState->isNull(LVal).isConstrainedTrue();
2359 if (RR && !LVIsNull)
2360 Result.combineWith(getParentTracker().track(LVal, RR, Opts, SFC));
2373 Report.
addVisitor<NoStoreFuncVisitor>(cast<SubRegion>(R), Opts.
Kind);
2377 Result.FoundSomethingToTrack =
true;
2378 Result.WasInterrupted =
true;
2380 MacroNullReturnSuppressionVisitor::addMacroVisitorIfNecessary(
2388 if (
V.getAsLocSymbol(
true))
2389 if (LVState->isNull(
V).isConstrainedTrue())
2392 false,
"Assuming pointer value is null");
2405 getParentTracker().track(
V, R, Opts, SFC);
2433 const bool BypassCXXNewExprEval = isa<CXXNewExpr>(
E);
2440 if (std::optional<CallExitEnd> CEE =
2442 if (CEE->getCalleeContext()->getCallSite() ==
E)
2455 if (!BypassCXXNewExprEval)
2458 if (SP->getStmt() ==
E && CurrentSFC == PredSFC)
2461 CurrentSFC = PredSFC;
2484 if (cast<Expr>(
E)->isGLValue())
2485 if (std::optional<Loc> LValue = RetVal.
getAs<
Loc>())
2486 RetVal = State->getSVal(*LValue);
2491 bool EnableNullFPSuppression =
false;
2493 if (std::optional<Loc> RetLoc = RetVal.
getAs<
Loc>())
2494 EnableNullFPSuppression = State->isNull(*RetLoc).isConstrainedTrue();
2497 Report.
addVisitor<ReturnVisitor>(&getParentTracker(), CalleeContext,
2498 EnableNullFPSuppression, Options,
2526 bool CanDereference =
true;
2528 if (SR->getPointeeStaticType()->isVoidType())
2529 CanDereference =
false;
2531 CanDereference =
false;
2538 RVal = LVState->getRawSVal(*L, Inner->getType());
2539 else if (CanDereference)
2540 RVal = LVState->getSVal(L->getRegion());
2542 if (CanDereference) {
2544 Result.FoundSomethingToTrack =
true;
2548 getParentTracker().track(RVal, L->getRegion(), Opts, SFC));
2552 if (isa_and_nonnull<SymbolicRegion>(RegionRVal)) {
2556 false,
"Assuming pointer value is null");
2557 Result.FoundSomethingToTrack =
true;
2584 const auto track = [&CombinedResult, &
Parent, ExprNode,
2585 Opts](
const Expr *Inner) {
2594 if (
const auto *ILE = dyn_cast<InitListExpr>(
E)) {
2595 if (ILE->getNumInits() == 1) {
2596 track(ILE->getInit(0));
2598 return CombinedResult;
2606 const auto *BO = dyn_cast<BinaryOperator>(
E);
2608 if (!BO || !BO->isMultiplicativeOp() || !
V.isZeroConstant())
2615 if (BO->getOpcode() == BO_Mul) {
2617 track(BO->getLHS());
2619 track(BO->getRHS());
2622 track(BO->getLHS());
2625 return CombinedResult;
2632 addLowPriorityHandler<ControlDependencyHandler>();
2633 addLowPriorityHandler<NilReceiverHandler>();
2634 addLowPriorityHandler<ArrayIndexHandler>();
2635 addLowPriorityHandler<InterestingLValueHandler>();
2636 addLowPriorityHandler<InlinedFunctionCallHandler>();
2637 addLowPriorityHandler<DefaultExpressionHandler>();
2638 addLowPriorityHandler<PRValueHandler>();
2640 addHighPriorityHandler<DefaultStoreHandler>();
2655 for (ExpressionHandlerPtr &Handler : ExpressionHandlers) {
2656 CombinedResult.
combineWith(Handler->handle(Inner, N, LVNode, Opts));
2665 return CombinedResult;
2670 if (!
V.isUnknown()) {
2671 Report.
addVisitor<StoreSiteFinder>(
this,
V, R, Opts, Origin);
2680 for (StoreHandlerPtr &Handler : StoreHandlers) {
2695 ->track(
E, InputNode, Opts)
2696 .FoundSomethingToTrack;
2712 const auto *ME = dyn_cast<ObjCMessageExpr>(S);
2715 if (
const Expr *Receiver = ME->getInstanceReceiver()) {
2718 if (state->isNull(
V).isConstrainedTrue())
2731 const Stmt *S =
P->getStmt();
2732 const Expr *Receiver = getNilReceiver(S, N);
2737 llvm::raw_svector_ostream
OS(Buf);
2739 if (
const auto *ME = dyn_cast<ObjCMessageExpr>(S)) {
2741 ME->getSelector().print(
OS);
2742 OS <<
"' not called";
2745 OS <<
"No method is called";
2747 OS <<
" because the receiver is nil";
2758 return std::make_shared<PathDiagnosticEventPiece>(L,
OS.str());
2772 auto piece = VisitNodeImpl(N, BRC, BR);
2774 piece->setTag(getTag());
2775 if (
auto *ev = dyn_cast<PathDiagnosticEventPiece>(piece.get()))
2776 ev->setPrunable(
true,
false);
2786 const std::pair<const ProgramPointTag *, const ProgramPointTag *> &Tags =
2791 if (std::optional<BlockEdge> BE = ProgPoint.
getAs<
BlockEdge>()) {
2792 const CFGBlock *SrcBlock = BE->getSrc();
2800 if (PreviousNodeTag == Tags.first || PreviousNodeTag == Tags.second)
2803 return VisitTerminator(Term, N, SrcBlock, BE->getDst(), BR, BRC);
2808 if (std::optional<PostStmt> PS = ProgPoint.
getAs<
PostStmt>()) {
2810 if (CurrentNodeTag != Tags.first && CurrentNodeTag != Tags.second)
2813 bool TookTrue = CurrentNodeTag == Tags.first;
2814 return VisitTrueTest(cast<Expr>(PS->getStmt()), BRC, BR, N, TookTrue);
2824 const Expr *Cond =
nullptr;
2844 case Stmt::IfStmtClass:
2845 Cond = cast<IfStmt>(Term)->getCond();
2847 case Stmt::ConditionalOperatorClass:
2848 Cond = cast<ConditionalOperator>(Term)->getCond();
2850 case Stmt::BinaryOperatorClass:
2854 const auto *BO = cast<BinaryOperator>(Term);
2855 assert(BO->isLogicalOp() &&
2856 "CFG terminator is not a short-circuit operator!");
2857 Cond = BO->getLHS();
2866 while (
const auto *InnerBO = dyn_cast<BinaryOperator>(Cond)) {
2867 if (!InnerBO->isLogicalOp())
2874 const bool TookTrue = *(srcBlk->
succ_begin()) == dstBlk;
2875 return VisitTrueTest(Cond, BRC, R, N, TookTrue);
2902 CurrentState->getSVal(Cond, LCtx).isUnknownOrUndef();
2906 const Expr *CondTmp = Cond;
2907 bool TookTrueTmp = TookTrue;
2914 case Stmt::BinaryOperatorClass:
2915 if (
auto P = VisitTrueTest(Cond, cast<BinaryOperator>(CondTmp),
2916 BRC, R, N, TookTrueTmp, IsAssuming))
2919 case Stmt::DeclRefExprClass:
2920 if (
auto P = VisitTrueTest(Cond, cast<DeclRefExpr>(CondTmp),
2921 BRC, R, N, TookTrueTmp, IsAssuming))
2924 case Stmt::MemberExprClass:
2925 if (
auto P = VisitTrueTest(Cond, cast<MemberExpr>(CondTmp),
2926 BRC, R, N, TookTrueTmp, IsAssuming))
2929 case Stmt::UnaryOperatorClass: {
2930 const auto *UO = cast<UnaryOperator>(CondTmp);
2931 if (UO->getOpcode() == UO_LNot) {
2932 TookTrueTmp = !TookTrueTmp;
2933 CondTmp = UO->getSubExpr();
2953 return std::make_shared<PathDiagnosticEventPiece>(
2954 Loc, TookTrue ? GenericTrueMessage : GenericFalseMessage);
2961 std::optional<bool> &prunable,
2962 bool IsSameFieldName) {
2963 const Expr *OriginalExpr = Ex;
2984 if (
const auto *DR = dyn_cast<DeclRefExpr>(Ex)) {
2985 const bool quotes = isa<VarDecl>(DR->getDecl());
3002 Out << DR->getDecl()->getDeclName().getAsString();
3008 if (
const auto *IL = dyn_cast<IntegerLiteral>(Ex)) {
3011 if (IL->getValue() == 0) {
3017 if (IL->getValue() == 0) {
3023 Out << IL->getValue();
3027 if (
const auto *ME = dyn_cast<MemberExpr>(Ex)) {
3028 if (!IsSameFieldName)
3029 Out <<
"field '" << ME->getMemberDecl()->getName() <<
'\'';
3046 bool shouldInvert =
false;
3047 std::optional<bool> shouldPrune;
3051 bool IsSameFieldName =
false;
3057 LhsME->getMemberDecl()->getName() == RhsME->getMemberDecl()->getName();
3061 llvm::raw_svector_ostream OutLHS(LhsString), OutRHS(RhsString);
3062 const bool isVarLHS = patternMatch(BExpr->
getLHS(), BExpr, OutLHS, BRC, R,
3063 N, shouldPrune, IsSameFieldName);
3064 const bool isVarRHS = patternMatch(BExpr->
getRHS(), BExpr, OutRHS, BRC, R,
3065 N, shouldPrune, IsSameFieldName);
3067 shouldInvert = !isVarLHS && isVarRHS;
3075 return VisitConditionVariable(LhsString, BExpr->
getLHS(), BRC, R, N,
3081 if (LhsString.empty() || RhsString.empty() ||
3087 llvm::raw_svector_ostream Out(buf);
3088 Out << (IsAssuming ?
"Assuming " :
"")
3089 << (shouldInvert ? RhsString : LhsString) <<
" is ";
3095 case BO_LT: Op = BO_GT;
break;
3096 case BO_GT: Op = BO_LT;
break;
3097 case BO_LE: Op = BO_GE;
break;
3098 case BO_GE: Op = BO_LE;
break;
3103 case BO_EQ: Op = BO_NE;
break;
3104 case BO_NE: Op = BO_EQ;
break;
3105 case BO_LT: Op = BO_GE;
break;
3106 case BO_GT: Op = BO_LE;
break;
3107 case BO_LE: Op = BO_GT;
break;
3108 case BO_GE: Op = BO_LT;
break;
3118 Out <<
"not equal to ";
3125 Out << (shouldInvert ? LhsString : RhsString);
3134 std::string Message = std::string(Out.str());
3135 Message[0] = toupper(Message[0]);
3140 if (!shouldInvert) {
3141 if (LhsME && LhsME->getMemberLoc().isValid())
3146 if (RhsME && RhsME->getMemberLoc().isValid())
3152 return std::make_shared<PathDiagnosticPopUpPiece>(
Loc, Message);
3156 auto event = std::make_shared<PathDiagnosticEventPiece>(
Loc, Message);
3158 event->setPrunable(*shouldPrune);
3169 llvm::raw_svector_ostream Out(buf);
3170 Out <<
"Assuming " << LhsString <<
" is ";
3172 if (!printValue(CondVarExpr, Out, N, TookTrue,
true))
3181 auto event = std::make_shared<PathDiagnosticEventPiece>(
Loc, Out.str());
3184 event->setPrunable(
false);
3193 const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl());
3198 llvm::raw_svector_ostream Out(Buf);
3200 Out << (IsAssuming ?
"Assuming '" :
"'") << VD->getDeclName() <<
"' is ";
3202 if (!printValue(DRE, Out, N, TookTrue, IsAssuming))
3213 return std::make_shared<PathDiagnosticPopUpPiece>(
Loc, Out.str());
3217 auto event = std::make_shared<PathDiagnosticEventPiece>(
Loc, Out.str());
3220 event->setPrunable(
false);
3222 return std::move(event);
3230 llvm::raw_svector_ostream Out(Buf);
3232 Out << (IsAssuming ?
"Assuming field '" :
"Field '")
3235 if (!printValue(ME, Out, N, TookTrue, IsAssuming))
3255 return std::make_shared<PathDiagnosticPopUpPiece>(
Loc, Out.str());
3257 auto event = std::make_shared<PathDiagnosticEventPiece>(
Loc, Out.str());
3259 event->setPrunable(
false);
3269 Out << (TookTrue ?
"non-null" :
"null");
3274 Out << (TookTrue ?
"non-nil" :
"nil");
3281 std::optional<const llvm::APSInt *> IntValue;
3285 if (IsAssuming || !IntValue) {
3287 Out << (TookTrue ?
"true" :
"false");
3289 Out << (TookTrue ?
"not equal to 0" :
"0");
3292 Out << ((*IntValue)->getBoolValue() ?
"true" :
"false");
3300constexpr llvm::StringLiteral ConditionBRVisitor::GenericTrueMessage;
3301constexpr llvm::StringLiteral ConditionBRVisitor::GenericFalseMessage;
3305 return Piece->
getString() == GenericTrueMessage ||
3306 Piece->
getString() == GenericFalseMessage;
3326 if (Options.ShouldSuppressFromCXXStandardLibrary) {
3336 if (
const auto *MD = dyn_cast<CXXMethodDecl>(
D)) {
3338 if (CD->
getName() ==
"list") {
3346 if (
const auto *MD = dyn_cast<CXXConstructorDecl>(
D)) {
3348 if (CD->
getName() ==
"__independent_bits_engine") {
3356 const auto *MD = dyn_cast<CXXMethodDecl>(LCtx->getDecl());
3367 if (CD->
getName() ==
"basic_string") {
3375 if (CD->
getName() ==
"shared_ptr") {
3387 while (
Loc.isMacroID()) {
3388 Loc =
Loc.getSpellingLoc();
3389 if (
SM.getFilename(
Loc).ends_with(
"sys/queue.h")) {
3417 for (
const auto ParamDecl : parms) {
3418 const MemRegion *ArgReg =
Call->getArgSVal(Idx).getAsRegion();
3426 assert(ParamDecl &&
"Formal parameter has no decl?");
3441 SVal BoundVal = State->getSVal(R);
3454int NoteTag::Kind = 0;
3458 ID.AddPointer(&Tag);
3469 if (std::optional<std::string> Msg =
T->generateMessage(BRC, R)) {
3472 auto Piece = std::make_shared<PathDiagnosticEventPiece>(
Loc, *Msg);
3473 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()
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].
ConditionTruthVal areEqual(ProgramStateRef state, SVal lhs, SVal rhs)
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
bool isZeroConstant() const
std::optional< T > getAs() const
Convert to the specified SVal type, returning std::nullopt if this SVal is not of the desired type.
const MemRegion * getAsRegion() const
SubRegion - A region that subsets another larger region.
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * getSuperRegion() const
bool isSubRegionOf(const MemRegion *R) const override
Check if the region is a subregion of the given region.
PathDiagnosticPieceRef VisitNode(const ExplodedNode *Succ, BugReporterContext &BRC, PathSensitiveBugReport &BR) override
Return a diagnostic piece which should be associated with the given node.
SuppressInlineDefensiveChecksVisitor(DefinedSVal Val, const ExplodedNode *N)
static const char * getTag()
Return the tag associated with this visitor.
void Profile(llvm::FoldingSetNodeID &ID) const override
SymbolicRegion - A special, "non-concrete" region.
void Profile(llvm::FoldingSetNodeID &ID) const override
PathDiagnosticPieceRef VisitNode(const ExplodedNode *N, BugReporterContext &BRC, PathSensitiveBugReport &R) override
Return a diagnostic piece which should be associated with the given node.
void Profile(llvm::FoldingSetNodeID &ID) const override
static const char * getTag()
Return the tag associated with this visitor.
PathDiagnosticPieceRef VisitNode(const ExplodedNode *N, BugReporterContext &BRC, PathSensitiveBugReport &BR) override
Return a diagnostic piece which should be associated with the given node.
When a region containing undefined value or '0' value is passed as an argument in a call,...
PathDiagnosticPieceRef VisitNode(const ExplodedNode *N, BugReporterContext &BRC, PathSensitiveBugReport &BR) override
Return a diagnostic piece which should be associated with the given node.
const VarDecl * getDecl() const override=0
Handles expressions during the tracking.
ExpressionHandler(Tracker &ParentTracker)
Handles stores during the tracking.
StoreHandler(Tracker &ParentTracker)
PathDiagnosticPieceRef constructNote(StoreInfo SI, BugReporterContext &BRC, StringRef NodeText)
A generalized component for tracking expressions, values, and stores.
static TrackerRef create(PathSensitiveBugReport &Report)
virtual PathDiagnosticPieceRef handle(StoreInfo SI, BugReporterContext &BRC, TrackingOptions Opts)
Handle the store operation and produce the note.
Tracker(PathSensitiveBugReport &Report)
virtual Result track(const Expr *E, const ExplodedNode *N, TrackingOptions Opts={})
Track expression value back to its point of origin.
Visitor that tracks expressions and values.
Value representing integer constant.
While nonloc::CompoundVal covers a few simple use cases, nonloc::LazyCompoundVal is a more performant...
LLVM_ATTRIBUTE_RETURNS_NONNULL const TypedValueRegion * getRegion() const
This function itself is immaterial.
const internal::VariadicDynCastAllOfMatcher< Stmt, ObjCIvarRefExpr > objcIvarRefExpr
Matches a reference to an ObjCIvar.
const internal::ArgumentAdaptingMatcherFunc< internal::HasDescendantMatcher > hasDescendant
Matches AST nodes that have descendant AST nodes that match the provided matcher.
SmallVector< BoundNodes, 1 > match(MatcherT Matcher, const NodeT &Node, ASTContext &Context)
Returns the results of matching Matcher on Node.
const internal::VariadicDynCastAllOfMatcher< Stmt, BinaryOperator > binaryOperator
Matches binary operator expressions.
internal::Matcher< Stmt > StatementMatcher
static std::string getMacroName(MacroType Macro, GtestCmp Cmp)
internal::PolymorphicMatcher< internal::HasDeclarationMatcher, void(internal::HasDeclarationSupportedTypes), internal::Matcher< Decl > > hasDeclaration(const internal::Matcher< Decl > &InnerMatcher)
Matches a node if the declaration associated with that node matches the given matcher.
const internal::VariadicAllOfMatcher< Stmt > stmt
Matches statements.
const Expr * getDerefExpr(const Stmt *S)
Given that expression S represents a pointer that would be dereferenced, try to find a sub-expression...
bool trackExpressionValue(const ExplodedNode *N, const Expr *E, PathSensitiveBugReport &R, TrackingOptions Opts={})
Attempts to add visitors to track expression value back to its point of origin.
void trackStoredValue(SVal V, const MemRegion *R, PathSensitiveBugReport &Report, TrackingOptions Opts={}, const StackFrameContext *Origin=nullptr)
Track how the value got stored into the given region and where it came from.
TrackingKind
Specifies the type of tracking for an expression.
@ Thorough
Default tracking kind – specifies that as much information should be gathered about the tracked expre...
@ Condition
Specifies that a more moderate tracking should be used for the expression value.
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
std::shared_ptr< PathDiagnosticPiece > PathDiagnosticPieceRef
bool Ret(InterpState &S, CodePtr &PC, 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.