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)) {
116 }
else if (B->isAssignmentOp()) {
124 }
else if (
const auto *
U = dyn_cast<UnaryOperator>(E)) {
125 if (
U->getOpcode() == UO_Deref ||
U->getOpcode() == UO_AddrOf ||
126 (
U->isIncrementDecrementOp() &&
U->getType()->isPointerType())) {
137 else if (
const auto *ME = dyn_cast<MemberExpr>(E)) {
146 if (ME->getMemberDecl()->getType()->isReferenceType())
149 }
else if (
const auto *IvarRef = dyn_cast<ObjCIvarRefExpr>(E)) {
150 E = IvarRef->getBase();
151 }
else if (
const auto *AE = dyn_cast<ArraySubscriptExpr>(E)) {
153 }
else if (
const auto *PE = dyn_cast<ParenExpr>(E)) {
154 E = PE->getSubExpr();
155 }
else if (
const auto *FE = dyn_cast<FullExpr>(E)) {
156 E = FE->getSubExpr();
166 if (
const auto *CE = dyn_cast<ImplicitCastExpr>(E))
167 if (CE->getCastKind() == CK_LValueToRValue)
168 E = CE->getSubExpr();
174 if (
const auto *DR = dyn_cast<DeclRefExpr>(E))
175 return dyn_cast<VarDecl>(DR->getDecl());
181 bool LookingForReference =
true) {
182 if (
const auto *ME = dyn_cast<MemberExpr>(E)) {
192 const auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl());
196 if (FD->getType()->isReferenceType()) {
198 return N->
getState()->getLValue(FD, StructSVal).getAsRegion();
221 if (LeftVal == RightVal)
232 return LLCV->
getRegion() == RLCV->getRegion() &&
233 LLCV->getStore() == LeftNode->
getState()->getStore() &&
234 RLCV->getStore() == RightNode->
getState()->getStore();
249 if (
const auto *DRE = dyn_cast<DeclRefExpr>(CondVarExpr))
250 if (
const auto *VD = dyn_cast<VarDecl>(DRE->getDecl()))
251 return State->getSVal(State->getLValue(VD, LCtx));
253 if (
const auto *ME = dyn_cast<MemberExpr>(CondVarExpr))
254 if (
const auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl()))
255 if (
auto FieldL = State->getSVal(ME, LCtx).getAs<
Loc>())
256 return State->getRawSVal(*FieldL, FD->getType());
261static std::optional<const llvm::APSInt *>
266 return &CI->getValue();
280 if (std::optional<bugreporter::TrackingKind> K =
282 return *K == bugreporter::TrackingKind::Condition;
307 if (!
Loc.isMacroID())
309 while (
SM.isMacroArgExpansion(
Loc))
310 Loc =
SM.getImmediateExpansionRange(
Loc).getBegin();
311 std::pair<FileID, unsigned> TLInfo =
SM.getDecomposedLoc(
Loc);
338 SVal ValueAtN = N->
getState()->getSVal(RegionOfInterest);
340 .
areEqual(State, ValueAtN, ValueAfter)
371 auto P = std::make_shared<PathDiagnosticEventPiece>(
383bool NoStateChangeFuncVisitor::isModifiedInFrame(
const ExplodedNode *N) {
386 if (!FramesModifyingCalculated.count(SCtx))
387 findModifyingFrames(N);
388 return FramesModifying.count(SCtx);
391void NoStateChangeFuncVisitor::markFrameAsModifying(
394 auto p = FramesModifying.insert(SCtx);
410 auto IsMatchingCallExitEnd = [OrigSCtx](
const ExplodedNode *N) {
414 while (N && !IsMatchingCallExitEnd(N)) {
416 "This function is to be used on the trimmed ExplodedGraph!");
422void NoStateChangeFuncVisitor::findModifyingFrames(
430 const ExplodedNode *CurrCallExitBeginN = CallExitBeginN;
437 CurrCallExitBeginN = CurrN;
439 FramesModifyingCalculated.insert(CurrentSCtx);
444 if (
auto CE = CurrN->getLocationAs<
CallEnter>()) {
447 markFrameAsModifying(CurrentSCtx);
458 if (CE->getCalleeContext() == OriginalSCtx) {
459 markFrameAsModifying(CurrentSCtx);
465 markFrameAsModifying(CurrentSCtx);
478 if (!CallExitLoc || isModifiedInFrame(N))
493 if (
Call->isInSystemHeader()) {
508 if (
const auto *MC = dyn_cast<ObjCMethodCall>(
Call)) {
515 if (
const auto *CCall = dyn_cast<CXXConstructorCall>(
Call)) {
542 static const unsigned DEREFERENCE_LIMIT = 2;
549 MmrMgr(R->getMemRegionManager()),
550 SM(MmrMgr.getContext().getSourceManager()),
551 PP(MmrMgr.getContext().getPrintingPolicy()) {}
553 void Profile(llvm::FoldingSetNodeID &
ID)
const override {
556 ID.AddPointer(RegionOfInterest);
562 bool wasModifiedBeforeCallExit(
const ExplodedNode *CurrN,
571 const std::optional<RegionVector>
573 const MemRegion *R,
const RegionVector &Vec = {},
597 const MemRegion *MatchedRegion, StringRef FirstElement,
598 bool FirstIsReferenceType,
unsigned IndirectionLevel);
600 bool prettyPrintRegionName(
const RegionVector &FieldChain,
602 StringRef FirstElement,
bool FirstIsReferenceType,
603 unsigned IndirectionLevel,
604 llvm::raw_svector_ostream &os);
606 StringRef prettyPrintFirstElement(StringRef FirstElement,
607 bool MoreItemsExpected,
608 int IndirectionLevel,
609 llvm::raw_svector_ostream &os);
617 using namespace ast_matchers;
618 const char *IvarBind =
"Ivar";
622 hasOperatorName(
"="),
623 hasLHS(ignoringParenImpCasts(
629 if (IvarRef->isFreeIvar())
632 const Expr *
Base = IvarRef->getBase();
633 if (
const auto *ICE = dyn_cast<ImplicitCastExpr>(
Base))
634 Base = ICE->getSubExpr();
636 if (
const auto *DRE = dyn_cast<DeclRefExpr>(
Base))
637 if (
const auto *ID = dyn_cast<ImplicitParamDecl>(DRE->getDecl()))
652const std::optional<NoStoreFuncVisitor::RegionVector>
653NoStoreFuncVisitor::findRegionOfInterestInRecord(
658 if (depth == DEREFERENCE_LIMIT)
661 if (
const auto *RDX = dyn_cast<CXXRecordDecl>(RD))
662 if (!RDX->hasDefinition())
667 if (
const auto *RDX = dyn_cast<CXXRecordDecl>(RD))
668 for (
const auto &II : RDX->bases())
669 if (
const RecordDecl *RRD = II.getType()->getAsRecordDecl())
670 if (std::optional<RegionVector> Out =
671 findRegionOfInterestInRecord(RRD, State, R, Vec, depth))
677 const SVal V = State->getSVal(FR);
680 RegionVector VecF = Vec;
683 if (RegionOfInterest == VR)
688 findRegionOfInterestInRecord(RRD, State, FR, VecF, depth + 1))
696 if (std::optional<RegionVector> Out =
697 findRegionOfInterestInRecord(RRD, State, VR, VecF, depth + 1))
708 if (
const auto *IvarR = dyn_cast<ObjCIvarRegion>(RegionOfInterest)) {
709 const MemRegion *SelfRegion =
Call.getReceiverSVal().getAsRegion();
710 if (RegionOfInterest->isSubRegionOf(SelfRegion) &&
713 return maybeEmitNote(R,
Call, N, {}, SelfRegion,
"self",
724 if (RegionOfInterest->isSubRegionOf(ThisR) && !
Call.getDecl()->isImplicit())
725 return maybeEmitNote(R,
Call, N, {}, ThisR,
"this",
742 for (
unsigned I = 0; I <
Call.getNumArgs() && I <
Parameters.size(); ++I) {
748 unsigned IndirectionLevel = 1;
750 while (
const MemRegion *MR =
V.getAsRegion()) {
752 return maybeEmitNote(R,
Call, N, {}, MR, ParamName,
753 ParamIsReferenceType, IndirectionLevel);
756 if (PT.isNull() || PT->isVoidType())
761 if (
const RecordDecl *RD = PT->getAsRecordDecl())
762 if (std::optional<RegionVector>
P =
763 findRegionOfInterestInRecord(RD, State, MR))
764 return maybeEmitNote(R,
Call, N, *
P, RegionOfInterest, ParamName,
765 ParamIsReferenceType, IndirectionLevel);
767 V = State->getSVal(MR, PT);
776bool NoStoreFuncVisitor::wasModifiedBeforeCallExit(
778 return ::wasRegionOfInterestModifiedAt(
779 RegionOfInterest, CurrN,
780 CallExitBeginN->
getState()->getSVal(RegionOfInterest));
784 ", which participates in a condition later";
788 const RegionVector &FieldChain,
const MemRegion *MatchedRegion,
789 StringRef FirstElement,
bool FirstIsReferenceType,
790 unsigned IndirectionLevel) {
802 llvm::raw_svector_ostream os(sbuf);
803 os <<
"Returning without writing to '";
806 if (!prettyPrintRegionName(FieldChain, MatchedRegion, FirstElement,
807 FirstIsReferenceType, IndirectionLevel, os))
813 return std::make_shared<PathDiagnosticEventPiece>(L, os.str());
816bool NoStoreFuncVisitor::prettyPrintRegionName(
const RegionVector &FieldChain,
818 StringRef FirstElement,
819 bool FirstIsReferenceType,
820 unsigned IndirectionLevel,
821 llvm::raw_svector_ostream &os) {
823 if (FirstIsReferenceType)
826 RegionVector RegionSequence;
829 assert(RegionOfInterest->isSubRegionOf(MatchedRegion));
831 while (R != MatchedRegion) {
832 RegionSequence.push_back(R);
833 R = cast<SubRegion>(R)->getSuperRegion();
835 std::reverse(RegionSequence.begin(), RegionSequence.end());
836 RegionSequence.append(FieldChain.begin(), FieldChain.end());
839 for (
const MemRegion *R : RegionSequence) {
843 if (isa<CXXBaseObjectRegion, CXXTempObjectRegion>(R))
847 Sep = prettyPrintFirstElement(FirstElement,
849 IndirectionLevel, os);
854 if (!isa<DeclRegion>(R))
857 const auto *DR = cast<DeclRegion>(R);
858 Sep = DR->getValueType()->isAnyPointerType() ?
"->" :
".";
859 DR->getDecl()->getDeclName().print(os, PP);
863 prettyPrintFirstElement(FirstElement,
864 false, IndirectionLevel, os);
868StringRef NoStoreFuncVisitor::prettyPrintFirstElement(
869 StringRef FirstElement,
bool MoreItemsExpected,
int IndirectionLevel,
870 llvm::raw_svector_ostream &os) {
873 if (IndirectionLevel > 0 && MoreItemsExpected) {
878 if (IndirectionLevel > 0 && MoreItemsExpected)
881 for (
int i = 0; i < IndirectionLevel; i++)
885 if (IndirectionLevel > 0 && MoreItemsExpected)
901 const SVal ValueAtDereference;
905 bool WasModified =
false;
908 MacroNullReturnSuppressionVisitor(
const SubRegion *R,
const SVal V)
909 : RegionOfInterest(R), ValueAtDereference(
V) {}
922 if (
auto Loc = matchAssignment(N)) {
937 static void addMacroVisitorIfNecessary(
942 if (EnableNullFPSuppression && Options.ShouldSuppressNullReturnPaths &&
948 void* getTag()
const {
950 return static_cast<void *
>(&Tag);
953 void Profile(llvm::FoldingSetNodeID &
ID)
const override {
954 ID.AddPointer(getTag());
960 std::optional<SourceLocation> matchAssignment(
const ExplodedNode *N) {
967 if (
const auto *DS = dyn_cast<DeclStmt>(S)) {
968 if (
const auto *VD = dyn_cast<VarDecl>(DS->getSingleDecl()))
969 if (
const Expr *RHS = VD->getInit())
970 if (RegionOfInterest->isSubRegionOf(
971 State->getLValue(VD, LCtx).getAsRegion()))
972 return RHS->getBeginLoc();
973 }
else if (
const auto *BO = dyn_cast<BinaryOperator>(S)) {
975 const Expr *RHS = BO->getRHS();
976 if (BO->isAssignmentOp() && RegionOfInterest->isSubRegionOf(R)) {
1003 bool EnableNullFPSuppression;
1004 bool ShouldInvalidate =
true;
1013 EnableNullFPSuppression(Suppressed), Options(Options), TKind(TKind) {}
1015 static void *getTag() {
1017 return static_cast<void *
>(&Tag);
1020 void Profile(llvm::FoldingSetNodeID &
ID)
const override {
1021 ID.AddPointer(ReturnVisitor::getTag());
1022 ID.AddPointer(CalleeSFC);
1023 ID.AddBoolean(EnableNullFPSuppression);
1037 const auto *
Ret = dyn_cast<ReturnStmt>(SP->getStmt());
1044 SVal V = State->getSVal(Ret, CalleeSFC);
1045 if (
V.isUnknownOrUndef())
1051 const Expr *RetE =
Ret->getRetValue();
1052 assert(RetE &&
"Tracking a return value for a void function");
1055 std::optional<Loc> LValue;
1057 if ((LValue =
V.getAs<
Loc>())) {
1058 SVal RValue = State->getRawSVal(*LValue, RetE->
getType());
1059 if (isa<DefinedSVal>(RValue))
1065 if (isa<nonloc::LazyCompoundVal, nonloc::CompoundVal>(
V))
1071 getParentTracker().track(RetE, N, {TKind, EnableNullFPSuppression});
1075 llvm::raw_svector_ostream Out(Msg);
1077 bool WouldEventBeMeaningless =
false;
1079 if (State->isNull(
V).isConstrainedTrue()) {
1085 if (EnableNullFPSuppression &&
1086 Options.ShouldAvoidSuppressingNullArgumentPaths)
1087 Mode = MaybeUnsuppress;
1090 Out <<
"Returning nil";
1092 Out <<
"Returning null pointer";
1095 Out <<
"Returning zero";
1100 Out <<
"Returning the value " << CI->getValue();
1108 WouldEventBeMeaningless =
true;
1110 Out << (isa<Loc>(
V) ?
"Returning pointer" :
"Returning value");
1115 if (
const MemRegion *MR = LValue->getAsRegion()) {
1116 if (MR->canPrintPretty()) {
1117 Out <<
" (reference to ";
1118 MR->printPretty(Out);
1124 if (
const auto *DR = dyn_cast<DeclRefExpr>(RetE))
1125 if (
const auto *DD = dyn_cast<DeclaratorDecl>(DR->getDecl()))
1126 Out <<
" (loaded from '" << *DD <<
"')";
1130 if (!L.isValid() || !L.asLocation().isValid())
1133 if (TKind == bugreporter::TrackingKind::Condition)
1136 auto EventPiece = std::make_shared<PathDiagnosticEventPiece>(L, Out.str());
1140 if (WouldEventBeMeaningless)
1141 EventPiece->setPrunable(
true);
1151 assert(Options.ShouldAvoidSuppressingNullArgumentPaths);
1158 if (CE->getCalleeContext() != CalleeSFC)
1171 for (
unsigned I = 0, E =
Call->getNumArgs(); I != E; ++I) {
1172 std::optional<Loc> ArgV =
Call->getArgSVal(I).getAs<
Loc>();
1176 const Expr *ArgE =
Call->getArgExpr(I);
1181 if (!State->isNull(*ArgV).isConstrainedTrue())
1184 if (getParentTracker()
1185 .track(ArgE, N, {TKind, EnableNullFPSuppression})
1186 .FoundSomethingToTrack)
1187 ShouldInvalidate =
false;
1202 return visitNodeInitial(N, BRC, BR);
1203 case MaybeUnsuppress:
1204 return visitNodeMaybeUnsuppress(N, BRC, BR);
1209 llvm_unreachable(
"Invalid visit mode!");
1214 if (EnableNullFPSuppression && ShouldInvalidate)
1215 BR.
markInvalid(ReturnVisitor::getTag(), CalleeSFC);
1228 bool Satisfied =
false;
1248 OriginSFC(OriginSFC) {
1252 void Profile(llvm::FoldingSetNodeID &
ID)
const override;
1260void StoreSiteFinder::Profile(llvm::FoldingSetNodeID &ID)
const {
1262 ID.AddPointer(&tag);
1265 ID.AddInteger(
static_cast<int>(Options.Kind));
1266 ID.AddBoolean(Options.EnableNullFPSuppression);
1284 const auto *FrameSpace = dyn_cast<StackSpaceRegion>(VarSpace);
1300 if (
const auto *TR = dyn_cast<TypedValueRegion>(R))
1301 return TR->getValueType()->isObjCObjectPointerType();
1319 const char *Action =
nullptr;
1323 Action = HasPrefix ?
"initialized to " :
"Initializing to ";
1326 Action = HasPrefix ?
"captured by block as " :
"Captured by block as ";
1329 llvm_unreachable(
"Unexpected store kind");
1332 if (isa<loc::ConcreteInt>(SI.
Value)) {
1336 OS << Action << CVal->getValue();
1339 OS << Action <<
"the value of ";
1350 if (isa<VarRegion>(SI.
Dest)) {
1351 const auto *VD = cast<VarDecl>(DS->getSingleDecl());
1353 if (VD->getInit()) {
1354 OS << (HasPrefix ?
"initialized" :
"Initializing")
1355 <<
" to a garbage value";
1357 OS << (HasPrefix ?
"declared" :
"Declaring")
1358 <<
" without an initial value";
1362 OS << (HasPrefix ?
"initialized" :
"Initialized") <<
" here";
1370 const auto *VR = cast<VarRegion>(SI.
Dest);
1371 const auto *D = VR->getDecl();
1375 if (isa<loc::ConcreteInt>(SI.
Value)) {
1376 OS << (
isObjCPointer(D) ?
"nil object reference" :
"null pointer value");
1379 OS <<
"uninitialized value";
1382 OS <<
"the value " << CI->getValue();
1391 if (
const auto *Param = dyn_cast<ParmVarDecl>(VR->getDecl())) {
1393 unsigned Idx = Param->getFunctionScopeIndex() + 1;
1394 OS <<
" via " << Idx << llvm::getOrdinalSuffix(Idx) <<
" parameter";
1399 }
else if (
const auto *ImplParam = dyn_cast<ImplicitParamDecl>(D)) {
1401 OS <<
" via implicit parameter 'self'";
1411 if (isa<loc::ConcreteInt>(SI.
Value)) {
1413 : (HasSuffix ?
"Null pointer value stored"
1414 :
"Storing null pointer value"));
1417 OS << (HasSuffix ?
"Uninitialized value stored"
1418 :
"Storing uninitialized value");
1422 OS <<
"The value " << CV->getValue() <<
" is assigned";
1424 OS <<
"Assigning " << CV->getValue();
1428 OS <<
"The value of ";
1430 OS <<
" is assigned";
1432 OS <<
"Assigning the value of ";
1437 OS << (HasSuffix ?
"Value assigned" :
"Assigning value");
1458 const auto *TVR = dyn_cast_or_null<TypedValueRegion>(R);
1466 std::stack<const TypedValueRegion *> TVRStack;
1467 while (isa<FieldRegion>(TVR) || isa<ElementRegion>(TVR)) {
1472 if (ITy == TVR->getValueType().getCanonicalType())
1476 TVR = cast<TypedValueRegion>(TVR->getSuperRegion());
1481 if (ITy != TVR->getValueType().getCanonicalType())
1485 while (!TVRStack.empty()) {
1486 TVR = TVRStack.top();
1491 if (!isa<InitListExpr>(
Init))
1494 ILE = cast<InitListExpr>(
Init);
1497 if (
const auto *FR = dyn_cast<FieldRegion>(TVR)) {
1498 const auto *FD = FR->
getDecl();
1500 if (FD->getFieldIndex() >= NumInits)
1504 }
else if (
const auto *ER = dyn_cast<ElementRegion>(TVR)) {
1505 const auto Ind = ER->getIndex();
1509 if (!Ind.isConstant())
1512 const auto IndVal = Ind.getAsInteger()->getLimitedValue();
1513 if (IndVal >= NumInits)
1531 const Expr *InitE =
nullptr;
1532 bool IsParam =
false;
1535 if (
const auto *VR = dyn_cast<VarRegion>(R)) {
1538 InitE = VR->getDecl()->getInit();
1544 if (std::optional<PostInitializer> PIP =
1547 if (FieldReg == R) {
1549 InitE = PIP->getInitializer()->getInit();
1564 if (!PS || PS->getLocationValue() != R)
1574 if (BO->isAssignmentOp())
1575 InitE = BO->getRHS();
1579 else if (
const auto *DS =
P->getStmtAs<
DeclStmt>()) {
1580 const auto *
Decl = DS->getSingleDecl();
1581 if (isa<VarDecl>(
Decl)) {
1582 const auto *VD = cast<VarDecl>(
Decl);
1590 if (
const auto *ILE = dyn_cast<InitListExpr>(VD->getInit()))
1595 const auto State = Succ->
getState();
1606 std::stack<const SubRegion *> SRStack;
1607 const SubRegion *SR = cast<SubRegion>(R);
1608 while (isa<FieldRegion>(SR) || isa<ElementRegion>(SR)) {
1614 const auto *OriginEx = CE->getArg(0);
1615 const auto OriginVal =
1621 SVal OriginField = OriginVal;
1622 while (!SRStack.empty()) {
1623 const auto *TopR = SRStack.top();
1626 if (
const auto *FR = dyn_cast<FieldRegion>(TopR)) {
1627 OriginField = State->getLValue(FR->
getDecl(), OriginField);
1628 }
else if (
const auto *ER = dyn_cast<ElementRegion>(TopR)) {
1629 OriginField = State->getLValue(ER->getElementType(),
1630 ER->getIndex(), OriginField);
1637 getParentTracker().track(
V, OriginField.
getAsRegion(), Options);
1658 if (
const auto *VR = dyn_cast<VarRegion>(R)) {
1660 if (
const auto *Param = dyn_cast<ParmVarDecl>(VR->getDecl())) {
1666 InitE =
Call->getArgExpr(Param->getFunctionScopeIndex());
1669 assert(isa<ImplicitParamDecl>(VR->getDecl()));
1670 InitE = cast<ObjCMessageExpr>(CE->getCalleeContext()->getCallSite())
1679 if (
const auto *TmpR = dyn_cast<CXXTempObjectRegion>(R))
1680 InitE = TmpR->getExpr();
1694 getParentTracker().track(InitE, StoreSite, Options);
1718 if (
SM.includedInBindings(N->
getState()->getStore(), Candidate)) {
1720 if (N->
getState()->getSVal(Candidate) ==
V) {
1721 OldRegion = Candidate;
1740 if (!OldRegion && StoreSite->
getState()->getSVal(R) ==
V) {
1745 NodeWithoutBinding && NodeWithoutBinding->
getState()->getSVal(R) ==
V;
1746 NodeWithoutBinding = NodeWithoutBinding->
getFirstPred()) {
1749 if (NodeWithoutBinding) {
1761 OldRegion = FB.getRegion();
1765 if (Options.Kind == TrackingKind::Condition && OriginSFC &&
1771 llvm::raw_svector_ostream os(sbuf);
1781 const Stmt *S = PS->getStmt();
1782 const auto *DS = dyn_cast<DeclStmt>(S);
1783 const auto *VR = dyn_cast<VarRegion>(R);
1787 }
else if (isa<BlockExpr>(S)) {
1793 if (
const auto *BDR =
1794 dyn_cast_or_null<BlockDataRegion>(
V.getAsRegion())) {
1795 if (
const VarRegion *OriginalR = BDR->getOriginalRegion(VR)) {
1796 getParentTracker().track(State->getSVal(OriginalR), OriginalR,
1797 Options, OriginSFC);
1803 isa<VarRegion>(SI.
Dest)) {
1807 return getParentTracker().handle(SI, BRC, Options);
1816 ID.AddPointer(&tag);
1817 ID.AddString(Message);
1818 ID.AddBoolean(Assumption);
1825 return "TrackConstraintBRVisitor";
1828bool TrackConstraintBRVisitor::isZeroCheck()
const {
1829 return !Assumption && Constraint.
getAs<
Loc>();
1832bool TrackConstraintBRVisitor::isUnderconstrained(
const ExplodedNode *N)
const {
1834 return N->
getState()->isNull(Constraint).isUnderconstrained();
1835 return (
bool)N->
getState()->assume(Constraint, !Assumption);
1846 if (!IsTrackingTurnedOn)
1847 if (!isUnderconstrained(N))
1848 IsTrackingTurnedOn =
true;
1849 if (!IsTrackingTurnedOn)
1854 if (isUnderconstrained(PrevN)) {
1861 assert(!isUnderconstrained(N));
1869 if (isa_and_nonnull<NoteTag>(
P.getTag()))
1877 auto X = std::make_shared<PathDiagnosticEventPiece>(L, Message);
1879 return std::move(
X);
1894 if (!Options.ShouldSuppressInlinedDefensiveChecks)
1899 llvm::FoldingSetNodeID &ID)
const {
1906 return "IDCVisitor";
1918 if (!IsTrackingTurnedOn)
1919 if (Succ->
getState()->isNull(
V).isConstrainedTrue())
1920 IsTrackingTurnedOn =
true;
1921 if (!IsTrackingTurnedOn)
1926 if (!Pred->
getState()->isNull(
V).isConstrainedTrue() &&
1927 Succ->
getState()->isNull(
V).isConstrainedTrue()) {
1933 if (CurLC != ReportLC && !CurLC->
isParentOf(ReportLC)) {
1948 const Stmt *CurTerminatorStmt =
nullptr;
1950 CurTerminatorStmt = BE->getSrc()->getTerminator().getStmt();
1952 const Stmt *CurStmt = SP->getStmt();
1962 if (!CurTerminatorStmt)
1996class TrackControlDependencyCondBRVisitor final
2000 llvm::SmallSet<const CFGBlock *, 32> VisitedBlocks;
2003 TrackControlDependencyCondBRVisitor(
TrackerRef ParentTracker,
2006 ControlDeps(&O->getCFG()) {}
2008 void Profile(llvm::FoldingSetNodeID &
ID)
const override {
2019static std::shared_ptr<PathDiagnosticEventPiece>
2032 return std::make_shared<PathDiagnosticEventPiece>(
2035 (Twine() +
"Tracking condition '" + ConditionText +
"'").str());
2063 if (
const auto *BinOp = dyn_cast<BinaryOperator>(ElseCond))
2064 if (BinOp->isLogicalOp())
2071TrackControlDependencyCondBRVisitor::VisitNode(
const ExplodedNode *N,
2081 if (!VisitedBlocks.insert(NB).second)
2087 if (!OriginB || !NB)
2093 if (ControlDeps.isControlDependent(OriginB, NB)) {
2119 if (isa<CallExpr>(InnerExpr))
2126 getParentTracker().track(InnerExpr, N,
2144 if (
const auto *FE = dyn_cast<FullExpr>(Ex))
2146 if (
const auto *OVE = dyn_cast<OpaqueValueExpr>(Ex))
2148 if (
const auto *POE = dyn_cast<PseudoObjectExpr>(Ex)) {
2149 const auto *PropRef = dyn_cast<ObjCPropertyRefExpr>(POE->getSyntacticForm());
2150 if (PropRef && PropRef->isMessagingGetter()) {
2151 const Expr *GetterMessageSend =
2152 POE->getSemanticExpr(POE->getNumSemanticExprs() - 1);
2159 if (
const auto *CO = dyn_cast<ConditionalOperator>(Ex)) {
2165 if (std::optional<BlockEdge> BE = ProgPoint.
getAs<
BlockEdge>()) {
2166 const CFGBlock *srcBlk = BE->getSrc();
2169 bool TookTrueBranch = (*(srcBlk->
succ_begin()) == BE->getDst());
2181 if (
auto *BO = dyn_cast<BinaryOperator>(Ex))
2185 if (
auto *UO = dyn_cast<UnaryOperator>(Ex)) {
2186 if (UO->getOpcode() == UO_LNot)
2197 if (UO->getOpcode() == UO_AddrOf && UO->getSubExpr()->isLValue())
2208 const Expr *Inner) {
2223 StringRef NodeText) {
2229 P.getLocationContext());
2237 return std::make_shared<PathDiagnosticEventPiece>(L, NodeText);
2249 llvm::raw_svector_ostream OS(Buffer);
2264 if (Opts.
Kind == bugreporter::TrackingKind::Condition)
2267 return constructNote(SI, BRC, OS.str());
2287 ->getAnalysisManager()
2288 .getAnalyzerOptions()
2289 .ShouldTrackConditions) {
2290 Report.
addVisitor<TrackControlDependencyCondBRVisitor>(
2291 &getParentTracker(), InputNode);
2309 if (
const Expr *Receiver =
2311 return getParentTracker().track(Receiver, LVNode, Opts);
2325 if (
const auto *Arr = dyn_cast<ArraySubscriptExpr>(Inner))
2326 return getParentTracker().track(
2327 Arr->getIdx(), LVNode,
2328 {Opts.Kind, false});
2353 bool LVIsNull = LVState->isNull(LVal).isConstrainedTrue();
2358 if (RR && !LVIsNull)
2359 Result.combineWith(getParentTracker().track(LVal, RR, Opts, SFC));
2372 Report.
addVisitor<NoStoreFuncVisitor>(cast<SubRegion>(R), Opts.
Kind);
2376 Result.FoundSomethingToTrack =
true;
2377 Result.WasInterrupted =
true;
2379 MacroNullReturnSuppressionVisitor::addMacroVisitorIfNecessary(
2387 if (
V.getAsLocSymbol(
true))
2388 if (LVState->isNull(
V).isConstrainedTrue())
2391 false,
"Assuming pointer value is null");
2404 getParentTracker().track(
V, R, Opts, SFC);
2432 const bool BypassCXXNewExprEval = isa<CXXNewExpr>(E);
2439 if (std::optional<CallExitEnd> CEE =
2441 if (CEE->getCalleeContext()->getCallSite() == E)
2454 if (!BypassCXXNewExprEval)
2457 if (SP->getStmt() == E && CurrentSFC == PredSFC)
2460 CurrentSFC = PredSFC;
2483 if (cast<Expr>(E)->isGLValue())
2484 if (std::optional<Loc> LValue = RetVal.
getAs<
Loc>())
2485 RetVal = State->getSVal(*LValue);
2490 bool EnableNullFPSuppression =
false;
2492 if (std::optional<Loc> RetLoc = RetVal.
getAs<
Loc>())
2493 EnableNullFPSuppression = State->isNull(*RetLoc).isConstrainedTrue();
2496 Report.
addVisitor<ReturnVisitor>(&getParentTracker(), CalleeContext,
2497 EnableNullFPSuppression, Options,
2525 bool CanDereference =
true;
2527 if (SR->getPointeeStaticType()->isVoidType())
2528 CanDereference =
false;
2530 CanDereference =
false;
2537 RVal = LVState->getRawSVal(*L, Inner->getType());
2538 else if (CanDereference)
2539 RVal = LVState->getSVal(L->getRegion());
2541 if (CanDereference) {
2543 Result.FoundSomethingToTrack =
true;
2547 getParentTracker().track(RVal, L->getRegion(), Opts, SFC));
2551 if (isa_and_nonnull<SymbolicRegion>(RegionRVal)) {
2555 false,
"Assuming pointer value is null");
2556 Result.FoundSomethingToTrack =
true;
2583 const auto track = [&CombinedResult, &
Parent, ExprNode,
2584 Opts](
const Expr *Inner) {
2593 if (
const auto *ILE = dyn_cast<InitListExpr>(E)) {
2594 if (ILE->getNumInits() == 1) {
2595 track(ILE->getInit(0));
2597 return CombinedResult;
2605 const auto *BO = dyn_cast<BinaryOperator>(E);
2607 if (!BO || !BO->isMultiplicativeOp() || !
V.isZeroConstant())
2614 if (BO->getOpcode() == BO_Mul) {
2616 track(BO->getLHS());
2618 track(BO->getRHS());
2621 track(BO->getLHS());
2624 return CombinedResult;
2631 addLowPriorityHandler<ControlDependencyHandler>();
2632 addLowPriorityHandler<NilReceiverHandler>();
2633 addLowPriorityHandler<ArrayIndexHandler>();
2634 addLowPriorityHandler<InterestingLValueHandler>();
2635 addLowPriorityHandler<InlinedFunctionCallHandler>();
2636 addLowPriorityHandler<DefaultExpressionHandler>();
2637 addLowPriorityHandler<PRValueHandler>();
2639 addHighPriorityHandler<DefaultStoreHandler>();
2654 for (ExpressionHandlerPtr &Handler : ExpressionHandlers) {
2655 CombinedResult.
combineWith(Handler->handle(Inner, N, LVNode, Opts));
2664 return CombinedResult;
2669 if (!
V.isUnknown()) {
2670 Report.
addVisitor<StoreSiteFinder>(
this,
V, R, Opts, Origin);
2679 for (StoreHandlerPtr &Handler : StoreHandlers) {
2694 ->track(E, InputNode, Opts)
2695 .FoundSomethingToTrack;
2711 const auto *ME = dyn_cast<ObjCMessageExpr>(S);
2714 if (
const Expr *Receiver = ME->getInstanceReceiver()) {
2717 if (state->isNull(
V).isConstrainedTrue())
2730 const Stmt *S =
P->getStmt();
2731 const Expr *Receiver = getNilReceiver(S, N);
2736 llvm::raw_svector_ostream
OS(Buf);
2738 if (
const auto *ME = dyn_cast<ObjCMessageExpr>(S)) {
2740 ME->getSelector().print(
OS);
2741 OS <<
"' not called";
2744 OS <<
"No method is called";
2746 OS <<
" because the receiver is nil";
2757 return std::make_shared<PathDiagnosticEventPiece>(L,
OS.str());
2771 auto piece = VisitNodeImpl(N, BRC, BR);
2773 piece->setTag(getTag());
2774 if (
auto *ev = dyn_cast<PathDiagnosticEventPiece>(piece.get()))
2775 ev->setPrunable(
true,
false);
2785 const std::pair<const ProgramPointTag *, const ProgramPointTag *> &Tags =
2790 if (std::optional<BlockEdge> BE = ProgPoint.
getAs<
BlockEdge>()) {
2791 const CFGBlock *SrcBlock = BE->getSrc();
2799 if (PreviousNodeTag == Tags.first || PreviousNodeTag == Tags.second)
2802 return VisitTerminator(Term, N, SrcBlock, BE->getDst(), BR, BRC);
2807 if (std::optional<PostStmt> PS = ProgPoint.
getAs<
PostStmt>()) {
2809 if (CurrentNodeTag != Tags.first && CurrentNodeTag != Tags.second)
2812 bool TookTrue = CurrentNodeTag == Tags.first;
2813 return VisitTrueTest(cast<Expr>(PS->getStmt()), BRC, BR, N, TookTrue);
2823 const Expr *Cond =
nullptr;
2843 case Stmt::IfStmtClass:
2844 Cond = cast<IfStmt>(Term)->getCond();
2846 case Stmt::ConditionalOperatorClass:
2847 Cond = cast<ConditionalOperator>(Term)->getCond();
2849 case Stmt::BinaryOperatorClass:
2853 const auto *BO = cast<BinaryOperator>(Term);
2854 assert(BO->isLogicalOp() &&
2855 "CFG terminator is not a short-circuit operator!");
2856 Cond = BO->getLHS();
2865 while (
const auto *InnerBO = dyn_cast<BinaryOperator>(Cond)) {
2866 if (!InnerBO->isLogicalOp())
2873 const bool TookTrue = *(srcBlk->
succ_begin()) == dstBlk;
2874 return VisitTrueTest(Cond, BRC, R, N, TookTrue);
2901 CurrentState->getSVal(Cond, LCtx).isUnknownOrUndef();
2905 const Expr *CondTmp = Cond;
2906 bool TookTrueTmp = TookTrue;
2913 case Stmt::BinaryOperatorClass:
2914 if (
auto P = VisitTrueTest(Cond, cast<BinaryOperator>(CondTmp),
2915 BRC, R, N, TookTrueTmp, IsAssuming))
2918 case Stmt::DeclRefExprClass:
2919 if (
auto P = VisitTrueTest(Cond, cast<DeclRefExpr>(CondTmp),
2920 BRC, R, N, TookTrueTmp, IsAssuming))
2923 case Stmt::MemberExprClass:
2924 if (
auto P = VisitTrueTest(Cond, cast<MemberExpr>(CondTmp),
2925 BRC, R, N, TookTrueTmp, IsAssuming))
2928 case Stmt::UnaryOperatorClass: {
2929 const auto *UO = cast<UnaryOperator>(CondTmp);
2930 if (UO->getOpcode() == UO_LNot) {
2931 TookTrueTmp = !TookTrueTmp;
2932 CondTmp = UO->getSubExpr();
2952 return std::make_shared<PathDiagnosticEventPiece>(
2953 Loc, TookTrue ? GenericTrueMessage : GenericFalseMessage);
2960 std::optional<bool> &prunable,
2961 bool IsSameFieldName) {
2962 const Expr *OriginalExpr = Ex;
2983 if (
const auto *DR = dyn_cast<DeclRefExpr>(Ex)) {
2984 const bool quotes = isa<VarDecl>(DR->getDecl());
3001 Out << DR->getDecl()->getDeclName().getAsString();
3007 if (
const auto *IL = dyn_cast<IntegerLiteral>(Ex)) {
3010 if (IL->getValue() == 0) {
3016 if (IL->getValue() == 0) {
3022 Out << IL->getValue();
3026 if (
const auto *ME = dyn_cast<MemberExpr>(Ex)) {
3027 if (!IsSameFieldName)
3028 Out <<
"field '" << ME->getMemberDecl()->getName() <<
'\'';
3045 bool shouldInvert =
false;
3046 std::optional<bool> shouldPrune;
3050 bool IsSameFieldName =
false;
3056 LhsME->getMemberDecl()->getName() == RhsME->getMemberDecl()->getName();
3060 llvm::raw_svector_ostream OutLHS(LhsString), OutRHS(RhsString);
3061 const bool isVarLHS = patternMatch(BExpr->
getLHS(), BExpr, OutLHS, BRC, R,
3062 N, shouldPrune, IsSameFieldName);
3063 const bool isVarRHS = patternMatch(BExpr->
getRHS(), BExpr, OutRHS, BRC, R,
3064 N, shouldPrune, IsSameFieldName);
3066 shouldInvert = !isVarLHS && isVarRHS;
3074 return VisitConditionVariable(LhsString, BExpr->
getLHS(), BRC, R, N,
3080 if (LhsString.empty() || RhsString.empty() ||
3086 llvm::raw_svector_ostream Out(buf);
3087 Out << (IsAssuming ?
"Assuming " :
"")
3088 << (shouldInvert ? RhsString : LhsString) <<
" is ";
3094 case BO_LT: Op = BO_GT;
break;
3095 case BO_GT: Op = BO_LT;
break;
3096 case BO_LE: Op = BO_GE;
break;
3097 case BO_GE: Op = BO_LE;
break;
3102 case BO_EQ: Op = BO_NE;
break;
3103 case BO_NE: Op = BO_EQ;
break;
3104 case BO_LT: Op = BO_GE;
break;
3105 case BO_GT: Op = BO_LE;
break;
3106 case BO_LE: Op = BO_GT;
break;
3107 case BO_GE: Op = BO_LT;
break;
3117 Out <<
"not equal to ";
3124 Out << (shouldInvert ? LhsString : RhsString);
3133 std::string Message = std::string(Out.str());
3134 Message[0] = toupper(Message[0]);
3139 if (!shouldInvert) {
3140 if (LhsME && LhsME->getMemberLoc().isValid())
3145 if (RhsME && RhsME->getMemberLoc().isValid())
3151 return std::make_shared<PathDiagnosticPopUpPiece>(
Loc, Message);
3155 auto event = std::make_shared<PathDiagnosticEventPiece>(
Loc, Message);
3157 event->setPrunable(*shouldPrune);
3168 llvm::raw_svector_ostream Out(buf);
3169 Out <<
"Assuming " << LhsString <<
" is ";
3171 if (!printValue(CondVarExpr, Out, N, TookTrue,
true))
3180 auto event = std::make_shared<PathDiagnosticEventPiece>(
Loc, Out.str());
3183 event->setPrunable(
false);
3192 const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl());
3197 llvm::raw_svector_ostream Out(Buf);
3199 Out << (IsAssuming ?
"Assuming '" :
"'") << VD->getDeclName() <<
"' is ";
3201 if (!printValue(DRE, Out, N, TookTrue, IsAssuming))
3212 return std::make_shared<PathDiagnosticPopUpPiece>(
Loc, Out.str());
3216 auto event = std::make_shared<PathDiagnosticEventPiece>(
Loc, Out.str());
3219 event->setPrunable(
false);
3221 return std::move(event);
3229 llvm::raw_svector_ostream Out(Buf);
3231 Out << (IsAssuming ?
"Assuming field '" :
"Field '")
3234 if (!printValue(ME, Out, N, TookTrue, IsAssuming))
3254 return std::make_shared<PathDiagnosticPopUpPiece>(
Loc, Out.str());
3256 auto event = std::make_shared<PathDiagnosticEventPiece>(
Loc, Out.str());
3258 event->setPrunable(
false);
3268 Out << (TookTrue ?
"non-null" :
"null");
3273 Out << (TookTrue ?
"non-nil" :
"nil");
3280 std::optional<const llvm::APSInt *> IntValue;
3284 if (IsAssuming || !IntValue) {
3286 Out << (TookTrue ?
"true" :
"false");
3288 Out << (TookTrue ?
"not equal to 0" :
"0");
3291 Out << ((*IntValue)->getBoolValue() ?
"true" :
"false");
3299constexpr llvm::StringLiteral ConditionBRVisitor::GenericTrueMessage;
3300constexpr llvm::StringLiteral ConditionBRVisitor::GenericFalseMessage;
3304 return Piece->
getString() == GenericTrueMessage ||
3305 Piece->
getString() == GenericFalseMessage;
3325 if (Options.ShouldSuppressFromCXXStandardLibrary) {
3335 if (
const auto *MD = dyn_cast<CXXMethodDecl>(D)) {
3337 if (CD->
getName() ==
"list") {
3345 if (
const auto *MD = dyn_cast<CXXConstructorDecl>(D)) {
3347 if (CD->
getName() ==
"__independent_bits_engine") {
3355 const auto *MD = dyn_cast<CXXMethodDecl>(LCtx->getDecl());
3366 if (CD->
getName() ==
"basic_string") {
3374 if (CD->
getName() ==
"shared_ptr") {
3386 while (
Loc.isMacroID()) {
3387 Loc =
Loc.getSpellingLoc();
3388 if (
SM.getFilename(
Loc).ends_with(
"sys/queue.h")) {
3416 for (
const auto ParamDecl : parms) {
3417 const MemRegion *ArgReg =
Call->getArgSVal(Idx).getAsRegion();
3425 assert(ParamDecl &&
"Formal parameter has no decl?");
3440 SVal BoundVal = State->getSVal(R);
3463 llvm::SMTSolverRef RefutationSolver = llvm::CreateZ3Solver();
3467 for (
const auto &I : Constraints) {
3469 auto RangeIt = I.second.begin();
3472 RefutationSolver, Ctx, Sym, RangeIt->From(), RangeIt->To(),
3474 while ((++RangeIt) != I.second.end()) {
3475 SMTConstraints = RefutationSolver->mkOr(
3477 RangeIt->From(), RangeIt->To(),
3481 RefutationSolver->addConstraint(SMTConstraints);
3485 std::optional<bool> IsSAT = RefutationSolver->check();
3494 const ExplodedNode *N,
bool OverwriteConstraintsOnExistingSyms) {
3500 for (
auto const &
C : NewCs) {
3502 if (!Constraints.contains(Sym)) {
3504 Constraints =
CF.add(Constraints, Sym,
C.second);
3505 }
else if (OverwriteConstraintsOnExistingSyms) {
3507 Constraints =
CF.remove(Constraints, Sym);
3508 Constraints =
CF.add(Constraints, Sym,
C.second);
3520 llvm::FoldingSetNodeID &ID)
const {
3522 ID.AddPointer(&Tag);
3529int NoteTag::Kind = 0;
3533 ID.AddPointer(&Tag);
3544 if (std::optional<std::string> Msg =
T->generateMessage(BRC, R)) {
3547 auto Piece = std::make_shared<PathDiagnosticEventPiece>(
Loc, *Msg);
3548 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.