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.AddString(Message);
1790 ID.AddBoolean(Assumption);
1797 return "TrackConstraintBRVisitor";
1800bool TrackConstraintBRVisitor::isZeroCheck()
const {
1801 return !Assumption && Constraint.
getAs<
Loc>();
1804bool TrackConstraintBRVisitor::isUnderconstrained(
const ExplodedNode *N)
const {
1806 return N->
getState()->isNull(Constraint).isUnderconstrained();
1807 return (
bool)N->
getState()->assume(Constraint, !Assumption);
1818 if (!IsTrackingTurnedOn)
1819 if (!isUnderconstrained(N))
1820 IsTrackingTurnedOn =
true;
1821 if (!IsTrackingTurnedOn)
1826 if (isUnderconstrained(PrevN)) {
1833 assert(!isUnderconstrained(N));
1841 if (isa_and_nonnull<NoteTag>(
P.getTag()))
1849 auto X = std::make_shared<PathDiagnosticEventPiece>(L, Message);
1851 return std::move(
X);
1866 if (!Options.ShouldSuppressInlinedDefensiveChecks)
1871 llvm::FoldingSetNodeID &ID)
const {
1878 return "IDCVisitor";
1890 if (!IsTrackingTurnedOn)
1891 if (Succ->
getState()->isNull(
V).isConstrainedTrue())
1892 IsTrackingTurnedOn =
true;
1893 if (!IsTrackingTurnedOn)
1898 if (!Pred->
getState()->isNull(
V).isConstrainedTrue() &&
1899 Succ->
getState()->isNull(
V).isConstrainedTrue()) {
1905 if (CurLC != ReportLC && !CurLC->
isParentOf(ReportLC)) {
1920 const Stmt *CurTerminatorStmt =
nullptr;
1922 CurTerminatorStmt = BE->getSrc()->getTerminator().getStmt();
1924 const Stmt *CurStmt = SP->getStmt();
1934 if (!CurTerminatorStmt)
1968class TrackControlDependencyCondBRVisitor final
1972 llvm::SmallSet<const CFGBlock *, 32> VisitedBlocks;
1975 TrackControlDependencyCondBRVisitor(
TrackerRef ParentTracker,
1978 ControlDeps(&O->getCFG()) {}
1980 void Profile(llvm::FoldingSetNodeID &
ID)
const override {
1991static std::shared_ptr<PathDiagnosticEventPiece>
2004 return std::make_shared<PathDiagnosticEventPiece>(
2007 (Twine() +
"Tracking condition '" + ConditionText +
"'").str());
2035 if (
const auto *BinOp = dyn_cast<BinaryOperator>(ElseCond))
2036 if (BinOp->isLogicalOp())
2043TrackControlDependencyCondBRVisitor::VisitNode(
const ExplodedNode *N,
2053 if (!VisitedBlocks.insert(NB).second)
2059 if (!OriginB || !NB)
2065 if (ControlDeps.isControlDependent(OriginB, NB)) {
2091 if (isa<CallExpr>(InnerExpr))
2098 getParentTracker().track(InnerExpr, N,
2116 if (
const auto *FE = dyn_cast<FullExpr>(Ex))
2118 if (
const auto *OVE = dyn_cast<OpaqueValueExpr>(Ex))
2120 if (
const auto *POE = dyn_cast<PseudoObjectExpr>(Ex)) {
2121 const auto *PropRef = dyn_cast<ObjCPropertyRefExpr>(POE->getSyntacticForm());
2122 if (PropRef && PropRef->isMessagingGetter()) {
2123 const Expr *GetterMessageSend =
2124 POE->getSemanticExpr(POE->getNumSemanticExprs() - 1);
2131 if (
const auto *CO = dyn_cast<ConditionalOperator>(Ex)) {
2137 if (std::optional<BlockEdge> BE = ProgPoint.
getAs<
BlockEdge>()) {
2138 const CFGBlock *srcBlk = BE->getSrc();
2141 bool TookTrueBranch = (*(srcBlk->
succ_begin()) == BE->getDst());
2153 if (
auto *BO = dyn_cast<BinaryOperator>(Ex))
2157 if (
auto *UO = dyn_cast<UnaryOperator>(Ex)) {
2158 if (UO->getOpcode() == UO_LNot)
2169 if (UO->getOpcode() == UO_AddrOf && UO->getSubExpr()->isLValue())
2180 const Expr *Inner) {
2195 StringRef NodeText) {
2201 P.getLocationContext());
2209 return std::make_shared<PathDiagnosticEventPiece>(L, NodeText);
2221 llvm::raw_svector_ostream OS(Buffer);
2236 if (Opts.
Kind == bugreporter::TrackingKind::Condition)
2239 return constructNote(SI, BRC, OS.str());
2259 ->getAnalysisManager()
2260 .getAnalyzerOptions()
2261 .ShouldTrackConditions) {
2262 Report.
addVisitor<TrackControlDependencyCondBRVisitor>(
2263 &getParentTracker(), InputNode);
2281 if (
const Expr *Receiver =
2283 return getParentTracker().track(Receiver, LVNode, Opts);
2297 if (
const auto *Arr = dyn_cast<ArraySubscriptExpr>(Inner))
2298 return getParentTracker().track(
2299 Arr->getIdx(), LVNode,
2300 {Opts.Kind, false});
2325 bool LVIsNull = LVState->isNull(LVal).isConstrainedTrue();
2330 if (RR && !LVIsNull)
2331 Result.combineWith(getParentTracker().track(LVal, RR, Opts, SFC));
2344 Report.
addVisitor<NoStoreFuncVisitor>(cast<SubRegion>(R), Opts.
Kind);
2348 Result.FoundSomethingToTrack =
true;
2349 Result.WasInterrupted =
true;
2351 MacroNullReturnSuppressionVisitor::addMacroVisitorIfNecessary(
2359 if (
V.getAsLocSymbol(
true))
2360 if (LVState->isNull(
V).isConstrainedTrue())
2363 false,
"Assuming pointer value is null");
2376 getParentTracker().track(
V, R, Opts, SFC);
2404 const bool BypassCXXNewExprEval = isa<CXXNewExpr>(E);
2411 if (std::optional<CallExitEnd> CEE =
2413 if (CEE->getCalleeContext()->getCallSite() == E)
2426 if (!BypassCXXNewExprEval)
2429 if (SP->getStmt() == E && CurrentSFC == PredSFC)
2432 CurrentSFC = PredSFC;
2455 if (cast<Expr>(E)->isGLValue())
2456 if (std::optional<Loc> LValue = RetVal.
getAs<
Loc>())
2457 RetVal = State->getSVal(*LValue);
2462 bool EnableNullFPSuppression =
false;
2464 if (std::optional<Loc> RetLoc = RetVal.
getAs<
Loc>())
2465 EnableNullFPSuppression = State->isNull(*RetLoc).isConstrainedTrue();
2468 Report.
addVisitor<ReturnVisitor>(&getParentTracker(), CalleeContext,
2469 EnableNullFPSuppression, Options,
2497 bool CanDereference =
true;
2499 if (SR->getPointeeStaticType()->isVoidType())
2500 CanDereference =
false;
2502 CanDereference =
false;
2509 RVal = LVState->getRawSVal(*L, Inner->getType());
2510 else if (CanDereference)
2511 RVal = LVState->getSVal(L->getRegion());
2513 if (CanDereference) {
2515 Result.FoundSomethingToTrack =
true;
2519 getParentTracker().track(*KV, L->getRegion(), Opts, SFC));
2523 if (isa_and_nonnull<SymbolicRegion>(RegionRVal)) {
2527 false,
"Assuming pointer value is null");
2528 Result.FoundSomethingToTrack =
true;
2555 const auto track = [&CombinedResult, &
Parent, ExprNode,
2556 Opts](
const Expr *Inner) {
2565 if (
const auto *ILE = dyn_cast<InitListExpr>(E)) {
2566 if (ILE->getNumInits() == 1) {
2567 track(ILE->getInit(0));
2569 return CombinedResult;
2577 const auto *BO = dyn_cast<BinaryOperator>(E);
2579 if (!BO || !BO->isMultiplicativeOp() || !
V.isZeroConstant())
2586 if (BO->getOpcode() == BO_Mul) {
2588 track(BO->getLHS());
2590 track(BO->getRHS());
2593 track(BO->getLHS());
2596 return CombinedResult;
2603 addLowPriorityHandler<ControlDependencyHandler>();
2604 addLowPriorityHandler<NilReceiverHandler>();
2605 addLowPriorityHandler<ArrayIndexHandler>();
2606 addLowPriorityHandler<InterestingLValueHandler>();
2607 addLowPriorityHandler<InlinedFunctionCallHandler>();
2608 addLowPriorityHandler<DefaultExpressionHandler>();
2609 addLowPriorityHandler<PRValueHandler>();
2611 addHighPriorityHandler<DefaultStoreHandler>();
2626 for (ExpressionHandlerPtr &Handler : ExpressionHandlers) {
2627 CombinedResult.
combineWith(Handler->handle(Inner, N, LVNode, Opts));
2636 return CombinedResult;
2642 Report.
addVisitor<StoreSiteFinder>(
this, *KV, R, Opts, Origin);
2651 for (StoreHandlerPtr &Handler : StoreHandlers) {
2666 ->track(E, InputNode, Opts)
2667 .FoundSomethingToTrack;
2683 const auto *ME = dyn_cast<ObjCMessageExpr>(S);
2686 if (
const Expr *Receiver = ME->getInstanceReceiver()) {
2689 if (state->isNull(
V).isConstrainedTrue())
2702 const Stmt *S =
P->getStmt();
2703 const Expr *Receiver = getNilReceiver(S, N);
2708 llvm::raw_svector_ostream
OS(Buf);
2710 if (
const auto *ME = dyn_cast<ObjCMessageExpr>(S)) {
2712 ME->getSelector().print(
OS);
2713 OS <<
"' not called";
2716 OS <<
"No method is called";
2718 OS <<
" because the receiver is nil";
2729 return std::make_shared<PathDiagnosticEventPiece>(L,
OS.str());
2743 auto piece = VisitNodeImpl(N, BRC, BR);
2745 piece->setTag(getTag());
2746 if (
auto *ev = dyn_cast<PathDiagnosticEventPiece>(piece.get()))
2747 ev->setPrunable(
true,
false);
2757 const std::pair<const ProgramPointTag *, const ProgramPointTag *> &Tags =
2762 if (std::optional<BlockEdge> BE = ProgPoint.
getAs<
BlockEdge>()) {
2763 const CFGBlock *SrcBlock = BE->getSrc();
2771 if (PreviousNodeTag == Tags.first || PreviousNodeTag == Tags.second)
2774 return VisitTerminator(Term, N, SrcBlock, BE->getDst(), BR, BRC);
2779 if (std::optional<PostStmt> PS = ProgPoint.
getAs<
PostStmt>()) {
2781 if (CurrentNodeTag != Tags.first && CurrentNodeTag != Tags.second)
2784 bool TookTrue = CurrentNodeTag == Tags.first;
2785 return VisitTrueTest(cast<Expr>(PS->getStmt()), BRC, BR, N, TookTrue);
2795 const Expr *Cond =
nullptr;
2815 case Stmt::IfStmtClass:
2816 Cond = cast<IfStmt>(Term)->getCond();
2818 case Stmt::ConditionalOperatorClass:
2819 Cond = cast<ConditionalOperator>(Term)->getCond();
2821 case Stmt::BinaryOperatorClass:
2825 const auto *BO = cast<BinaryOperator>(Term);
2826 assert(BO->isLogicalOp() &&
2827 "CFG terminator is not a short-circuit operator!");
2828 Cond = BO->getLHS();
2837 while (
const auto *InnerBO = dyn_cast<BinaryOperator>(Cond)) {
2838 if (!InnerBO->isLogicalOp())
2845 const bool TookTrue = *(srcBlk->
succ_begin()) == dstBlk;
2846 return VisitTrueTest(Cond, BRC, R, N, TookTrue);
2863 CurrentState->getSVal(Cond, LCtx).isUnknownOrUndef();
2867 const Expr *CondTmp = Cond;
2868 bool TookTrueTmp = TookTrue;
2875 case Stmt::BinaryOperatorClass:
2876 if (
auto P = VisitTrueTest(Cond, cast<BinaryOperator>(CondTmp),
2877 BRC, R, N, TookTrueTmp, IsAssuming))
2880 case Stmt::DeclRefExprClass:
2881 if (
auto P = VisitTrueTest(Cond, cast<DeclRefExpr>(CondTmp),
2882 BRC, R, N, TookTrueTmp, IsAssuming))
2885 case Stmt::MemberExprClass:
2886 if (
auto P = VisitTrueTest(Cond, cast<MemberExpr>(CondTmp),
2887 BRC, R, N, TookTrueTmp, IsAssuming))
2890 case Stmt::UnaryOperatorClass: {
2891 const auto *UO = cast<UnaryOperator>(CondTmp);
2892 if (UO->getOpcode() == UO_LNot) {
2893 TookTrueTmp = !TookTrueTmp;
2894 CondTmp = UO->getSubExpr();
2914 return std::make_shared<PathDiagnosticEventPiece>(
2915 Loc, TookTrue ? GenericTrueMessage : GenericFalseMessage);
2922 std::optional<bool> &prunable,
2923 bool IsSameFieldName) {
2924 const Expr *OriginalExpr = Ex;
2945 if (
const auto *DR = dyn_cast<DeclRefExpr>(Ex)) {
2946 const bool quotes = isa<VarDecl>(DR->getDecl());
2963 Out << DR->getDecl()->getDeclName().getAsString();
2969 if (
const auto *IL = dyn_cast<IntegerLiteral>(Ex)) {
2972 if (IL->getValue() == 0) {
2978 if (IL->getValue() == 0) {
2984 Out << IL->getValue();
2988 if (
const auto *ME = dyn_cast<MemberExpr>(Ex)) {
2989 if (!IsSameFieldName)
2990 Out <<
"field '" << ME->getMemberDecl()->getName() <<
'\'';
3007 bool shouldInvert =
false;
3008 std::optional<bool> shouldPrune;
3012 bool IsSameFieldName =
false;
3018 LhsME->getMemberDecl()->getName() == RhsME->getMemberDecl()->getName();
3022 llvm::raw_svector_ostream OutLHS(LhsString), OutRHS(RhsString);
3023 const bool isVarLHS = patternMatch(BExpr->
getLHS(), BExpr, OutLHS, BRC, R,
3024 N, shouldPrune, IsSameFieldName);
3025 const bool isVarRHS = patternMatch(BExpr->
getRHS(), BExpr, OutRHS, BRC, R,
3026 N, shouldPrune, IsSameFieldName);
3028 shouldInvert = !isVarLHS && isVarRHS;
3036 return VisitConditionVariable(LhsString, BExpr->
getLHS(), BRC, R, N,
3042 if (LhsString.empty() || RhsString.empty() ||
3048 llvm::raw_svector_ostream Out(buf);
3049 Out << (IsAssuming ?
"Assuming " :
"")
3050 << (shouldInvert ? RhsString : LhsString) <<
" is ";
3056 case BO_LT: Op = BO_GT;
break;
3057 case BO_GT: Op = BO_LT;
break;
3058 case BO_LE: Op = BO_GE;
break;
3059 case BO_GE: Op = BO_LE;
break;
3064 case BO_EQ: Op = BO_NE;
break;
3065 case BO_NE: Op = BO_EQ;
break;
3066 case BO_LT: Op = BO_GE;
break;
3067 case BO_GT: Op = BO_LE;
break;
3068 case BO_LE: Op = BO_GT;
break;
3069 case BO_GE: Op = BO_LT;
break;
3079 Out <<
"not equal to ";
3086 Out << (shouldInvert ? LhsString : RhsString);
3095 std::string Message = std::string(Out.str());
3096 Message[0] = toupper(Message[0]);
3101 if (!shouldInvert) {
3102 if (LhsME && LhsME->getMemberLoc().isValid())
3107 if (RhsME && RhsME->getMemberLoc().isValid())
3113 return std::make_shared<PathDiagnosticPopUpPiece>(
Loc, Message);
3117 auto event = std::make_shared<PathDiagnosticEventPiece>(
Loc, Message);
3119 event->setPrunable(*shouldPrune);
3130 llvm::raw_svector_ostream Out(buf);
3131 Out <<
"Assuming " << LhsString <<
" is ";
3133 if (!printValue(CondVarExpr, Out, N, TookTrue,
true))
3142 auto event = std::make_shared<PathDiagnosticEventPiece>(
Loc, Out.str());
3145 event->setPrunable(
false);
3154 const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl());
3159 llvm::raw_svector_ostream Out(Buf);
3161 Out << (IsAssuming ?
"Assuming '" :
"'") << VD->getDeclName() <<
"' is ";
3163 if (!printValue(DRE, Out, N, TookTrue, IsAssuming))
3174 return std::make_shared<PathDiagnosticPopUpPiece>(
Loc, Out.str());
3178 auto event = std::make_shared<PathDiagnosticEventPiece>(
Loc, Out.str());
3181 event->setPrunable(
false);
3183 return std::move(event);
3191 llvm::raw_svector_ostream Out(Buf);
3193 Out << (IsAssuming ?
"Assuming field '" :
"Field '")
3196 if (!printValue(ME, Out, N, TookTrue, IsAssuming))
3216 return std::make_shared<PathDiagnosticPopUpPiece>(
Loc, Out.str());
3218 auto event = std::make_shared<PathDiagnosticEventPiece>(
Loc, Out.str());
3220 event->setPrunable(
false);
3230 Out << (TookTrue ?
"non-null" :
"null");
3235 Out << (TookTrue ?
"non-nil" :
"nil");
3242 std::optional<const llvm::APSInt *> IntValue;
3246 if (IsAssuming || !IntValue) {
3248 Out << (TookTrue ?
"true" :
"false");
3250 Out << (TookTrue ?
"not equal to 0" :
"0");
3253 Out << ((*IntValue)->getBoolValue() ?
"true" :
"false");
3261constexpr llvm::StringLiteral ConditionBRVisitor::GenericTrueMessage;
3262constexpr llvm::StringLiteral ConditionBRVisitor::GenericFalseMessage;
3266 return Piece->
getString() == GenericTrueMessage ||
3267 Piece->
getString() == GenericFalseMessage;
3287 if (Options.ShouldSuppressFromCXXStandardLibrary) {
3297 if (
const auto *MD = dyn_cast<CXXMethodDecl>(D)) {
3299 if (CD->
getName() ==
"list") {
3307 if (
const auto *MD = dyn_cast<CXXConstructorDecl>(D)) {
3309 if (CD->
getName() ==
"__independent_bits_engine") {
3317 const auto *MD = dyn_cast<CXXMethodDecl>(LCtx->getDecl());
3328 if (CD->
getName() ==
"basic_string") {
3336 if (CD->
getName() ==
"shared_ptr") {
3348 while (
Loc.isMacroID()) {
3349 Loc =
Loc.getSpellingLoc();
3350 if (
SM.getFilename(
Loc).endswith(
"sys/queue.h")) {
3378 for (
const auto ParamDecl : parms) {
3379 const MemRegion *ArgReg = Call->getArgSVal(Idx).getAsRegion();
3387 assert(ParamDecl &&
"Formal parameter has no decl?");
3402 SVal BoundVal = State->getSVal(R);
3425 llvm::SMTSolverRef RefutationSolver = llvm::CreateZ3Solver();
3429 for (
const auto &I : Constraints) {
3431 auto RangeIt = I.second.begin();
3434 RefutationSolver, Ctx, Sym, RangeIt->From(), RangeIt->To(),
3436 while ((++RangeIt) != I.second.end()) {
3437 SMTConstraints = RefutationSolver->mkOr(
3439 RangeIt->From(), RangeIt->To(),
3443 RefutationSolver->addConstraint(SMTConstraints);
3447 std::optional<bool> IsSAT = RefutationSolver->check();
3456 const ExplodedNode *N,
bool OverwriteConstraintsOnExistingSyms) {
3462 for (
auto const &
C : NewCs) {
3464 if (!Constraints.contains(Sym)) {
3466 Constraints =
CF.add(Constraints, Sym,
C.second);
3467 }
else if (OverwriteConstraintsOnExistingSyms) {
3469 Constraints =
CF.remove(Constraints, Sym);
3470 Constraints =
CF.add(Constraints, Sym,
C.second);
3482 llvm::FoldingSetNodeID &ID)
const {
3484 ID.AddPointer(&Tag);
3491int NoteTag::Kind = 0;
3495 ID.AddPointer(&Tag);
3509 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.
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 Call(InterpState &S, CodePtr OpPC, const Function *Func)
bool Ret(InterpState &S, CodePtr &PC, APValue &Result)
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.