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, SF));
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, SF).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) {
382 if (!FramesModifyingCalculated.count(SF))
383 findModifyingFrames(N);
384 return FramesModifying.count(SF);
387void NoStateChangeFuncVisitor::markFrameAsModifying(
const StackFrame *SF) {
389 auto p = FramesModifying.insert(SF);
405 auto IsMatchingCallExitEnd = [OrigSF](
const ExplodedNode *N) {
409 while (N && !IsMatchingCallExitEnd(N)) {
411 "This function is to be used on the trimmed ExplodedGraph!");
417void NoStateChangeFuncVisitor::findModifyingFrames(
422 const StackFrame *
const OriginalSF = CallExitBeginN->
getStackFrame();
424 const ExplodedNode *CurrCallExitBeginN = CallExitBeginN;
425 const StackFrame *CurrentSF = OriginalSF;
427 for (
const ExplodedNode *CurrN = CallExitBeginN; CurrN;
428 CurrN = CurrN->getFirstPred()) {
430 if (CurrN->getLocationAs<CallExitBegin>()) {
431 CurrCallExitBeginN = CurrN;
432 CurrentSF = CurrN->getStackFrame();
433 FramesModifyingCalculated.insert(CurrentSF);
438 if (
auto CE = CurrN->getLocationAs<CallEnter>()) {
441 markFrameAsModifying(CurrentSF);
444 CurrentSF = CurrN->getStackFrame();
452 if (CE->getCalleeStackFrame() == OriginalSF) {
453 markFrameAsModifying(CurrentSF);
459 markFrameAsModifying(CurrentSF);
471 if (!CallExitLoc || isModifiedInFrame(N))
486 if (
Call->isInSystemHeader()) {
496 R.markInvalid(&i,
nullptr);
501 if (
const auto *MC = dyn_cast<ObjCMethodCall>(
Call)) {
508 if (
const auto *CCall = dyn_cast<CXXConstructorCall>(
Call)) {
522 const char *IvarBind =
"Ivar";
523 if (!Parent || !Parent->
hasBody())
526 hasOperatorName(
"="),
527 hasLHS(ignoringParenImpCasts(
533 if (IvarRef->isFreeIvar())
536 const Expr *
Base = IvarRef->getBase();
537 if (
const auto *ICE = dyn_cast<ImplicitCastExpr>(
Base))
538 Base = ICE->getSubExpr();
540 if (
const auto *DRE = dyn_cast<DeclRefExpr>(
Base))
541 if (
const auto *ID = dyn_cast<ImplicitParamDecl>(DRE->getDecl()))
556const std::optional<NoStoreFuncVisitor::RegionVector>
557NoStoreFuncVisitor::findRegionOfInterestInRecord(
559 const NoStoreFuncVisitor::RegionVector &Vec ,
562 if (depth == DEREFERENCE_LIMIT)
565 if (
const auto *RDX = dyn_cast<CXXRecordDecl>(RD))
566 if (!RDX->hasDefinition())
571 if (
const auto *RDX = dyn_cast<CXXRecordDecl>(RD))
572 for (
const auto &II : RDX->bases())
573 if (
const RecordDecl *RRD = II.getType()->getAsRecordDecl())
574 if (std::optional<RegionVector> Out =
575 findRegionOfInterestInRecord(RRD, State, R, Vec, depth))
578 for (
const FieldDecl *I : RD->
fields()) {
579 QualType FT = I->getType();
581 const SVal
V = State->getSVal(FR);
582 const MemRegion *VR =
V.getAsRegion();
584 RegionVector VecF = Vec;
587 if (RegionOfInterest == VR)
592 findRegionOfInterestInRecord(RRD, State, FR, VecF, depth + 1))
600 if (std::optional<RegionVector> Out =
601 findRegionOfInterestInRecord(RRD, State, VR, VecF, depth + 1))
612 if (
const auto *IvarR = dyn_cast<ObjCIvarRegion>(RegionOfInterest)) {
613 const MemRegion *SelfRegion =
Call.getReceiverSVal().getAsRegion();
614 if (RegionOfInterest->isSubRegionOf(SelfRegion) &&
617 return maybeEmitNote(R,
Call, N, {}, SelfRegion,
"self",
627 const MemRegion *ThisR =
Call.getCXXThisVal().getAsRegion();
628 if (RegionOfInterest->isSubRegionOf(ThisR) && !
Call.getDecl()->isImplicit())
629 return maybeEmitNote(R,
Call, N, {}, ThisR,
"this",
646 for (
unsigned I = 0; I <
Call.getNumArgs() && I <
Parameters.size(); ++I) {
648 SVal
V =
Call.getArgSVal(I);
652 unsigned IndirectionLevel = 1;
654 while (
const MemRegion *MR =
V.getAsRegion()) {
656 return maybeEmitNote(R,
Call, N, {}, MR, ParamName,
657 ParamIsReferenceType, IndirectionLevel);
660 if (PT.isNull() || PT->isVoidType())
665 if (
const RecordDecl *RD = PT->getAsRecordDecl())
666 if (std::optional<RegionVector> P =
667 findRegionOfInterestInRecord(RD, State, MR))
668 return maybeEmitNote(R,
Call, N, *P, RegionOfInterest, ParamName,
669 ParamIsReferenceType, IndirectionLevel);
671 V = State->getSVal(MR, PT);
680bool NoStoreFuncVisitor::wasModifiedBeforeCallExit(
682 return ::wasRegionOfInterestModifiedAt(
683 RegionOfInterest, CurrN,
684 CallExitBeginN->
getState()->getSVal(RegionOfInterest));
688 ", which participates in a condition later";
692 const RegionVector &FieldChain,
const MemRegion *MatchedRegion,
693 StringRef FirstElement,
bool FirstIsReferenceType,
694 unsigned IndirectionLevel) {
706 llvm::raw_svector_ostream os(sbuf);
707 os <<
"Returning without writing to '";
710 if (!prettyPrintRegionName(FieldChain, MatchedRegion, FirstElement,
711 FirstIsReferenceType, IndirectionLevel, os))
717 return std::make_shared<PathDiagnosticEventPiece>(L, os.str());
720bool NoStoreFuncVisitor::prettyPrintRegionName(
const RegionVector &FieldChain,
722 StringRef FirstElement,
723 bool FirstIsReferenceType,
724 unsigned IndirectionLevel,
725 llvm::raw_svector_ostream &os) {
727 if (FirstIsReferenceType)
730 RegionVector RegionSequence;
733 assert(RegionOfInterest->isSubRegionOf(MatchedRegion));
734 const MemRegion *
R = RegionOfInterest;
735 while (R != MatchedRegion) {
736 RegionSequence.push_back(R);
739 std::reverse(RegionSequence.begin(), RegionSequence.end());
740 RegionSequence.append(FieldChain.begin(), FieldChain.end());
743 for (
const MemRegion *R : RegionSequence) {
751 Sep = prettyPrintFirstElement(FirstElement,
753 IndirectionLevel, os);
762 Sep = DR->getValueType()->isAnyPointerType() ?
"->" :
".";
763 DR->getDecl()->getDeclName().print(os, PP);
767 prettyPrintFirstElement(FirstElement,
768 false, IndirectionLevel, os);
772StringRef NoStoreFuncVisitor::prettyPrintFirstElement(
773 StringRef FirstElement,
bool MoreItemsExpected,
int IndirectionLevel,
774 llvm::raw_svector_ostream &os) {
777 if (IndirectionLevel > 0 && MoreItemsExpected) {
782 if (IndirectionLevel > 0 && MoreItemsExpected)
785 for (
int i = 0; i < IndirectionLevel; i++)
789 if (IndirectionLevel > 0 && MoreItemsExpected)
804 const SubRegion *RegionOfInterest;
805 const SVal ValueAtDereference;
809 bool WasModified =
false;
812 MacroNullReturnSuppressionVisitor(
const SubRegion *R,
const SVal
V)
813 : RegionOfInterest(
R), ValueAtDereference(
V) {}
816 BugReporterContext &BRC,
817 PathSensitiveBugReport &BR)
override {
826 if (
auto Loc = matchAssignment(N)) {
828 std::string MacroName = std::string(
getMacroName(*Loc, BRC));
829 SourceLocation BugLoc = BugPoint->getStmt()->getBeginLoc();
841 static void addMacroVisitorIfNecessary(
842 const ExplodedNode *N,
const MemRegion *R,
843 bool EnableNullFPSuppression, PathSensitiveBugReport &BR,
845 AnalyzerOptions &Options = N->
getState()->getAnalysisManager().options;
846 if (EnableNullFPSuppression && Options.ShouldSuppressNullReturnPaths &&
848 BR.
addVisitor<MacroNullReturnSuppressionVisitor>(
R->getAs<SubRegion>(),
852 void* getTag()
const {
854 return static_cast<void *
>(&
Tag);
857 void Profile(llvm::FoldingSetNodeID &ID)
const override {
858 ID.AddPointer(getTag());
864 std::optional<SourceLocation> matchAssignment(
const ExplodedNode *N) {
870 if (
const auto *DS = dyn_cast<DeclStmt>(S)) {
871 if (
const auto *VD = dyn_cast<VarDecl>(DS->getSingleDecl()))
872 if (
const Expr *RHS = VD->getInit())
873 if (RegionOfInterest->isSubRegionOf(
875 return RHS->getBeginLoc();
876 }
else if (
const auto *BO = dyn_cast<BinaryOperator>(S)) {
878 const Expr *RHS = BO->getRHS();
879 if (BO->isAssignmentOp() && RegionOfInterest->isSubRegionOf(R)) {
898class ReturnVisitor :
public TrackingBugReporterVisitor {
899 const StackFrame *CalleeSF;
906 bool EnableNullFPSuppression;
907 bool ShouldInvalidate =
true;
908 AnalyzerOptions& Options;
912 ReturnVisitor(
TrackerRef ParentTracker,
const StackFrame *Frame,
913 bool Suppressed, AnalyzerOptions &Options,
915 : TrackingBugReporterVisitor(ParentTracker), CalleeSF(Frame),
916 EnableNullFPSuppression(Suppressed), Options(Options), TKind(TKind) {}
918 static void *getTag() {
920 return static_cast<void *
>(&
Tag);
923 void Profile(llvm::FoldingSetNodeID &ID)
const override {
924 ID.AddPointer(ReturnVisitor::getTag());
925 ID.AddPointer(CalleeSF);
926 ID.AddBoolean(EnableNullFPSuppression);
930 BugReporterContext &BRC,
931 PathSensitiveBugReport &BR) {
940 const auto *
Ret = dyn_cast<ReturnStmt>(SP->getStmt());
947 const Expr *RV =
Ret->getRetValue();
950 SVal
V = State->getSVal(RV, CalleeSF);
951 if (
V.isUnknownOrUndef())
957 const Expr *RetE =
Ret->getRetValue();
958 assert(RetE &&
"Tracking a return value for a void function");
961 std::optional<Loc> LValue;
963 if ((LValue =
V.getAs<Loc>())) {
964 SVal RValue = State->getRawSVal(*LValue, RetE->
getType());
977 getParentTracker().track(RetE, N, {TKind, EnableNullFPSuppression});
981 llvm::raw_svector_ostream
Out(Msg);
983 bool WouldEventBeMeaningless =
false;
985 if (State->isNull(
V).isConstrainedTrue()) {
991 if (EnableNullFPSuppression &&
992 Options.ShouldAvoidSuppressingNullArgumentPaths)
993 Mode = MaybeUnsuppress;
996 Out <<
"Returning nil";
998 Out <<
"Returning null pointer";
1001 Out <<
"Returning zero";
1005 if (
auto CI =
V.getAs<nonloc::ConcreteInt>()) {
1006 Out <<
"Returning the value " << CI->getValue();
1014 WouldEventBeMeaningless =
true;
1016 Out << (isa<Loc>(
V) ?
"Returning pointer" :
"Returning value");
1021 if (
const MemRegion *MR = LValue->getAsRegion()) {
1022 if (MR->canPrintPretty()) {
1023 Out <<
" (reference to ";
1024 MR->printPretty(Out);
1030 if (
const auto *DR = dyn_cast<DeclRefExpr>(RetE))
1031 if (
const auto *DD = dyn_cast<DeclaratorDecl>(DR->getDecl()))
1032 Out <<
" (loaded from '" << *DD <<
"')";
1036 if (!L.isValid() || !L.asLocation().isValid())
1039 if (TKind == bugreporter::TrackingKind::Condition)
1042 auto EventPiece = std::make_shared<PathDiagnosticEventPiece>(L,
Out.str());
1046 if (WouldEventBeMeaningless)
1047 EventPiece->setPrunable(
true);
1055 BugReporterContext &BRC,
1056 PathSensitiveBugReport &BR) {
1057 assert(Options.ShouldAvoidSuppressingNullArgumentPaths);
1060 std::optional<CallEnter> CE = N->
getLocationAs<CallEnter>();
1064 if (CE->getCalleeStackFrame() != CalleeSF)
1077 for (
unsigned I = 0, E =
Call->getNumArgs(); I != E; ++I) {
1078 std::optional<Loc> ArgV =
Call->getArgSVal(I).getAs<Loc>();
1082 const Expr *ArgE =
Call->getArgExpr(I);
1087 if (!State->isNull(*ArgV).isConstrainedTrue())
1090 if (getParentTracker()
1091 .track(ArgE, N, {TKind, EnableNullFPSuppression})
1092 .FoundSomethingToTrack)
1093 ShouldInvalidate =
false;
1104 BugReporterContext &BRC,
1105 PathSensitiveBugReport &BR)
override {
1108 return visitNodeInitial(N, BRC, BR);
1109 case MaybeUnsuppress:
1110 return visitNodeMaybeUnsuppress(N, BRC, BR);
1115 llvm_unreachable(
"Invalid visit mode!");
1118 void finalizeVisitor(BugReporterContext &,
const ExplodedNode *,
1119 PathSensitiveBugReport &BR)
override {
1120 if (EnableNullFPSuppression && ShouldInvalidate)
1121 BR.
markInvalid(ReturnVisitor::getTag(), CalleeSF);
1131class StoreSiteFinder final :
public TrackingBugReporterVisitor {
1134 bool Satisfied =
false;
1136 TrackingOptions Options;
1137 const StackFrame *OriginSF;
1151 const MemRegion *R, TrackingOptions Options,
1152 const StackFrame *OriginSF =
nullptr)
1153 : TrackingBugReporterVisitor(ParentTracker),
R(
R),
V(
V), Options(Options),
1154 OriginSF(OriginSF) {
1158 void Profile(llvm::FoldingSetNodeID &ID)
const override;
1161 BugReporterContext &BRC,
1162 PathSensitiveBugReport &BR)
override;
1166void StoreSiteFinder::Profile(llvm::FoldingSetNodeID &ID)
const {
1168 ID.AddPointer(&tag);
1171 ID.AddInteger(
static_cast<int>(Options.Kind));
1172 ID.AddBoolean(Options.EnableNullFPSuppression);
1189 const auto *FrameSpace =
1196 [[maybe_unused]]
bool IsLocalStaticOrLocalExtern =
1198 assert(IsLocalStaticOrLocalExtern &&
1199 "Declared a variable on the stack without Stack memspace?");
1208 if (R->isBoundable())
1209 if (
const auto *TR = dyn_cast<TypedValueRegion>(R))
1210 return TR->getValueType()->isObjCObjectPointerType();
1220using DestTypeValue = std::pair<const StoreInfo &, loc::ConcreteInt>;
1222llvm::raw_ostream &
operator<<(llvm::raw_ostream &
OS,
const DestTypeValue &Val) {
1223 if (
auto *TyR = Val.first.Dest->getAs<
TypedRegion>()) {
1224 QualType LocTy = TyR->getLocationType();
1226 if (
auto *PtrTy = LocTy->
getAs<PointerType>()) {
1227 std::string PStr = PtrTy->getPointeeType().getAsString();
1229 OS <<
"(" << PStr <<
")";
1233 SmallString<16> ValStr;
1234 Val.second.getValue()->toString(ValStr, 10,
true);
1249 const char *Action =
nullptr;
1253 Action = HasPrefix ?
"initialized to " :
"Initializing to ";
1256 Action = HasPrefix ?
"captured by block as " :
"Captured by block as ";
1259 llvm_unreachable(
"Unexpected store kind");
1263 if (!*CVal->getValue())
1266 OS << Action << DestTypeValue(SI, *CVal);
1269 OS << Action << CVal->getValue();
1272 OS << Action <<
"the value of ";
1286 if (VD->getInit()) {
1287 OS << (HasPrefix ?
"initialized" :
"Initializing")
1288 <<
" to a garbage value";
1290 OS << (HasPrefix ?
"declared" :
"Declaring")
1291 <<
" without an initial value";
1295 OS << (HasPrefix ?
"initialized" :
"Initialized") <<
" here";
1304 const auto *D = VR->getDecl();
1309 if (!*CI->getValue())
1310 OS << (
isObjCPointer(D) ?
"nil object reference" :
"null pointer value");
1312 OS << (
isObjCPointer(D) ?
"object reference of value " :
"pointer value ")
1313 << DestTypeValue(SI, *CI);
1316 OS <<
"uninitialized value";
1319 OS <<
"the value " << CI->getValue();
1328 if (
const auto *Param = dyn_cast<ParmVarDecl>(VR->getDecl())) {
1330 unsigned Idx = Param->getFunctionScopeIndex() + 1;
1331 OS <<
" via " << Idx << llvm::getOrdinalSuffix(Idx) <<
" parameter";
1336 }
else if (
const auto *ImplParam = dyn_cast<ImplicitParamDecl>(D)) {
1338 OS <<
" via implicit parameter 'self'";
1352 ?
"nil object reference stored"
1353 : (HasSuffix ?
"Null pointer value stored"
1354 :
"Storing null pointer value"));
1357 OS <<
"object reference of value " << DestTypeValue(SI, *CV)
1361 OS <<
"Pointer value of " << DestTypeValue(SI, *CV) <<
" stored";
1363 OS <<
"Storing pointer value of " << DestTypeValue(SI, *CV);
1367 OS << (HasSuffix ?
"Uninitialized value stored"
1368 :
"Storing uninitialized value");
1372 OS <<
"The value " << CV->getValue() <<
" is assigned";
1374 OS <<
"Assigning " << CV->getValue();
1378 OS <<
"The value of ";
1380 OS <<
" is assigned";
1382 OS <<
"Assigning the value of ";
1387 OS << (HasSuffix ?
"Value assigned" :
"Assigning value");
1408 const auto *TVR = dyn_cast_or_null<TypedValueRegion>(R);
1416 std::stack<const TypedValueRegion *> TVRStack;
1422 if (ITy == TVR->getValueType().getCanonicalType())
1431 if (ITy != TVR->getValueType().getCanonicalType())
1435 while (!TVRStack.empty()) {
1436 TVR = TVRStack.top();
1447 if (
const auto *FR = dyn_cast<FieldRegion>(TVR)) {
1448 const auto *FD = FR->
getDecl();
1450 if (FD->getFieldIndex() >= NumInits)
1454 }
else if (
const auto *ER = dyn_cast<ElementRegion>(TVR)) {
1455 const auto Ind = ER->getIndex();
1459 if (!Ind.isConstant())
1462 const auto IndVal = Ind.getAsInteger()->getLimitedValue();
1463 if (IndVal >= NumInits)
1481 const Expr *InitE =
nullptr;
1482 bool IsParam =
false;
1485 if (
const auto *VR = dyn_cast<VarRegion>(R)) {
1488 InitE = VR->getDecl()->getInit();
1494 if (std::optional<PostInitializer> PIP =
1497 if (FieldReg == R) {
1499 InitE = PIP->getInitializer()->getInit();
1513 std::optional<PostStore> PS = Succ->
getLocationAs<PostStore>();
1514 if (!PS || PS->getLocationValue() != R)
1520 if (std::optional<PostStmt> P = Succ->
getLocationAs<PostStmt>()) {
1523 if (
const BinaryOperator *BO = P->getStmtAs<BinaryOperator>()) {
1524 if (BO->isAssignmentOp())
1525 InitE = BO->getRHS();
1529 else if (
const auto *DS = P->getStmtAs<DeclStmt>()) {
1530 const auto *
Decl = DS->getSingleDecl();
1540 if (
const auto *ILE = dyn_cast<InitListExpr>(VD->getInit()))
1543 }
else if (
const auto *CE = P->getStmtAs<CXXConstructExpr>()) {
1545 const auto State = Succ->
getState();
1556 std::stack<const SubRegion *> SRStack;
1564 const auto *OriginEx = CE->getArg(0);
1565 const auto OriginVal =
1571 SVal OriginField = OriginVal;
1572 while (!SRStack.empty()) {
1573 const auto *TopR = SRStack.top();
1576 if (
const auto *FR = dyn_cast<FieldRegion>(TopR)) {
1577 OriginField = State->getLValue(FR->
getDecl(), OriginField);
1578 }
else if (
const auto *ER = dyn_cast<ElementRegion>(TopR)) {
1579 OriginField = State->getLValue(ER->getElementType(),
1580 ER->getIndex(), OriginField);
1587 getParentTracker().track(
V, OriginField.
getAsRegion(), Options);
1592 else if (
const auto *ILE = P->getStmtAs<InitListExpr>()) {
1607 if (std::optional<CallEnter> CE = Succ->
getLocationAs<CallEnter>()) {
1608 if (
const auto *VR = dyn_cast<VarRegion>(R)) {
1610 if (
const auto *Param = dyn_cast<ParmVarDecl>(VR->getDecl())) {
1616 InitE =
Call->getArgExpr(Param->getFunctionScopeIndex());
1622 ->getInstanceReceiver()
1623 ->IgnoreParenCasts();
1631 if (
const auto *TmpR = dyn_cast<CXXTempObjectRegion>(R))
1632 InitE = TmpR->getExpr();
1646 getParentTracker().track(InitE, StoreSite, Options);
1670 if (
SM.includedInBindings(N->
getState()->getStore(), Candidate)) {
1672 if (N->
getState()->getSVal(Candidate) ==
V) {
1673 OldRegion = Candidate;
1692 if (!OldRegion && StoreSite->
getState()->getSVal(R) ==
V) {
1697 NodeWithoutBinding && NodeWithoutBinding->
getState()->getSVal(R) ==
V;
1698 NodeWithoutBinding = NodeWithoutBinding->
getFirstPred()) {
1701 if (NodeWithoutBinding) {
1713 OldRegion = FB.getRegion();
1717 if (Options.Kind == TrackingKind::Condition && OriginSF &&
1722 SmallString<256> sbuf;
1723 llvm::raw_svector_ostream os(sbuf);
1732 if (std::optional<PostStmt> PS = StoreSite->
getLocationAs<PostStmt>()) {
1733 const Stmt *S = PS->getStmt();
1734 const auto *DS = dyn_cast<DeclStmt>(S);
1735 const auto *VR = dyn_cast<VarRegion>(R);
1739 }
else if (
const auto *BExpr = dyn_cast<BlockExpr>(S)) {
1745 if (
const auto *BDR =
1746 dyn_cast_or_null<BlockDataRegion>(
V.getAsRegion())) {
1747 if (
const VarRegion *OriginalR = BDR->getOriginalRegion(VR)) {
1748 getParentTracker().track(State->getSVal(OriginalR), OriginalR,
1759 return getParentTracker().handle(SI, BRC, Options);
1768 ID.AddPointer(&tag);
1769 ID.AddString(Message);
1770 ID.AddBoolean(Assumption);
1777 return "TrackConstraintBRVisitor";
1780bool TrackConstraintBRVisitor::isZeroCheck()
const {
1781 return !Assumption && Constraint.
getAs<
Loc>();
1784bool TrackConstraintBRVisitor::isUnderconstrained(
const ExplodedNode *N)
const {
1786 return N->
getState()->isNull(Constraint).isUnderconstrained();
1787 return (
bool)N->
getState()->assume(Constraint, !Assumption);
1798 if (!IsTrackingTurnedOn)
1799 if (!isUnderconstrained(N))
1800 IsTrackingTurnedOn =
true;
1801 if (!IsTrackingTurnedOn)
1806 if (isUnderconstrained(PrevN)) {
1813 assert(!isUnderconstrained(N));
1821 if (isa_and_nonnull<NoteTag>(P.
getTag()))
1829 auto X = std::make_shared<PathDiagnosticEventPiece>(L, Message);
1831 return std::move(
X);
1846 if (!Options.ShouldSuppressInlinedDefensiveChecks)
1851 llvm::FoldingSetNodeID &ID)
const {
1858 return "IDCVisitor";
1870 if (!IsTrackingTurnedOn)
1871 if (Succ->
getState()->isNull(V).isConstrainedTrue())
1872 IsTrackingTurnedOn =
true;
1873 if (!IsTrackingTurnedOn)
1878 if (!Pred->
getState()->isNull(V).isConstrainedTrue() &&
1879 Succ->
getState()->isNull(V).isConstrainedTrue()) {
1885 if (CurSF != ReportSF && !CurSF->
isParentOf(ReportSF)) {
1900 const Stmt *CurTerminatorStmt =
nullptr;
1902 CurTerminatorStmt = BE->getSrc()->getTerminator().getStmt();
1904 const Stmt *CurStmt = SP->getStmt();
1914 if (!CurTerminatorStmt)
1948class TrackControlDependencyCondBRVisitor final
1955 TrackControlDependencyCondBRVisitor(
TrackerRef ParentTracker,
1958 ControlDeps(&O->getCFG()) {}
1960 void Profile(llvm::FoldingSetNodeID &ID)
const override {
1971static std::shared_ptr<PathDiagnosticEventPiece>
1984 return std::make_shared<PathDiagnosticEventPiece>(
1987 (Twine() +
"Tracking condition '" + ConditionText +
"'").str());
2015 if (
const auto *BinOp = dyn_cast<BinaryOperator>(ElseCond))
2016 if (BinOp->isLogicalOp())
2023TrackControlDependencyCondBRVisitor::VisitNode(
const ExplodedNode *N,
2030 CFGBlock *NB =
const_cast<CFGBlock *
>(N->
getCFGBlock());
2033 if (!VisitedBlocks.insert(NB).second)
2036 CFGBlock *OriginB =
const_cast<CFGBlock *
>(Origin->getCFGBlock());
2039 if (!OriginB || !NB)
2045 if (ControlDeps.isControlDependent(OriginB, NB)) {
2078 getParentTracker().track(InnerExpr, N,
2096 if (
const auto *FE = dyn_cast<FullExpr>(Ex))
2098 if (
const auto *OVE = dyn_cast<OpaqueValueExpr>(Ex))
2100 if (
const auto *POE = dyn_cast<PseudoObjectExpr>(Ex)) {
2101 const auto *PropRef = dyn_cast<ObjCPropertyRefExpr>(POE->getSyntacticForm());
2102 if (PropRef && PropRef->isMessagingGetter()) {
2103 const Expr *GetterMessageSend =
2104 POE->getSemanticExpr(POE->getNumSemanticExprs() - 1);
2111 if (
const auto *CO = dyn_cast<ConditionalOperator>(Ex)) {
2117 if (std::optional<BlockEdge> BE = ProgPoint.
getAs<
BlockEdge>()) {
2118 const CFGBlock *srcBlk = BE->getSrc();
2121 bool TookTrueBranch = (*(srcBlk->
succ_begin()) == BE->getDst());
2133 if (
auto *BO = dyn_cast<BinaryOperator>(Ex))
2137 if (
auto *UO = dyn_cast<UnaryOperator>(Ex)) {
2138 if (UO->getOpcode() == UO_LNot)
2149 if (UO->getOpcode() == UO_AddrOf && UO->getSubExpr()->isLValue())
2160 const Expr *Inner) {
2175 StringRef NodeText) {
2189 return std::make_shared<PathDiagnosticEventPiece>(L, NodeText);
2201 llvm::raw_svector_ostream
OS(Buffer);
2219 return constructNote(SI, BRC,
OS.str());
2239 ->getAnalysisManager()
2240 .getAnalyzerOptions()
2241 .ShouldTrackConditions) {
2242 Report.addVisitor<TrackControlDependencyCondBRVisitor>(
2243 &getParentTracker(), InputNode);
2251class NilReceiverHandler final :
public ExpressionHandler {
2255 Tracker::Result handle(
const Expr *Inner,
const ExplodedNode *InputNode,
2256 const ExplodedNode *LVNode,
2257 TrackingOptions Opts)
override {
2261 if (
const Expr *Receiver =
2263 return getParentTracker().track(Receiver, LVNode, Opts);
2269class ArrayIndexHandler final :
public ExpressionHandler {
2273 Tracker::Result handle(
const Expr *Inner,
const ExplodedNode *InputNode,
2274 const ExplodedNode *LVNode,
2275 TrackingOptions Opts)
override {
2277 if (
const auto *Arr = dyn_cast<ArraySubscriptExpr>(Inner))
2278 return getParentTracker().track(
2279 Arr->getIdx(), LVNode,
2280 {Opts.Kind, false});
2287class InterestingLValueHandler final :
public ExpressionHandler {
2291 Tracker::Result handle(
const Expr *Inner,
const ExplodedNode *InputNode,
2292 const ExplodedNode *LVNode,
2293 TrackingOptions Opts)
override {
2296 PathSensitiveBugReport &
Report = getParentTracker().getReport();
2302 SVal LVal = LVNode->
getSVal(Inner);
2305 bool LVIsNull = LVState->isNull(LVal).isConstrainedTrue();
2310 if (RR && !LVIsNull)
2311 Result.combineWith(getParentTracker().track(LVal, RR, Opts, SF));
2317 const MemRegion *
R =
2318 (RR && LVIsNull) ? RR : LVNode->getSVal(Inner).getAsRegion();
2323 SVal
V = LVState->getRawSVal(loc::MemRegionVal(R));
2328 Result.FoundSomethingToTrack =
true;
2329 Result.WasInterrupted =
true;
2331 MacroNullReturnSuppressionVisitor::addMacroVisitorIfNecessary(
2335 Report.addVisitor<UndefOrNullArgVisitor>(
R);
2339 if (
V.getAsLocSymbol(
true))
2340 if (LVState->isNull(
V).isConstrainedTrue())
2341 Report.addVisitor<TrackConstraintBRVisitor>(
2342 V.castAs<DefinedSVal>(),
2343 false,
"Assuming pointer value is null");
2346 if (
auto DV =
V.getAs<DefinedSVal>())
2354 Report.addVisitor<SuppressInlineDefensiveChecksVisitor>(*DV,
2356 getParentTracker().track(
V, R, Opts, SF);
2371class InlinedFunctionCallHandler final :
public ExpressionHandler {
2374 Tracker::Result handle(
const Expr *E,
const ExplodedNode *InputNode,
2375 const ExplodedNode *ExprNode,
2376 TrackingOptions Opts)
override {
2391 if (std::optional<CallExitEnd> CEE =
2393 if (CEE->getCalleeStackFrame()->getCallSite() == E)
2406 if (!BypassCXXNewExprEval)
2407 if (std::optional<StmtPoint> SP = ExprNode->
getLocationAs<StmtPoint>())
2409 if (SP->getStmt() == E && CurrentSF == PredSF)
2422 std::optional<CallExitEnd> CEE = ExprNode->
getLocationAs<CallExitEnd>();
2426 const StackFrame *CalleeSF = CEE->getCalleeStackFrame();
2432 SVal RetVal = ExprNode->
getSVal(E);
2436 if (std::optional<Loc> LValue = RetVal.
getAs<Loc>())
2437 RetVal = State->getSVal(*LValue);
2440 AnalyzerOptions &Options = State->getAnalysisManager().options;
2442 bool EnableNullFPSuppression =
false;
2444 if (std::optional<Loc> RetLoc = RetVal.
getAs<Loc>())
2445 EnableNullFPSuppression = State->isNull(*RetLoc).isConstrainedTrue();
2447 PathSensitiveBugReport &
Report = getParentTracker().getReport();
2448 Report.addVisitor<ReturnVisitor>(&getParentTracker(), CalleeSF,
2449 EnableNullFPSuppression, Options,
2455class DefaultExpressionHandler final :
public ExpressionHandler {
2459 Tracker::Result handle(
const Expr *Inner,
const ExplodedNode *InputNode,
2460 const ExplodedNode *LVNode,
2461 TrackingOptions Opts)
override {
2464 PathSensitiveBugReport &
Report = getParentTracker().getReport();
2469 SVal
V = LVState->getSValAsScalarOrLoc(Inner, LVNode->
getStackFrame());
2472 if (
auto L =
V.getAs<loc::MemRegionVal>()) {
2477 bool CanDereference =
true;
2478 if (
const auto *SR = L->getRegionAs<SymbolicRegion>()) {
2479 if (SR->getPointeeStaticType()->isVoidType())
2480 CanDereference =
false;
2481 }
else if (L->getRegionAs<AllocaRegion>())
2482 CanDereference =
false;
2489 RVal = LVState->getRawSVal(*L, Inner->
getType());
2490 else if (CanDereference)
2491 RVal = LVState->getSVal(L->getRegion());
2493 if (CanDereference) {
2494 Report.addVisitor<UndefOrNullArgVisitor>(L->getRegion());
2495 Result.FoundSomethingToTrack =
true;
2499 getParentTracker().track(RVal, L->getRegion(), Opts, SF));
2503 if (isa_and_nonnull<SymbolicRegion>(RegionRVal)) {
2504 Report.markInteresting(RegionRVal, Opts.
Kind);
2505 Report.addVisitor<TrackConstraintBRVisitor>(
2506 loc::MemRegionVal(RegionRVal),
2507 false,
"Assuming pointer value is null");
2508 Result.FoundSomethingToTrack =
true;
2518class PRValueHandler final :
public ExpressionHandler {
2522 Tracker::Result handle(
const Expr *E,
const ExplodedNode *InputNode,
2523 const ExplodedNode *ExprNode,
2524 TrackingOptions Opts)
override {
2532 Tracker::Result CombinedResult;
2533 Tracker &Parent = getParentTracker();
2535 const auto track = [&CombinedResult, &Parent, ExprNode,
2536 Opts](
const Expr *Inner) {
2545 if (
const auto *ILE = dyn_cast<InitListExpr>(E)) {
2546 if (ILE->getNumInits() == 1) {
2547 track(ILE->getInit(0));
2549 return CombinedResult;
2556 SVal
V = RVState->getSValAsScalarOrLoc(E, RVNode->
getStackFrame());
2557 const auto *BO = dyn_cast<BinaryOperator>(E);
2559 if (!BO || !BO->isMultiplicativeOp() || !
V.isZeroConstant())
2562 SVal RHSV = RVState->getSVal(BO->getRHS(), RVNode->
getStackFrame());
2563 SVal LHSV = RVState->getSVal(BO->getLHS(), RVNode->
getStackFrame());
2566 if (BO->getOpcode() == BO_Mul) {
2568 track(BO->getLHS());
2570 track(BO->getRHS());
2573 track(BO->getLHS());
2576 return CombinedResult;
2606 for (ExpressionHandlerPtr &Handler : ExpressionHandlers) {
2607 CombinedResult.
combineWith(Handler->handle(Inner, N, LVNode, Opts));
2616 return CombinedResult;
2621 if (!
V.isUnknown()) {
2622 Report.addVisitor<StoreSiteFinder>(
this,
V, R, Opts, Origin);
2631 for (StoreHandlerPtr &Handler : StoreHandlers) {
2646 ->track(E, InputNode, Opts)
2647 .FoundSomethingToTrack;
2663 const auto *ME = dyn_cast<ObjCMessageExpr>(S);
2666 if (
const Expr *Receiver = ME->getInstanceReceiver()) {
2669 if (state->isNull(
V).isConstrainedTrue())
2682 const Stmt *S = P->getStmt();
2688 llvm::raw_svector_ostream
OS(Buf);
2690 if (
const auto *ME = dyn_cast<ObjCMessageExpr>(S)) {
2692 ME->getSelector().print(
OS);
2693 OS <<
"' not called";
2696 OS <<
"No method is called";
2698 OS <<
" because the receiver is nil";
2709 return std::make_shared<PathDiagnosticEventPiece>(L,
OS.str());
2726 if (
auto *ev = dyn_cast<PathDiagnosticEventPiece>(piece.get()))
2727 ev->setPrunable(
true,
false);
2737 const std::pair<const ProgramPointTag *, const ProgramPointTag *> &Tags =
2742 if (std::optional<BlockEdge> BE = ProgPoint.
getAs<
BlockEdge>()) {
2743 const CFGBlock *SrcBlock = BE->getSrc();
2751 if (PreviousNodeTag == Tags.first || PreviousNodeTag == Tags.second)
2759 if (std::optional<PostStmt> PS = ProgPoint.
getAs<
PostStmt>()) {
2761 if (CurrentNodeTag != Tags.first && CurrentNodeTag != Tags.second)
2764 bool TookTrue = CurrentNodeTag == Tags.first;
2795 case Stmt::IfStmtClass: {
2798 if (IfStatement->isConsteval())
2800 Cond = IfStatement->getCond();
2803 case Stmt::ConditionalOperatorClass:
2806 case Stmt::BinaryOperatorClass:
2811 assert(BO->isLogicalOp() &&
2812 "CFG terminator is not a short-circuit operator!");
2813 Cond = BO->getLHS();
2822 while (
const auto *InnerBO = dyn_cast<BinaryOperator>(
Cond)) {
2823 if (!InnerBO->isLogicalOp())
2825 Cond = InnerBO->getRHS()->IgnoreParens();
2830 const bool TookTrue = *(srcBlk->
succ_begin()) == dstBlk;
2858 CurrentState->getSVal(
Cond, SF).isUnknownOrUndef();
2863 bool TookTrueTmp = TookTrue;
2870 case Stmt::BinaryOperatorClass:
2872 BRC, R, N, TookTrueTmp, IsAssuming))
2875 case Stmt::DeclRefExprClass:
2877 BRC, R, N, TookTrueTmp, IsAssuming))
2880 case Stmt::MemberExprClass:
2882 BRC, R, N, TookTrueTmp, IsAssuming))
2885 case Stmt::UnaryOperatorClass: {
2887 if (UO->getOpcode() == UO_LNot) {
2888 TookTrueTmp = !TookTrueTmp;
2889 CondTmp = UO->getSubExpr();
2909 return std::make_shared<PathDiagnosticEventPiece>(
2910 Loc, TookTrue ? GenericTrueMessage : GenericFalseMessage);
2917 std::optional<bool> &prunable,
2918 bool IsSameFieldName) {
2919 const Expr *OriginalExpr = Ex;
2940 if (
const auto *DR = dyn_cast<DeclRefExpr>(Ex)) {
2958 Out << DR->getDecl()->getDeclName().getAsString();
2964 if (
const auto *IL = dyn_cast<IntegerLiteral>(Ex)) {
2967 if (IL->getValue() == 0) {
2973 if (IL->getValue() == 0) {
2979 Out << IL->getValue();
2983 if (
const auto *ME = dyn_cast<MemberExpr>(Ex)) {
2984 if (!IsSameFieldName)
2985 Out <<
"field '" << ME->getMemberDecl()->getName() <<
'\'';
3002 bool shouldInvert =
false;
3003 std::optional<bool> shouldPrune;
3007 bool IsSameFieldName =
false;
3013 LhsME->getMemberDecl()->getName() == RhsME->getMemberDecl()->getName();
3017 llvm::raw_svector_ostream OutLHS(LhsString), OutRHS(RhsString);
3019 N, shouldPrune, IsSameFieldName);
3021 N, shouldPrune, IsSameFieldName);
3023 shouldInvert = !isVarLHS && isVarRHS;
3037 if (LhsString.empty() || RhsString.empty() ||
3043 llvm::raw_svector_ostream Out(buf);
3044 Out << (IsAssuming ?
"Assuming " :
"")
3045 << (shouldInvert ? RhsString : LhsString) <<
" is ";
3051 case BO_LT: Op = BO_GT;
break;
3052 case BO_GT: Op = BO_LT;
break;
3053 case BO_LE: Op = BO_GE;
break;
3054 case BO_GE: Op = BO_LE;
break;
3059 case BO_EQ: Op = BO_NE;
break;
3060 case BO_NE: Op = BO_EQ;
break;
3061 case BO_LT: Op = BO_GE;
break;
3062 case BO_GT: Op = BO_LE;
break;
3063 case BO_LE: Op = BO_GT;
break;
3064 case BO_GE: Op = BO_LT;
break;
3074 Out <<
"not equal to ";
3081 Out << (shouldInvert ? LhsString : RhsString);
3090 std::string Message = std::string(Out.str());
3091 Message[0] = toupper(Message[0]);
3096 if (!shouldInvert) {
3097 if (LhsME && LhsME->getMemberLoc().isValid())
3102 if (RhsME && RhsME->getMemberLoc().isValid())
3108 return std::make_shared<PathDiagnosticPopUpPiece>(
Loc, Message);
3112 auto event = std::make_shared<PathDiagnosticEventPiece>(
Loc, Message);
3114 event->setPrunable(*shouldPrune);
3125 llvm::raw_svector_ostream Out(buf);
3126 Out <<
"Assuming " << LhsString <<
" is ";
3128 if (!
printValue(CondVarExpr, Out, N, TookTrue,
true))
3137 auto event = std::make_shared<PathDiagnosticEventPiece>(
Loc, Out.str());
3140 event->setPrunable(
false);
3149 const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl());
3154 llvm::raw_svector_ostream Out(Buf);
3156 Out << (IsAssuming ?
"Assuming '" :
"'") << VD->getDeclName() <<
"' is ";
3158 if (!
printValue(DRE, Out, N, TookTrue, IsAssuming))
3169 return std::make_shared<PathDiagnosticPopUpPiece>(
Loc, Out.str());
3173 auto event = std::make_shared<PathDiagnosticEventPiece>(
Loc, Out.str());
3176 event->setPrunable(
false);
3178 return std::move(event);
3186 llvm::raw_svector_ostream Out(Buf);
3188 Out << (IsAssuming ?
"Assuming field '" :
"Field '")
3191 if (!
printValue(ME, Out, N, TookTrue, IsAssuming))
3211 return std::make_shared<PathDiagnosticPopUpPiece>(
Loc, Out.str());
3213 auto event = std::make_shared<PathDiagnosticEventPiece>(
Loc, Out.str());
3215 event->setPrunable(
false);
3225 Out << (TookTrue ?
"non-null" :
"null");
3230 Out << (TookTrue ?
"non-nil" :
"nil");
3237 std::optional<const llvm::APSInt *> IntValue;
3241 if (IsAssuming || !IntValue) {
3243 Out << (TookTrue ?
"true" :
"false");
3245 Out << (TookTrue ?
"not equal to 0" :
"0");
3248 Out << ((*IntValue)->getBoolValue() ?
"true" :
"false");
3258 return Piece->
getString() == GenericTrueMessage ||
3259 Piece->
getString() == GenericFalseMessage;
3279 if (Options.ShouldSuppressFromCXXStandardLibrary) {
3289 if (
const auto *MD = dyn_cast<CXXMethodDecl>(D)) {
3291 if (CD->
getName() ==
"list") {
3299 if (
const auto *MD = dyn_cast<CXXConstructorDecl>(D)) {
3301 if (CD->
getName() ==
"__independent_bits_engine") {
3308 const auto *MD = dyn_cast<CXXMethodDecl>(SF->
getDecl());
3319 if (CD->
getName() ==
"basic_string") {
3327 if (CD->
getName() ==
"shared_ptr") {
3339 while (
Loc.isMacroID()) {
3340 Loc =
Loc.getSpellingLoc();
3341 if (
SM.getFilename(
Loc).ends_with(
"sys/queue.h")) {
3369 for (
const auto ParamDecl : parms) {
3370 const MemRegion *ArgReg =
Call->getArgSVal(Idx).getAsRegion();
3378 assert(ParamDecl &&
"Formal parameter has no decl?");
3381 if (!(T->isAnyPointerType() || T->isReferenceType())) {
3388 if (T->getPointeeType().isConstQualified())
3393 SVal BoundVal = State->getSVal(R);
3406int NoteTag::Kind = 0;
3410 ID.AddPointer(&Tag);
3421 if (std::optional<std::string> Msg = T->generateMessage(BRC, R)) {
3424 auto Piece = std::make_shared<PathDiagnosticEventPiece>(
Loc, *Msg);
3425 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.
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
const StackFrame * getStackFrame() const
std::optional< T > getAs() const
Convert to the specified ProgramPoint type, returning std::nullopt if this ProgramPoint is not of the...
A (possibly-)qualified type.
bool isNull() const
Return true if this QualType doesn't point to a type yet.
QualType getCanonicalType() const
bool isConstQualified() const
Determine whether this type is const-qualified.
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.
bool isParentOf(const StackFrame *SF) const
LLVM_ATTRIBUTE_RETURNS_NONNULL AnalysisDeclContext * getAnalysisDeclContext() const
const Expr * getCallSite() const
const Decl * getDecl() const
const StackFrame * getParent() const
It might return null.
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()
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 StackFrame *SF) 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.