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(SF))
384 findModifyingFrames(N);
385 return FramesModifying.count(SF);
388void NoStateChangeFuncVisitor::markFrameAsModifying(
const StackFrame *SF) {
390 auto p = FramesModifying.insert(SF);
406 auto IsMatchingCallExitEnd = [OrigSF](
const ExplodedNode *N) {
410 while (N && !IsMatchingCallExitEnd(N)) {
412 "This function is to be used on the trimmed ExplodedGraph!");
418void NoStateChangeFuncVisitor::findModifyingFrames(
423 const StackFrame *
const OriginalSF =
426 const ExplodedNode *CurrCallExitBeginN = CallExitBeginN;
427 const StackFrame *CurrentSF = OriginalSF;
429 for (
const ExplodedNode *CurrN = CallExitBeginN; CurrN;
430 CurrN = CurrN->getFirstPred()) {
432 if (CurrN->getLocationAs<CallExitBegin>()) {
433 CurrCallExitBeginN = CurrN;
435 FramesModifyingCalculated.insert(CurrentSF);
440 if (
auto CE = CurrN->getLocationAs<CallEnter>()) {
443 markFrameAsModifying(CurrentSF);
454 if (CE->getCalleeContext() == OriginalSF) {
455 markFrameAsModifying(CurrentSF);
461 markFrameAsModifying(CurrentSF);
474 if (!CallExitLoc || isModifiedInFrame(N))
489 if (
Call->isInSystemHeader()) {
499 R.markInvalid(&i,
nullptr);
504 if (
const auto *MC = dyn_cast<ObjCMethodCall>(
Call)) {
511 if (
const auto *CCall = dyn_cast<CXXConstructorCall>(
Call)) {
525 const char *IvarBind =
"Ivar";
526 if (!Parent || !Parent->
hasBody())
529 hasOperatorName(
"="),
530 hasLHS(ignoringParenImpCasts(
536 if (IvarRef->isFreeIvar())
539 const Expr *
Base = IvarRef->getBase();
540 if (
const auto *ICE = dyn_cast<ImplicitCastExpr>(
Base))
541 Base = ICE->getSubExpr();
543 if (
const auto *DRE = dyn_cast<DeclRefExpr>(
Base))
544 if (
const auto *ID = dyn_cast<ImplicitParamDecl>(DRE->getDecl()))
559const std::optional<NoStoreFuncVisitor::RegionVector>
560NoStoreFuncVisitor::findRegionOfInterestInRecord(
562 const NoStoreFuncVisitor::RegionVector &Vec ,
565 if (depth == DEREFERENCE_LIMIT)
568 if (
const auto *RDX = dyn_cast<CXXRecordDecl>(RD))
569 if (!RDX->hasDefinition())
574 if (
const auto *RDX = dyn_cast<CXXRecordDecl>(RD))
575 for (
const auto &II : RDX->bases())
576 if (
const RecordDecl *RRD = II.getType()->getAsRecordDecl())
577 if (std::optional<RegionVector> Out =
578 findRegionOfInterestInRecord(RRD, State, R, Vec, depth))
581 for (
const FieldDecl *I : RD->
fields()) {
582 QualType FT = I->getType();
584 const SVal
V = State->getSVal(FR);
585 const MemRegion *VR =
V.getAsRegion();
587 RegionVector VecF = Vec;
590 if (RegionOfInterest == VR)
595 findRegionOfInterestInRecord(RRD, State, FR, VecF, depth + 1))
603 if (std::optional<RegionVector> Out =
604 findRegionOfInterestInRecord(RRD, State, VR, VecF, depth + 1))
615 if (
const auto *IvarR = dyn_cast<ObjCIvarRegion>(RegionOfInterest)) {
616 const MemRegion *SelfRegion =
Call.getReceiverSVal().getAsRegion();
617 if (RegionOfInterest->isSubRegionOf(SelfRegion) &&
620 return maybeEmitNote(R,
Call, N, {}, SelfRegion,
"self",
630 const MemRegion *ThisR =
Call.getCXXThisVal().getAsRegion();
631 if (RegionOfInterest->isSubRegionOf(ThisR) && !
Call.getDecl()->isImplicit())
632 return maybeEmitNote(R,
Call, N, {}, ThisR,
"this",
649 for (
unsigned I = 0; I <
Call.getNumArgs() && I <
Parameters.size(); ++I) {
651 SVal
V =
Call.getArgSVal(I);
655 unsigned IndirectionLevel = 1;
657 while (
const MemRegion *MR =
V.getAsRegion()) {
659 return maybeEmitNote(R,
Call, N, {}, MR, ParamName,
660 ParamIsReferenceType, IndirectionLevel);
663 if (PT.isNull() || PT->isVoidType())
668 if (
const RecordDecl *RD = PT->getAsRecordDecl())
669 if (std::optional<RegionVector> P =
670 findRegionOfInterestInRecord(RD, State, MR))
671 return maybeEmitNote(R,
Call, N, *P, RegionOfInterest, ParamName,
672 ParamIsReferenceType, IndirectionLevel);
674 V = State->getSVal(MR, PT);
683bool NoStoreFuncVisitor::wasModifiedBeforeCallExit(
685 return ::wasRegionOfInterestModifiedAt(
686 RegionOfInterest, CurrN,
687 CallExitBeginN->
getState()->getSVal(RegionOfInterest));
691 ", which participates in a condition later";
695 const RegionVector &FieldChain,
const MemRegion *MatchedRegion,
696 StringRef FirstElement,
bool FirstIsReferenceType,
697 unsigned IndirectionLevel) {
709 llvm::raw_svector_ostream os(sbuf);
710 os <<
"Returning without writing to '";
713 if (!prettyPrintRegionName(FieldChain, MatchedRegion, FirstElement,
714 FirstIsReferenceType, IndirectionLevel, os))
720 return std::make_shared<PathDiagnosticEventPiece>(L, os.str());
723bool NoStoreFuncVisitor::prettyPrintRegionName(
const RegionVector &FieldChain,
725 StringRef FirstElement,
726 bool FirstIsReferenceType,
727 unsigned IndirectionLevel,
728 llvm::raw_svector_ostream &os) {
730 if (FirstIsReferenceType)
733 RegionVector RegionSequence;
736 assert(RegionOfInterest->isSubRegionOf(MatchedRegion));
737 const MemRegion *
R = RegionOfInterest;
738 while (R != MatchedRegion) {
739 RegionSequence.push_back(R);
742 std::reverse(RegionSequence.begin(), RegionSequence.end());
743 RegionSequence.append(FieldChain.begin(), FieldChain.end());
746 for (
const MemRegion *R : RegionSequence) {
754 Sep = prettyPrintFirstElement(FirstElement,
756 IndirectionLevel, os);
765 Sep = DR->getValueType()->isAnyPointerType() ?
"->" :
".";
766 DR->getDecl()->getDeclName().print(os, PP);
770 prettyPrintFirstElement(FirstElement,
771 false, IndirectionLevel, os);
775StringRef NoStoreFuncVisitor::prettyPrintFirstElement(
776 StringRef FirstElement,
bool MoreItemsExpected,
int IndirectionLevel,
777 llvm::raw_svector_ostream &os) {
780 if (IndirectionLevel > 0 && MoreItemsExpected) {
785 if (IndirectionLevel > 0 && MoreItemsExpected)
788 for (
int i = 0; i < IndirectionLevel; i++)
792 if (IndirectionLevel > 0 && MoreItemsExpected)
807 const SubRegion *RegionOfInterest;
808 const SVal ValueAtDereference;
812 bool WasModified =
false;
815 MacroNullReturnSuppressionVisitor(
const SubRegion *R,
const SVal
V)
816 : RegionOfInterest(
R), ValueAtDereference(
V) {}
819 BugReporterContext &BRC,
820 PathSensitiveBugReport &BR)
override {
829 if (
auto Loc = matchAssignment(N)) {
831 std::string MacroName = std::string(
getMacroName(*Loc, BRC));
832 SourceLocation BugLoc = BugPoint->getStmt()->getBeginLoc();
844 static void addMacroVisitorIfNecessary(
845 const ExplodedNode *N,
const MemRegion *R,
846 bool EnableNullFPSuppression, PathSensitiveBugReport &BR,
848 AnalyzerOptions &Options = N->
getState()->getAnalysisManager().options;
849 if (EnableNullFPSuppression && Options.ShouldSuppressNullReturnPaths &&
851 BR.
addVisitor<MacroNullReturnSuppressionVisitor>(
R->getAs<SubRegion>(),
855 void* getTag()
const {
857 return static_cast<void *
>(&
Tag);
860 void Profile(llvm::FoldingSetNodeID &ID)
const override {
861 ID.AddPointer(getTag());
867 std::optional<SourceLocation> matchAssignment(
const ExplodedNode *N) {
874 if (
const auto *DS = dyn_cast<DeclStmt>(S)) {
875 if (
const auto *VD = dyn_cast<VarDecl>(DS->getSingleDecl()))
876 if (
const Expr *RHS = VD->getInit())
877 if (RegionOfInterest->isSubRegionOf(
878 State->getLValue(VD, LCtx).getAsRegion()))
879 return RHS->getBeginLoc();
880 }
else if (
const auto *BO = dyn_cast<BinaryOperator>(S)) {
882 const Expr *RHS = BO->getRHS();
883 if (BO->isAssignmentOp() && RegionOfInterest->isSubRegionOf(R)) {
902class ReturnVisitor :
public TrackingBugReporterVisitor {
903 const StackFrame *CalleeSF;
910 bool EnableNullFPSuppression;
911 bool ShouldInvalidate =
true;
912 AnalyzerOptions& Options;
916 ReturnVisitor(
TrackerRef ParentTracker,
const StackFrame *Frame,
917 bool Suppressed, AnalyzerOptions &Options,
919 : TrackingBugReporterVisitor(ParentTracker), CalleeSF(Frame),
920 EnableNullFPSuppression(Suppressed), Options(Options), TKind(TKind) {}
922 static void *getTag() {
924 return static_cast<void *
>(&
Tag);
927 void Profile(llvm::FoldingSetNodeID &ID)
const override {
928 ID.AddPointer(ReturnVisitor::getTag());
929 ID.AddPointer(CalleeSF);
930 ID.AddBoolean(EnableNullFPSuppression);
934 BugReporterContext &BRC,
935 PathSensitiveBugReport &BR) {
944 const auto *
Ret = dyn_cast<ReturnStmt>(SP->getStmt());
951 const Expr *RV =
Ret->getRetValue();
954 SVal
V = State->getSVal(RV, CalleeSF);
955 if (
V.isUnknownOrUndef())
961 const Expr *RetE =
Ret->getRetValue();
962 assert(RetE &&
"Tracking a return value for a void function");
965 std::optional<Loc> LValue;
967 if ((LValue =
V.getAs<Loc>())) {
968 SVal RValue = State->getRawSVal(*LValue, RetE->
getType());
981 getParentTracker().track(RetE, N, {TKind, EnableNullFPSuppression});
985 llvm::raw_svector_ostream
Out(Msg);
987 bool WouldEventBeMeaningless =
false;
989 if (State->isNull(
V).isConstrainedTrue()) {
995 if (EnableNullFPSuppression &&
996 Options.ShouldAvoidSuppressingNullArgumentPaths)
997 Mode = MaybeUnsuppress;
1000 Out <<
"Returning nil";
1002 Out <<
"Returning null pointer";
1005 Out <<
"Returning zero";
1009 if (
auto CI =
V.getAs<nonloc::ConcreteInt>()) {
1010 Out <<
"Returning the value " << CI->getValue();
1018 WouldEventBeMeaningless =
true;
1020 Out << (isa<Loc>(
V) ?
"Returning pointer" :
"Returning value");
1025 if (
const MemRegion *MR = LValue->getAsRegion()) {
1026 if (MR->canPrintPretty()) {
1027 Out <<
" (reference to ";
1028 MR->printPretty(Out);
1034 if (
const auto *DR = dyn_cast<DeclRefExpr>(RetE))
1035 if (
const auto *DD = dyn_cast<DeclaratorDecl>(DR->getDecl()))
1036 Out <<
" (loaded from '" << *DD <<
"')";
1040 if (!L.isValid() || !L.asLocation().isValid())
1043 if (TKind == bugreporter::TrackingKind::Condition)
1046 auto EventPiece = std::make_shared<PathDiagnosticEventPiece>(L,
Out.str());
1050 if (WouldEventBeMeaningless)
1051 EventPiece->setPrunable(
true);
1059 BugReporterContext &BRC,
1060 PathSensitiveBugReport &BR) {
1061 assert(Options.ShouldAvoidSuppressingNullArgumentPaths);
1064 std::optional<CallEnter> CE = N->
getLocationAs<CallEnter>();
1068 if (CE->getCalleeContext() != CalleeSF)
1081 for (
unsigned I = 0, E =
Call->getNumArgs(); I != E; ++I) {
1082 std::optional<Loc> ArgV =
Call->getArgSVal(I).getAs<Loc>();
1086 const Expr *ArgE =
Call->getArgExpr(I);
1091 if (!State->isNull(*ArgV).isConstrainedTrue())
1094 if (getParentTracker()
1095 .track(ArgE, N, {TKind, EnableNullFPSuppression})
1096 .FoundSomethingToTrack)
1097 ShouldInvalidate =
false;
1108 BugReporterContext &BRC,
1109 PathSensitiveBugReport &BR)
override {
1112 return visitNodeInitial(N, BRC, BR);
1113 case MaybeUnsuppress:
1114 return visitNodeMaybeUnsuppress(N, BRC, BR);
1119 llvm_unreachable(
"Invalid visit mode!");
1122 void finalizeVisitor(BugReporterContext &,
const ExplodedNode *,
1123 PathSensitiveBugReport &BR)
override {
1124 if (EnableNullFPSuppression && ShouldInvalidate)
1125 BR.
markInvalid(ReturnVisitor::getTag(), CalleeSF);
1135class StoreSiteFinder final :
public TrackingBugReporterVisitor {
1138 bool Satisfied =
false;
1140 TrackingOptions Options;
1141 const StackFrame *OriginSF;
1155 const MemRegion *R, TrackingOptions Options,
1156 const StackFrame *OriginSF =
nullptr)
1157 : TrackingBugReporterVisitor(ParentTracker),
R(
R),
V(
V), Options(Options),
1158 OriginSF(OriginSF) {
1162 void Profile(llvm::FoldingSetNodeID &ID)
const override;
1165 BugReporterContext &BRC,
1166 PathSensitiveBugReport &BR)
override;
1170void StoreSiteFinder::Profile(llvm::FoldingSetNodeID &ID)
const {
1172 ID.AddPointer(&tag);
1175 ID.AddInteger(
static_cast<int>(Options.Kind));
1176 ID.AddBoolean(Options.EnableNullFPSuppression);
1193 const auto *FrameSpace =
1200 [[maybe_unused]]
bool IsLocalStaticOrLocalExtern =
1202 assert(IsLocalStaticOrLocalExtern &&
1203 "Declared a variable on the stack without Stack memspace?");
1213 if (R->isBoundable())
1214 if (
const auto *TR = dyn_cast<TypedValueRegion>(R))
1215 return TR->getValueType()->isObjCObjectPointerType();
1225using DestTypeValue = std::pair<const StoreInfo &, loc::ConcreteInt>;
1227llvm::raw_ostream &
operator<<(llvm::raw_ostream &
OS,
const DestTypeValue &Val) {
1228 if (
auto *TyR = Val.first.Dest->getAs<
TypedRegion>()) {
1229 QualType LocTy = TyR->getLocationType();
1231 if (
auto *PtrTy = LocTy->
getAs<PointerType>()) {
1232 std::string PStr = PtrTy->getPointeeType().getAsString();
1234 OS <<
"(" << PStr <<
")";
1238 SmallString<16> ValStr;
1239 Val.second.getValue()->toString(ValStr, 10,
true);
1254 const char *Action =
nullptr;
1258 Action = HasPrefix ?
"initialized to " :
"Initializing to ";
1261 Action = HasPrefix ?
"captured by block as " :
"Captured by block as ";
1264 llvm_unreachable(
"Unexpected store kind");
1268 if (!*CVal->getValue())
1271 OS << Action << DestTypeValue(SI, *CVal);
1274 OS << Action << CVal->getValue();
1277 OS << Action <<
"the value of ";
1291 if (VD->getInit()) {
1292 OS << (HasPrefix ?
"initialized" :
"Initializing")
1293 <<
" to a garbage value";
1295 OS << (HasPrefix ?
"declared" :
"Declaring")
1296 <<
" without an initial value";
1300 OS << (HasPrefix ?
"initialized" :
"Initialized") <<
" here";
1309 const auto *D = VR->getDecl();
1314 if (!*CI->getValue())
1315 OS << (
isObjCPointer(D) ?
"nil object reference" :
"null pointer value");
1317 OS << (
isObjCPointer(D) ?
"object reference of value " :
"pointer value ")
1318 << DestTypeValue(SI, *CI);
1321 OS <<
"uninitialized value";
1324 OS <<
"the value " << CI->getValue();
1333 if (
const auto *Param = dyn_cast<ParmVarDecl>(VR->getDecl())) {
1335 unsigned Idx = Param->getFunctionScopeIndex() + 1;
1336 OS <<
" via " << Idx << llvm::getOrdinalSuffix(Idx) <<
" parameter";
1341 }
else if (
const auto *ImplParam = dyn_cast<ImplicitParamDecl>(D)) {
1343 OS <<
" via implicit parameter 'self'";
1357 ?
"nil object reference stored"
1358 : (HasSuffix ?
"Null pointer value stored"
1359 :
"Storing null pointer value"));
1362 OS <<
"object reference of value " << DestTypeValue(SI, *CV)
1366 OS <<
"Pointer value of " << DestTypeValue(SI, *CV) <<
" stored";
1368 OS <<
"Storing pointer value of " << DestTypeValue(SI, *CV);
1372 OS << (HasSuffix ?
"Uninitialized value stored"
1373 :
"Storing uninitialized value");
1377 OS <<
"The value " << CV->getValue() <<
" is assigned";
1379 OS <<
"Assigning " << CV->getValue();
1383 OS <<
"The value of ";
1385 OS <<
" is assigned";
1387 OS <<
"Assigning the value of ";
1392 OS << (HasSuffix ?
"Value assigned" :
"Assigning value");
1413 const auto *TVR = dyn_cast_or_null<TypedValueRegion>(R);
1421 std::stack<const TypedValueRegion *> TVRStack;
1427 if (ITy == TVR->getValueType().getCanonicalType())
1436 if (ITy != TVR->getValueType().getCanonicalType())
1440 while (!TVRStack.empty()) {
1441 TVR = TVRStack.top();
1452 if (
const auto *FR = dyn_cast<FieldRegion>(TVR)) {
1453 const auto *FD = FR->
getDecl();
1455 if (FD->getFieldIndex() >= NumInits)
1459 }
else if (
const auto *ER = dyn_cast<ElementRegion>(TVR)) {
1460 const auto Ind = ER->getIndex();
1464 if (!Ind.isConstant())
1467 const auto IndVal = Ind.getAsInteger()->getLimitedValue();
1468 if (IndVal >= NumInits)
1486 const Expr *InitE =
nullptr;
1487 bool IsParam =
false;
1490 if (
const auto *VR = dyn_cast<VarRegion>(R)) {
1493 InitE = VR->getDecl()->getInit();
1499 if (std::optional<PostInitializer> PIP =
1502 if (FieldReg == R) {
1504 InitE = PIP->getInitializer()->getInit();
1518 std::optional<PostStore> PS = Succ->
getLocationAs<PostStore>();
1519 if (!PS || PS->getLocationValue() != R)
1525 if (std::optional<PostStmt> P = Succ->
getLocationAs<PostStmt>()) {
1528 if (
const BinaryOperator *BO = P->getStmtAs<BinaryOperator>()) {
1529 if (BO->isAssignmentOp())
1530 InitE = BO->getRHS();
1534 else if (
const auto *DS = P->getStmtAs<DeclStmt>()) {
1535 const auto *
Decl = DS->getSingleDecl();
1545 if (
const auto *ILE = dyn_cast<InitListExpr>(VD->getInit()))
1548 }
else if (
const auto *CE = P->getStmtAs<CXXConstructExpr>()) {
1550 const auto State = Succ->
getState();
1561 std::stack<const SubRegion *> SRStack;
1569 const auto *OriginEx = CE->getArg(0);
1570 const auto OriginVal =
1576 SVal OriginField = OriginVal;
1577 while (!SRStack.empty()) {
1578 const auto *TopR = SRStack.top();
1581 if (
const auto *FR = dyn_cast<FieldRegion>(TopR)) {
1582 OriginField = State->getLValue(FR->
getDecl(), OriginField);
1583 }
else if (
const auto *ER = dyn_cast<ElementRegion>(TopR)) {
1584 OriginField = State->getLValue(ER->getElementType(),
1585 ER->getIndex(), OriginField);
1592 getParentTracker().track(
V, OriginField.
getAsRegion(), Options);
1597 else if (
const auto *ILE = P->getStmtAs<InitListExpr>()) {
1612 if (std::optional<CallEnter> CE = Succ->
getLocationAs<CallEnter>()) {
1613 if (
const auto *VR = dyn_cast<VarRegion>(R)) {
1615 if (
const auto *Param = dyn_cast<ParmVarDecl>(VR->getDecl())) {
1621 InitE =
Call->getArgExpr(Param->getFunctionScopeIndex());
1626 ->getInstanceReceiver()->IgnoreParenCasts();
1634 if (
const auto *TmpR = dyn_cast<CXXTempObjectRegion>(R))
1635 InitE = TmpR->getExpr();
1649 getParentTracker().track(InitE, StoreSite, Options);
1673 if (
SM.includedInBindings(N->
getState()->getStore(), Candidate)) {
1675 if (N->
getState()->getSVal(Candidate) ==
V) {
1676 OldRegion = Candidate;
1695 if (!OldRegion && StoreSite->
getState()->getSVal(R) ==
V) {
1700 NodeWithoutBinding && NodeWithoutBinding->
getState()->getSVal(R) ==
V;
1701 NodeWithoutBinding = NodeWithoutBinding->
getFirstPred()) {
1704 if (NodeWithoutBinding) {
1716 OldRegion = FB.getRegion();
1720 if (Options.Kind == TrackingKind::Condition && OriginSF &&
1725 SmallString<256> sbuf;
1726 llvm::raw_svector_ostream os(sbuf);
1735 if (std::optional<PostStmt> PS = StoreSite->
getLocationAs<PostStmt>()) {
1736 const Stmt *S = PS->getStmt();
1737 const auto *DS = dyn_cast<DeclStmt>(S);
1738 const auto *VR = dyn_cast<VarRegion>(R);
1742 }
else if (
const auto *BExpr = dyn_cast<BlockExpr>(S)) {
1748 if (
const auto *BDR =
1749 dyn_cast_or_null<BlockDataRegion>(
V.getAsRegion())) {
1750 if (
const VarRegion *OriginalR = BDR->getOriginalRegion(VR)) {
1751 getParentTracker().track(State->getSVal(OriginalR), OriginalR,
1762 return getParentTracker().handle(SI, BRC, Options);
1771 ID.AddPointer(&tag);
1772 ID.AddString(Message);
1773 ID.AddBoolean(Assumption);
1780 return "TrackConstraintBRVisitor";
1783bool TrackConstraintBRVisitor::isZeroCheck()
const {
1784 return !Assumption && Constraint.
getAs<
Loc>();
1787bool TrackConstraintBRVisitor::isUnderconstrained(
const ExplodedNode *N)
const {
1789 return N->
getState()->isNull(Constraint).isUnderconstrained();
1790 return (
bool)N->
getState()->assume(Constraint, !Assumption);
1801 if (!IsTrackingTurnedOn)
1802 if (!isUnderconstrained(N))
1803 IsTrackingTurnedOn =
true;
1804 if (!IsTrackingTurnedOn)
1809 if (isUnderconstrained(PrevN)) {
1816 assert(!isUnderconstrained(N));
1824 if (isa_and_nonnull<NoteTag>(P.
getTag()))
1832 auto X = std::make_shared<PathDiagnosticEventPiece>(L, Message);
1834 return std::move(
X);
1849 if (!Options.ShouldSuppressInlinedDefensiveChecks)
1854 llvm::FoldingSetNodeID &ID)
const {
1861 return "IDCVisitor";
1873 if (!IsTrackingTurnedOn)
1874 if (Succ->
getState()->isNull(V).isConstrainedTrue())
1875 IsTrackingTurnedOn =
true;
1876 if (!IsTrackingTurnedOn)
1881 if (!Pred->
getState()->isNull(V).isConstrainedTrue() &&
1882 Succ->
getState()->isNull(V).isConstrainedTrue()) {
1888 if (CurLC != ReportLC && !CurLC->
isParentOf(ReportLC)) {
1903 const Stmt *CurTerminatorStmt =
nullptr;
1905 CurTerminatorStmt = BE->getSrc()->getTerminator().getStmt();
1907 const Stmt *CurStmt = SP->getStmt();
1917 if (!CurTerminatorStmt)
1951class TrackControlDependencyCondBRVisitor final
1958 TrackControlDependencyCondBRVisitor(
TrackerRef ParentTracker,
1961 ControlDeps(&O->getCFG()) {}
1963 void Profile(llvm::FoldingSetNodeID &ID)
const override {
1974static std::shared_ptr<PathDiagnosticEventPiece>
1987 return std::make_shared<PathDiagnosticEventPiece>(
1990 (Twine() +
"Tracking condition '" + ConditionText +
"'").str());
2018 if (
const auto *BinOp = dyn_cast<BinaryOperator>(ElseCond))
2019 if (BinOp->isLogicalOp())
2026TrackControlDependencyCondBRVisitor::VisitNode(
const ExplodedNode *N,
2033 CFGBlock *NB =
const_cast<CFGBlock *
>(N->
getCFGBlock());
2036 if (!VisitedBlocks.insert(NB).second)
2039 CFGBlock *OriginB =
const_cast<CFGBlock *
>(Origin->getCFGBlock());
2042 if (!OriginB || !NB)
2048 if (ControlDeps.isControlDependent(OriginB, NB)) {
2081 getParentTracker().track(InnerExpr, N,
2099 if (
const auto *FE = dyn_cast<FullExpr>(Ex))
2101 if (
const auto *OVE = dyn_cast<OpaqueValueExpr>(Ex))
2103 if (
const auto *POE = dyn_cast<PseudoObjectExpr>(Ex)) {
2104 const auto *PropRef = dyn_cast<ObjCPropertyRefExpr>(POE->getSyntacticForm());
2105 if (PropRef && PropRef->isMessagingGetter()) {
2106 const Expr *GetterMessageSend =
2107 POE->getSemanticExpr(POE->getNumSemanticExprs() - 1);
2114 if (
const auto *CO = dyn_cast<ConditionalOperator>(Ex)) {
2120 if (std::optional<BlockEdge> BE = ProgPoint.
getAs<
BlockEdge>()) {
2121 const CFGBlock *srcBlk = BE->getSrc();
2124 bool TookTrueBranch = (*(srcBlk->
succ_begin()) == BE->getDst());
2136 if (
auto *BO = dyn_cast<BinaryOperator>(Ex))
2140 if (
auto *UO = dyn_cast<UnaryOperator>(Ex)) {
2141 if (UO->getOpcode() == UO_LNot)
2152 if (UO->getOpcode() == UO_AddrOf && UO->getSubExpr()->isLValue())
2163 const Expr *Inner) {
2178 StringRef NodeText) {
2192 return std::make_shared<PathDiagnosticEventPiece>(L, NodeText);
2204 llvm::raw_svector_ostream
OS(Buffer);
2222 return constructNote(SI, BRC,
OS.str());
2242 ->getAnalysisManager()
2243 .getAnalyzerOptions()
2244 .ShouldTrackConditions) {
2245 Report.addVisitor<TrackControlDependencyCondBRVisitor>(
2246 &getParentTracker(), InputNode);
2254class NilReceiverHandler final :
public ExpressionHandler {
2258 Tracker::Result handle(
const Expr *Inner,
const ExplodedNode *InputNode,
2259 const ExplodedNode *LVNode,
2260 TrackingOptions Opts)
override {
2264 if (
const Expr *Receiver =
2266 return getParentTracker().track(Receiver, LVNode, Opts);
2272class ArrayIndexHandler final :
public ExpressionHandler {
2276 Tracker::Result handle(
const Expr *Inner,
const ExplodedNode *InputNode,
2277 const ExplodedNode *LVNode,
2278 TrackingOptions Opts)
override {
2280 if (
const auto *Arr = dyn_cast<ArraySubscriptExpr>(Inner))
2281 return getParentTracker().track(
2282 Arr->getIdx(), LVNode,
2283 {Opts.Kind, false});
2290class InterestingLValueHandler final :
public ExpressionHandler {
2294 Tracker::Result handle(
const Expr *Inner,
const ExplodedNode *InputNode,
2295 const ExplodedNode *LVNode,
2296 TrackingOptions Opts)
override {
2299 PathSensitiveBugReport &
Report = getParentTracker().getReport();
2305 SVal LVal = LVNode->
getSVal(Inner);
2308 bool LVIsNull = LVState->isNull(LVal).isConstrainedTrue();
2313 if (RR && !LVIsNull)
2314 Result.combineWith(getParentTracker().track(LVal, RR, Opts, SF));
2320 const MemRegion *
R =
2321 (RR && LVIsNull) ? RR : LVNode->getSVal(Inner).getAsRegion();
2326 SVal
V = LVState->getRawSVal(loc::MemRegionVal(R));
2331 Result.FoundSomethingToTrack =
true;
2332 Result.WasInterrupted =
true;
2334 MacroNullReturnSuppressionVisitor::addMacroVisitorIfNecessary(
2338 Report.addVisitor<UndefOrNullArgVisitor>(
R);
2342 if (
V.getAsLocSymbol(
true))
2343 if (LVState->isNull(
V).isConstrainedTrue())
2344 Report.addVisitor<TrackConstraintBRVisitor>(
2345 V.castAs<DefinedSVal>(),
2346 false,
"Assuming pointer value is null");
2349 if (
auto DV =
V.getAs<DefinedSVal>())
2357 Report.addVisitor<SuppressInlineDefensiveChecksVisitor>(*DV,
2359 getParentTracker().track(
V, R, Opts, SF);
2374class InlinedFunctionCallHandler final :
public ExpressionHandler {
2377 Tracker::Result handle(
const Expr *E,
const ExplodedNode *InputNode,
2378 const ExplodedNode *ExprNode,
2379 TrackingOptions Opts)
override {
2394 if (std::optional<CallExitEnd> CEE =
2396 if (CEE->getCalleeContext()->getCallSite() == E)
2409 if (!BypassCXXNewExprEval)
2410 if (std::optional<StmtPoint> SP = ExprNode->
getLocationAs<StmtPoint>())
2412 if (SP->getStmt() == E && CurrentSF == PredSF)
2425 std::optional<CallExitEnd> CEE = ExprNode->
getLocationAs<CallExitEnd>();
2429 const StackFrame *CalleeContext = CEE->getCalleeContext();
2435 SVal RetVal = ExprNode->
getSVal(E);
2439 if (std::optional<Loc> LValue = RetVal.
getAs<Loc>())
2440 RetVal = State->getSVal(*LValue);
2443 AnalyzerOptions &Options = State->getAnalysisManager().options;
2445 bool EnableNullFPSuppression =
false;
2447 if (std::optional<Loc> RetLoc = RetVal.
getAs<Loc>())
2448 EnableNullFPSuppression = State->isNull(*RetLoc).isConstrainedTrue();
2450 PathSensitiveBugReport &
Report = getParentTracker().getReport();
2451 Report.addVisitor<ReturnVisitor>(&getParentTracker(), CalleeContext,
2452 EnableNullFPSuppression, Options,
2458class DefaultExpressionHandler final :
public ExpressionHandler {
2462 Tracker::Result handle(
const Expr *Inner,
const ExplodedNode *InputNode,
2463 const ExplodedNode *LVNode,
2464 TrackingOptions Opts)
override {
2467 PathSensitiveBugReport &
Report = getParentTracker().getReport();
2475 if (
auto L =
V.getAs<loc::MemRegionVal>()) {
2480 bool CanDereference =
true;
2481 if (
const auto *SR = L->getRegionAs<SymbolicRegion>()) {
2482 if (SR->getPointeeStaticType()->isVoidType())
2483 CanDereference =
false;
2484 }
else if (L->getRegionAs<AllocaRegion>())
2485 CanDereference =
false;
2492 RVal = LVState->getRawSVal(*L, Inner->
getType());
2493 else if (CanDereference)
2494 RVal = LVState->getSVal(L->getRegion());
2496 if (CanDereference) {
2497 Report.addVisitor<UndefOrNullArgVisitor>(L->getRegion());
2498 Result.FoundSomethingToTrack =
true;
2502 getParentTracker().track(RVal, L->getRegion(), Opts, SF));
2506 if (isa_and_nonnull<SymbolicRegion>(RegionRVal)) {
2507 Report.markInteresting(RegionRVal, Opts.
Kind);
2508 Report.addVisitor<TrackConstraintBRVisitor>(
2509 loc::MemRegionVal(RegionRVal),
2510 false,
"Assuming pointer value is null");
2511 Result.FoundSomethingToTrack =
true;
2521class PRValueHandler final :
public ExpressionHandler {
2525 Tracker::Result handle(
const Expr *E,
const ExplodedNode *InputNode,
2526 const ExplodedNode *ExprNode,
2527 TrackingOptions Opts)
override {
2535 Tracker::Result CombinedResult;
2536 Tracker &Parent = getParentTracker();
2538 const auto track = [&CombinedResult, &Parent, ExprNode,
2539 Opts](
const Expr *Inner) {
2548 if (
const auto *ILE = dyn_cast<InitListExpr>(E)) {
2549 if (ILE->getNumInits() == 1) {
2550 track(ILE->getInit(0));
2552 return CombinedResult;
2560 const auto *BO = dyn_cast<BinaryOperator>(E);
2562 if (!BO || !BO->isMultiplicativeOp() || !
V.isZeroConstant())
2569 if (BO->getOpcode() == BO_Mul) {
2571 track(BO->getLHS());
2573 track(BO->getRHS());
2576 track(BO->getLHS());
2579 return CombinedResult;
2609 for (ExpressionHandlerPtr &Handler : ExpressionHandlers) {
2610 CombinedResult.
combineWith(Handler->handle(Inner, N, LVNode, Opts));
2619 return CombinedResult;
2624 if (!
V.isUnknown()) {
2625 Report.addVisitor<StoreSiteFinder>(
this,
V, R, Opts, Origin);
2634 for (StoreHandlerPtr &Handler : StoreHandlers) {
2649 ->track(E, InputNode, Opts)
2650 .FoundSomethingToTrack;
2666 const auto *ME = dyn_cast<ObjCMessageExpr>(S);
2669 if (
const Expr *Receiver = ME->getInstanceReceiver()) {
2672 if (state->isNull(
V).isConstrainedTrue())
2685 const Stmt *S = P->getStmt();
2691 llvm::raw_svector_ostream
OS(Buf);
2693 if (
const auto *ME = dyn_cast<ObjCMessageExpr>(S)) {
2695 ME->getSelector().print(
OS);
2696 OS <<
"' not called";
2699 OS <<
"No method is called";
2701 OS <<
" because the receiver is nil";
2712 return std::make_shared<PathDiagnosticEventPiece>(L,
OS.str());
2729 if (
auto *ev = dyn_cast<PathDiagnosticEventPiece>(piece.get()))
2730 ev->setPrunable(
true,
false);
2740 const std::pair<const ProgramPointTag *, const ProgramPointTag *> &Tags =
2745 if (std::optional<BlockEdge> BE = ProgPoint.
getAs<
BlockEdge>()) {
2746 const CFGBlock *SrcBlock = BE->getSrc();
2754 if (PreviousNodeTag == Tags.first || PreviousNodeTag == Tags.second)
2762 if (std::optional<PostStmt> PS = ProgPoint.
getAs<
PostStmt>()) {
2764 if (CurrentNodeTag != Tags.first && CurrentNodeTag != Tags.second)
2767 bool TookTrue = CurrentNodeTag == Tags.first;
2798 case Stmt::IfStmtClass: {
2801 if (IfStatement->isConsteval())
2803 Cond = IfStatement->getCond();
2806 case Stmt::ConditionalOperatorClass:
2809 case Stmt::BinaryOperatorClass:
2814 assert(BO->isLogicalOp() &&
2815 "CFG terminator is not a short-circuit operator!");
2816 Cond = BO->getLHS();
2825 while (
const auto *InnerBO = dyn_cast<BinaryOperator>(
Cond)) {
2826 if (!InnerBO->isLogicalOp())
2828 Cond = InnerBO->getRHS()->IgnoreParens();
2833 const bool TookTrue = *(srcBlk->
succ_begin()) == dstBlk;
2861 CurrentState->getSVal(
Cond, LCtx).isUnknownOrUndef();
2866 bool TookTrueTmp = TookTrue;
2873 case Stmt::BinaryOperatorClass:
2875 BRC, R, N, TookTrueTmp, IsAssuming))
2878 case Stmt::DeclRefExprClass:
2880 BRC, R, N, TookTrueTmp, IsAssuming))
2883 case Stmt::MemberExprClass:
2885 BRC, R, N, TookTrueTmp, IsAssuming))
2888 case Stmt::UnaryOperatorClass: {
2890 if (UO->getOpcode() == UO_LNot) {
2891 TookTrueTmp = !TookTrueTmp;
2892 CondTmp = UO->getSubExpr();
2912 return std::make_shared<PathDiagnosticEventPiece>(
2913 Loc, TookTrue ? GenericTrueMessage : GenericFalseMessage);
2920 std::optional<bool> &prunable,
2921 bool IsSameFieldName) {
2922 const Expr *OriginalExpr = Ex;
2943 if (
const auto *DR = dyn_cast<DeclRefExpr>(Ex)) {
2961 Out << DR->getDecl()->getDeclName().getAsString();
2967 if (
const auto *IL = dyn_cast<IntegerLiteral>(Ex)) {
2970 if (IL->getValue() == 0) {
2976 if (IL->getValue() == 0) {
2982 Out << IL->getValue();
2986 if (
const auto *ME = dyn_cast<MemberExpr>(Ex)) {
2987 if (!IsSameFieldName)
2988 Out <<
"field '" << ME->getMemberDecl()->getName() <<
'\'';
3005 bool shouldInvert =
false;
3006 std::optional<bool> shouldPrune;
3010 bool IsSameFieldName =
false;
3016 LhsME->getMemberDecl()->getName() == RhsME->getMemberDecl()->getName();
3020 llvm::raw_svector_ostream OutLHS(LhsString), OutRHS(RhsString);
3022 N, shouldPrune, IsSameFieldName);
3024 N, shouldPrune, IsSameFieldName);
3026 shouldInvert = !isVarLHS && isVarRHS;
3040 if (LhsString.empty() || RhsString.empty() ||
3046 llvm::raw_svector_ostream Out(buf);
3047 Out << (IsAssuming ?
"Assuming " :
"")
3048 << (shouldInvert ? RhsString : LhsString) <<
" is ";
3054 case BO_LT: Op = BO_GT;
break;
3055 case BO_GT: Op = BO_LT;
break;
3056 case BO_LE: Op = BO_GE;
break;
3057 case BO_GE: Op = BO_LE;
break;
3062 case BO_EQ: Op = BO_NE;
break;
3063 case BO_NE: Op = BO_EQ;
break;
3064 case BO_LT: Op = BO_GE;
break;
3065 case BO_GT: Op = BO_LE;
break;
3066 case BO_LE: Op = BO_GT;
break;
3067 case BO_GE: Op = BO_LT;
break;
3077 Out <<
"not equal to ";
3084 Out << (shouldInvert ? LhsString : RhsString);
3093 std::string Message = std::string(Out.str());
3094 Message[0] = toupper(Message[0]);
3099 if (!shouldInvert) {
3100 if (LhsME && LhsME->getMemberLoc().isValid())
3105 if (RhsME && RhsME->getMemberLoc().isValid())
3111 return std::make_shared<PathDiagnosticPopUpPiece>(
Loc, Message);
3115 auto event = std::make_shared<PathDiagnosticEventPiece>(
Loc, Message);
3117 event->setPrunable(*shouldPrune);
3128 llvm::raw_svector_ostream Out(buf);
3129 Out <<
"Assuming " << LhsString <<
" is ";
3131 if (!
printValue(CondVarExpr, Out, N, TookTrue,
true))
3140 auto event = std::make_shared<PathDiagnosticEventPiece>(
Loc, Out.str());
3143 event->setPrunable(
false);
3152 const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl());
3157 llvm::raw_svector_ostream Out(Buf);
3159 Out << (IsAssuming ?
"Assuming '" :
"'") << VD->getDeclName() <<
"' is ";
3161 if (!
printValue(DRE, Out, N, TookTrue, IsAssuming))
3172 return std::make_shared<PathDiagnosticPopUpPiece>(
Loc, Out.str());
3176 auto event = std::make_shared<PathDiagnosticEventPiece>(
Loc, Out.str());
3179 event->setPrunable(
false);
3181 return std::move(event);
3189 llvm::raw_svector_ostream Out(Buf);
3191 Out << (IsAssuming ?
"Assuming field '" :
"Field '")
3194 if (!
printValue(ME, Out, N, TookTrue, IsAssuming))
3214 return std::make_shared<PathDiagnosticPopUpPiece>(
Loc, Out.str());
3216 auto event = std::make_shared<PathDiagnosticEventPiece>(
Loc, Out.str());
3218 event->setPrunable(
false);
3228 Out << (TookTrue ?
"non-null" :
"null");
3233 Out << (TookTrue ?
"non-nil" :
"nil");
3240 std::optional<const llvm::APSInt *> IntValue;
3244 if (IsAssuming || !IntValue) {
3246 Out << (TookTrue ?
"true" :
"false");
3248 Out << (TookTrue ?
"not equal to 0" :
"0");
3251 Out << ((*IntValue)->getBoolValue() ?
"true" :
"false");
3261 return Piece->
getString() == GenericTrueMessage ||
3262 Piece->
getString() == GenericFalseMessage;
3282 if (Options.ShouldSuppressFromCXXStandardLibrary) {
3292 if (
const auto *MD = dyn_cast<CXXMethodDecl>(D)) {
3294 if (CD->
getName() ==
"list") {
3302 if (
const auto *MD = dyn_cast<CXXConstructorDecl>(D)) {
3304 if (CD->
getName() ==
"__independent_bits_engine") {
3312 const auto *MD = dyn_cast<CXXMethodDecl>(LCtx->getDecl());
3323 if (CD->
getName() ==
"basic_string") {
3331 if (CD->
getName() ==
"shared_ptr") {
3343 while (
Loc.isMacroID()) {
3344 Loc =
Loc.getSpellingLoc();
3345 if (
SM.getFilename(
Loc).ends_with(
"sys/queue.h")) {
3373 for (
const auto ParamDecl : parms) {
3374 const MemRegion *ArgReg =
Call->getArgSVal(Idx).getAsRegion();
3382 assert(ParamDecl &&
"Formal parameter has no decl?");
3385 if (!(T->isAnyPointerType() || T->isReferenceType())) {
3392 if (T->getPointeeType().isConstQualified())
3397 SVal BoundVal = State->getSVal(R);
3410int NoteTag::Kind = 0;
3414 ID.AddPointer(&Tag);
3425 if (std::optional<std::string> Msg = T->generateMessage(BRC, R)) {
3428 auto Piece = std::make_shared<PathDiagnosticEventPiece>(
Loc, *Msg);
3429 Piece->setPrunable(T->isPrunable());
Defines the clang::ASTContext interface.
This file defines AnalysisDeclContext, a class that manages the analysis context data for context sen...
static bool isInterestingExpr(const Expr *E, const ExplodedNode *N, const PathSensitiveBugReport *B)
static const ExplodedNode * findNodeForExpression(const ExplodedNode *N, const Expr *Inner)
Find the ExplodedNode where the lvalue (the value of 'Ex') was computed.
static void showBRParamDiagnostics(llvm::raw_svector_ostream &OS, StoreInfo SI)
Display diagnostics for passing bad region as a parameter.
static const Expr * peelOffPointerArithmetic(const BinaryOperator *B)
static const Expr * tryExtractInitializerFromList(const InitListExpr *ILE, const MemRegion *R)
static bool wasRegionOfInterestModifiedAt(const SubRegion *RegionOfInterest, const ExplodedNode *N, SVal ValueAfter)
static llvm::StringLiteral WillBeUsedForACondition
static bool isFunctionMacroExpansion(SourceLocation Loc, const SourceManager &SM)
static std::shared_ptr< PathDiagnosticEventPiece > constructDebugPieceForTrackedCondition(const Expr *Cond, const ExplodedNode *N, BugReporterContext &BRC)
static const MemRegion * getLocationRegionIfReference(const Expr *E, const ExplodedNode *N, bool LookingForReference=true)
static bool hasVisibleUpdate(const ExplodedNode *LeftNode, SVal LeftVal, const ExplodedNode *RightNode, SVal RightVal)
Comparing internal representations of symbolic values (via SVal::operator==()) is a valid way to chec...
static bool potentiallyWritesIntoIvar(const Decl *Parent, const ObjCIvarDecl *Ivar)
static std::optional< const llvm::APSInt * > getConcreteIntegerValue(const Expr *CondVarExpr, const ExplodedNode *N)
static bool isVarAnInterestingCondition(const Expr *CondVarExpr, const ExplodedNode *N, const PathSensitiveBugReport *B)
static void showBRDefaultDiagnostics(llvm::raw_svector_ostream &OS, StoreInfo SI)
Show default diagnostics for storing bad region.
static std::optional< SVal > getSValForVar(const Expr *CondVarExpr, const ExplodedNode *N)
static const Expr * peelOffOuterExpr(const Expr *Ex, const ExplodedNode *N)
static const VarDecl * getVarDeclForExpression(const Expr *E)
static bool isTrivialCopyOrMoveCtor(const CXXConstructExpr *CE)
static StringRef getMacroName(SourceLocation Loc, BugReporterContext &BRC)
static bool isObjCPointer(const MemRegion *R)
static bool isAssertlikeBlock(const CFGBlock *B, ASTContext &Context)
static bool isInitializationOfVar(const ExplodedNode *N, const VarRegion *VR)
Returns true if N represents the DeclStmt declaring and initializing VR.
static const ExplodedNode * getMatchingCallExitEnd(const ExplodedNode *N)
static void showBRDiagnostics(llvm::raw_svector_ostream &OS, StoreInfo SI)
Show diagnostics for initializing or declaring a region R with a bad value.
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
Defines the clang::Expr interface and subclasses for C++ expressions.
Defines the clang::IdentifierInfo, clang::IdentifierTable, and clang::Selector interfaces.
Result
Implement __builtin_bit_cast and related operations.
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
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 Stmt * getTerminatorCondition(bool StripParens=true) const
const Expr * getLastCondition() const
unsigned succ_size() const
const CFGBlock * getBlock(const Stmt *S) const
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 byte-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.
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 StackFrame * 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).
bool inTopFrame() const override
const Expr * getCallSite() const
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 StackFrame *CalleeSF, 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
SVal getSVal(const Expr *E) const
Get the value of an arbitrary expression at this node.
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 LocationContext * getLocationContext() const
std::optional< T > getLocationAs() const &
ExplodedNode * getFirstPred()
unsigned succ_size() const
const StackFrame * getStackFrame() 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
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.
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 Expr *E, const LocationContext *LCtx) const
Returns the SVal bound to the expression E 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.
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...
void trackStoredValue(SVal V, const MemRegion *R, PathSensitiveBugReport &Report, TrackingOptions Opts={}, const StackFrame *Origin=nullptr)
Track how the value got stored into the given region and where it came from.
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.
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
PRESERVE_NONE 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
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.