48#include "llvm/ADT/ArrayRef.h"
49#include "llvm/ADT/STLExtras.h"
50#include "llvm/ADT/SmallPtrSet.h"
51#include "llvm/ADT/SmallString.h"
52#include "llvm/ADT/SmallVector.h"
53#include "llvm/ADT/StringExtras.h"
54#include "llvm/ADT/StringRef.h"
55#include "llvm/Support/Casting.h"
56#include "llvm/Support/ErrorHandling.h"
57#include "llvm/Support/raw_ostream.h"
67using namespace bugreporter;
101 const auto *E = dyn_cast<Expr>(S);
106 if (
const auto *CE = dyn_cast<CastExpr>(E)) {
107 if (CE->getCastKind() == CK_LValueToRValue) {
111 E = CE->getSubExpr();
112 }
else if (
const auto *B = dyn_cast<BinaryOperator>(E)) {
121 }
else if (
const auto *
U = dyn_cast<UnaryOperator>(E)) {
122 if (
U->getOpcode() == UO_Deref ||
U->getOpcode() == UO_AddrOf ||
123 (
U->isIncrementDecrementOp() &&
U->getType()->isPointerType())) {
134 else if (
const auto *ME = dyn_cast<MemberExpr>(E)) {
136 }
else if (
const auto *IvarRef = dyn_cast<ObjCIvarRefExpr>(E)) {
137 E = IvarRef->getBase();
138 }
else if (
const auto *AE = dyn_cast<ArraySubscriptExpr>(E)) {
140 }
else if (
const auto *PE = dyn_cast<ParenExpr>(E)) {
141 E = PE->getSubExpr();
142 }
else if (
const auto *FE = dyn_cast<FullExpr>(E)) {
143 E = FE->getSubExpr();
153 if (
const auto *CE = dyn_cast<ImplicitCastExpr>(E))
154 if (CE->getCastKind() == CK_LValueToRValue)
155 E = CE->getSubExpr();
162 bool LookingForReference =
true) {
163 if (
const auto *DR = dyn_cast<DeclRefExpr>(E)) {
164 if (
const auto *VD = dyn_cast<VarDecl>(DR->getDecl())) {
165 if (LookingForReference && !VD->getType()->isReferenceType())
192 if (LeftVal == RightVal)
203 return LLCV->
getRegion() == RLCV->getRegion() &&
204 LLCV->getStore() == LeftNode->
getState()->getStore() &&
205 RLCV->getStore() == RightNode->
getState()->getStore();
220 if (
const auto *DRE = dyn_cast<DeclRefExpr>(CondVarExpr))
221 if (
const auto *VD = dyn_cast<VarDecl>(DRE->getDecl()))
222 return State->getSVal(State->getLValue(VD, LCtx));
224 if (
const auto *ME = dyn_cast<MemberExpr>(CondVarExpr))
225 if (
const auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl()))
226 if (
auto FieldL = State->getSVal(ME, LCtx).getAs<
Loc>())
227 return State->getRawSVal(*FieldL, FD->getType());
232static std::optional<const llvm::APSInt *>
237 return &CI->getValue();
251 if (std::optional<bugreporter::TrackingKind> K =
253 return *K == bugreporter::TrackingKind::Condition;
278 if (!
Loc.isMacroID())
280 while (
SM.isMacroArgExpansion(
Loc))
281 Loc =
SM.getImmediateExpansionRange(
Loc).getBegin();
282 std::pair<FileID, unsigned> TLInfo =
SM.getDecomposedLoc(
Loc);
309 SVal ValueAtN = N->
getState()->getSVal(RegionOfInterest);
311 .
areEqual(State, ValueAtN, ValueAfter)
342 auto P = std::make_shared<PathDiagnosticEventPiece>(
354bool NoStateChangeFuncVisitor::isModifiedInFrame(
const ExplodedNode *N) {
357 if (!FramesModifyingCalculated.count(SCtx))
358 findModifyingFrames(N);
359 return FramesModifying.count(SCtx);
362void NoStateChangeFuncVisitor::markFrameAsModifying(
365 auto p = FramesModifying.insert(SCtx);
381 auto IsMatchingCallExitEnd = [OrigSCtx](
const ExplodedNode *N) {
385 while (N && !IsMatchingCallExitEnd(N)) {
387 "This function is to be used on the trimmed ExplodedGraph!");
393void NoStateChangeFuncVisitor::findModifyingFrames(
401 const ExplodedNode *CurrCallExitBeginN = CallExitBeginN;
408 CurrCallExitBeginN = CurrN;
410 FramesModifyingCalculated.insert(CurrentSCtx);
415 if (
auto CE = CurrN->getLocationAs<
CallEnter>()) {
418 markFrameAsModifying(CurrentSCtx);
429 if (CE->getCalleeContext() == OriginalSCtx) {
430 markFrameAsModifying(CurrentSCtx);
436 markFrameAsModifying(CurrentSCtx);
449 if (!CallExitLoc || isModifiedInFrame(N))
464 if (Call->isInSystemHeader()) {
479 if (
const auto *MC = dyn_cast<ObjCMethodCall>(Call)) {
486 if (
const auto *CCall = dyn_cast<CXXConstructorCall>(Call)) {
513 static const unsigned DEREFERENCE_LIMIT = 2;
520 MmrMgr(R->getMemRegionManager()),
521 SM(MmrMgr.getContext().getSourceManager()),
522 PP(MmrMgr.getContext().getPrintingPolicy()) {}
524 void Profile(llvm::FoldingSetNodeID &ID)
const override {
527 ID.AddPointer(RegionOfInterest);
533 bool wasModifiedBeforeCallExit(
const ExplodedNode *CurrN,
542 const std::optional<RegionVector>
544 const MemRegion *R,
const RegionVector &Vec = {},
568 const MemRegion *MatchedRegion, StringRef FirstElement,
569 bool FirstIsReferenceType,
unsigned IndirectionLevel);
571 bool prettyPrintRegionName(
const RegionVector &FieldChain,
573 StringRef FirstElement,
bool FirstIsReferenceType,
574 unsigned IndirectionLevel,
575 llvm::raw_svector_ostream &os);
577 StringRef prettyPrintFirstElement(StringRef FirstElement,
578 bool MoreItemsExpected,
579 int IndirectionLevel,
580 llvm::raw_svector_ostream &os);
588 using namespace ast_matchers;
589 const char *IvarBind =
"Ivar";
593 hasOperatorName(
"="),
594 hasLHS(ignoringParenImpCasts(
600 if (IvarRef->isFreeIvar())
603 const Expr *
Base = IvarRef->getBase();
604 if (
const auto *ICE = dyn_cast<ImplicitCastExpr>(
Base))
605 Base = ICE->getSubExpr();
607 if (
const auto *DRE = dyn_cast<DeclRefExpr>(
Base))
608 if (
const auto *ID = dyn_cast<ImplicitParamDecl>(DRE->getDecl()))
623const std::optional<NoStoreFuncVisitor::RegionVector>
624NoStoreFuncVisitor::findRegionOfInterestInRecord(
629 if (depth == DEREFERENCE_LIMIT)
632 if (
const auto *RDX = dyn_cast<CXXRecordDecl>(RD))
633 if (!RDX->hasDefinition())
638 if (
const auto *RDX = dyn_cast<CXXRecordDecl>(RD))
639 for (
const auto &II : RDX->bases())
640 if (
const RecordDecl *RRD = II.getType()->getAsRecordDecl())
641 if (std::optional<RegionVector> Out =
642 findRegionOfInterestInRecord(RRD, State, R, Vec, depth))
648 const SVal V = State->getSVal(FR);
651 RegionVector VecF = Vec;
654 if (RegionOfInterest == VR)
659 findRegionOfInterestInRecord(RRD, State, FR, VecF, depth + 1))
667 if (std::optional<RegionVector> Out =
668 findRegionOfInterestInRecord(RRD, State, VR, VecF, depth + 1))
679 if (
const auto *IvarR = dyn_cast<ObjCIvarRegion>(RegionOfInterest)) {
680 const MemRegion *SelfRegion =
Call.getReceiverSVal().getAsRegion();
681 if (RegionOfInterest->isSubRegionOf(SelfRegion) &&
684 return maybeEmitNote(R, Call, N, {}, SelfRegion,
"self",
695 if (RegionOfInterest->isSubRegionOf(ThisR) && !
Call.getDecl()->isImplicit())
696 return maybeEmitNote(R, Call, N, {}, ThisR,
"this",
713 for (
unsigned I = 0; I <
Call.getNumArgs() && I <
Parameters.size(); ++I) {
719 unsigned IndirectionLevel = 1;
721 while (
const MemRegion *MR =
V.getAsRegion()) {
723 return maybeEmitNote(R, Call, N, {}, MR, ParamName,
724 ParamIsReferenceType, IndirectionLevel);
727 if (PT.isNull() || PT->isVoidType())
732 if (
const RecordDecl *RD = PT->getAsRecordDecl())
733 if (std::optional<RegionVector>
P =
734 findRegionOfInterestInRecord(RD, State, MR))
735 return maybeEmitNote(R, Call, N, *
P, RegionOfInterest, ParamName,
736 ParamIsReferenceType, IndirectionLevel);
738 V = State->getSVal(MR, PT);
747bool NoStoreFuncVisitor::wasModifiedBeforeCallExit(
749 return ::wasRegionOfInterestModifiedAt(
750 RegionOfInterest, CurrN,
751 CallExitBeginN->
getState()->getSVal(RegionOfInterest));
755 ", which participates in a condition later";
759 const RegionVector &FieldChain,
const MemRegion *MatchedRegion,
760 StringRef FirstElement,
bool FirstIsReferenceType,
761 unsigned IndirectionLevel) {
773 llvm::raw_svector_ostream os(sbuf);
774 os <<
"Returning without writing to '";
777 if (!prettyPrintRegionName(FieldChain, MatchedRegion, FirstElement,
778 FirstIsReferenceType, IndirectionLevel, os))
784 return std::make_shared<PathDiagnosticEventPiece>(L, os.str());
787bool NoStoreFuncVisitor::prettyPrintRegionName(
const RegionVector &FieldChain,
789 StringRef FirstElement,
790 bool FirstIsReferenceType,
791 unsigned IndirectionLevel,
792 llvm::raw_svector_ostream &os) {
794 if (FirstIsReferenceType)
797 RegionVector RegionSequence;
800 assert(RegionOfInterest->isSubRegionOf(MatchedRegion));
802 while (R != MatchedRegion) {
803 RegionSequence.push_back(R);
804 R = cast<SubRegion>(R)->getSuperRegion();
806 std::reverse(RegionSequence.begin(), RegionSequence.end());
807 RegionSequence.append(FieldChain.begin(), FieldChain.end());
810 for (
const MemRegion *R : RegionSequence) {
814 if (isa<CXXBaseObjectRegion, CXXTempObjectRegion>(R))
818 Sep = prettyPrintFirstElement(FirstElement,
820 IndirectionLevel, os);
825 if (!isa<DeclRegion>(R))
828 const auto *DR = cast<DeclRegion>(R);
829 Sep = DR->getValueType()->isAnyPointerType() ?
"->" :
".";
830 DR->getDecl()->getDeclName().print(os, PP);
834 prettyPrintFirstElement(FirstElement,
835 false, IndirectionLevel, os);
839StringRef NoStoreFuncVisitor::prettyPrintFirstElement(
840 StringRef FirstElement,
bool MoreItemsExpected,
int IndirectionLevel,
841 llvm::raw_svector_ostream &os) {
844 if (IndirectionLevel > 0 && MoreItemsExpected) {
849 if (IndirectionLevel > 0 && MoreItemsExpected)
852 for (
int i = 0; i < IndirectionLevel; i++)
856 if (IndirectionLevel > 0 && MoreItemsExpected)
872 const SVal ValueAtDereference;
876 bool WasModified =
false;
879 MacroNullReturnSuppressionVisitor(
const SubRegion *R,
const SVal V)
880 : RegionOfInterest(R), ValueAtDereference(
V) {}
893 if (
auto Loc = matchAssignment(N)) {
908 static void addMacroVisitorIfNecessary(
913 if (EnableNullFPSuppression && Options.ShouldSuppressNullReturnPaths &&
919 void* getTag()
const {
921 return static_cast<void *
>(&Tag);
924 void Profile(llvm::FoldingSetNodeID &ID)
const override {
925 ID.AddPointer(getTag());
931 std::optional<SourceLocation> matchAssignment(
const ExplodedNode *N) {
938 if (
const auto *DS = dyn_cast<DeclStmt>(S)) {
939 if (
const auto *VD = dyn_cast<VarDecl>(DS->getSingleDecl()))
940 if (
const Expr *RHS = VD->getInit())
941 if (RegionOfInterest->isSubRegionOf(
942 State->getLValue(VD, LCtx).getAsRegion()))
943 return RHS->getBeginLoc();
944 }
else if (
const auto *BO = dyn_cast<BinaryOperator>(S)) {
946 const Expr *RHS = BO->getRHS();
947 if (BO->isAssignmentOp() && RegionOfInterest->isSubRegionOf(R)) {
974 bool EnableNullFPSuppression;
975 bool ShouldInvalidate =
true;
984 EnableNullFPSuppression(Suppressed), Options(Options), TKind(TKind) {}
986 static void *getTag() {
988 return static_cast<void *
>(&Tag);
991 void Profile(llvm::FoldingSetNodeID &ID)
const override {
992 ID.AddPointer(ReturnVisitor::getTag());
993 ID.AddPointer(CalleeSFC);
994 ID.AddBoolean(EnableNullFPSuppression);
1008 const auto *
Ret = dyn_cast<ReturnStmt>(SP->getStmt());
1015 SVal V = State->getSVal(Ret, CalleeSFC);
1016 if (
V.isUnknownOrUndef())
1022 const Expr *RetE =
Ret->getRetValue();
1023 assert(RetE &&
"Tracking a return value for a void function");
1026 std::optional<Loc> LValue;
1028 if ((LValue =
V.getAs<
Loc>())) {
1029 SVal RValue = State->getRawSVal(*LValue, RetE->
getType());
1030 if (isa<DefinedSVal>(RValue))
1036 if (isa<nonloc::LazyCompoundVal, nonloc::CompoundVal>(
V))
1042 getParentTracker().track(RetE, N, {TKind, EnableNullFPSuppression});
1046 llvm::raw_svector_ostream Out(Msg);
1048 bool WouldEventBeMeaningless =
false;
1050 if (State->isNull(
V).isConstrainedTrue()) {
1056 if (EnableNullFPSuppression &&
1057 Options.ShouldAvoidSuppressingNullArgumentPaths)
1058 Mode = MaybeUnsuppress;
1061 Out <<
"Returning nil";
1063 Out <<
"Returning null pointer";
1066 Out <<
"Returning zero";
1071 Out <<
"Returning the value " << CI->getValue();
1079 WouldEventBeMeaningless =
true;
1081 Out << (isa<Loc>(
V) ?
"Returning pointer" :
"Returning value");
1086 if (
const MemRegion *MR = LValue->getAsRegion()) {
1087 if (MR->canPrintPretty()) {
1088 Out <<
" (reference to ";
1089 MR->printPretty(Out);
1095 if (
const auto *DR = dyn_cast<DeclRefExpr>(RetE))
1096 if (
const auto *DD = dyn_cast<DeclaratorDecl>(DR->getDecl()))
1097 Out <<
" (loaded from '" << *DD <<
"')";
1101 if (!L.isValid() || !L.asLocation().isValid())
1104 if (TKind == bugreporter::TrackingKind::Condition)
1107 auto EventPiece = std::make_shared<PathDiagnosticEventPiece>(L, Out.str());
1111 if (WouldEventBeMeaningless)
1112 EventPiece->setPrunable(
true);
1122 assert(Options.ShouldAvoidSuppressingNullArgumentPaths);
1129 if (CE->getCalleeContext() != CalleeSFC)
1142 for (
unsigned I = 0, E =
Call->getNumArgs(); I != E; ++I) {
1143 std::optional<Loc> ArgV =
Call->getArgSVal(I).getAs<
Loc>();
1147 const Expr *ArgE =
Call->getArgExpr(I);
1152 if (!State->isNull(*ArgV).isConstrainedTrue())
1155 if (getParentTracker()
1156 .track(ArgE, N, {TKind, EnableNullFPSuppression})
1157 .FoundSomethingToTrack)
1158 ShouldInvalidate =
false;
1173 return visitNodeInitial(N, BRC, BR);
1174 case MaybeUnsuppress:
1175 return visitNodeMaybeUnsuppress(N, BRC, BR);
1180 llvm_unreachable(
"Invalid visit mode!");
1185 if (EnableNullFPSuppression && ShouldInvalidate)
1186 BR.
markInvalid(ReturnVisitor::getTag(), CalleeSFC);
1199 bool Satisfied =
false;
1219 OriginSFC(OriginSFC) {
1223 void Profile(llvm::FoldingSetNodeID &ID)
const override;
1231void StoreSiteFinder::Profile(llvm::FoldingSetNodeID &ID)
const {
1233 ID.AddPointer(&tag);
1236 ID.AddInteger(
static_cast<int>(Options.Kind));
1237 ID.AddBoolean(Options.EnableNullFPSuppression);
1255 const auto *FrameSpace = dyn_cast<StackSpaceRegion>(VarSpace);
1271 if (
const auto *TR = dyn_cast<TypedValueRegion>(R))
1272 return TR->getValueType()->isObjCObjectPointerType();
1290 const char *Action =
nullptr;
1294 Action = HasPrefix ?
"initialized to " :
"Initializing to ";
1297 Action = HasPrefix ?
"captured by block as " :
"Captured by block as ";
1300 llvm_unreachable(
"Unexpected store kind");
1303 if (isa<loc::ConcreteInt>(SI.
Value)) {
1307 OS << Action << CVal->getValue();
1310 OS << Action <<
"the value of ";
1321 if (isa<VarRegion>(SI.
Dest)) {
1322 const auto *VD = cast<VarDecl>(DS->getSingleDecl());
1324 if (VD->getInit()) {
1325 OS << (HasPrefix ?
"initialized" :
"Initializing")
1326 <<
" to a garbage value";
1328 OS << (HasPrefix ?
"declared" :
"Declaring")
1329 <<
" without an initial value";
1333 OS << (HasPrefix ?
"initialized" :
"Initialized") <<
" here";
1341 const auto *VR = cast<VarRegion>(SI.
Dest);
1342 const auto *D = VR->getDecl();
1346 if (isa<loc::ConcreteInt>(SI.
Value)) {
1347 OS << (
isObjCPointer(D) ?
"nil object reference" :
"null pointer value");
1350 OS <<
"uninitialized value";
1353 OS <<
"the value " << CI->getValue();
1362 if (
const auto *Param = dyn_cast<ParmVarDecl>(VR->getDecl())) {
1364 unsigned Idx = Param->getFunctionScopeIndex() + 1;
1365 OS <<
" via " << Idx << llvm::getOrdinalSuffix(Idx) <<
" parameter";
1370 }
else if (
const auto *ImplParam = dyn_cast<ImplicitParamDecl>(D)) {
1371 if (ImplParam->getParameterKind() ==
1373 OS <<
" via implicit parameter 'self'";
1383 if (isa<loc::ConcreteInt>(SI.
Value)) {
1385 : (HasSuffix ?
"Null pointer value stored"
1386 :
"Storing null pointer value"));
1389 OS << (HasSuffix ?
"Uninitialized value stored"
1390 :
"Storing uninitialized value");
1394 OS <<
"The value " << CV->getValue() <<
" is assigned";
1396 OS <<
"Assigning " << CV->getValue();
1400 OS <<
"The value of ";
1402 OS <<
" is assigned";
1404 OS <<
"Assigning the value of ";
1409 OS << (HasSuffix ?
"Value assigned" :
"Assigning value");
1430 const auto *TVR = dyn_cast_or_null<TypedValueRegion>(R);
1438 std::stack<const TypedValueRegion *> TVRStack;
1439 while (isa<FieldRegion>(TVR) || isa<ElementRegion>(TVR)) {
1444 if (ITy == TVR->getValueType().getCanonicalType())
1448 TVR = cast<TypedValueRegion>(TVR->getSuperRegion());
1453 if (ITy != TVR->getValueType().getCanonicalType())
1456 const Expr *Init = ILE;
1457 while (!TVRStack.empty()) {
1458 TVR = TVRStack.top();
1463 if (!isa<InitListExpr>(Init))
1466 ILE = cast<InitListExpr>(Init);
1469 if (
const auto *FR = dyn_cast<FieldRegion>(TVR)) {
1470 const auto *FD = FR->
getDecl();
1472 if (FD->getFieldIndex() >= NumInits)
1475 Init = ILE->
getInit(FD->getFieldIndex());
1476 }
else if (
const auto *ER = dyn_cast<ElementRegion>(TVR)) {
1477 const auto Ind = ER->getIndex();
1481 if (!Ind.isConstant())
1484 const auto IndVal = Ind.getAsInteger()->getLimitedValue();
1485 if (IndVal >= NumInits)
1503 const Expr *InitE =
nullptr;
1504 bool IsParam =
false;
1507 if (
const auto *VR = dyn_cast<VarRegion>(R)) {
1510 InitE = VR->getDecl()->getInit();
1516 if (std::optional<PostInitializer> PIP =
1519 if (FieldReg == R) {
1521 InitE = PIP->getInitializer()->getInit();
1536 if (!PS || PS->getLocationValue() != R)
1546 if (BO->isAssignmentOp())
1547 InitE = BO->getRHS();
1551 else if (
const auto *DS =
P->getStmtAs<
DeclStmt>()) {
1552 const auto *
Decl = DS->getSingleDecl();
1553 if (isa<VarDecl>(
Decl)) {
1554 const auto *VD = cast<VarDecl>(
Decl);
1562 if (
const auto *ILE = dyn_cast<InitListExpr>(VD->getInit()))
1567 const auto State = Succ->
getState();
1578 std::stack<const SubRegion *> SRStack;
1579 const SubRegion *SR = cast<SubRegion>(R);
1580 while (isa<FieldRegion>(SR) || isa<ElementRegion>(SR)) {
1586 const auto *OriginEx = CE->getArg(0);
1587 const auto OriginVal =
1593 SVal OriginField = OriginVal;
1594 while (!SRStack.empty()) {
1595 const auto *TopR = SRStack.top();
1598 if (
const auto *FR = dyn_cast<FieldRegion>(TopR)) {
1599 OriginField = State->getLValue(FR->
getDecl(), OriginField);
1600 }
else if (
const auto *ER = dyn_cast<ElementRegion>(TopR)) {
1601 OriginField = State->getLValue(ER->getElementType(),
1602 ER->getIndex(), OriginField);
1609 getParentTracker().track(
V, OriginField.
getAsRegion(), Options);
1630 if (
const auto *VR = dyn_cast<VarRegion>(R)) {
1632 if (
const auto *Param = dyn_cast<ParmVarDecl>(VR->getDecl())) {
1638 InitE =
Call->getArgExpr(Param->getFunctionScopeIndex());
1641 assert(isa<ImplicitParamDecl>(VR->getDecl()));
1642 InitE = cast<ObjCMessageExpr>(CE->getCalleeContext()->getCallSite())
1651 if (
const auto *TmpR = dyn_cast<CXXTempObjectRegion>(R))
1652 InitE = TmpR->getExpr();
1666 getParentTracker().track(InitE, StoreSite, Options);
1690 if (
SM.includedInBindings(N->
getState()->getStore(), Candidate)) {
1692 if (N->
getState()->getSVal(Candidate) ==
V) {
1693 OldRegion = Candidate;
1712 if (!OldRegion && StoreSite->
getState()->getSVal(R) ==
V) {
1717 NodeWithoutBinding && NodeWithoutBinding->
getState()->getSVal(R) ==
V;
1718 NodeWithoutBinding = NodeWithoutBinding->
getFirstPred()) {
1721 if (NodeWithoutBinding) {
1733 OldRegion = FB.getRegion();
1737 if (Options.Kind == TrackingKind::Condition && OriginSFC &&
1743 llvm::raw_svector_ostream os(sbuf);
1753 const Stmt *S = PS->getStmt();
1754 const auto *DS = dyn_cast<DeclStmt>(S);
1755 const auto *VR = dyn_cast<VarRegion>(R);
1759 }
else if (isa<BlockExpr>(S)) {
1765 if (
const auto *BDR =
1766 dyn_cast_or_null<BlockDataRegion>(
V.getAsRegion())) {
1767 if (
const VarRegion *OriginalR = BDR->getOriginalRegion(VR)) {
1768 getParentTracker().track(State->getSVal(OriginalR), OriginalR,
1769 Options, OriginSFC);
1775 isa<VarRegion>(SI.
Dest)) {
1779 return getParentTracker().handle(SI, BRC, Options);
1788 ID.AddPointer(&tag);
1789 ID.AddBoolean(Assumption);
1796 return "TrackConstraintBRVisitor";
1799bool TrackConstraintBRVisitor::isUnderconstrained(
const ExplodedNode *N)
const {
1801 return N->
getState()->isNull(Constraint).isUnderconstrained();
1802 return (
bool)N->
getState()->assume(Constraint, !Assumption);
1813 if (!IsTrackingTurnedOn)
1814 if (!isUnderconstrained(N))
1815 IsTrackingTurnedOn =
true;
1816 if (!IsTrackingTurnedOn)
1821 if (isUnderconstrained(PrevN)) {
1828 assert(!isUnderconstrained(N));
1833 llvm::raw_svector_ostream os(sbuf);
1835 if (isa<Loc>(Constraint)) {
1836 os <<
"Assuming pointer value is ";
1837 os << (Assumption ?
"non-null" :
"null");
1840 if (os.str().empty())
1849 if (isa_and_nonnull<NoteTag>(
P.getTag()))
1857 auto X = std::make_shared<PathDiagnosticEventPiece>(L, os.str());
1859 return std::move(
X);
1874 if (!Options.ShouldSuppressInlinedDefensiveChecks)
1879 llvm::FoldingSetNodeID &ID)
const {
1886 return "IDCVisitor";
1898 if (!IsTrackingTurnedOn)
1899 if (Succ->
getState()->isNull(
V).isConstrainedTrue())
1900 IsTrackingTurnedOn =
true;
1901 if (!IsTrackingTurnedOn)
1906 if (!Pred->
getState()->isNull(
V).isConstrainedTrue() &&
1907 Succ->
getState()->isNull(
V).isConstrainedTrue()) {
1913 if (CurLC != ReportLC && !CurLC->
isParentOf(ReportLC)) {
1928 const Stmt *CurTerminatorStmt =
nullptr;
1930 CurTerminatorStmt = BE->getSrc()->getTerminator().getStmt();
1932 const Stmt *CurStmt = SP->getStmt();
1942 if (!CurTerminatorStmt)
1976class TrackControlDependencyCondBRVisitor final
1980 llvm::SmallSet<const CFGBlock *, 32> VisitedBlocks;
1983 TrackControlDependencyCondBRVisitor(
TrackerRef ParentTracker,
1986 ControlDeps(&O->getCFG()) {}
1988 void Profile(llvm::FoldingSetNodeID &ID)
const override {
1999static std::shared_ptr<PathDiagnosticEventPiece>
2012 return std::make_shared<PathDiagnosticEventPiece>(
2015 (Twine() +
"Tracking condition '" + ConditionText +
"'").str());
2043 if (
const auto *BinOp = dyn_cast<BinaryOperator>(ElseCond))
2044 if (BinOp->isLogicalOp())
2051TrackControlDependencyCondBRVisitor::VisitNode(
const ExplodedNode *N,
2061 if (!VisitedBlocks.insert(NB).second)
2067 if (!OriginB || !NB)
2073 if (ControlDeps.isControlDependent(OriginB, NB)) {
2099 if (isa<CallExpr>(InnerExpr))
2106 getParentTracker().track(InnerExpr, N,
2124 if (
const auto *FE = dyn_cast<FullExpr>(Ex))
2126 if (
const auto *OVE = dyn_cast<OpaqueValueExpr>(Ex))
2128 if (
const auto *POE = dyn_cast<PseudoObjectExpr>(Ex)) {
2129 const auto *PropRef = dyn_cast<ObjCPropertyRefExpr>(POE->getSyntacticForm());
2130 if (PropRef && PropRef->isMessagingGetter()) {
2131 const Expr *GetterMessageSend =
2132 POE->getSemanticExpr(POE->getNumSemanticExprs() - 1);
2139 if (
const auto *CO = dyn_cast<ConditionalOperator>(Ex)) {
2145 if (std::optional<BlockEdge> BE = ProgPoint.
getAs<
BlockEdge>()) {
2146 const CFGBlock *srcBlk = BE->getSrc();
2149 bool TookTrueBranch = (*(srcBlk->
succ_begin()) == BE->getDst());
2161 if (
auto *BO = dyn_cast<BinaryOperator>(Ex))
2165 if (
auto *UO = dyn_cast<UnaryOperator>(Ex)) {
2166 if (UO->getOpcode() == UO_LNot)
2177 if (UO->getOpcode() == UO_AddrOf && UO->getSubExpr()->isLValue())
2188 const Expr *Inner) {
2203 StringRef NodeText) {
2209 P.getLocationContext());
2217 return std::make_shared<PathDiagnosticEventPiece>(L, NodeText);
2229 llvm::raw_svector_ostream
OS(Buffer);
2244 if (Opts.
Kind == bugreporter::TrackingKind::Condition)
2247 return constructNote(SI, BRC,
OS.str());
2267 ->getAnalysisManager()
2268 .getAnalyzerOptions()
2269 .ShouldTrackConditions) {
2270 Report.
addVisitor<TrackControlDependencyCondBRVisitor>(
2271 &getParentTracker(), InputNode);
2289 if (
const Expr *Receiver =
2291 return getParentTracker().track(Receiver, LVNode, Opts);
2305 if (
const auto *Arr = dyn_cast<ArraySubscriptExpr>(Inner))
2306 return getParentTracker().track(
2307 Arr->getIdx(), LVNode,
2308 {Opts.Kind, false});
2333 bool LVIsNull = LVState->isNull(LVal).isConstrainedTrue();
2338 if (RR && !LVIsNull)
2339 Result.combineWith(getParentTracker().track(LVal, RR, Opts, SFC));
2352 Report.
addVisitor<NoStoreFuncVisitor>(cast<SubRegion>(R), Opts.
Kind);
2356 Result.FoundSomethingToTrack =
true;
2357 Result.WasInterrupted =
true;
2359 MacroNullReturnSuppressionVisitor::addMacroVisitorIfNecessary(
2367 if (
V.getAsLocSymbol(
true))
2368 if (LVState->isNull(
V).isConstrainedTrue())
2383 getParentTracker().track(
V, R, Opts, SFC);
2411 const bool BypassCXXNewExprEval = isa<CXXNewExpr>(E);
2418 if (std::optional<CallExitEnd> CEE =
2420 if (CEE->getCalleeContext()->getCallSite() == E)
2433 if (!BypassCXXNewExprEval)
2436 if (SP->getStmt() == E && CurrentSFC == PredSFC)
2439 CurrentSFC = PredSFC;
2462 if (cast<Expr>(E)->isGLValue())
2463 if (std::optional<Loc> LValue = RetVal.
getAs<
Loc>())
2464 RetVal = State->getSVal(*LValue);
2469 bool EnableNullFPSuppression =
false;
2471 if (std::optional<Loc> RetLoc = RetVal.
getAs<
Loc>())
2472 EnableNullFPSuppression = State->isNull(*RetLoc).isConstrainedTrue();
2475 Report.
addVisitor<ReturnVisitor>(&getParentTracker(), CalleeContext,
2476 EnableNullFPSuppression, Options,
2504 bool CanDereference =
true;
2506 if (SR->getPointeeStaticType()->isVoidType())
2507 CanDereference =
false;
2509 CanDereference =
false;
2516 RVal = LVState->getRawSVal(*L, Inner->getType());
2517 else if (CanDereference)
2518 RVal = LVState->getSVal(L->getRegion());
2520 if (CanDereference) {
2522 Result.FoundSomethingToTrack =
true;
2526 getParentTracker().track(*KV, L->getRegion(), Opts, SFC));
2530 if (isa_and_nonnull<SymbolicRegion>(RegionRVal)) {
2535 Result.FoundSomethingToTrack =
true;
2562 const auto track = [&CombinedResult, &
Parent, ExprNode,
2563 Opts](
const Expr *Inner) {
2572 if (
const auto *ILE = dyn_cast<InitListExpr>(E)) {
2573 if (ILE->getNumInits() == 1) {
2574 track(ILE->getInit(0));
2576 return CombinedResult;
2584 const auto *BO = dyn_cast<BinaryOperator>(E);
2586 if (!BO || !BO->isMultiplicativeOp() || !
V.isZeroConstant())
2593 if (BO->getOpcode() == BO_Mul) {
2595 track(BO->getLHS());
2597 track(BO->getRHS());
2600 track(BO->getLHS());
2603 return CombinedResult;
2610 addLowPriorityHandler<ControlDependencyHandler>();
2611 addLowPriorityHandler<NilReceiverHandler>();
2612 addLowPriorityHandler<ArrayIndexHandler>();
2613 addLowPriorityHandler<InterestingLValueHandler>();
2614 addLowPriorityHandler<InlinedFunctionCallHandler>();
2615 addLowPriorityHandler<DefaultExpressionHandler>();
2616 addLowPriorityHandler<PRValueHandler>();
2618 addHighPriorityHandler<DefaultStoreHandler>();
2633 for (ExpressionHandlerPtr &Handler : ExpressionHandlers) {
2634 CombinedResult.
combineWith(Handler->handle(Inner, N, LVNode, Opts));
2643 return CombinedResult;
2649 Report.
addVisitor<StoreSiteFinder>(
this, *KV, R, Opts, Origin);
2658 for (StoreHandlerPtr &Handler : StoreHandlers) {
2673 ->track(E, InputNode, Opts)
2674 .FoundSomethingToTrack;
2690 const auto *ME = dyn_cast<ObjCMessageExpr>(S);
2693 if (
const Expr *Receiver = ME->getInstanceReceiver()) {
2696 if (state->isNull(
V).isConstrainedTrue())
2709 const Stmt *S =
P->getStmt();
2710 const Expr *Receiver = getNilReceiver(S, N);
2715 llvm::raw_svector_ostream
OS(Buf);
2717 if (
const auto *ME = dyn_cast<ObjCMessageExpr>(S)) {
2719 ME->getSelector().print(
OS);
2720 OS <<
"' not called";
2723 OS <<
"No method is called";
2725 OS <<
" because the receiver is nil";
2736 return std::make_shared<PathDiagnosticEventPiece>(L,
OS.str());
2750 auto piece = VisitNodeImpl(N, BRC, BR);
2752 piece->setTag(getTag());
2753 if (
auto *ev = dyn_cast<PathDiagnosticEventPiece>(piece.get()))
2754 ev->setPrunable(
true,
false);
2764 const std::pair<const ProgramPointTag *, const ProgramPointTag *> &Tags =
2769 if (std::optional<BlockEdge> BE = ProgPoint.
getAs<
BlockEdge>()) {
2770 const CFGBlock *SrcBlock = BE->getSrc();
2778 if (PreviousNodeTag == Tags.first || PreviousNodeTag == Tags.second)
2781 return VisitTerminator(Term, N, SrcBlock, BE->getDst(), BR, BRC);
2786 if (std::optional<PostStmt> PS = ProgPoint.
getAs<
PostStmt>()) {
2788 if (CurrentNodeTag != Tags.first && CurrentNodeTag != Tags.second)
2791 bool TookTrue = CurrentNodeTag == Tags.first;
2792 return VisitTrueTest(cast<Expr>(PS->getStmt()), BRC, BR, N, TookTrue);
2802 const Expr *Cond =
nullptr;
2822 case Stmt::IfStmtClass:
2823 Cond = cast<IfStmt>(Term)->getCond();
2825 case Stmt::ConditionalOperatorClass:
2826 Cond = cast<ConditionalOperator>(Term)->getCond();
2828 case Stmt::BinaryOperatorClass:
2832 const auto *BO = cast<BinaryOperator>(Term);
2833 assert(BO->isLogicalOp() &&
2834 "CFG terminator is not a short-circuit operator!");
2835 Cond = BO->getLHS();
2844 while (
const auto *InnerBO = dyn_cast<BinaryOperator>(Cond)) {
2845 if (!InnerBO->isLogicalOp())
2852 const bool TookTrue = *(srcBlk->
succ_begin()) == dstBlk;
2853 return VisitTrueTest(Cond, BRC, R, N, TookTrue);
2870 CurrentState->getSVal(Cond, LCtx).isUnknownOrUndef();
2874 const Expr *CondTmp = Cond;
2875 bool TookTrueTmp = TookTrue;
2882 case Stmt::BinaryOperatorClass:
2883 if (
auto P = VisitTrueTest(Cond, cast<BinaryOperator>(CondTmp),
2884 BRC, R, N, TookTrueTmp, IsAssuming))
2887 case Stmt::DeclRefExprClass:
2888 if (
auto P = VisitTrueTest(Cond, cast<DeclRefExpr>(CondTmp),
2889 BRC, R, N, TookTrueTmp, IsAssuming))
2892 case Stmt::MemberExprClass:
2893 if (
auto P = VisitTrueTest(Cond, cast<MemberExpr>(CondTmp),
2894 BRC, R, N, TookTrueTmp, IsAssuming))
2897 case Stmt::UnaryOperatorClass: {
2898 const auto *UO = cast<UnaryOperator>(CondTmp);
2899 if (UO->getOpcode() == UO_LNot) {
2900 TookTrueTmp = !TookTrueTmp;
2901 CondTmp = UO->getSubExpr();
2921 return std::make_shared<PathDiagnosticEventPiece>(
2922 Loc, TookTrue ? GenericTrueMessage : GenericFalseMessage);
2929 std::optional<bool> &prunable,
2930 bool IsSameFieldName) {
2931 const Expr *OriginalExpr = Ex;
2952 if (
const auto *DR = dyn_cast<DeclRefExpr>(Ex)) {
2953 const bool quotes = isa<VarDecl>(DR->getDecl());
2970 Out << DR->getDecl()->getDeclName().getAsString();
2976 if (
const auto *IL = dyn_cast<IntegerLiteral>(Ex)) {
2979 if (IL->getValue() == 0) {
2985 if (IL->getValue() == 0) {
2991 Out << IL->getValue();
2995 if (
const auto *ME = dyn_cast<MemberExpr>(Ex)) {
2996 if (!IsSameFieldName)
2997 Out <<
"field '" << ME->getMemberDecl()->getName() <<
'\'';
3014 bool shouldInvert =
false;
3015 std::optional<bool> shouldPrune;
3019 bool IsSameFieldName =
false;
3025 LhsME->getMemberDecl()->getName() == RhsME->getMemberDecl()->getName();
3029 llvm::raw_svector_ostream OutLHS(LhsString), OutRHS(RhsString);
3030 const bool isVarLHS = patternMatch(BExpr->
getLHS(), BExpr, OutLHS, BRC, R,
3031 N, shouldPrune, IsSameFieldName);
3032 const bool isVarRHS = patternMatch(BExpr->
getRHS(), BExpr, OutRHS, BRC, R,
3033 N, shouldPrune, IsSameFieldName);
3035 shouldInvert = !isVarLHS && isVarRHS;
3043 return VisitConditionVariable(LhsString, BExpr->
getLHS(), BRC, R, N,
3049 if (LhsString.empty() || RhsString.empty() ||
3055 llvm::raw_svector_ostream Out(buf);
3056 Out << (IsAssuming ?
"Assuming " :
"")
3057 << (shouldInvert ? RhsString : LhsString) <<
" is ";
3063 case BO_LT: Op = BO_GT;
break;
3064 case BO_GT: Op = BO_LT;
break;
3065 case BO_LE: Op = BO_GE;
break;
3066 case BO_GE: Op = BO_LE;
break;
3071 case BO_EQ: Op = BO_NE;
break;
3072 case BO_NE: Op = BO_EQ;
break;
3073 case BO_LT: Op = BO_GE;
break;
3074 case BO_GT: Op = BO_LE;
break;
3075 case BO_LE: Op = BO_GT;
break;
3076 case BO_GE: Op = BO_LT;
break;
3086 Out <<
"not equal to ";
3093 Out << (shouldInvert ? LhsString : RhsString);
3102 std::string Message = std::string(Out.str());
3103 Message[0] = toupper(Message[0]);
3108 if (!shouldInvert) {
3109 if (LhsME && LhsME->getMemberLoc().isValid())
3114 if (RhsME && RhsME->getMemberLoc().isValid())
3120 return std::make_shared<PathDiagnosticPopUpPiece>(
Loc, Message);
3124 auto event = std::make_shared<PathDiagnosticEventPiece>(
Loc, Message);
3126 event->setPrunable(*shouldPrune);
3137 llvm::raw_svector_ostream Out(buf);
3138 Out <<
"Assuming " << LhsString <<
" is ";
3140 if (!printValue(CondVarExpr, Out, N, TookTrue,
true))
3149 auto event = std::make_shared<PathDiagnosticEventPiece>(
Loc, Out.str());
3152 event->setPrunable(
false);
3161 const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl());
3166 llvm::raw_svector_ostream Out(Buf);
3168 Out << (IsAssuming ?
"Assuming '" :
"'") << VD->getDeclName() <<
"' is ";
3170 if (!printValue(DRE, Out, N, TookTrue, IsAssuming))
3181 return std::make_shared<PathDiagnosticPopUpPiece>(
Loc, Out.str());
3185 auto event = std::make_shared<PathDiagnosticEventPiece>(
Loc, Out.str());
3188 event->setPrunable(
false);
3190 return std::move(event);
3198 llvm::raw_svector_ostream Out(Buf);
3200 Out << (IsAssuming ?
"Assuming field '" :
"Field '")
3203 if (!printValue(ME, Out, N, TookTrue, IsAssuming))
3223 return std::make_shared<PathDiagnosticPopUpPiece>(
Loc, Out.str());
3225 auto event = std::make_shared<PathDiagnosticEventPiece>(
Loc, Out.str());
3227 event->setPrunable(
false);
3237 Out << (TookTrue ?
"non-null" :
"null");
3242 Out << (TookTrue ?
"non-nil" :
"nil");
3249 std::optional<const llvm::APSInt *> IntValue;
3253 if (IsAssuming || !IntValue) {
3255 Out << (TookTrue ?
"true" :
"false");
3257 Out << (TookTrue ?
"not equal to 0" :
"0");
3260 Out << ((*IntValue)->getBoolValue() ?
"true" :
"false");
3268constexpr llvm::StringLiteral ConditionBRVisitor::GenericTrueMessage;
3269constexpr llvm::StringLiteral ConditionBRVisitor::GenericFalseMessage;
3273 return Piece->
getString() == GenericTrueMessage ||
3274 Piece->
getString() == GenericFalseMessage;
3294 if (Options.ShouldSuppressFromCXXStandardLibrary) {
3304 if (
const auto *MD = dyn_cast<CXXMethodDecl>(D)) {
3306 if (CD->
getName() ==
"list") {
3314 if (
const auto *MD = dyn_cast<CXXConstructorDecl>(D)) {
3316 if (CD->
getName() ==
"__independent_bits_engine") {
3324 const auto *MD = dyn_cast<CXXMethodDecl>(LCtx->getDecl());
3335 if (CD->
getName() ==
"basic_string") {
3343 if (CD->
getName() ==
"shared_ptr") {
3355 while (
Loc.isMacroID()) {
3356 Loc =
Loc.getSpellingLoc();
3357 if (
SM.getFilename(
Loc).endswith(
"sys/queue.h")) {
3385 for (
const auto ParamDecl : parms) {
3386 const MemRegion *ArgReg = Call->getArgSVal(Idx).getAsRegion();
3394 assert(ParamDecl &&
"Formal parameter has no decl?");
3409 SVal BoundVal = State->getSVal(R);
3432 llvm::SMTSolverRef RefutationSolver = llvm::CreateZ3Solver();
3436 for (
const auto &I : Constraints) {
3438 auto RangeIt = I.second.begin();
3441 RefutationSolver, Ctx, Sym, RangeIt->From(), RangeIt->To(),
3443 while ((++RangeIt) != I.second.end()) {
3444 SMTConstraints = RefutationSolver->mkOr(
3446 RangeIt->From(), RangeIt->To(),
3450 RefutationSolver->addConstraint(SMTConstraints);
3454 std::optional<bool> IsSAT = RefutationSolver->check();
3463 const ExplodedNode *N,
bool OverwriteConstraintsOnExistingSyms) {
3469 for (
auto const &
C : NewCs) {
3471 if (!Constraints.contains(Sym)) {
3473 Constraints =
CF.add(Constraints, Sym,
C.second);
3474 }
else if (OverwriteConstraintsOnExistingSyms) {
3476 Constraints =
CF.remove(Constraints, Sym);
3477 Constraints =
CF.add(Constraints, Sym,
C.second);
3489 llvm::FoldingSetNodeID &ID)
const {
3491 ID.AddPointer(&Tag);
3498int NoteTag::Kind = 0;
3502 ID.AddPointer(&Tag);
3516 auto Piece = std::make_shared<PathDiagnosticEventPiece>(
Loc, *Msg);
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 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.
static CompilationDatabasePluginRegistry::Add< FixedCompilationDatabasePlugin > X("fixed-compilation-database", "Reads plain-text flags file")
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...
@ ObjCSelf
Parameter for Objective-C 'self' argument.
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 ...
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
Represents an SVal that is guaranteed to not be UnknownVal.
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.
std::optional< std::string > generateMessage(BugReporterContext &BRC, PathSensitiveBugReport &R) const
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.
void trackStoredValue(KnownSVal 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.
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.
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)
bool Call(InterpState &S, CodePtr &PC, const Function *Func)
bool isa(CodeGen::Address addr)
@ C
Languages that the frontend can parse and compile.
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.