48#include "llvm/ADT/ArrayRef.h"
49#include "llvm/ADT/STLExtras.h"
50#include "llvm/ADT/SmallPtrSet.h"
51#include "llvm/ADT/SmallString.h"
52#include "llvm/ADT/SmallVector.h"
53#include "llvm/ADT/StringExtras.h"
54#include "llvm/ADT/StringRef.h"
55#include "llvm/Support/Casting.h"
56#include "llvm/Support/ErrorHandling.h"
57#include "llvm/Support/raw_ostream.h"
68using namespace bugreporter;
102 const auto *
E = dyn_cast<Expr>(S);
107 if (
const auto *CE = dyn_cast<CastExpr>(
E)) {
108 if (CE->getCastKind() == CK_LValueToRValue) {
112 E = CE->getSubExpr();
113 }
else if (
const auto *B = dyn_cast<BinaryOperator>(
E)) {
117 }
else if (B->isAssignmentOp()) {
125 }
else if (
const auto *
U = dyn_cast<UnaryOperator>(
E)) {
126 if (
U->getOpcode() == UO_Deref ||
U->getOpcode() == UO_AddrOf ||
127 (
U->isIncrementDecrementOp() &&
U->getType()->isPointerType())) {
138 else if (
const auto *ME = dyn_cast<MemberExpr>(
E)) {
147 if (ME->getMemberDecl()->getType()->isReferenceType())
150 }
else if (
const auto *IvarRef = dyn_cast<ObjCIvarRefExpr>(
E)) {
151 E = IvarRef->getBase();
152 }
else if (
const auto *AE = dyn_cast<ArraySubscriptExpr>(
E)) {
154 }
else if (
const auto *PE = dyn_cast<ParenExpr>(
E)) {
155 E = PE->getSubExpr();
156 }
else if (
const auto *FE = dyn_cast<FullExpr>(
E)) {
157 E = FE->getSubExpr();
167 if (
const auto *CE = dyn_cast<ImplicitCastExpr>(
E))
168 if (CE->getCastKind() == CK_LValueToRValue)
169 E = CE->getSubExpr();
175 if (
const auto *DR = dyn_cast<DeclRefExpr>(
E))
176 return dyn_cast<VarDecl>(DR->getDecl());
182 bool LookingForReference =
true) {
183 if (
const auto *ME = dyn_cast<MemberExpr>(
E)) {
193 const auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl());
197 if (FD->getType()->isReferenceType()) {
199 return N->
getState()->getLValue(FD, StructSVal).getAsRegion();
222 if (LeftVal == RightVal)
233 return LLCV->
getRegion() == RLCV->getRegion() &&
234 LLCV->getStore() == LeftNode->
getState()->getStore() &&
235 RLCV->getStore() == RightNode->
getState()->getStore();
250 if (
const auto *DRE = dyn_cast<DeclRefExpr>(CondVarExpr))
251 if (
const auto *VD = dyn_cast<VarDecl>(DRE->getDecl()))
252 return State->getSVal(State->getLValue(VD, LCtx));
254 if (
const auto *ME = dyn_cast<MemberExpr>(CondVarExpr))
255 if (
const auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl()))
256 if (
auto FieldL = State->getSVal(ME, LCtx).getAs<
Loc>())
257 return State->getRawSVal(*FieldL, FD->getType());
262static std::optional<const llvm::APSInt *>
267 return CI->getValue().get();
281 if (std::optional<bugreporter::TrackingKind> K =
283 return *K == bugreporter::TrackingKind::Condition;
308 if (!
Loc.isMacroID())
310 while (
SM.isMacroArgExpansion(
Loc))
311 Loc =
SM.getImmediateExpansionRange(
Loc).getBegin();
312 std::pair<FileID, unsigned> TLInfo =
SM.getDecomposedLoc(
Loc);
339 SVal ValueAtN = N->
getState()->getSVal(RegionOfInterest);
341 .
areEqual(State, ValueAtN, ValueAfter)
372 auto P = std::make_shared<PathDiagnosticEventPiece>(
384bool NoStateChangeFuncVisitor::isModifiedInFrame(
const ExplodedNode *N) {
387 if (!FramesModifyingCalculated.count(SCtx))
388 findModifyingFrames(N);
389 return FramesModifying.count(SCtx);
392void NoStateChangeFuncVisitor::markFrameAsModifying(
395 auto p = FramesModifying.insert(SCtx);
411 auto IsMatchingCallExitEnd = [OrigSCtx](
const ExplodedNode *N) {
415 while (N && !IsMatchingCallExitEnd(N)) {
417 "This function is to be used on the trimmed ExplodedGraph!");
423void NoStateChangeFuncVisitor::findModifyingFrames(
431 const ExplodedNode *CurrCallExitBeginN = CallExitBeginN;
438 CurrCallExitBeginN = CurrN;
440 FramesModifyingCalculated.insert(CurrentSCtx);
445 if (
auto CE = CurrN->getLocationAs<
CallEnter>()) {
448 markFrameAsModifying(CurrentSCtx);
459 if (CE->getCalleeContext() == OriginalSCtx) {
460 markFrameAsModifying(CurrentSCtx);
466 markFrameAsModifying(CurrentSCtx);
479 if (!CallExitLoc || isModifiedInFrame(N))
494 if (
Call->isInSystemHeader()) {
509 if (
const auto *MC = dyn_cast<ObjCMethodCall>(
Call)) {
516 if (
const auto *CCall = dyn_cast<CXXConstructorCall>(
Call)) {
529 using namespace ast_matchers;
530 const char *IvarBind =
"Ivar";
534 hasOperatorName(
"="),
535 hasLHS(ignoringParenImpCasts(
541 if (IvarRef->isFreeIvar())
544 const Expr *
Base = IvarRef->getBase();
545 if (
const auto *ICE = dyn_cast<ImplicitCastExpr>(
Base))
546 Base = ICE->getSubExpr();
548 if (
const auto *DRE = dyn_cast<DeclRefExpr>(
Base))
549 if (
const auto *ID = dyn_cast<ImplicitParamDecl>(DRE->getDecl()))
564const std::optional<NoStoreFuncVisitor::RegionVector>
565NoStoreFuncVisitor::findRegionOfInterestInRecord(
570 if (depth == DEREFERENCE_LIMIT)
573 if (
const auto *RDX = dyn_cast<CXXRecordDecl>(RD))
574 if (!RDX->hasDefinition())
579 if (
const auto *RDX = dyn_cast<CXXRecordDecl>(RD))
580 for (
const auto &II : RDX->bases())
581 if (
const RecordDecl *RRD = II.getType()->getAsRecordDecl())
582 if (std::optional<RegionVector> Out =
583 findRegionOfInterestInRecord(RRD, State, R, Vec, depth))
589 const SVal V = State->getSVal(FR);
592 RegionVector VecF = Vec;
595 if (RegionOfInterest == VR)
600 findRegionOfInterestInRecord(RRD, State, FR, VecF, depth + 1))
608 if (std::optional<RegionVector> Out =
609 findRegionOfInterestInRecord(RRD, State, VR, VecF, depth + 1))
620 if (
const auto *IvarR = dyn_cast<ObjCIvarRegion>(RegionOfInterest)) {
621 const MemRegion *SelfRegion =
Call.getReceiverSVal().getAsRegion();
625 return maybeEmitNote(R,
Call, N, {}, SelfRegion,
"self",
637 return maybeEmitNote(R,
Call, N, {}, ThisR,
"this",
654 for (
unsigned I = 0; I <
Call.getNumArgs() && I <
Parameters.size(); ++I) {
660 unsigned IndirectionLevel = 1;
662 while (
const MemRegion *MR =
V.getAsRegion()) {
664 return maybeEmitNote(R,
Call, N, {}, MR, ParamName,
665 ParamIsReferenceType, IndirectionLevel);
668 if (PT.isNull() || PT->isVoidType())
673 if (
const RecordDecl *RD = PT->getAsRecordDecl())
674 if (std::optional<RegionVector>
P =
675 findRegionOfInterestInRecord(RD, State, MR))
676 return maybeEmitNote(R,
Call, N, *
P, RegionOfInterest, ParamName,
677 ParamIsReferenceType, IndirectionLevel);
679 V = State->getSVal(MR, PT);
688bool NoStoreFuncVisitor::wasModifiedBeforeCallExit(
690 return ::wasRegionOfInterestModifiedAt(
691 RegionOfInterest, CurrN,
692 CallExitBeginN->
getState()->getSVal(RegionOfInterest));
696 ", which participates in a condition later";
700 const RegionVector &FieldChain,
const MemRegion *MatchedRegion,
701 StringRef FirstElement,
bool FirstIsReferenceType,
702 unsigned IndirectionLevel) {
714 llvm::raw_svector_ostream os(sbuf);
715 os <<
"Returning without writing to '";
718 if (!prettyPrintRegionName(FieldChain, MatchedRegion, FirstElement,
719 FirstIsReferenceType, IndirectionLevel, os))
725 return std::make_shared<PathDiagnosticEventPiece>(L, os.str());
728bool NoStoreFuncVisitor::prettyPrintRegionName(
const RegionVector &FieldChain,
730 StringRef FirstElement,
731 bool FirstIsReferenceType,
732 unsigned IndirectionLevel,
733 llvm::raw_svector_ostream &os) {
735 if (FirstIsReferenceType)
738 RegionVector RegionSequence;
743 while (R != MatchedRegion) {
744 RegionSequence.push_back(R);
745 R = cast<SubRegion>(R)->getSuperRegion();
747 std::reverse(RegionSequence.begin(), RegionSequence.end());
748 RegionSequence.append(FieldChain.begin(), FieldChain.end());
751 for (
const MemRegion *R : RegionSequence) {
755 if (isa<CXXBaseObjectRegion, CXXTempObjectRegion>(R))
759 Sep = prettyPrintFirstElement(FirstElement,
761 IndirectionLevel, os);
766 if (!isa<DeclRegion>(R))
769 const auto *DR = cast<DeclRegion>(R);
770 Sep = DR->getValueType()->isAnyPointerType() ?
"->" :
".";
771 DR->getDecl()->getDeclName().print(os, PP);
775 prettyPrintFirstElement(FirstElement,
776 false, IndirectionLevel, os);
780StringRef NoStoreFuncVisitor::prettyPrintFirstElement(
781 StringRef FirstElement,
bool MoreItemsExpected,
int IndirectionLevel,
782 llvm::raw_svector_ostream &os) {
785 if (IndirectionLevel > 0 && MoreItemsExpected) {
790 if (IndirectionLevel > 0 && MoreItemsExpected)
793 for (
int i = 0; i < IndirectionLevel; i++)
797 if (IndirectionLevel > 0 && MoreItemsExpected)
813 const SVal ValueAtDereference;
817 bool WasModified =
false;
820 MacroNullReturnSuppressionVisitor(
const SubRegion *R,
const SVal V)
821 : RegionOfInterest(R), ValueAtDereference(
V) {}
834 if (
auto Loc = matchAssignment(N)) {
849 static void addMacroVisitorIfNecessary(
854 if (EnableNullFPSuppression && Options.ShouldSuppressNullReturnPaths &&
860 void* getTag()
const {
862 return static_cast<void *
>(&
Tag);
865 void Profile(llvm::FoldingSetNodeID &
ID)
const override {
866 ID.AddPointer(getTag());
872 std::optional<SourceLocation> matchAssignment(
const ExplodedNode *N) {
879 if (
const auto *DS = dyn_cast<DeclStmt>(S)) {
880 if (
const auto *VD = dyn_cast<VarDecl>(DS->getSingleDecl()))
881 if (
const Expr *RHS = VD->getInit())
882 if (RegionOfInterest->isSubRegionOf(
883 State->getLValue(VD, LCtx).getAsRegion()))
884 return RHS->getBeginLoc();
885 }
else if (
const auto *BO = dyn_cast<BinaryOperator>(S)) {
887 const Expr *RHS = BO->getRHS();
888 if (BO->isAssignmentOp() && RegionOfInterest->isSubRegionOf(R)) {
915 bool EnableNullFPSuppression;
916 bool ShouldInvalidate =
true;
925 EnableNullFPSuppression(Suppressed), Options(Options), TKind(TKind) {}
927 static void *getTag() {
929 return static_cast<void *
>(&
Tag);
932 void Profile(llvm::FoldingSetNodeID &
ID)
const override {
933 ID.AddPointer(ReturnVisitor::getTag());
934 ID.AddPointer(CalleeSFC);
935 ID.AddBoolean(EnableNullFPSuppression);
949 const auto *
Ret = dyn_cast<ReturnStmt>(SP->getStmt());
956 SVal V = State->getSVal(Ret, CalleeSFC);
957 if (
V.isUnknownOrUndef())
963 const Expr *RetE =
Ret->getRetValue();
964 assert(RetE &&
"Tracking a return value for a void function");
967 std::optional<Loc> LValue;
969 if ((LValue =
V.getAs<
Loc>())) {
970 SVal RValue = State->getRawSVal(*LValue, RetE->
getType());
971 if (isa<DefinedSVal>(RValue))
977 if (isa<nonloc::LazyCompoundVal, nonloc::CompoundVal>(
V))
983 getParentTracker().track(RetE, N, {TKind, EnableNullFPSuppression});
987 llvm::raw_svector_ostream Out(Msg);
989 bool WouldEventBeMeaningless =
false;
991 if (State->isNull(
V).isConstrainedTrue()) {
997 if (EnableNullFPSuppression &&
998 Options.ShouldAvoidSuppressingNullArgumentPaths)
999 Mode = MaybeUnsuppress;
1002 Out <<
"Returning nil";
1004 Out <<
"Returning null pointer";
1007 Out <<
"Returning zero";
1012 Out <<
"Returning the value " << CI->getValue();
1020 WouldEventBeMeaningless =
true;
1022 Out << (isa<Loc>(
V) ?
"Returning pointer" :
"Returning value");
1027 if (
const MemRegion *MR = LValue->getAsRegion()) {
1028 if (MR->canPrintPretty()) {
1029 Out <<
" (reference to ";
1030 MR->printPretty(Out);
1036 if (
const auto *DR = dyn_cast<DeclRefExpr>(RetE))
1037 if (
const auto *DD = dyn_cast<DeclaratorDecl>(DR->getDecl()))
1038 Out <<
" (loaded from '" << *DD <<
"')";
1042 if (!L.isValid() || !L.asLocation().isValid())
1045 if (TKind == bugreporter::TrackingKind::Condition)
1048 auto EventPiece = std::make_shared<PathDiagnosticEventPiece>(L, Out.str());
1052 if (WouldEventBeMeaningless)
1053 EventPiece->setPrunable(
true);
1063 assert(Options.ShouldAvoidSuppressingNullArgumentPaths);
1070 if (CE->getCalleeContext() != CalleeSFC)
1083 for (
unsigned I = 0,
E =
Call->getNumArgs(); I !=
E; ++I) {
1084 std::optional<Loc> ArgV =
Call->getArgSVal(I).getAs<
Loc>();
1088 const Expr *ArgE =
Call->getArgExpr(I);
1093 if (!State->isNull(*ArgV).isConstrainedTrue())
1096 if (getParentTracker()
1097 .track(ArgE, N, {TKind, EnableNullFPSuppression})
1098 .FoundSomethingToTrack)
1099 ShouldInvalidate =
false;
1114 return visitNodeInitial(N, BRC, BR);
1115 case MaybeUnsuppress:
1116 return visitNodeMaybeUnsuppress(N, BRC, BR);
1121 llvm_unreachable(
"Invalid visit mode!");
1126 if (EnableNullFPSuppression && ShouldInvalidate)
1127 BR.
markInvalid(ReturnVisitor::getTag(), CalleeSFC);
1140 bool Satisfied =
false;
1160 OriginSFC(OriginSFC) {
1164 void Profile(llvm::FoldingSetNodeID &
ID)
const override;
1172void StoreSiteFinder::Profile(llvm::FoldingSetNodeID &ID)
const {
1174 ID.AddPointer(&tag);
1177 ID.AddInteger(
static_cast<int>(Options.Kind));
1178 ID.AddBoolean(Options.EnableNullFPSuppression);
1196 const auto *FrameSpace = dyn_cast<StackSpaceRegion>(VarSpace);
1212 if (
const auto *TR = dyn_cast<TypedValueRegion>(R))
1213 return TR->getValueType()->isObjCObjectPointerType();
1219 return D->getType()->isObjCObjectPointerType();
1231 const char *Action =
nullptr;
1235 Action = HasPrefix ?
"initialized to " :
"Initializing to ";
1238 Action = HasPrefix ?
"captured by block as " :
"Captured by block as ";
1241 llvm_unreachable(
"Unexpected store kind");
1244 if (isa<loc::ConcreteInt>(SI.
Value)) {
1248 OS << Action << CVal->getValue();
1251 OS << Action <<
"the value of ";
1262 if (isa<VarRegion>(SI.
Dest)) {
1263 const auto *VD = cast<VarDecl>(DS->getSingleDecl());
1265 if (VD->getInit()) {
1266 OS << (HasPrefix ?
"initialized" :
"Initializing")
1267 <<
" to a garbage value";
1269 OS << (HasPrefix ?
"declared" :
"Declaring")
1270 <<
" without an initial value";
1274 OS << (HasPrefix ?
"initialized" :
"Initialized") <<
" here";
1282 const auto *VR = cast<VarRegion>(SI.
Dest);
1283 const auto *
D = VR->getDecl();
1287 if (isa<loc::ConcreteInt>(SI.
Value)) {
1291 OS <<
"uninitialized value";
1294 OS <<
"the value " << CI->getValue();
1303 if (
const auto *Param = dyn_cast<ParmVarDecl>(VR->getDecl())) {
1305 unsigned Idx = Param->getFunctionScopeIndex() + 1;
1306 OS <<
" via " << Idx << llvm::getOrdinalSuffix(Idx) <<
" parameter";
1311 }
else if (
const auto *ImplParam = dyn_cast<ImplicitParamDecl>(
D)) {
1313 OS <<
" via implicit parameter 'self'";
1323 if (isa<loc::ConcreteInt>(SI.
Value)) {
1325 : (HasSuffix ?
"Null pointer value stored"
1326 :
"Storing null pointer value"));
1329 OS << (HasSuffix ?
"Uninitialized value stored"
1330 :
"Storing uninitialized value");
1334 OS <<
"The value " << CV->getValue() <<
" is assigned";
1336 OS <<
"Assigning " << CV->getValue();
1340 OS <<
"The value of ";
1342 OS <<
" is assigned";
1344 OS <<
"Assigning the value of ";
1349 OS << (HasSuffix ?
"Value assigned" :
"Assigning value");
1370 const auto *TVR = dyn_cast_or_null<TypedValueRegion>(R);
1378 std::stack<const TypedValueRegion *> TVRStack;
1379 while (isa<FieldRegion>(TVR) || isa<ElementRegion>(TVR)) {
1384 if (ITy == TVR->getValueType().getCanonicalType())
1388 TVR = cast<TypedValueRegion>(TVR->getSuperRegion());
1393 if (ITy != TVR->getValueType().getCanonicalType())
1397 while (!TVRStack.empty()) {
1398 TVR = TVRStack.top();
1403 if (!isa<InitListExpr>(
Init))
1406 ILE = cast<InitListExpr>(
Init);
1409 if (
const auto *FR = dyn_cast<FieldRegion>(TVR)) {
1410 const auto *FD = FR->
getDecl();
1412 if (FD->getFieldIndex() >= NumInits)
1416 }
else if (
const auto *ER = dyn_cast<ElementRegion>(TVR)) {
1417 const auto Ind = ER->getIndex();
1421 if (!Ind.isConstant())
1424 const auto IndVal = Ind.getAsInteger()->getLimitedValue();
1425 if (IndVal >= NumInits)
1443 const Expr *InitE =
nullptr;
1444 bool IsParam =
false;
1447 if (
const auto *VR = dyn_cast<VarRegion>(R)) {
1450 InitE = VR->getDecl()->getInit();
1456 if (std::optional<PostInitializer> PIP =
1459 if (FieldReg == R) {
1461 InitE = PIP->getInitializer()->getInit();
1476 if (!PS || PS->getLocationValue() != R)
1486 if (BO->isAssignmentOp())
1487 InitE = BO->getRHS();
1491 else if (
const auto *DS =
P->getStmtAs<
DeclStmt>()) {
1492 const auto *
Decl = DS->getSingleDecl();
1493 if (isa<VarDecl>(
Decl)) {
1494 const auto *VD = cast<VarDecl>(
Decl);
1502 if (
const auto *ILE = dyn_cast<InitListExpr>(VD->getInit()))
1507 const auto State = Succ->
getState();
1518 std::stack<const SubRegion *> SRStack;
1519 const SubRegion *SR = cast<SubRegion>(R);
1520 while (isa<FieldRegion>(SR) || isa<ElementRegion>(SR)) {
1526 const auto *OriginEx = CE->getArg(0);
1527 const auto OriginVal =
1533 SVal OriginField = OriginVal;
1534 while (!SRStack.empty()) {
1535 const auto *TopR = SRStack.top();
1538 if (
const auto *FR = dyn_cast<FieldRegion>(TopR)) {
1539 OriginField = State->getLValue(FR->
getDecl(), OriginField);
1540 }
else if (
const auto *ER = dyn_cast<ElementRegion>(TopR)) {
1541 OriginField = State->getLValue(ER->getElementType(),
1542 ER->getIndex(), OriginField);
1549 getParentTracker().track(
V, OriginField.
getAsRegion(), Options);
1570 if (
const auto *VR = dyn_cast<VarRegion>(R)) {
1572 if (
const auto *Param = dyn_cast<ParmVarDecl>(VR->getDecl())) {
1578 InitE =
Call->getArgExpr(Param->getFunctionScopeIndex());
1581 assert(isa<ImplicitParamDecl>(VR->getDecl()));
1582 InitE = cast<ObjCMessageExpr>(CE->getCalleeContext()->getCallSite())
1591 if (
const auto *TmpR = dyn_cast<CXXTempObjectRegion>(R))
1592 InitE = TmpR->getExpr();
1606 getParentTracker().track(InitE, StoreSite, Options);
1630 if (
SM.includedInBindings(N->
getState()->getStore(), Candidate)) {
1632 if (N->
getState()->getSVal(Candidate) ==
V) {
1633 OldRegion = Candidate;
1652 if (!OldRegion && StoreSite->
getState()->getSVal(R) ==
V) {
1657 NodeWithoutBinding && NodeWithoutBinding->
getState()->getSVal(R) ==
V;
1658 NodeWithoutBinding = NodeWithoutBinding->
getFirstPred()) {
1661 if (NodeWithoutBinding) {
1673 OldRegion = FB.getRegion();
1677 if (Options.Kind == TrackingKind::Condition && OriginSFC &&
1683 llvm::raw_svector_ostream os(sbuf);
1693 const Stmt *S = PS->getStmt();
1694 const auto *DS = dyn_cast<DeclStmt>(S);
1695 const auto *VR = dyn_cast<VarRegion>(R);
1699 }
else if (isa<BlockExpr>(S)) {
1705 if (
const auto *BDR =
1706 dyn_cast_or_null<BlockDataRegion>(
V.getAsRegion())) {
1707 if (
const VarRegion *OriginalR = BDR->getOriginalRegion(VR)) {
1708 getParentTracker().track(State->getSVal(OriginalR), OriginalR,
1709 Options, OriginSFC);
1715 isa<VarRegion>(SI.
Dest)) {
1719 return getParentTracker().handle(SI, BRC, Options);
1728 ID.AddPointer(&tag);
1729 ID.AddString(Message);
1730 ID.AddBoolean(Assumption);
1737 return "TrackConstraintBRVisitor";
1740bool TrackConstraintBRVisitor::isZeroCheck()
const {
1741 return !Assumption && Constraint.
getAs<
Loc>();
1744bool TrackConstraintBRVisitor::isUnderconstrained(
const ExplodedNode *N)
const {
1746 return N->
getState()->isNull(Constraint).isUnderconstrained();
1747 return (
bool)N->
getState()->assume(Constraint, !Assumption);
1758 if (!IsTrackingTurnedOn)
1759 if (!isUnderconstrained(N))
1760 IsTrackingTurnedOn =
true;
1761 if (!IsTrackingTurnedOn)
1766 if (isUnderconstrained(PrevN)) {
1773 assert(!isUnderconstrained(N));
1781 if (isa_and_nonnull<NoteTag>(
P.getTag()))
1789 auto X = std::make_shared<PathDiagnosticEventPiece>(L, Message);
1791 return std::move(
X);
1806 if (!Options.ShouldSuppressInlinedDefensiveChecks)
1811 llvm::FoldingSetNodeID &ID)
const {
1818 return "IDCVisitor";
1830 if (!IsTrackingTurnedOn)
1831 if (Succ->
getState()->isNull(
V).isConstrainedTrue())
1832 IsTrackingTurnedOn =
true;
1833 if (!IsTrackingTurnedOn)
1838 if (!Pred->
getState()->isNull(
V).isConstrainedTrue() &&
1839 Succ->
getState()->isNull(
V).isConstrainedTrue()) {
1845 if (CurLC != ReportLC && !CurLC->
isParentOf(ReportLC)) {
1860 const Stmt *CurTerminatorStmt =
nullptr;
1862 CurTerminatorStmt = BE->getSrc()->getTerminator().getStmt();
1864 const Stmt *CurStmt = SP->getStmt();
1874 if (!CurTerminatorStmt)
1908class TrackControlDependencyCondBRVisitor final
1912 llvm::SmallSet<const CFGBlock *, 32> VisitedBlocks;
1915 TrackControlDependencyCondBRVisitor(
TrackerRef ParentTracker,
1918 ControlDeps(&O->getCFG()) {}
1920 void Profile(llvm::FoldingSetNodeID &
ID)
const override {
1931static std::shared_ptr<PathDiagnosticEventPiece>
1944 return std::make_shared<PathDiagnosticEventPiece>(
1947 (Twine() +
"Tracking condition '" + ConditionText +
"'").str());
1975 if (
const auto *BinOp = dyn_cast<BinaryOperator>(ElseCond))
1976 if (BinOp->isLogicalOp())
1983TrackControlDependencyCondBRVisitor::VisitNode(
const ExplodedNode *N,
1993 if (!VisitedBlocks.insert(NB).second)
1999 if (!OriginB || !NB)
2005 if (ControlDeps.isControlDependent(OriginB, NB)) {
2031 if (isa<CallExpr>(InnerExpr))
2038 getParentTracker().track(InnerExpr, N,
2056 if (
const auto *FE = dyn_cast<FullExpr>(Ex))
2058 if (
const auto *OVE = dyn_cast<OpaqueValueExpr>(Ex))
2060 if (
const auto *POE = dyn_cast<PseudoObjectExpr>(Ex)) {
2061 const auto *PropRef = dyn_cast<ObjCPropertyRefExpr>(POE->getSyntacticForm());
2062 if (PropRef && PropRef->isMessagingGetter()) {
2063 const Expr *GetterMessageSend =
2064 POE->getSemanticExpr(POE->getNumSemanticExprs() - 1);
2071 if (
const auto *CO = dyn_cast<ConditionalOperator>(Ex)) {
2077 if (std::optional<BlockEdge> BE = ProgPoint.
getAs<
BlockEdge>()) {
2078 const CFGBlock *srcBlk = BE->getSrc();
2081 bool TookTrueBranch = (*(srcBlk->
succ_begin()) == BE->getDst());
2093 if (
auto *BO = dyn_cast<BinaryOperator>(Ex))
2097 if (
auto *UO = dyn_cast<UnaryOperator>(Ex)) {
2098 if (UO->getOpcode() == UO_LNot)
2109 if (UO->getOpcode() == UO_AddrOf && UO->getSubExpr()->isLValue())
2120 const Expr *Inner) {
2135 StringRef NodeText) {
2141 P.getLocationContext());
2149 return std::make_shared<PathDiagnosticEventPiece>(L, NodeText);
2161 llvm::raw_svector_ostream OS(Buffer);
2176 if (Opts.
Kind == bugreporter::TrackingKind::Condition)
2179 return constructNote(SI, BRC, OS.str());
2199 ->getAnalysisManager()
2200 .getAnalyzerOptions()
2201 .ShouldTrackConditions) {
2202 Report.addVisitor<TrackControlDependencyCondBRVisitor>(
2203 &getParentTracker(), InputNode);
2221 if (
const Expr *Receiver =
2223 return getParentTracker().track(Receiver, LVNode, Opts);
2237 if (
const auto *Arr = dyn_cast<ArraySubscriptExpr>(Inner))
2238 return getParentTracker().track(
2239 Arr->getIdx(), LVNode,
2240 {Opts.Kind, false});
2265 bool LVIsNull = LVState->isNull(LVal).isConstrainedTrue();
2270 if (RR && !LVIsNull)
2271 Result.combineWith(getParentTracker().track(LVal, RR, Opts, SFC));
2288 Result.FoundSomethingToTrack =
true;
2289 Result.WasInterrupted =
true;
2291 MacroNullReturnSuppressionVisitor::addMacroVisitorIfNecessary(
2299 if (
V.getAsLocSymbol(
true))
2300 if (LVState->isNull(
V).isConstrainedTrue())
2303 false,
"Assuming pointer value is null");
2316 getParentTracker().track(
V, R, Opts, SFC);
2344 const bool BypassCXXNewExprEval = isa<CXXNewExpr>(
E);
2351 if (std::optional<CallExitEnd> CEE =
2353 if (CEE->getCalleeContext()->getCallSite() ==
E)
2366 if (!BypassCXXNewExprEval)
2369 if (SP->getStmt() ==
E && CurrentSFC == PredSFC)
2372 CurrentSFC = PredSFC;
2395 if (cast<Expr>(
E)->isGLValue())
2396 if (std::optional<Loc> LValue = RetVal.
getAs<
Loc>())
2397 RetVal = State->getSVal(*LValue);
2402 bool EnableNullFPSuppression =
false;
2404 if (std::optional<Loc> RetLoc = RetVal.
getAs<
Loc>())
2405 EnableNullFPSuppression = State->isNull(*RetLoc).isConstrainedTrue();
2408 Report.addVisitor<ReturnVisitor>(&getParentTracker(), CalleeContext,
2409 EnableNullFPSuppression, Options,
2437 bool CanDereference =
true;
2439 if (SR->getPointeeStaticType()->isVoidType())
2440 CanDereference =
false;
2442 CanDereference =
false;
2449 RVal = LVState->getRawSVal(*L, Inner->getType());
2450 else if (CanDereference)
2451 RVal = LVState->getSVal(L->getRegion());
2453 if (CanDereference) {
2455 Result.FoundSomethingToTrack =
true;
2459 getParentTracker().track(RVal, L->getRegion(), Opts, SFC));
2463 if (isa_and_nonnull<SymbolicRegion>(RegionRVal)) {
2464 Report.markInteresting(RegionRVal, Opts.
Kind);
2467 false,
"Assuming pointer value is null");
2468 Result.FoundSomethingToTrack =
true;
2495 const auto track = [&CombinedResult, &
Parent, ExprNode,
2496 Opts](
const Expr *Inner) {
2505 if (
const auto *ILE = dyn_cast<InitListExpr>(
E)) {
2506 if (ILE->getNumInits() == 1) {
2507 track(ILE->getInit(0));
2509 return CombinedResult;
2517 const auto *BO = dyn_cast<BinaryOperator>(
E);
2519 if (!BO || !BO->isMultiplicativeOp() || !
V.isZeroConstant())
2526 if (BO->getOpcode() == BO_Mul) {
2528 track(BO->getLHS());
2530 track(BO->getRHS());
2533 track(BO->getLHS());
2536 return CombinedResult;
2543 addLowPriorityHandler<ControlDependencyHandler>();
2544 addLowPriorityHandler<NilReceiverHandler>();
2545 addLowPriorityHandler<ArrayIndexHandler>();
2546 addLowPriorityHandler<InterestingLValueHandler>();
2547 addLowPriorityHandler<InlinedFunctionCallHandler>();
2548 addLowPriorityHandler<DefaultExpressionHandler>();
2549 addLowPriorityHandler<PRValueHandler>();
2551 addHighPriorityHandler<DefaultStoreHandler>();
2566 for (ExpressionHandlerPtr &Handler : ExpressionHandlers) {
2567 CombinedResult.
combineWith(Handler->handle(Inner, N, LVNode, Opts));
2576 return CombinedResult;
2581 if (!
V.isUnknown()) {
2582 Report.addVisitor<StoreSiteFinder>(
this,
V, R, Opts, Origin);
2591 for (StoreHandlerPtr &Handler : StoreHandlers) {
2606 ->track(
E, InputNode, Opts)
2607 .FoundSomethingToTrack;
2623 const auto *ME = dyn_cast<ObjCMessageExpr>(S);
2626 if (
const Expr *Receiver = ME->getInstanceReceiver()) {
2629 if (state->isNull(
V).isConstrainedTrue())
2642 const Stmt *S =
P->getStmt();
2643 const Expr *Receiver = getNilReceiver(S, N);
2648 llvm::raw_svector_ostream
OS(Buf);
2650 if (
const auto *ME = dyn_cast<ObjCMessageExpr>(S)) {
2652 ME->getSelector().print(
OS);
2653 OS <<
"' not called";
2656 OS <<
"No method is called";
2658 OS <<
" because the receiver is nil";
2669 return std::make_shared<PathDiagnosticEventPiece>(L,
OS.str());
2683 auto piece = VisitNodeImpl(N, BRC, BR);
2685 piece->setTag(getTag());
2686 if (
auto *ev = dyn_cast<PathDiagnosticEventPiece>(piece.get()))
2687 ev->setPrunable(
true,
false);
2697 const std::pair<const ProgramPointTag *, const ProgramPointTag *> &Tags =
2702 if (std::optional<BlockEdge> BE = ProgPoint.
getAs<
BlockEdge>()) {
2703 const CFGBlock *SrcBlock = BE->getSrc();
2711 if (PreviousNodeTag == Tags.first || PreviousNodeTag == Tags.second)
2714 return VisitTerminator(Term, N, SrcBlock, BE->getDst(), BR, BRC);
2719 if (std::optional<PostStmt> PS = ProgPoint.
getAs<
PostStmt>()) {
2721 if (CurrentNodeTag != Tags.first && CurrentNodeTag != Tags.second)
2724 bool TookTrue = CurrentNodeTag == Tags.first;
2725 return VisitTrueTest(cast<Expr>(PS->getStmt()), BRC, BR, N, TookTrue);
2735 const Expr *Cond =
nullptr;
2755 case Stmt::IfStmtClass:
2756 Cond = cast<IfStmt>(Term)->getCond();
2758 case Stmt::ConditionalOperatorClass:
2759 Cond = cast<ConditionalOperator>(Term)->getCond();
2761 case Stmt::BinaryOperatorClass:
2765 const auto *BO = cast<BinaryOperator>(Term);
2766 assert(BO->isLogicalOp() &&
2767 "CFG terminator is not a short-circuit operator!");
2768 Cond = BO->getLHS();
2777 while (
const auto *InnerBO = dyn_cast<BinaryOperator>(Cond)) {
2778 if (!InnerBO->isLogicalOp())
2785 const bool TookTrue = *(srcBlk->
succ_begin()) == dstBlk;
2786 return VisitTrueTest(Cond, BRC, R, N, TookTrue);
2813 CurrentState->getSVal(Cond, LCtx).isUnknownOrUndef();
2817 const Expr *CondTmp = Cond;
2818 bool TookTrueTmp = TookTrue;
2825 case Stmt::BinaryOperatorClass:
2826 if (
auto P = VisitTrueTest(Cond, cast<BinaryOperator>(CondTmp),
2827 BRC, R, N, TookTrueTmp, IsAssuming))
2830 case Stmt::DeclRefExprClass:
2831 if (
auto P = VisitTrueTest(Cond, cast<DeclRefExpr>(CondTmp),
2832 BRC, R, N, TookTrueTmp, IsAssuming))
2835 case Stmt::MemberExprClass:
2836 if (
auto P = VisitTrueTest(Cond, cast<MemberExpr>(CondTmp),
2837 BRC, R, N, TookTrueTmp, IsAssuming))
2840 case Stmt::UnaryOperatorClass: {
2841 const auto *UO = cast<UnaryOperator>(CondTmp);
2842 if (UO->getOpcode() == UO_LNot) {
2843 TookTrueTmp = !TookTrueTmp;
2844 CondTmp = UO->getSubExpr();
2864 return std::make_shared<PathDiagnosticEventPiece>(
2865 Loc, TookTrue ? GenericTrueMessage : GenericFalseMessage);
2872 std::optional<bool> &prunable,
2873 bool IsSameFieldName) {
2874 const Expr *OriginalExpr = Ex;
2895 if (
const auto *DR = dyn_cast<DeclRefExpr>(Ex)) {
2896 const bool quotes = isa<VarDecl>(DR->getDecl());
2913 Out << DR->getDecl()->getDeclName().getAsString();
2919 if (
const auto *IL = dyn_cast<IntegerLiteral>(Ex)) {
2922 if (IL->getValue() == 0) {
2928 if (IL->getValue() == 0) {
2934 Out << IL->getValue();
2938 if (
const auto *ME = dyn_cast<MemberExpr>(Ex)) {
2939 if (!IsSameFieldName)
2940 Out <<
"field '" << ME->getMemberDecl()->getName() <<
'\'';
2957 bool shouldInvert =
false;
2958 std::optional<bool> shouldPrune;
2962 bool IsSameFieldName =
false;
2968 LhsME->getMemberDecl()->getName() == RhsME->getMemberDecl()->getName();
2972 llvm::raw_svector_ostream OutLHS(LhsString), OutRHS(RhsString);
2973 const bool isVarLHS = patternMatch(BExpr->
getLHS(), BExpr, OutLHS, BRC, R,
2974 N, shouldPrune, IsSameFieldName);
2975 const bool isVarRHS = patternMatch(BExpr->
getRHS(), BExpr, OutRHS, BRC, R,
2976 N, shouldPrune, IsSameFieldName);
2978 shouldInvert = !isVarLHS && isVarRHS;
2986 return VisitConditionVariable(LhsString, BExpr->
getLHS(), BRC, R, N,
2992 if (LhsString.empty() || RhsString.empty() ||
2998 llvm::raw_svector_ostream Out(buf);
2999 Out << (IsAssuming ?
"Assuming " :
"")
3000 << (shouldInvert ? RhsString : LhsString) <<
" is ";
3006 case BO_LT: Op = BO_GT;
break;
3007 case BO_GT: Op = BO_LT;
break;
3008 case BO_LE: Op = BO_GE;
break;
3009 case BO_GE: Op = BO_LE;
break;
3014 case BO_EQ: Op = BO_NE;
break;
3015 case BO_NE: Op = BO_EQ;
break;
3016 case BO_LT: Op = BO_GE;
break;
3017 case BO_GT: Op = BO_LE;
break;
3018 case BO_LE: Op = BO_GT;
break;
3019 case BO_GE: Op = BO_LT;
break;
3029 Out <<
"not equal to ";
3036 Out << (shouldInvert ? LhsString : RhsString);
3045 std::string Message = std::string(Out.str());
3046 Message[0] = toupper(Message[0]);
3051 if (!shouldInvert) {
3052 if (LhsME && LhsME->getMemberLoc().isValid())
3057 if (RhsME && RhsME->getMemberLoc().isValid())
3063 return std::make_shared<PathDiagnosticPopUpPiece>(
Loc, Message);
3067 auto event = std::make_shared<PathDiagnosticEventPiece>(
Loc, Message);
3069 event->setPrunable(*shouldPrune);
3080 llvm::raw_svector_ostream Out(buf);
3081 Out <<
"Assuming " << LhsString <<
" is ";
3083 if (!printValue(CondVarExpr, Out, N, TookTrue,
true))
3092 auto event = std::make_shared<PathDiagnosticEventPiece>(
Loc, Out.str());
3095 event->setPrunable(
false);
3104 const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl());
3109 llvm::raw_svector_ostream Out(Buf);
3111 Out << (IsAssuming ?
"Assuming '" :
"'") << VD->getDeclName() <<
"' is ";
3113 if (!printValue(DRE, Out, N, TookTrue, IsAssuming))
3124 return std::make_shared<PathDiagnosticPopUpPiece>(
Loc, Out.str());
3128 auto event = std::make_shared<PathDiagnosticEventPiece>(
Loc, Out.str());
3131 event->setPrunable(
false);
3133 return std::move(event);
3141 llvm::raw_svector_ostream Out(Buf);
3143 Out << (IsAssuming ?
"Assuming field '" :
"Field '")
3146 if (!printValue(ME, Out, N, TookTrue, IsAssuming))
3166 return std::make_shared<PathDiagnosticPopUpPiece>(
Loc, Out.str());
3168 auto event = std::make_shared<PathDiagnosticEventPiece>(
Loc, Out.str());
3170 event->setPrunable(
false);
3180 Out << (TookTrue ?
"non-null" :
"null");
3185 Out << (TookTrue ?
"non-nil" :
"nil");
3192 std::optional<const llvm::APSInt *> IntValue;
3196 if (IsAssuming || !IntValue) {
3198 Out << (TookTrue ?
"true" :
"false");
3200 Out << (TookTrue ?
"not equal to 0" :
"0");
3203 Out << ((*IntValue)->getBoolValue() ?
"true" :
"false");
3211constexpr llvm::StringLiteral ConditionBRVisitor::GenericTrueMessage;
3212constexpr llvm::StringLiteral ConditionBRVisitor::GenericFalseMessage;
3216 return Piece->
getString() == GenericTrueMessage ||
3217 Piece->
getString() == GenericFalseMessage;
3237 if (Options.ShouldSuppressFromCXXStandardLibrary) {
3247 if (
const auto *MD = dyn_cast<CXXMethodDecl>(
D)) {
3249 if (CD->
getName() ==
"list") {
3257 if (
const auto *MD = dyn_cast<CXXConstructorDecl>(
D)) {
3259 if (CD->
getName() ==
"__independent_bits_engine") {
3267 const auto *MD = dyn_cast<CXXMethodDecl>(LCtx->getDecl());
3278 if (CD->
getName() ==
"basic_string") {
3286 if (CD->
getName() ==
"shared_ptr") {
3298 while (
Loc.isMacroID()) {
3299 Loc =
Loc.getSpellingLoc();
3300 if (
SM.getFilename(
Loc).ends_with(
"sys/queue.h")) {
3328 for (
const auto ParamDecl : parms) {
3329 const MemRegion *ArgReg =
Call->getArgSVal(Idx).getAsRegion();
3337 assert(ParamDecl &&
"Formal parameter has no decl?");
3352 SVal BoundVal = State->getSVal(R);
3365int NoteTag::Kind = 0;
3369 ID.AddPointer(&Tag);
3380 if (std::optional<std::string> Msg =
T->generateMessage(BRC, R)) {
3383 auto Piece = std::make_shared<PathDiagnosticEventPiece>(
Loc, *Msg);
3384 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.
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
Defines the clang::SourceLocation class and associated facilities.
Defines the SourceManager interface.
C Language Family Type Representation.
static bool isPointerToConst(const QualType &QT)
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
const LangOptions & getLangOpts() const
CFGStmtMap * getCFGStmtMap()
static bool isInStdNamespace(const Decl *D)
Stores options for the analyzer from the command line.
AnalysisDiagClients AnalysisDiagOpt
A builtin binary operation expression such as "x + y" or "x <= y".
bool isComparisonOp() const
StringRef getOpcodeStr() const
static bool isAdditiveOp(Opcode Opc)
bool isAssignmentOp() const
Represents a single basic block in a source-level CFG.
bool isInevitablySinking() const
Returns true if the block would eventually end with a sink (a noreturn node).
succ_iterator succ_begin()
Stmt * getTerminatorStmt()
const Expr * getLastCondition() const
Stmt * getTerminatorCondition(bool StripParens=true)
unsigned succ_size() const
CFGBlock * getBlock(Stmt *S)
Returns the CFGBlock the specified Stmt* appears in.
unsigned size() const
Return the total number of CFGBlocks within the CFG This is simply a renaming of the getNumBlockIDs()...
bool isLinear() const
Returns true if the CFG has no branches.
A boolean literal, per ([C++ lex.bool] Boolean literals).
Represents a call to a C++ constructor.
CXXConstructorDecl * getConstructor() const
Get the constructor that this expression will (ultimately) call.
bool isCopyOrMoveConstructor(unsigned &TypeQuals) const
Determine whether this is a copy or move constructor.
Represents a C++ struct/union/class.
Represents a point when we begin processing an inlined call.
Represents a point when we start the call exit sequence (for inlined call).
Represents a point when we finish the call exit sequence (for inlined call).
Represents a character-granular source range.
static CharSourceRange getTokenRange(SourceRange R)
DeclContext * getParent()
getParent - Returns the containing DeclContext.
A reference to a declared variable, function, enum, etc.
DeclStmt - Adaptor class for mixing declarations with statements and expressions.
const Decl * getSingleDecl() const
Decl - This represents one declaration (or definition), e.g.
This represents one expression.
Expr * IgnoreParenCasts() LLVM_READONLY
Skip past any parentheses and casts which might surround this expression until reaching a fixed point...
Expr * IgnoreParens() LLVM_READONLY
Skip past any parentheses which might surround this expression until reaching a fixed point.
Expr * IgnoreImpCasts() LLVM_READONLY
Skip past any implicit casts which might surround this expression until reaching a fixed point.
Represents a member of a struct/union/class.
A SourceLocation and its associated SourceManager.
GNUNullExpr - Implements the GNU __null extension, which is a name for a null pointer constant that h...
Describes an C or C++ initializer list.
unsigned getNumInits() const
const Expr * getInit(unsigned Init) const
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
static StringRef getSourceText(CharSourceRange Range, const SourceManager &SM, const LangOptions &LangOpts, bool *Invalid=nullptr)
Returns a string for the source that the range encompasses.
static StringRef getImmediateMacroName(SourceLocation Loc, const SourceManager &SM, const LangOptions &LangOpts)
Retrieve the name of the immediate macro expansion.
static CharSourceRange getAsCharRange(SourceRange Range, const SourceManager &SM, const LangOptions &LangOpts)
Given a token range, produce a corresponding CharSourceRange that is not a token range.
static bool isAtStartOfMacroExpansion(SourceLocation loc, const SourceManager &SM, const LangOptions &LangOpts, SourceLocation *MacroBegin=nullptr)
Returns true if the given MacroID location points at the first token of the macro expansion.
static bool isAtEndOfMacroExpansion(SourceLocation loc, const SourceManager &SM, const LangOptions &LangOpts, SourceLocation *MacroEnd=nullptr)
Returns true if the given MacroID location points at the last token of the macro expansion.
It wraps the AnalysisDeclContext to represent both the call stack with the help of StackFrameContext ...
bool isParentOf(const LocationContext *LC) const
const Decl * getDecl() const
LLVM_ATTRIBUTE_RETURNS_NONNULL AnalysisDeclContext * getAnalysisDeclContext() const
const LocationContext * getParent() const
It might return null.
const StackFrameContext * getStackFrame() const
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
SourceLocation getMemberLoc() const
getMemberLoc - Return the location of the "member", in X->F, it is the location of 'F'.
ValueDecl * getMemberDecl() const
Retrieve the member declaration to which this expression refers.
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
std::string getNameAsString() const
Get a human-readable name for the declaration, even if it is one of the special kinds of names (C++ c...
ObjCBoolLiteralExpr - Objective-C Boolean Literal.
ObjCIvarDecl - Represents an ObjC instance variable.
ObjCIvarRefExpr - A reference to an ObjC instance variable.
Represents a parameter to a function.
Represents a program point after a store evaluation.
ProgramPoints can be "tagged" as representing points specific to a given analysis entity.
const ProgramPointTag * getTag() const
std::optional< T > getAs() const
Convert to the specified ProgramPoint type, returning std::nullopt if this ProgramPoint is not of the...
A (possibly-)qualified type.
bool isNull() const
Return true if this QualType doesn't point to a type yet.
QualType getCanonicalType() const
bool isConstQualified() const
Determine whether this type is const-qualified.
Represents a struct/union/class.
field_range fields() const
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
This class handles loading and caching of source files into memory.
A trivial tuple used to represent a source range.
Each ExpansionInfo encodes the expansion location - where the token was ultimately expanded,...
bool isFunctionMacroExpansion() const
This is a discriminated union of FileInfo and ExpansionInfo.
const ExpansionInfo & getExpansion() const
It represents a stack frame of the call stack (based on CallEvent).
const Stmt * getCallSite() const
bool inTopFrame() const override
const Stmt * getStmt() const
Stmt - This represents one statement.
SourceLocation getEndLoc() const LLVM_READONLY
StmtClass getStmtClass() const
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
SourceLocation getBeginLoc() const LLVM_READONLY
bool isBooleanType() const
bool isPointerType() const
bool isReferenceType() const
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
bool isIntegralOrEnumerationType() const
Determine whether this type is an integral or enumeration type.
bool isObjCObjectPointerType() const
bool isAnyPointerType() const
RecordDecl * getAsRecordDecl() const
Retrieves the RecordDecl this type refers to.
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
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.
AllocaRegion - A region that represents an untyped blob of bytes created by a call to 'alloca'.
StringRef getDescription() const
A verbose warning message that is appropriate for displaying next to the source code that introduces ...
ASTContext & getASTContext() const
ProgramStateManager & getStateManager() const
const SourceManager & getSourceManager() const
const AnalyzerOptions & getAnalyzerOptions() const
BugReporterVisitors are used to add custom diagnostics along a path.
static PathDiagnosticPieceRef getDefaultEndPath(const BugReporterContext &BRC, const ExplodedNode *N, const PathSensitiveBugReport &BR)
Generates the default final diagnostic piece.
virtual PathDiagnosticPieceRef getEndPath(BugReporterContext &BRC, const ExplodedNode *N, PathSensitiveBugReport &BR)
Provide custom definition for the final diagnostic piece on the path - the piece, which is displayed ...
virtual void finalizeVisitor(BugReporterContext &BRC, const ExplodedNode *EndPathNode, PathSensitiveBugReport &BR)
Last function called on the visitor, no further calls to VisitNode would follow.
Represents a call to a C++ constructor.
Manages the lifetime of CallEvent objects.
CallEventRef getCaller(const StackFrameContext *CalleeCtx, ProgramStateRef State)
Gets an outside caller given a callee context.
Represents an abstract call to a function or method along a particular path.
static bool isCallStmt(const Stmt *S)
Returns true if this is a statement is a function or method call of some kind.
PathDiagnosticPieceRef VisitTerminator(const Stmt *Term, const ExplodedNode *N, const CFGBlock *SrcBlk, const CFGBlock *DstBlk, PathSensitiveBugReport &R, BugReporterContext &BRC)
bool printValue(const Expr *CondVarExpr, raw_ostream &Out, const ExplodedNode *N, bool TookTrue, bool IsAssuming)
Tries to print the value of the given expression.
PathDiagnosticPieceRef VisitNode(const ExplodedNode *N, BugReporterContext &BRC, PathSensitiveBugReport &BR) override
Return a diagnostic piece which should be associated with the given node.
bool patternMatch(const Expr *Ex, const Expr *ParentEx, raw_ostream &Out, BugReporterContext &BRC, PathSensitiveBugReport &R, const ExplodedNode *N, std::optional< bool > &prunable, bool IsSameFieldName)
static bool isPieceMessageGeneric(const PathDiagnosticPiece *Piece)
PathDiagnosticPieceRef VisitConditionVariable(StringRef LhsString, const Expr *CondVarExpr, BugReporterContext &BRC, PathSensitiveBugReport &R, const ExplodedNode *N, bool TookTrue)
PathDiagnosticPieceRef VisitTrueTest(const Expr *Cond, BugReporterContext &BRC, PathSensitiveBugReport &R, const ExplodedNode *N, bool TookTrue)
static const char * getTag()
Return the tag associated with this visitor.
PathDiagnosticPieceRef VisitNodeImpl(const ExplodedNode *N, BugReporterContext &BRC, PathSensitiveBugReport &BR)
bool isConstrainedTrue() const
Return true if the constraint is perfectly constrained to 'true'.
bool isValid() const =delete
static bool isInterestingLValueExpr(const Expr *Ex)
Returns true if nodes for the given expression kind are always kept around.
const CFGBlock * getCFGBlock() const
const ProgramStateRef & getState() const
const Stmt * getStmtForDiagnostics() const
If the node's program point corresponds to a statement, retrieve that statement.
ProgramPoint getLocation() const
getLocation - Returns the edge associated with the given node.
ExplodedNode * getFirstSucc()
const StackFrameContext * getStackFrame() const
SVal getSVal(const Stmt *S) const
Get the value of an arbitrary expression at this node.
const LocationContext * getLocationContext() const
std::optional< T > getLocationAs() const &
ExplodedNode * getFirstPred()
unsigned succ_size() const
static std::pair< const ProgramPointTag *, const ProgramPointTag * > 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.
const FieldRegion * getFieldRegion(const FieldDecl *fd, const SubRegion *superRegion)
getFieldRegion - Retrieve or create the memory region associated with a specified FieldDecl.
MemRegion - The root abstract class for all memory regions.
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemSpaceRegion * getMemorySpace() const
virtual bool isBoundable() const
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * StripCasts(bool StripBaseAndDerivedCasts=true) const
virtual bool isSubRegionOf(const MemRegion *R) const
Check if the region is a subregion of the given region.
virtual void printPretty(raw_ostream &os) const
Print the region for use in diagnostics.
const RegionTy * getAs() const
virtual bool canPrintPretty() const
Returns true if this region can be printed in a user-friendly way.
MemSpaceRegion - A memory region that represents a "memory space"; for example, the set of global var...
PathDiagnosticPieceRef VisitNode(const ExplodedNode *N, BugReporterContext &BRC, PathSensitiveBugReport &BR) override
Return a diagnostic piece which should be associated with the given node.
static const Expr * getNilReceiver(const Stmt *S, const ExplodedNode *N)
If the statement is a message send expression with nil receiver, returns the receiver expression.
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.
Put a diagnostic on return statement of all inlined functions for which the region of interest Region...
The tag upon which the TagVisitor reacts.
Represents any expression that calls an Objective-C method.
static PathDiagnosticLocation createBegin(const Decl *D, const SourceManager &SM)
Create a location for the beginning of the declaration.
FullSourceLoc asLocation() const
static PathDiagnosticLocation create(const Decl *D, const SourceManager &SM)
Create a location corresponding to the given declaration.
bool hasValidLocation() const
StringRef getString() const
void markInteresting(SymbolRef sym, bugreporter::TrackingKind TKind=bugreporter::TrackingKind::Thorough)
Marks a symbol as interesting.
PathDiagnosticLocation getLocation() const override
The primary location of the bug report that points at the undesirable behavior in the code.
ArrayRef< SourceRange > getRanges() const override
Get the SourceRanges associated with the report.
const ExplodedNode * getErrorNode() const
bool addTrackedCondition(const ExplodedNode *Cond)
Notes that the condition of the CFGBlock associated with Cond is being tracked.
void markInvalid(const void *Tag, const void *Data)
Marks the current report as invalid, meaning that it is probably a false positive and should not be r...
void addVisitor(std::unique_ptr< BugReporterVisitor > visitor)
Add custom or predefined bug report visitors to this report.
std::optional< bugreporter::TrackingKind > getInterestingnessKind(SymbolRef sym) const
bool isInteresting(SymbolRef sym) const
SValBuilder & getSValBuilder()
CallEventManager & getCallEventManager()
bool haveEqualConstraints(ProgramStateRef S1, ProgramStateRef S2) const
void iterBindings(ProgramStateRef state, StoreManager::BindingsHandler &F)
StoreManager & getStoreManager()
ProgramState - This class encapsulates:
Loc getLValue(const CXXBaseSpecifier &BaseSpec, const SubRegion *Super) const
Get the lvalue for a base class object reference.
SVal getSVal(const Stmt *S, const LocationContext *LCtx) const
Returns the SVal bound to the statement 'S' in the state's environment.
A Range represents the closed range [from, to].
ConditionTruthVal areEqual(ProgramStateRef state, SVal lhs, SVal rhs)
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
bool isZeroConstant() const
std::optional< T > getAs() const
Convert to the specified SVal type, returning std::nullopt if this SVal is not of the desired type.
const MemRegion * getAsRegion() const
SubRegion - A region that subsets another larger region.
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * getSuperRegion() const
bool isSubRegionOf(const MemRegion *R) const override
Check if the region is a subregion of the given region.
PathDiagnosticPieceRef VisitNode(const ExplodedNode *Succ, BugReporterContext &BRC, PathSensitiveBugReport &BR) override
Return a diagnostic piece which should be associated with the given node.
SuppressInlineDefensiveChecksVisitor(DefinedSVal Val, const ExplodedNode *N)
static const char * getTag()
Return the tag associated with this visitor.
void Profile(llvm::FoldingSetNodeID &ID) const override
SymbolicRegion - A special, "non-concrete" region.
void Profile(llvm::FoldingSetNodeID &ID) const override
PathDiagnosticPieceRef VisitNode(const ExplodedNode *N, BugReporterContext &BRC, PathSensitiveBugReport &R) override
Return a diagnostic piece which should be associated with the given node.
void Profile(llvm::FoldingSetNodeID &ID) const override
static const char * getTag()
Return the tag associated with this visitor.
PathDiagnosticPieceRef VisitNode(const ExplodedNode *N, BugReporterContext &BRC, PathSensitiveBugReport &BR) override
Return a diagnostic piece which should be associated with the given node.
When a region containing undefined value or '0' value is passed as an argument in a call,...
PathDiagnosticPieceRef VisitNode(const ExplodedNode *N, BugReporterContext &BRC, PathSensitiveBugReport &BR) override
Return a diagnostic piece which should be associated with the given node.
const VarDecl * getDecl() const override=0
Handles expressions during the tracking.
ExpressionHandler(Tracker &ParentTracker)
Handles stores during the tracking.
StoreHandler(Tracker &ParentTracker)
PathDiagnosticPieceRef constructNote(StoreInfo SI, BugReporterContext &BRC, StringRef NodeText)
A generalized component for tracking expressions, values, and stores.
static TrackerRef create(PathSensitiveBugReport &Report)
virtual PathDiagnosticPieceRef handle(StoreInfo SI, BugReporterContext &BRC, TrackingOptions Opts)
Handle the store operation and produce the note.
Tracker(PathSensitiveBugReport &Report)
virtual Result track(const Expr *E, const ExplodedNode *N, TrackingOptions Opts={})
Track expression value back to its point of origin.
Visitor that tracks expressions and values.
Value representing integer constant.
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.
const internal::VariadicDynCastAllOfMatcher< Stmt, BinaryOperator > binaryOperator
Matches binary operator expressions.
internal::Matcher< Stmt > StatementMatcher
static std::string getMacroName(MacroType Macro, GtestCmp Cmp)
internal::PolymorphicMatcher< internal::HasDeclarationMatcher, void(internal::HasDeclarationSupportedTypes), internal::Matcher< Decl > > hasDeclaration(const internal::Matcher< Decl > &InnerMatcher)
Matches a node if the declaration associated with that node matches the given matcher.
const internal::VariadicAllOfMatcher< Stmt > stmt
Matches statements.
const Expr * getDerefExpr(const Stmt *S)
Given that expression S represents a pointer that would be dereferenced, try to find a sub-expression...
bool trackExpressionValue(const ExplodedNode *N, const Expr *E, PathSensitiveBugReport &R, TrackingOptions Opts={})
Attempts to add visitors to track expression value back to its point of origin.
void trackStoredValue(SVal V, const MemRegion *R, PathSensitiveBugReport &Report, TrackingOptions Opts={}, const StackFrameContext *Origin=nullptr)
Track how the value got stored into the given region and where it came from.
TrackingKind
Specifies the type of tracking for an expression.
@ Thorough
Default tracking kind – specifies that as much information should be gathered about the tracked expre...
@ Condition
Specifies that a more moderate tracking should be used for the expression value.
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
std::shared_ptr< PathDiagnosticPiece > PathDiagnosticPieceRef
bool Ret(InterpState &S, CodePtr &PC)
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
const FunctionProtoType * T
@ 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.