47#include "llvm/ADT/ArrayRef.h"
48#include "llvm/ADT/SmallPtrSet.h"
49#include "llvm/ADT/SmallString.h"
50#include "llvm/ADT/StringExtras.h"
51#include "llvm/ADT/StringRef.h"
52#include "llvm/Support/Casting.h"
53#include "llvm/Support/ErrorHandling.h"
54#include "llvm/Support/raw_ostream.h"
98 const auto *E = dyn_cast<Expr>(S);
103 if (
const auto *CE = dyn_cast<CastExpr>(E)) {
104 if (CE->getCastKind() == CK_LValueToRValue) {
108 E = CE->getSubExpr();
109 }
else if (
const auto *B = dyn_cast<BinaryOperator>(E)) {
113 }
else if (B->isAssignmentOp()) {
121 }
else if (
const auto *
U = dyn_cast<UnaryOperator>(E)) {
122 if (
U->getOpcode() == UO_Deref ||
U->getOpcode() == UO_AddrOf ||
123 (
U->isIncrementDecrementOp() &&
U->getType()->isPointerType())) {
134 else if (
const auto *ME = dyn_cast<MemberExpr>(E)) {
143 if (ME->getMemberDecl()->getType()->isReferenceType())
146 }
else if (
const auto *IvarRef = dyn_cast<ObjCIvarRefExpr>(E)) {
147 E = IvarRef->getBase();
148 }
else if (
const auto *AE = dyn_cast<ArraySubscriptExpr>(E)) {
150 }
else if (
const auto *PE = dyn_cast<ParenExpr>(E)) {
151 E = PE->getSubExpr();
152 }
else if (
const auto *FE = dyn_cast<FullExpr>(E)) {
153 E = FE->getSubExpr();
163 if (
const auto *CE = dyn_cast<ImplicitCastExpr>(E))
164 if (CE->getCastKind() == CK_LValueToRValue)
165 E = CE->getSubExpr();
171 if (
const auto *DR = dyn_cast<DeclRefExpr>(E))
172 return dyn_cast<VarDecl>(DR->getDecl());
178 bool LookingForReference =
true) {
179 if (
const auto *ME = dyn_cast<MemberExpr>(E)) {
189 const auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl());
193 if (FD->getType()->isReferenceType()) {
195 return N->
getState()->getLValue(FD, StructSVal).getAsRegion();
218 if (LeftVal == RightVal)
229 return LLCV->
getRegion() == RLCV->getRegion() &&
230 LLCV->getStore() == LeftNode->
getState()->getStore() &&
231 RLCV->getStore() == RightNode->
getState()->getStore();
246 if (
const auto *DRE = dyn_cast<DeclRefExpr>(CondVarExpr))
247 if (
const auto *VD = dyn_cast<VarDecl>(DRE->getDecl()))
248 return State->getSVal(State->getLValue(VD, LCtx));
250 if (
const auto *ME = dyn_cast<MemberExpr>(CondVarExpr))
251 if (
const auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl()))
252 if (
auto FieldL = State->getSVal(ME, LCtx).getAs<
Loc>())
253 return State->getRawSVal(*FieldL, FD->getType());
258static std::optional<const llvm::APSInt *>
263 return CI->getValue().get();
277 if (std::optional<bugreporter::TrackingKind> K =
279 return *K == bugreporter::TrackingKind::Condition;
304 if (!
Loc.isMacroID())
306 while (
SM.isMacroArgExpansion(
Loc))
307 Loc =
SM.getImmediateExpansionRange(
Loc).getBegin();
335 SVal ValueAtN = N->
getState()->getSVal(RegionOfInterest);
337 .
areEqual(State, ValueAtN, ValueAfter)
368 auto P = std::make_shared<PathDiagnosticEventPiece>(
380bool NoStateChangeFuncVisitor::isModifiedInFrame(
const ExplodedNode *N) {
383 if (!FramesModifyingCalculated.count(SCtx))
384 findModifyingFrames(N);
385 return FramesModifying.count(SCtx);
388void NoStateChangeFuncVisitor::markFrameAsModifying(
391 auto p = FramesModifying.insert(SCtx);
407 auto IsMatchingCallExitEnd = [OrigSCtx](
const ExplodedNode *N) {
411 while (N && !IsMatchingCallExitEnd(N)) {
413 "This function is to be used on the trimmed ExplodedGraph!");
419void NoStateChangeFuncVisitor::findModifyingFrames(
424 const StackFrameContext *
const OriginalSCtx =
427 const ExplodedNode *CurrCallExitBeginN = CallExitBeginN;
428 const StackFrameContext *CurrentSCtx = OriginalSCtx;
430 for (
const ExplodedNode *CurrN = CallExitBeginN; CurrN;
431 CurrN = CurrN->getFirstPred()) {
433 if (CurrN->getLocationAs<CallExitBegin>()) {
434 CurrCallExitBeginN = CurrN;
436 FramesModifyingCalculated.insert(CurrentSCtx);
441 if (
auto CE = CurrN->getLocationAs<CallEnter>()) {
444 markFrameAsModifying(CurrentSCtx);
455 if (CE->getCalleeContext() == OriginalSCtx) {
456 markFrameAsModifying(CurrentSCtx);
462 markFrameAsModifying(CurrentSCtx);
475 if (!CallExitLoc || isModifiedInFrame(N))
490 if (
Call->isInSystemHeader()) {
505 if (
const auto *MC = dyn_cast<ObjCMethodCall>(
Call)) {
512 if (
const auto *CCall = dyn_cast<CXXConstructorCall>(
Call)) {
526 const char *IvarBind =
"Ivar";
527 if (!Parent || !Parent->
hasBody())
530 hasOperatorName(
"="),
531 hasLHS(ignoringParenImpCasts(
537 if (IvarRef->isFreeIvar())
540 const Expr *
Base = IvarRef->getBase();
541 if (
const auto *ICE = dyn_cast<ImplicitCastExpr>(
Base))
542 Base = ICE->getSubExpr();
544 if (
const auto *DRE = dyn_cast<DeclRefExpr>(
Base))
545 if (
const auto *ID = dyn_cast<ImplicitParamDecl>(DRE->getDecl()))
560const std::optional<NoStoreFuncVisitor::RegionVector>
561NoStoreFuncVisitor::findRegionOfInterestInRecord(
563 const NoStoreFuncVisitor::RegionVector &Vec ,
566 if (depth == DEREFERENCE_LIMIT)
569 if (
const auto *RDX = dyn_cast<CXXRecordDecl>(RD))
570 if (!RDX->hasDefinition())
575 if (
const auto *RDX = dyn_cast<CXXRecordDecl>(RD))
576 for (
const auto &II : RDX->bases())
577 if (
const RecordDecl *RRD = II.getType()->getAsRecordDecl())
578 if (std::optional<RegionVector> Out =
579 findRegionOfInterestInRecord(RRD, State, R, Vec, depth))
582 for (
const FieldDecl *I : RD->
fields()) {
583 QualType FT = I->getType();
585 const SVal
V = State->getSVal(FR);
586 const MemRegion *VR =
V.getAsRegion();
588 RegionVector VecF = Vec;
591 if (RegionOfInterest == VR)
596 findRegionOfInterestInRecord(RRD, State, FR, VecF, depth + 1))
604 if (std::optional<RegionVector> Out =
605 findRegionOfInterestInRecord(RRD, State, VR, VecF, depth + 1))
616 if (
const auto *IvarR = dyn_cast<ObjCIvarRegion>(RegionOfInterest)) {
617 const MemRegion *SelfRegion =
Call.getReceiverSVal().getAsRegion();
618 if (RegionOfInterest->isSubRegionOf(SelfRegion) &&
621 return maybeEmitNote(R,
Call, N, {}, SelfRegion,
"self",
631 const MemRegion *ThisR =
Call.getCXXThisVal().getAsRegion();
632 if (RegionOfInterest->isSubRegionOf(ThisR) && !
Call.getDecl()->isImplicit())
633 return maybeEmitNote(R,
Call, N, {}, ThisR,
"this",
650 for (
unsigned I = 0; I <
Call.getNumArgs() && I <
Parameters.size(); ++I) {
652 SVal
V =
Call.getArgSVal(I);
656 unsigned IndirectionLevel = 1;
658 while (
const MemRegion *MR =
V.getAsRegion()) {
660 return maybeEmitNote(R,
Call, N, {}, MR, ParamName,
661 ParamIsReferenceType, IndirectionLevel);
664 if (PT.isNull() || PT->isVoidType())
669 if (
const RecordDecl *RD = PT->getAsRecordDecl())
670 if (std::optional<RegionVector> P =
671 findRegionOfInterestInRecord(RD, State, MR))
672 return maybeEmitNote(R,
Call, N, *P, RegionOfInterest, ParamName,
673 ParamIsReferenceType, IndirectionLevel);
675 V = State->getSVal(MR, PT);
684bool NoStoreFuncVisitor::wasModifiedBeforeCallExit(
686 return ::wasRegionOfInterestModifiedAt(
687 RegionOfInterest, CurrN,
688 CallExitBeginN->
getState()->getSVal(RegionOfInterest));
692 ", which participates in a condition later";
696 const RegionVector &FieldChain,
const MemRegion *MatchedRegion,
697 StringRef FirstElement,
bool FirstIsReferenceType,
698 unsigned IndirectionLevel) {
710 llvm::raw_svector_ostream os(sbuf);
711 os <<
"Returning without writing to '";
714 if (!prettyPrintRegionName(FieldChain, MatchedRegion, FirstElement,
715 FirstIsReferenceType, IndirectionLevel, os))
721 return std::make_shared<PathDiagnosticEventPiece>(L, os.str());
724bool NoStoreFuncVisitor::prettyPrintRegionName(
const RegionVector &FieldChain,
726 StringRef FirstElement,
727 bool FirstIsReferenceType,
728 unsigned IndirectionLevel,
729 llvm::raw_svector_ostream &os) {
731 if (FirstIsReferenceType)
734 RegionVector RegionSequence;
737 assert(RegionOfInterest->isSubRegionOf(MatchedRegion));
738 const MemRegion *R = RegionOfInterest;
739 while (R != MatchedRegion) {
740 RegionSequence.push_back(R);
743 std::reverse(RegionSequence.begin(), RegionSequence.end());
744 RegionSequence.append(FieldChain.begin(), FieldChain.end());
747 for (
const MemRegion *R : RegionSequence) {
755 Sep = prettyPrintFirstElement(FirstElement,
757 IndirectionLevel, os);
766 Sep = DR->getValueType()->isAnyPointerType() ?
"->" :
".";
767 DR->getDecl()->getDeclName().print(os, PP);
771 prettyPrintFirstElement(FirstElement,
772 false, IndirectionLevel, os);
776StringRef NoStoreFuncVisitor::prettyPrintFirstElement(
777 StringRef FirstElement,
bool MoreItemsExpected,
int IndirectionLevel,
778 llvm::raw_svector_ostream &os) {
781 if (IndirectionLevel > 0 && MoreItemsExpected) {
786 if (IndirectionLevel > 0 && MoreItemsExpected)
789 for (
int i = 0; i < IndirectionLevel; i++)
793 if (IndirectionLevel > 0 && MoreItemsExpected)
808 const SubRegion *RegionOfInterest;
809 const SVal ValueAtDereference;
813 bool WasModified =
false;
816 MacroNullReturnSuppressionVisitor(
const SubRegion *R,
const SVal
V)
817 : RegionOfInterest(R), ValueAtDereference(
V) {}
820 BugReporterContext &BRC,
821 PathSensitiveBugReport &BR)
override {
830 if (
auto Loc = matchAssignment(N)) {
832 std::string MacroName = std::string(
getMacroName(*Loc, BRC));
833 SourceLocation BugLoc = BugPoint->getStmt()->getBeginLoc();
845 static void addMacroVisitorIfNecessary(
846 const ExplodedNode *N,
const MemRegion *R,
847 bool EnableNullFPSuppression, PathSensitiveBugReport &BR,
849 AnalyzerOptions &Options = N->
getState()->getAnalysisManager().options;
850 if (EnableNullFPSuppression && Options.ShouldSuppressNullReturnPaths &&
852 BR.
addVisitor<MacroNullReturnSuppressionVisitor>(R->
getAs<SubRegion>(),
856 void* getTag()
const {
858 return static_cast<void *
>(&
Tag);
861 void Profile(llvm::FoldingSetNodeID &ID)
const override {
862 ID.AddPointer(getTag());
868 std::optional<SourceLocation> matchAssignment(
const ExplodedNode *N) {
875 if (
const auto *DS = dyn_cast<DeclStmt>(S)) {
876 if (
const auto *VD = dyn_cast<VarDecl>(DS->getSingleDecl()))
877 if (
const Expr *RHS = VD->getInit())
878 if (RegionOfInterest->isSubRegionOf(
879 State->getLValue(VD, LCtx).getAsRegion()))
880 return RHS->getBeginLoc();
881 }
else if (
const auto *BO = dyn_cast<BinaryOperator>(S)) {
883 const Expr *RHS = BO->getRHS();
884 if (BO->isAssignmentOp() && RegionOfInterest->isSubRegionOf(R)) {
903class ReturnVisitor :
public TrackingBugReporterVisitor {
904 const StackFrameContext *CalleeSFC;
911 bool EnableNullFPSuppression;
912 bool ShouldInvalidate =
true;
913 AnalyzerOptions& Options;
917 ReturnVisitor(
TrackerRef ParentTracker,
const StackFrameContext *Frame,
918 bool Suppressed, AnalyzerOptions &Options,
920 : TrackingBugReporterVisitor(ParentTracker), CalleeSFC(Frame),
921 EnableNullFPSuppression(Suppressed), Options(Options), TKind(TKind) {}
923 static void *getTag() {
925 return static_cast<void *
>(&
Tag);
928 void Profile(llvm::FoldingSetNodeID &ID)
const override {
929 ID.AddPointer(ReturnVisitor::getTag());
930 ID.AddPointer(CalleeSFC);
931 ID.AddBoolean(EnableNullFPSuppression);
935 BugReporterContext &BRC,
936 PathSensitiveBugReport &BR) {
945 const auto *
Ret = dyn_cast<ReturnStmt>(SP->getStmt());
952 SVal
V = State->getSVal(Ret, CalleeSFC);
953 if (
V.isUnknownOrUndef())
959 const Expr *RetE =
Ret->getRetValue();
960 assert(RetE &&
"Tracking a return value for a void function");
963 std::optional<Loc> LValue;
965 if ((LValue =
V.getAs<Loc>())) {
966 SVal RValue = State->getRawSVal(*LValue, RetE->
getType());
979 getParentTracker().track(RetE, N, {TKind, EnableNullFPSuppression});
983 llvm::raw_svector_ostream
Out(Msg);
985 bool WouldEventBeMeaningless =
false;
987 if (State->isNull(
V).isConstrainedTrue()) {
993 if (EnableNullFPSuppression &&
994 Options.ShouldAvoidSuppressingNullArgumentPaths)
995 Mode = MaybeUnsuppress;
998 Out <<
"Returning nil";
1000 Out <<
"Returning null pointer";
1003 Out <<
"Returning zero";
1007 if (
auto CI =
V.getAs<nonloc::ConcreteInt>()) {
1008 Out <<
"Returning the value " << CI->getValue();
1016 WouldEventBeMeaningless =
true;
1018 Out << (isa<Loc>(
V) ?
"Returning pointer" :
"Returning value");
1023 if (
const MemRegion *MR = LValue->getAsRegion()) {
1024 if (MR->canPrintPretty()) {
1025 Out <<
" (reference to ";
1026 MR->printPretty(Out);
1032 if (
const auto *DR = dyn_cast<DeclRefExpr>(RetE))
1033 if (
const auto *DD = dyn_cast<DeclaratorDecl>(DR->getDecl()))
1034 Out <<
" (loaded from '" << *DD <<
"')";
1038 if (!L.isValid() || !L.asLocation().isValid())
1041 if (TKind == bugreporter::TrackingKind::Condition)
1044 auto EventPiece = std::make_shared<PathDiagnosticEventPiece>(L,
Out.str());
1048 if (WouldEventBeMeaningless)
1049 EventPiece->setPrunable(
true);
1057 BugReporterContext &BRC,
1058 PathSensitiveBugReport &BR) {
1059 assert(Options.ShouldAvoidSuppressingNullArgumentPaths);
1062 std::optional<CallEnter> CE = N->
getLocationAs<CallEnter>();
1066 if (CE->getCalleeContext() != CalleeSFC)
1079 for (
unsigned I = 0, E =
Call->getNumArgs(); I != E; ++I) {
1080 std::optional<Loc> ArgV =
Call->getArgSVal(I).getAs<Loc>();
1084 const Expr *ArgE =
Call->getArgExpr(I);
1089 if (!State->isNull(*ArgV).isConstrainedTrue())
1092 if (getParentTracker()
1093 .track(ArgE, N, {TKind, EnableNullFPSuppression})
1094 .FoundSomethingToTrack)
1095 ShouldInvalidate =
false;
1106 BugReporterContext &BRC,
1107 PathSensitiveBugReport &BR)
override {
1110 return visitNodeInitial(N, BRC, BR);
1111 case MaybeUnsuppress:
1112 return visitNodeMaybeUnsuppress(N, BRC, BR);
1117 llvm_unreachable(
"Invalid visit mode!");
1120 void finalizeVisitor(BugReporterContext &,
const ExplodedNode *,
1121 PathSensitiveBugReport &BR)
override {
1122 if (EnableNullFPSuppression && ShouldInvalidate)
1123 BR.
markInvalid(ReturnVisitor::getTag(), CalleeSFC);
1133class StoreSiteFinder final :
public TrackingBugReporterVisitor {
1136 bool Satisfied =
false;
1138 TrackingOptions Options;
1139 const StackFrameContext *OriginSFC;
1153 const MemRegion *R, TrackingOptions Options,
1154 const StackFrameContext *OriginSFC =
nullptr)
1155 : TrackingBugReporterVisitor(ParentTracker), R(R),
V(
V), Options(Options),
1156 OriginSFC(OriginSFC) {
1160 void Profile(llvm::FoldingSetNodeID &ID)
const override;
1163 BugReporterContext &BRC,
1164 PathSensitiveBugReport &BR)
override;
1168void StoreSiteFinder::Profile(llvm::FoldingSetNodeID &ID)
const {
1170 ID.AddPointer(&tag);
1173 ID.AddInteger(
static_cast<int>(Options.Kind));
1174 ID.AddBoolean(Options.EnableNullFPSuppression);
1191 const auto *FrameSpace =
1198 [[maybe_unused]]
bool IsLocalStaticOrLocalExtern =
1200 assert(IsLocalStaticOrLocalExtern &&
1201 "Declared a variable on the stack without Stack memspace?");
1212 if (
const auto *TR = dyn_cast<TypedValueRegion>(R))
1213 return TR->getValueType()->isObjCObjectPointerType();
1223using DestTypeValue = std::pair<const StoreInfo &, loc::ConcreteInt>;
1225llvm::raw_ostream &
operator<<(llvm::raw_ostream &
OS,
const DestTypeValue &Val) {
1226 if (
auto *TyR = Val.first.Dest->getAs<
TypedRegion>()) {
1227 QualType LocTy = TyR->getLocationType();
1229 if (
auto *PtrTy = LocTy->
getAs<PointerType>()) {
1230 std::string PStr = PtrTy->getPointeeType().getAsString();
1232 OS <<
"(" << PStr <<
")";
1236 SmallString<16> ValStr;
1237 Val.second.getValue()->toString(ValStr, 10,
true);
1252 const char *Action =
nullptr;
1256 Action = HasPrefix ?
"initialized to " :
"Initializing to ";
1259 Action = HasPrefix ?
"captured by block as " :
"Captured by block as ";
1262 llvm_unreachable(
"Unexpected store kind");
1266 if (!*CVal->getValue())
1269 OS << Action << DestTypeValue(SI, *CVal);
1272 OS << Action << CVal->getValue();
1275 OS << Action <<
"the value of ";
1289 if (VD->getInit()) {
1290 OS << (HasPrefix ?
"initialized" :
"Initializing")
1291 <<
" to a garbage value";
1293 OS << (HasPrefix ?
"declared" :
"Declaring")
1294 <<
" without an initial value";
1298 OS << (HasPrefix ?
"initialized" :
"Initialized") <<
" here";
1307 const auto *D = VR->getDecl();
1312 if (!*CI->getValue())
1313 OS << (
isObjCPointer(D) ?
"nil object reference" :
"null pointer value");
1315 OS << (
isObjCPointer(D) ?
"object reference of value " :
"pointer value ")
1316 << DestTypeValue(SI, *CI);
1319 OS <<
"uninitialized value";
1322 OS <<
"the value " << CI->getValue();
1331 if (
const auto *Param = dyn_cast<ParmVarDecl>(VR->getDecl())) {
1333 unsigned Idx = Param->getFunctionScopeIndex() + 1;
1334 OS <<
" via " << Idx << llvm::getOrdinalSuffix(Idx) <<
" parameter";
1339 }
else if (
const auto *ImplParam = dyn_cast<ImplicitParamDecl>(D)) {
1341 OS <<
" via implicit parameter 'self'";
1355 ?
"nil object reference stored"
1356 : (HasSuffix ?
"Null pointer value stored"
1357 :
"Storing null pointer value"));
1360 OS <<
"object reference of value " << DestTypeValue(SI, *CV)
1364 OS <<
"Pointer value of " << DestTypeValue(SI, *CV) <<
" stored";
1366 OS <<
"Storing pointer value of " << DestTypeValue(SI, *CV);
1370 OS << (HasSuffix ?
"Uninitialized value stored"
1371 :
"Storing uninitialized value");
1375 OS <<
"The value " << CV->getValue() <<
" is assigned";
1377 OS <<
"Assigning " << CV->getValue();
1381 OS <<
"The value of ";
1383 OS <<
" is assigned";
1385 OS <<
"Assigning the value of ";
1390 OS << (HasSuffix ?
"Value assigned" :
"Assigning value");
1411 const auto *TVR = dyn_cast_or_null<TypedValueRegion>(R);
1419 std::stack<const TypedValueRegion *> TVRStack;
1425 if (ITy == TVR->getValueType().getCanonicalType())
1434 if (ITy != TVR->getValueType().getCanonicalType())
1438 while (!TVRStack.empty()) {
1439 TVR = TVRStack.top();
1450 if (
const auto *FR = dyn_cast<FieldRegion>(TVR)) {
1451 const auto *FD = FR->
getDecl();
1453 if (FD->getFieldIndex() >= NumInits)
1457 }
else if (
const auto *ER = dyn_cast<ElementRegion>(TVR)) {
1458 const auto Ind = ER->getIndex();
1462 if (!Ind.isConstant())
1465 const auto IndVal = Ind.getAsInteger()->getLimitedValue();
1466 if (IndVal >= NumInits)
1484 const Expr *InitE =
nullptr;
1485 bool IsParam =
false;
1488 if (
const auto *VR = dyn_cast<VarRegion>(R)) {
1491 InitE = VR->getDecl()->getInit();
1497 if (std::optional<PostInitializer> PIP =
1500 if (FieldReg == R) {
1502 InitE = PIP->getInitializer()->getInit();
1516 std::optional<PostStore> PS = Succ->
getLocationAs<PostStore>();
1517 if (!PS || PS->getLocationValue() != R)
1523 if (std::optional<PostStmt> P = Succ->
getLocationAs<PostStmt>()) {
1526 if (
const BinaryOperator *BO = P->getStmtAs<BinaryOperator>()) {
1527 if (BO->isAssignmentOp())
1528 InitE = BO->getRHS();
1532 else if (
const auto *DS = P->getStmtAs<DeclStmt>()) {
1533 const auto *
Decl = DS->getSingleDecl();
1543 if (
const auto *ILE = dyn_cast<InitListExpr>(VD->getInit()))
1546 }
else if (
const auto *CE = P->getStmtAs<CXXConstructExpr>()) {
1548 const auto State = Succ->
getState();
1559 std::stack<const SubRegion *> SRStack;
1567 const auto *OriginEx = CE->getArg(0);
1568 const auto OriginVal =
1574 SVal OriginField = OriginVal;
1575 while (!SRStack.empty()) {
1576 const auto *TopR = SRStack.top();
1579 if (
const auto *FR = dyn_cast<FieldRegion>(TopR)) {
1580 OriginField = State->getLValue(FR->
getDecl(), OriginField);
1581 }
else if (
const auto *ER = dyn_cast<ElementRegion>(TopR)) {
1582 OriginField = State->getLValue(ER->getElementType(),
1583 ER->getIndex(), OriginField);
1590 getParentTracker().track(
V, OriginField.
getAsRegion(), Options);
1595 else if (
const auto *ILE = P->getStmtAs<InitListExpr>()) {
1610 if (std::optional<CallEnter> CE = Succ->
getLocationAs<CallEnter>()) {
1611 if (
const auto *VR = dyn_cast<VarRegion>(R)) {
1613 if (
const auto *Param = dyn_cast<ParmVarDecl>(VR->getDecl())) {
1619 InitE =
Call->getArgExpr(Param->getFunctionScopeIndex());
1624 ->getInstanceReceiver()->IgnoreParenCasts();
1632 if (
const auto *TmpR = dyn_cast<CXXTempObjectRegion>(R))
1633 InitE = TmpR->getExpr();
1647 getParentTracker().track(InitE, StoreSite, Options);
1671 if (
SM.includedInBindings(N->
getState()->getStore(), Candidate)) {
1673 if (N->
getState()->getSVal(Candidate) ==
V) {
1674 OldRegion = Candidate;
1693 if (!OldRegion && StoreSite->
getState()->getSVal(R) ==
V) {
1698 NodeWithoutBinding && NodeWithoutBinding->
getState()->getSVal(R) ==
V;
1699 NodeWithoutBinding = NodeWithoutBinding->
getFirstPred()) {
1702 if (NodeWithoutBinding) {
1714 OldRegion = FB.getRegion();
1718 if (Options.Kind == TrackingKind::Condition && OriginSFC &&
1723 SmallString<256> sbuf;
1724 llvm::raw_svector_ostream os(sbuf);
1733 if (std::optional<PostStmt> PS = StoreSite->
getLocationAs<PostStmt>()) {
1734 const Stmt *S = PS->getStmt();
1735 const auto *DS = dyn_cast<DeclStmt>(S);
1736 const auto *VR = dyn_cast<VarRegion>(R);
1746 if (
const auto *BDR =
1747 dyn_cast_or_null<BlockDataRegion>(
V.getAsRegion())) {
1748 if (
const VarRegion *OriginalR = BDR->getOriginalRegion(VR)) {
1749 getParentTracker().track(State->getSVal(OriginalR), OriginalR,
1750 Options, OriginSFC);
1760 return getParentTracker().handle(SI, BRC, Options);
1769 ID.AddPointer(&tag);
1770 ID.AddString(Message);
1771 ID.AddBoolean(Assumption);
1778 return "TrackConstraintBRVisitor";
1781bool TrackConstraintBRVisitor::isZeroCheck()
const {
1782 return !Assumption && Constraint.
getAs<
Loc>();
1785bool TrackConstraintBRVisitor::isUnderconstrained(
const ExplodedNode *N)
const {
1787 return N->
getState()->isNull(Constraint).isUnderconstrained();
1788 return (
bool)N->
getState()->assume(Constraint, !Assumption);
1799 if (!IsTrackingTurnedOn)
1800 if (!isUnderconstrained(N))
1801 IsTrackingTurnedOn =
true;
1802 if (!IsTrackingTurnedOn)
1807 if (isUnderconstrained(PrevN)) {
1814 assert(!isUnderconstrained(N));
1822 if (isa_and_nonnull<NoteTag>(P.
getTag()))
1830 auto X = std::make_shared<PathDiagnosticEventPiece>(L, Message);
1832 return std::move(
X);
1847 if (!Options.ShouldSuppressInlinedDefensiveChecks)
1852 llvm::FoldingSetNodeID &ID)
const {
1859 return "IDCVisitor";
1871 if (!IsTrackingTurnedOn)
1872 if (Succ->
getState()->isNull(V).isConstrainedTrue())
1873 IsTrackingTurnedOn =
true;
1874 if (!IsTrackingTurnedOn)
1879 if (!Pred->
getState()->isNull(V).isConstrainedTrue() &&
1880 Succ->
getState()->isNull(V).isConstrainedTrue()) {
1886 if (CurLC != ReportLC && !CurLC->
isParentOf(ReportLC)) {
1901 const Stmt *CurTerminatorStmt =
nullptr;
1903 CurTerminatorStmt = BE->getSrc()->getTerminator().getStmt();
1905 const Stmt *CurStmt = SP->getStmt();
1915 if (!CurTerminatorStmt)
1949class TrackControlDependencyCondBRVisitor final
1956 TrackControlDependencyCondBRVisitor(
TrackerRef ParentTracker,
1959 ControlDeps(&O->getCFG()) {}
1961 void Profile(llvm::FoldingSetNodeID &ID)
const override {
1972static std::shared_ptr<PathDiagnosticEventPiece>
1985 return std::make_shared<PathDiagnosticEventPiece>(
1988 (Twine() +
"Tracking condition '" + ConditionText +
"'").str());
2016 if (
const auto *BinOp = dyn_cast<BinaryOperator>(ElseCond))
2017 if (BinOp->isLogicalOp())
2024TrackControlDependencyCondBRVisitor::VisitNode(
const ExplodedNode *N,
2031 CFGBlock *NB =
const_cast<CFGBlock *
>(N->
getCFGBlock());
2034 if (!VisitedBlocks.insert(NB).second)
2037 CFGBlock *OriginB =
const_cast<CFGBlock *
>(Origin->getCFGBlock());
2040 if (!OriginB || !NB)
2046 if (ControlDeps.isControlDependent(OriginB, NB)) {
2079 getParentTracker().track(InnerExpr, N,
2097 if (
const auto *FE = dyn_cast<FullExpr>(Ex))
2099 if (
const auto *OVE = dyn_cast<OpaqueValueExpr>(Ex))
2101 if (
const auto *POE = dyn_cast<PseudoObjectExpr>(Ex)) {
2102 const auto *PropRef = dyn_cast<ObjCPropertyRefExpr>(POE->getSyntacticForm());
2103 if (PropRef && PropRef->isMessagingGetter()) {
2104 const Expr *GetterMessageSend =
2105 POE->getSemanticExpr(POE->getNumSemanticExprs() - 1);
2112 if (
const auto *CO = dyn_cast<ConditionalOperator>(Ex)) {
2118 if (std::optional<BlockEdge> BE = ProgPoint.
getAs<
BlockEdge>()) {
2119 const CFGBlock *srcBlk = BE->getSrc();
2122 bool TookTrueBranch = (*(srcBlk->
succ_begin()) == BE->getDst());
2134 if (
auto *BO = dyn_cast<BinaryOperator>(Ex))
2138 if (
auto *UO = dyn_cast<UnaryOperator>(Ex)) {
2139 if (UO->getOpcode() == UO_LNot)
2150 if (UO->getOpcode() == UO_AddrOf && UO->getSubExpr()->isLValue())
2161 const Expr *Inner) {
2176 StringRef NodeText) {
2190 return std::make_shared<PathDiagnosticEventPiece>(L, NodeText);
2202 llvm::raw_svector_ostream
OS(Buffer);
2220 return constructNote(SI, BRC,
OS.str());
2240 ->getAnalysisManager()
2241 .getAnalyzerOptions()
2242 .ShouldTrackConditions) {
2243 Report.addVisitor<TrackControlDependencyCondBRVisitor>(
2244 &getParentTracker(), InputNode);
2252class NilReceiverHandler final :
public ExpressionHandler {
2256 Tracker::Result handle(
const Expr *Inner,
const ExplodedNode *InputNode,
2257 const ExplodedNode *LVNode,
2258 TrackingOptions Opts)
override {
2262 if (
const Expr *Receiver =
2264 return getParentTracker().track(Receiver, LVNode, Opts);
2270class ArrayIndexHandler final :
public ExpressionHandler {
2274 Tracker::Result handle(
const Expr *Inner,
const ExplodedNode *InputNode,
2275 const ExplodedNode *LVNode,
2276 TrackingOptions Opts)
override {
2278 if (
const auto *Arr = dyn_cast<ArraySubscriptExpr>(Inner))
2279 return getParentTracker().track(
2280 Arr->getIdx(), LVNode,
2281 {Opts.Kind, false});
2288class InterestingLValueHandler final :
public ExpressionHandler {
2292 Tracker::Result handle(
const Expr *Inner,
const ExplodedNode *InputNode,
2293 const ExplodedNode *LVNode,
2294 TrackingOptions Opts)
override {
2297 PathSensitiveBugReport &
Report = getParentTracker().getReport();
2303 SVal LVal = LVNode->
getSVal(Inner);
2306 bool LVIsNull = LVState->isNull(LVal).isConstrainedTrue();
2311 if (RR && !LVIsNull)
2312 Result.combineWith(getParentTracker().track(LVal, RR, Opts, SFC));
2318 const MemRegion *R =
2319 (RR && LVIsNull) ? RR : LVNode->getSVal(Inner).getAsRegion();
2324 SVal
V = LVState->getRawSVal(loc::MemRegionVal(R));
2329 Result.FoundSomethingToTrack =
true;
2330 Result.WasInterrupted =
true;
2332 MacroNullReturnSuppressionVisitor::addMacroVisitorIfNecessary(
2336 Report.addVisitor<UndefOrNullArgVisitor>(R);
2340 if (
V.getAsLocSymbol(
true))
2341 if (LVState->isNull(
V).isConstrainedTrue())
2342 Report.addVisitor<TrackConstraintBRVisitor>(
2343 V.castAs<DefinedSVal>(),
2344 false,
"Assuming pointer value is null");
2347 if (
auto DV =
V.getAs<DefinedSVal>())
2355 Report.addVisitor<SuppressInlineDefensiveChecksVisitor>(*DV,
2357 getParentTracker().track(
V, R, Opts, SFC);
2372class InlinedFunctionCallHandler final :
public ExpressionHandler {
2375 Tracker::Result handle(
const Expr *E,
const ExplodedNode *InputNode,
2376 const ExplodedNode *ExprNode,
2377 TrackingOptions Opts)
override {
2388 const StackFrameContext *CurrentSFC = ExprNode->
getStackFrame();
2392 if (std::optional<CallExitEnd> CEE =
2394 if (CEE->getCalleeContext()->getCallSite() == E)
2402 const StackFrameContext *PredSFC = ExprNode->
getStackFrame();
2407 if (!BypassCXXNewExprEval)
2408 if (std::optional<StmtPoint> SP = ExprNode->
getLocationAs<StmtPoint>())
2410 if (SP->getStmt() == E && CurrentSFC == PredSFC)
2413 CurrentSFC = PredSFC;
2423 std::optional<CallExitEnd> CEE = ExprNode->
getLocationAs<CallExitEnd>();
2427 const StackFrameContext *CalleeContext = CEE->getCalleeContext();
2433 SVal RetVal = ExprNode->
getSVal(E);
2437 if (std::optional<Loc> LValue = RetVal.
getAs<Loc>())
2438 RetVal = State->getSVal(*LValue);
2441 AnalyzerOptions &Options = State->getAnalysisManager().options;
2443 bool EnableNullFPSuppression =
false;
2445 if (std::optional<Loc> RetLoc = RetVal.
getAs<Loc>())
2446 EnableNullFPSuppression = State->isNull(*RetLoc).isConstrainedTrue();
2448 PathSensitiveBugReport &
Report = getParentTracker().getReport();
2449 Report.addVisitor<ReturnVisitor>(&getParentTracker(), CalleeContext,
2450 EnableNullFPSuppression, Options,
2456class DefaultExpressionHandler final :
public ExpressionHandler {
2460 Tracker::Result handle(
const Expr *Inner,
const ExplodedNode *InputNode,
2461 const ExplodedNode *LVNode,
2462 TrackingOptions Opts)
override {
2465 PathSensitiveBugReport &
Report = getParentTracker().getReport();
2473 if (
auto L =
V.getAs<loc::MemRegionVal>()) {
2478 bool CanDereference =
true;
2479 if (
const auto *SR = L->getRegionAs<SymbolicRegion>()) {
2480 if (SR->getPointeeStaticType()->isVoidType())
2481 CanDereference =
false;
2482 }
else if (L->getRegionAs<AllocaRegion>())
2483 CanDereference =
false;
2490 RVal = LVState->getRawSVal(*L, Inner->
getType());
2491 else if (CanDereference)
2492 RVal = LVState->getSVal(L->getRegion());
2494 if (CanDereference) {
2495 Report.addVisitor<UndefOrNullArgVisitor>(L->getRegion());
2496 Result.FoundSomethingToTrack =
true;
2500 getParentTracker().track(RVal, L->getRegion(), Opts, SFC));
2504 if (isa_and_nonnull<SymbolicRegion>(RegionRVal)) {
2505 Report.markInteresting(RegionRVal, Opts.
Kind);
2506 Report.addVisitor<TrackConstraintBRVisitor>(
2507 loc::MemRegionVal(RegionRVal),
2508 false,
"Assuming pointer value is null");
2509 Result.FoundSomethingToTrack =
true;
2519class PRValueHandler final :
public ExpressionHandler {
2523 Tracker::Result handle(
const Expr *E,
const ExplodedNode *InputNode,
2524 const ExplodedNode *ExprNode,
2525 TrackingOptions Opts)
override {
2533 Tracker::Result CombinedResult;
2534 Tracker &Parent = getParentTracker();
2536 const auto track = [&CombinedResult, &Parent, ExprNode,
2537 Opts](
const Expr *Inner) {
2546 if (
const auto *ILE = dyn_cast<InitListExpr>(E)) {
2547 if (ILE->getNumInits() == 1) {
2548 track(ILE->getInit(0));
2550 return CombinedResult;
2558 const auto *BO = dyn_cast<BinaryOperator>(E);
2560 if (!BO || !BO->isMultiplicativeOp() || !
V.isZeroConstant())
2567 if (BO->getOpcode() == BO_Mul) {
2569 track(BO->getLHS());
2571 track(BO->getRHS());
2574 track(BO->getLHS());
2577 return CombinedResult;
2607 for (ExpressionHandlerPtr &Handler : ExpressionHandlers) {
2608 CombinedResult.
combineWith(Handler->handle(Inner, N, LVNode, Opts));
2617 return CombinedResult;
2622 if (!
V.isUnknown()) {
2623 Report.addVisitor<StoreSiteFinder>(
this,
V, R, Opts, Origin);
2632 for (StoreHandlerPtr &Handler : StoreHandlers) {
2647 ->track(E, InputNode, Opts)
2648 .FoundSomethingToTrack;
2664 const auto *ME = dyn_cast<ObjCMessageExpr>(S);
2667 if (
const Expr *Receiver = ME->getInstanceReceiver()) {
2670 if (state->isNull(
V).isConstrainedTrue())
2683 const Stmt *S = P->getStmt();
2689 llvm::raw_svector_ostream
OS(Buf);
2691 if (
const auto *ME = dyn_cast<ObjCMessageExpr>(S)) {
2693 ME->getSelector().print(
OS);
2694 OS <<
"' not called";
2697 OS <<
"No method is called";
2699 OS <<
" because the receiver is nil";
2710 return std::make_shared<PathDiagnosticEventPiece>(L,
OS.str());
2727 if (
auto *ev = dyn_cast<PathDiagnosticEventPiece>(piece.get()))
2728 ev->setPrunable(
true,
false);
2738 const std::pair<const ProgramPointTag *, const ProgramPointTag *> &Tags =
2743 if (std::optional<BlockEdge> BE = ProgPoint.
getAs<
BlockEdge>()) {
2744 const CFGBlock *SrcBlock = BE->getSrc();
2752 if (PreviousNodeTag == Tags.first || PreviousNodeTag == Tags.second)
2760 if (std::optional<PostStmt> PS = ProgPoint.
getAs<
PostStmt>()) {
2762 if (CurrentNodeTag != Tags.first && CurrentNodeTag != Tags.second)
2765 bool TookTrue = CurrentNodeTag == Tags.first;
2796 case Stmt::IfStmtClass: {
2799 if (IfStatement->isConsteval())
2801 Cond = IfStatement->getCond();
2804 case Stmt::ConditionalOperatorClass:
2807 case Stmt::BinaryOperatorClass:
2812 assert(BO->isLogicalOp() &&
2813 "CFG terminator is not a short-circuit operator!");
2814 Cond = BO->getLHS();
2823 while (
const auto *InnerBO = dyn_cast<BinaryOperator>(
Cond)) {
2824 if (!InnerBO->isLogicalOp())
2826 Cond = InnerBO->getRHS()->IgnoreParens();
2831 const bool TookTrue = *(srcBlk->
succ_begin()) == dstBlk;
2859 CurrentState->getSVal(
Cond, LCtx).isUnknownOrUndef();
2864 bool TookTrueTmp = TookTrue;
2871 case Stmt::BinaryOperatorClass:
2873 BRC, R, N, TookTrueTmp, IsAssuming))
2876 case Stmt::DeclRefExprClass:
2878 BRC, R, N, TookTrueTmp, IsAssuming))
2881 case Stmt::MemberExprClass:
2883 BRC, R, N, TookTrueTmp, IsAssuming))
2886 case Stmt::UnaryOperatorClass: {
2888 if (UO->getOpcode() == UO_LNot) {
2889 TookTrueTmp = !TookTrueTmp;
2890 CondTmp = UO->getSubExpr();
2910 return std::make_shared<PathDiagnosticEventPiece>(
2911 Loc, TookTrue ? GenericTrueMessage : GenericFalseMessage);
2918 std::optional<bool> &prunable,
2919 bool IsSameFieldName) {
2920 const Expr *OriginalExpr = Ex;
2941 if (
const auto *DR = dyn_cast<DeclRefExpr>(Ex)) {
2959 Out << DR->getDecl()->getDeclName().getAsString();
2965 if (
const auto *IL = dyn_cast<IntegerLiteral>(Ex)) {
2968 if (IL->getValue() == 0) {
2974 if (IL->getValue() == 0) {
2980 Out << IL->getValue();
2984 if (
const auto *ME = dyn_cast<MemberExpr>(Ex)) {
2985 if (!IsSameFieldName)
2986 Out <<
"field '" << ME->getMemberDecl()->getName() <<
'\'';
3003 bool shouldInvert =
false;
3004 std::optional<bool> shouldPrune;
3008 bool IsSameFieldName =
false;
3014 LhsME->getMemberDecl()->getName() == RhsME->getMemberDecl()->getName();
3018 llvm::raw_svector_ostream OutLHS(LhsString), OutRHS(RhsString);
3020 N, shouldPrune, IsSameFieldName);
3022 N, shouldPrune, IsSameFieldName);
3024 shouldInvert = !isVarLHS && isVarRHS;
3038 if (LhsString.empty() || RhsString.empty() ||
3044 llvm::raw_svector_ostream Out(buf);
3045 Out << (IsAssuming ?
"Assuming " :
"")
3046 << (shouldInvert ? RhsString : LhsString) <<
" is ";
3052 case BO_LT: Op = BO_GT;
break;
3053 case BO_GT: Op = BO_LT;
break;
3054 case BO_LE: Op = BO_GE;
break;
3055 case BO_GE: Op = BO_LE;
break;
3060 case BO_EQ: Op = BO_NE;
break;
3061 case BO_NE: Op = BO_EQ;
break;
3062 case BO_LT: Op = BO_GE;
break;
3063 case BO_GT: Op = BO_LE;
break;
3064 case BO_LE: Op = BO_GT;
break;
3065 case BO_GE: Op = BO_LT;
break;
3075 Out <<
"not equal to ";
3082 Out << (shouldInvert ? LhsString : RhsString);
3091 std::string Message = std::string(Out.str());
3092 Message[0] = toupper(Message[0]);
3097 if (!shouldInvert) {
3098 if (LhsME && LhsME->getMemberLoc().isValid())
3103 if (RhsME && RhsME->getMemberLoc().isValid())
3109 return std::make_shared<PathDiagnosticPopUpPiece>(
Loc, Message);
3113 auto event = std::make_shared<PathDiagnosticEventPiece>(
Loc, Message);
3115 event->setPrunable(*shouldPrune);
3126 llvm::raw_svector_ostream Out(buf);
3127 Out <<
"Assuming " << LhsString <<
" is ";
3129 if (!
printValue(CondVarExpr, Out, N, TookTrue,
true))
3138 auto event = std::make_shared<PathDiagnosticEventPiece>(
Loc, Out.str());
3141 event->setPrunable(
false);
3150 const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl());
3155 llvm::raw_svector_ostream Out(Buf);
3157 Out << (IsAssuming ?
"Assuming '" :
"'") << VD->getDeclName() <<
"' is ";
3159 if (!
printValue(DRE, Out, N, TookTrue, IsAssuming))
3170 return std::make_shared<PathDiagnosticPopUpPiece>(
Loc, Out.str());
3174 auto event = std::make_shared<PathDiagnosticEventPiece>(
Loc, Out.str());
3177 event->setPrunable(
false);
3179 return std::move(event);
3187 llvm::raw_svector_ostream Out(Buf);
3189 Out << (IsAssuming ?
"Assuming field '" :
"Field '")
3192 if (!
printValue(ME, Out, N, TookTrue, IsAssuming))
3212 return std::make_shared<PathDiagnosticPopUpPiece>(
Loc, Out.str());
3214 auto event = std::make_shared<PathDiagnosticEventPiece>(
Loc, Out.str());
3216 event->setPrunable(
false);
3226 Out << (TookTrue ?
"non-null" :
"null");
3231 Out << (TookTrue ?
"non-nil" :
"nil");
3238 std::optional<const llvm::APSInt *> IntValue;
3242 if (IsAssuming || !IntValue) {
3244 Out << (TookTrue ?
"true" :
"false");
3246 Out << (TookTrue ?
"not equal to 0" :
"0");
3249 Out << ((*IntValue)->getBoolValue() ?
"true" :
"false");
3257constexpr llvm::StringLiteral ConditionBRVisitor::GenericTrueMessage;
3258constexpr llvm::StringLiteral ConditionBRVisitor::GenericFalseMessage;
3262 return Piece->
getString() == GenericTrueMessage ||
3263 Piece->
getString() == GenericFalseMessage;
3283 if (Options.ShouldSuppressFromCXXStandardLibrary) {
3293 if (
const auto *MD = dyn_cast<CXXMethodDecl>(D)) {
3295 if (CD->
getName() ==
"list") {
3303 if (
const auto *MD = dyn_cast<CXXConstructorDecl>(D)) {
3305 if (CD->
getName() ==
"__independent_bits_engine") {
3313 const auto *MD = dyn_cast<CXXMethodDecl>(LCtx->getDecl());
3324 if (CD->
getName() ==
"basic_string") {
3332 if (CD->
getName() ==
"shared_ptr") {
3344 while (
Loc.isMacroID()) {
3345 Loc =
Loc.getSpellingLoc();
3346 if (
SM.getFilename(
Loc).ends_with(
"sys/queue.h")) {
3374 for (
const auto ParamDecl : parms) {
3375 const MemRegion *ArgReg =
Call->getArgSVal(Idx).getAsRegion();
3383 assert(ParamDecl &&
"Formal parameter has no decl?");
3386 if (!(
T->isAnyPointerType() ||
T->isReferenceType())) {
3393 if (
T->getPointeeType().isConstQualified())
3398 SVal BoundVal = State->getSVal(R);
3411int NoteTag::Kind = 0;
3415 ID.AddPointer(&Tag);
3426 if (std::optional<std::string> Msg =
T->generateMessage(BRC, R)) {
3429 auto Piece = std::make_shared<PathDiagnosticEventPiece>(
Loc, *Msg);
3430 Piece->setPrunable(
T->isPrunable());
Defines the clang::ASTContext interface.
This file defines AnalysisDeclContext, a class that manages the analysis context data for context sen...
static bool isInterestingExpr(const Expr *E, const ExplodedNode *N, const PathSensitiveBugReport *B)
static const ExplodedNode * findNodeForExpression(const ExplodedNode *N, const Expr *Inner)
Find the ExplodedNode where the lvalue (the value of 'Ex') was computed.
static void showBRParamDiagnostics(llvm::raw_svector_ostream &OS, StoreInfo SI)
Display diagnostics for passing bad region as a parameter.
static const Expr * peelOffPointerArithmetic(const BinaryOperator *B)
static const Expr * tryExtractInitializerFromList(const InitListExpr *ILE, const MemRegion *R)
static bool wasRegionOfInterestModifiedAt(const SubRegion *RegionOfInterest, const ExplodedNode *N, SVal ValueAfter)
static llvm::StringLiteral WillBeUsedForACondition
static bool isFunctionMacroExpansion(SourceLocation Loc, const SourceManager &SM)
static std::shared_ptr< PathDiagnosticEventPiece > constructDebugPieceForTrackedCondition(const Expr *Cond, const ExplodedNode *N, BugReporterContext &BRC)
static const MemRegion * getLocationRegionIfReference(const Expr *E, const ExplodedNode *N, bool LookingForReference=true)
static bool hasVisibleUpdate(const ExplodedNode *LeftNode, SVal LeftVal, const ExplodedNode *RightNode, SVal RightVal)
Comparing internal representations of symbolic values (via SVal::operator==()) is a valid way to chec...
static bool potentiallyWritesIntoIvar(const Decl *Parent, const ObjCIvarDecl *Ivar)
static std::optional< const llvm::APSInt * > getConcreteIntegerValue(const Expr *CondVarExpr, const ExplodedNode *N)
static bool isVarAnInterestingCondition(const Expr *CondVarExpr, const ExplodedNode *N, const PathSensitiveBugReport *B)
static void showBRDefaultDiagnostics(llvm::raw_svector_ostream &OS, StoreInfo SI)
Show default diagnostics for storing bad region.
static std::optional< SVal > getSValForVar(const Expr *CondVarExpr, const ExplodedNode *N)
static const Expr * peelOffOuterExpr(const Expr *Ex, const ExplodedNode *N)
static const VarDecl * getVarDeclForExpression(const Expr *E)
static bool isTrivialCopyOrMoveCtor(const CXXConstructExpr *CE)
static 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".
static bool isComparisonOp(Opcode Opc)
StringRef getOpcodeStr() const
static bool isAdditiveOp(Opcode Opc)
static bool isAssignmentOp(Opcode Opc)
BinaryOperatorKind Opcode
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.
ASTContext & getASTContext() const LLVM_READONLY
virtual Stmt * getBody() const
getBody - If this Decl represents a declaration for a body of code, such as a function or method defi...
virtual bool hasBody() const
Returns true if this Decl represents a declaration for a body of code, such as a function or method d...
bool isLocalExternDecl() const
Determine whether this is a block-scope declaration with linkage.
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 * IgnoreImpCasts() LLVM_READONLY
Skip past any implicit casts which might surround this expression until reaching a fixed point.
A SourceLocation and its associated SourceManager.
GNUNullExpr - Implements the GNU __null extension, which is a name for a null pointer constant that h...
Describes an C or C++ initializer list.
unsigned getNumInits() const
const Expr * getInit(unsigned Init) const
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
static StringRef getSourceText(CharSourceRange Range, const SourceManager &SM, const LangOptions &LangOpts, bool *Invalid=nullptr)
Returns a string for the source that the range encompasses.
static StringRef getImmediateMacroName(SourceLocation Loc, const SourceManager &SM, const LangOptions &LangOpts)
Retrieve the name of the immediate macro expansion.
static CharSourceRange getAsCharRange(SourceRange Range, const SourceManager &SM, const LangOptions &LangOpts)
Given a token range, produce a corresponding CharSourceRange that is not a token range.
static bool isAtStartOfMacroExpansion(SourceLocation loc, const SourceManager &SM, const LangOptions &LangOpts, SourceLocation *MacroBegin=nullptr)
Returns true if the given MacroID location points at the first token of the macro expansion.
static bool isAtEndOfMacroExpansion(SourceLocation loc, const SourceManager &SM, const LangOptions &LangOpts, SourceLocation *MacroEnd=nullptr)
Returns true if the given MacroID location points at the last token of the macro expansion.
It wraps the AnalysisDeclContext to represent both the call stack with the help of StackFrameContext ...
bool isParentOf(const LocationContext *LC) const
const Decl * getDecl() const
LLVM_ATTRIBUTE_RETURNS_NONNULL AnalysisDeclContext * getAnalysisDeclContext() const
const LocationContext * getParent() const
It might return null.
const StackFrameContext * getStackFrame() const
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
SourceLocation getMemberLoc() const
getMemberLoc - Return the location of the "member", in X->F, it is the location of 'F'.
ValueDecl * getMemberDecl() const
Retrieve the member declaration to which this expression refers.
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
std::string getNameAsString() const
Get a human-readable name for the declaration, even if it is one of the special kinds of names (C++ c...
ObjCBoolLiteralExpr - Objective-C Boolean Literal.
ObjCIvarDecl - Represents an ObjC instance variable.
ObjCIvarRefExpr - A reference to an ObjC instance variable.
Represents a 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...
const LocationContext * getLocationContext() const
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.
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
RecordDecl * getAsRecordDecl() const
Retrieves the RecordDecl this type refers to.
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
const T * getAs() const
Member-template getAs<specific type>'.
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Represents a variable declaration or definition.
bool isStaticLocal() const
Returns true if a variable with function scope is a static local variable.
bool hasLocalStorage() const
Returns true if a variable with function scope is a non-static local variable.
Maps string IDs to AST nodes matched by parts of a matcher.
A safe wrapper around APSInt objects allocated and owned by BasicValueFactory.
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 * > getEagerlyAssumeBifurcationTags()
LLVM_ATTRIBUTE_RETURNS_NONNULL const FieldDecl * getDecl() const override
void finalizeVisitor(BugReporterContext &BRC, const ExplodedNode *N, PathSensitiveBugReport &BR) override
Last function called on the visitor, no further calls to VisitNode would follow.
MemRegion - The root abstract class for all memory regions.
const MemSpace * getMemorySpaceAs(ProgramStateRef State) 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.
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.
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.
bugreporter::TrackingKind TKind
virtual bool wasModifiedInFunction(const ExplodedNode *CallEnterN, const ExplodedNode *CallExitEndN)
PathDiagnosticPieceRef VisitNode(const ExplodedNode *N, BugReporterContext &BR, PathSensitiveBugReport &R) final
Return a diagnostic piece which should be associated with the given node.
virtual PathDiagnosticPieceRef maybeEmitNoteForParameters(PathSensitiveBugReport &R, const CallEvent &Call, const ExplodedNode *N)=0
Consume the information on the non-modifying stack frame in order to either emit a note or not.
The tag upon which the TagVisitor reacts.
Represents any expression that calls an Objective-C method.
static PathDiagnosticLocation createBegin(const Decl *D, const SourceManager &SM)
Create a location for the beginning of the declaration.
FullSourceLoc asLocation() const
static PathDiagnosticLocation create(const Decl *D, const SourceManager &SM)
Create a location corresponding to the given declaration.
bool hasValidLocation() const
StringRef getString() const
void markInteresting(SymbolRef sym, bugreporter::TrackingKind TKind=bugreporter::TrackingKind::Thorough)
Marks a symbol as interesting.
PathDiagnosticLocation getLocation() const override
The primary location of the bug report that points at the undesirable behavior in the code.
ArrayRef< SourceRange > getRanges() const override
Get the SourceRanges associated with the report.
const ExplodedNode * getErrorNode() const
bool addTrackedCondition(const ExplodedNode *Cond)
Notes that the condition of the CFGBlock associated with Cond is being tracked.
void markInvalid(const void *Tag, const void *Data)
Marks the current report as invalid, meaning that it is probably a false positive and should not be r...
void addVisitor(std::unique_ptr< BugReporterVisitor > visitor)
Add custom or predefined bug report visitors to this report.
std::optional< bugreporter::TrackingKind > getInterestingnessKind(SymbolRef sym) const
bool isInteresting(SymbolRef sym) const
SValBuilder & getSValBuilder()
CallEventManager & getCallEventManager()
bool haveEqualConstraints(ProgramStateRef S1, ProgramStateRef S2) const
void iterBindings(ProgramStateRef state, StoreManager::BindingsHandler &F)
StoreManager & getStoreManager()
ProgramState - This class encapsulates:
Loc getLValue(const CXXBaseSpecifier &BaseSpec, const SubRegion *Super) const
Get the lvalue for a base class object reference.
SVal getSVal(const Stmt *S, const LocationContext *LCtx) const
Returns the SVal bound to the statement 'S' in the state's environment.
A Range represents the closed range [from, to].
ConditionTruthVal areEqual(ProgramStateRef state, SVal lhs, SVal rhs)
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
bool isZeroConstant() const
std::optional< T > getAs() const
Convert to the specified SVal type, returning std::nullopt if this SVal is not of the desired type.
const MemRegion * getAsRegion() const
SubRegion - A region that subsets another larger region.
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * getSuperRegion() const
bool isSubRegionOf(const MemRegion *R) const override
Check if the region is a subregion of the given region.
PathDiagnosticPieceRef VisitNode(const ExplodedNode *Succ, BugReporterContext &BRC, PathSensitiveBugReport &BR) override
Return a diagnostic piece which should be associated with the given node.
SuppressInlineDefensiveChecksVisitor(DefinedSVal Val, const ExplodedNode *N)
static const char * getTag()
Return the tag associated with this visitor.
void Profile(llvm::FoldingSetNodeID &ID) const override
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.
TypedRegion - An abstract class representing regions that are typed.
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)
void addLowPriorityHandler(ExpressionHandlerPtr SH)
Add custom expression handler with the lowest priority.
static TrackerRef create(PathSensitiveBugReport &Report)
virtual PathDiagnosticPieceRef handle(StoreInfo SI, BugReporterContext &BRC, TrackingOptions Opts)
Handle the store operation and produce the note.
void addHighPriorityHandler(ExpressionHandlerPtr SH)
Add custom expression handler with the highest priority.
Tracker(PathSensitiveBugReport &Report)
virtual Result track(const Expr *E, const ExplodedNode *N, TrackingOptions Opts={})
Track expression value back to its point of origin.
Visitor that tracks expressions and values.
Value representing integer constant.
While nonloc::CompoundVal covers a few simple use cases, nonloc::LazyCompoundVal is a more performant...
LLVM_ATTRIBUTE_RETURNS_NONNULL const TypedValueRegion * getRegion() const
This function itself is immaterial.
const internal::VariadicDynCastAllOfMatcher< Stmt, ObjCIvarRefExpr > objcIvarRefExpr
Matches a reference to an ObjCIvar.
const internal::ArgumentAdaptingMatcherFunc< internal::HasDescendantMatcher > hasDescendant
Matches AST nodes that have descendant AST nodes that match the provided matcher.
SmallVector< BoundNodes, 1 > match(MatcherT Matcher, const NodeT &Node, ASTContext &Context)
Returns the results of matching Matcher on Node.
internal::Matcher< Stmt > StatementMatcher
const internal::VariadicDynCastAllOfMatcher< Stmt, BinaryOperator > binaryOperator
Matches binary operator expressions.
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.
llvm::IntrusiveRefCntPtr< Tracker > TrackerRef
const Expr * getDerefExpr(const Stmt *S)
Given that expression S represents a pointer that would be dereferenced, try to find a sub-expression...
bool trackExpressionValue(const ExplodedNode *N, const Expr *E, PathSensitiveBugReport &R, TrackingOptions Opts={})
Attempts to add visitors to track expression value back to its point of origin.
void trackStoredValue(SVal V, const MemRegion *R, PathSensitiveBugReport &Report, TrackingOptions Opts={}, const StackFrameContext *Origin=nullptr)
Track how the value got stored into the given region and where it came from.
TrackingKind
Specifies the type of tracking for an expression.
@ Thorough
Default tracking kind – specifies that as much information should be gathered about the tracked expre...
@ Condition
Specifies that a more moderate tracking should be used for the expression value.
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
raw_ostream & operator<<(raw_ostream &os, const MemRegion *R)
std::shared_ptr< PathDiagnosticPiece > PathDiagnosticPieceRef
bool Ret(InterpState &S, CodePtr &PC)
std::variant< struct RequiresDecl, struct HeaderDecl, struct UmbrellaDirDecl, struct ModuleDecl, struct ExcludeDecl, struct ExportDecl, struct ExportAsDecl, struct ExternModuleDecl, struct UseDecl, struct LinkDecl, struct ConfigMacrosDecl, struct ConflictDecl > Decl
All declarations that can appear in a module declaration.
The JSON file list parser is used to communicate input to InstallAPI.
@ Match
This is not an overload because the signature exactly matches an existing declaration.
bool isa(CodeGen::Address addr)
std::pair< FileID, unsigned > FileIDAndOffset
@ Result
The result type of a method or function.
const FunctionProtoType * T
U cast(CodeGen::Address addr)
@ ObjCSelf
Parameter for Objective-C 'self' argument.
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.