37#include "llvm/ADT/STLExtras.h"
38#include "llvm/ADT/StringExtras.h"
39#include "llvm/Support/Path.h"
53 std::min(
static_cast<char>(Lhs),
static_cast<char>(Rhs)));
56const char *getNullabilityString(
Nullability Nullab) {
58 case Nullability::Contradicted:
59 return "contradicted";
60 case Nullability::Nullable:
62 case Nullability::Unspecified:
64 case Nullability::Nonnull:
67 llvm_unreachable(
"Unexpected enumeration.");
73enum class ErrorKind :
int {
77 NullableAssignedToNonnull,
78 NullableReturnedToNonnull,
80 NullablePassedToNonnull
83class NullabilityChecker
85 check::Bind, check::PreCall, check::PreStmt<ReturnStmt>,
86 check::PostCall, check::PostStmt<ExplicitCastExpr>,
87 check::PostObjCMessage, check::DeadSymbols, eval::Assume,
88 check::Location, check::Event<ImplicitNullDerefEvent>,
89 check::BeginFunction> {
98 bool NoDiagnoseCallsToSystemHeaders =
false;
100 void checkBind(SVal L, SVal
V,
const Stmt *S,
bool AtDeclInit,
101 CheckerContext &
C)
const;
102 void checkPostStmt(
const ExplicitCastExpr *CE, CheckerContext &
C)
const;
103 void checkPreStmt(
const ReturnStmt *S, CheckerContext &
C)
const;
104 void checkPostObjCMessage(
const ObjCMethodCall &M, CheckerContext &
C)
const;
105 void checkPostCall(
const CallEvent &
Call, CheckerContext &
C)
const;
106 void checkPreCall(
const CallEvent &
Call, CheckerContext &
C)
const;
107 void checkDeadSymbols(SymbolReaper &SR, CheckerContext &
C)
const;
108 void checkEvent(ImplicitNullDerefEvent Event)
const;
109 void checkLocation(SVal Location,
bool IsLoad,
const Stmt *S,
110 CheckerContext &
C)
const;
111 void checkBeginFunction(CheckerContext &Ctx)
const;
113 bool Assumption)
const;
115 void printState(raw_ostream &Out,
ProgramStateRef State,
const char *NL,
116 const char *Sep)
const override;
118 StringRef getDebugTag()
const override {
return "NullabilityChecker"; }
123 CheckerFrontendWithBugType NullPassedToNonnull{
"Nullability",
125 CheckerFrontendWithBugType NullReturnedFromNonnull{
"Nullability",
127 CheckerFrontendWithBugType NullableDereferenced{
"Nullability",
129 CheckerFrontendWithBugType NullablePassedToNonnull{
"Nullability",
131 CheckerFrontendWithBugType NullableReturnedFromNonnull{
138 bool NeedTracking =
false;
141 class NullabilityBugVisitor :
public BugReporterVisitor {
143 NullabilityBugVisitor(
const MemRegion *M) : Region(M) {}
145 void Profile(llvm::FoldingSetNodeID &ID)
const override {
148 ID.AddPointer(Region);
152 BugReporterContext &BRC,
153 PathSensitiveBugReport &BR)
override;
157 const MemRegion *Region;
165 void reportBugIfInvariantHolds(StringRef Msg, ErrorKind
Error,
166 const BugType &BT, ExplodedNode *N,
167 const MemRegion *Region, CheckerContext &
C,
168 const Stmt *ValueExpr =
nullptr,
169 bool SuppressPath =
false)
const;
171 void reportBug(StringRef Msg, ErrorKind
Error,
const BugType &BT,
172 ExplodedNode *N,
const MemRegion *Region, BugReporter &BR,
173 const Stmt *ValueExpr =
nullptr)
const {
174 auto R = std::make_unique<PathSensitiveBugReport>(BT, Msg, N);
176 R->markInteresting(Region);
177 R->addVisitor<NullabilityBugVisitor>(Region);
180 R->addRange(ValueExpr->getSourceRange());
181 if (
Error == ErrorKind::NilAssignedToNonnull ||
182 Error == ErrorKind::NilPassedToNonnull ||
183 Error == ErrorKind::NilReturnedToNonnull)
184 if (
const auto *Ex = dyn_cast<Expr>(ValueExpr))
192 const SymbolicRegion *getTrackRegion(SVal Val,
193 bool CheckSuperRegion =
false)
const;
197 bool isDiagnosableCall(
const CallEvent &
Call)
const {
198 if (NoDiagnoseCallsToSystemHeaders &&
Call.isInSystemHeader())
205class NullabilityState {
207 NullabilityState(
Nullability Nullab,
const Stmt *Source =
nullptr)
208 : Nullab(Nullab), Source(Source) {}
210 const Stmt *getNullabilitySource()
const {
return Source; }
214 void Profile(llvm::FoldingSetNodeID &ID)
const {
215 ID.AddInteger(
static_cast<char>(Nullab));
216 ID.AddPointer(Source);
219 void print(raw_ostream &Out)
const {
220 Out << getNullabilityString(Nullab) <<
"\n";
232bool operator==(NullabilityState Lhs, NullabilityState Rhs) {
233 return Lhs.getValue() == Rhs.getValue() &&
234 Lhs.getNullabilitySource() == Rhs.getNullabilitySource();
240using ObjectPropPair = std::pair<const MemRegion *, const IdentifierInfo *>;
243struct ConstrainedPropertyVal {
246 DefinedOrUnknownSVal Value;
249 bool isConstrainedNonnull;
251 ConstrainedPropertyVal(DefinedOrUnknownSVal SV)
252 : Value(SV), isConstrainedNonnull(
false) {}
254 void Profile(llvm::FoldingSetNodeID &ID)
const {
256 ID.AddInteger(isConstrainedNonnull ? 1 : 0);
260bool operator==(
const ConstrainedPropertyVal &Lhs,
261 const ConstrainedPropertyVal &Rhs) {
262 return Lhs.Value == Rhs.Value &&
263 Lhs.isConstrainedNonnull == Rhs.isConstrainedNonnull;
271 ConstrainedPropertyVal)
312 return T->isAnyPointerType() ||
T->isBlockPointerType();
316NullabilityChecker::getTrackRegion(
SVal Val,
bool CheckSuperRegion)
const {
320 auto RegionSVal = Val.
getAs<loc::MemRegionVal>();
324 const MemRegion *Region = RegionSVal->getRegion();
326 if (CheckSuperRegion) {
327 if (
const SubRegion *FieldReg = Region->
getAs<FieldRegion>()) {
328 if (
const auto *ER = dyn_cast<ElementRegion>(FieldReg->getSuperRegion()))
330 return dyn_cast<SymbolicRegion>(FieldReg->getSuperRegion());
332 if (
auto ElementReg = Region->
getAs<ElementRegion>())
333 return dyn_cast<SymbolicRegion>(ElementReg->getSuperRegion());
336 return dyn_cast<SymbolicRegion>(Region);
340 const ExplodedNode *N, BugReporterContext &BRC,
341 PathSensitiveBugReport &BR) {
345 const NullabilityState *TrackedNullab = State->get<NullabilityMap>(Region);
346 const NullabilityState *TrackedNullabPrev =
347 StatePrev->get<NullabilityMap>(Region);
351 if (TrackedNullabPrev &&
352 TrackedNullabPrev->getValue() == TrackedNullab->getValue())
356 const Stmt *S = TrackedNullab->getNullabilitySource();
364 std::string InfoText =
365 (llvm::Twine(
"Nullability '") +
366 getNullabilityString(TrackedNullab->getValue()) +
"' is inferred")
372 return std::make_shared<PathDiagnosticEventPiece>(Pos, InfoText,
true);
406 for (
const auto *ParamDecl : Params) {
407 if (ParamDecl->isParameterPack())
410 SVal LV = State->getLValue(ParamDecl, LocCtxt);
422 auto *MD = dyn_cast<ObjCMethodDecl>(LocCtxt->
getDecl());
423 if (!MD || !MD->isInstanceMethod())
430 SVal SelfVal = State->getSVal(State->getRegion(SelfDecl, LocCtxt));
433 dyn_cast<ObjCObjectPointerType>(SelfDecl->
getType());
441 for (
const auto *IvarDecl : ID->ivars()) {
442 SVal LV = State->getLValue(IvarDecl, SelfVal);
452 if (State->get<InvariantViolated>())
461 if (
const auto *BD = dyn_cast<BlockDecl>(D))
462 Params = BD->parameters();
463 else if (
const auto *FD = dyn_cast<FunctionDecl>(D))
464 Params = FD->parameters();
465 else if (
const auto *MD = dyn_cast<ObjCMethodDecl>(D))
466 Params = MD->parameters();
473 C.addTransition(State->set<InvariantViolated>(
true), N);
479void NullabilityChecker::reportBugIfInvariantHolds(
480 StringRef Msg, ErrorKind
Error,
const BugType &BT, ExplodedNode *N,
481 const MemRegion *Region, CheckerContext &
C,
const Stmt *ValueExpr,
482 bool SuppressPath)
const {
488 OriginalState = OriginalState->set<InvariantViolated>(
true);
489 N =
C.addTransition(OriginalState, N);
492 reportBug(Msg,
Error, BT, N, Region,
C.getBugReporter(), ValueExpr);
496void NullabilityChecker::checkDeadSymbols(SymbolReaper &SR,
497 CheckerContext &
C)
const {
499 NullabilityMapTy Nullabilities = State->get<NullabilityMap>();
500 for (
const MemRegion *Reg : llvm::make_first_range(Nullabilities)) {
501 const auto *Region = Reg->
getAs<SymbolicRegion>();
502 assert(Region &&
"Non-symbolic region is tracked.");
503 if (SR.
isDead(Region->getSymbol())) {
504 State = State->remove<NullabilityMap>(Reg);
510 PropertyAccessesMapTy PropertyAccesses = State->get<PropertyAccessesMap>();
511 for (
ObjectPropPair PropKey : llvm::make_first_range(PropertyAccesses)) {
512 const MemRegion *ReceiverRegion = PropKey.first;
514 State = State->remove<PropertyAccessesMap>(PropKey);
524 C.addTransition(State);
530void NullabilityChecker::checkEvent(ImplicitNullDerefEvent Event)
const {
534 const MemRegion *Region =
535 getTrackRegion(Event.
Location,
true);
540 const NullabilityState *TrackedNullability =
541 State->get<NullabilityMap>(Region);
543 if (!TrackedNullability)
546 if (NullableDereferenced.isEnabled() &&
547 TrackedNullability->getValue() == Nullability::Nullable) {
548 BugReporter &BR = *Event.
BR;
552 reportBug(
"Nullable pointer is dereferenced",
553 ErrorKind::NullableDereferenced, NullableDereferenced,
556 reportBug(
"Nullable pointer is passed to a callee that requires a "
558 ErrorKind::NullablePassedToNonnull, NullableDereferenced,
564void NullabilityChecker::checkBeginFunction(CheckerContext &
C)
const {
568 const LocationContext *LCtx =
C.getLocationContext();
570 if (!AbstractCall || AbstractCall->parameters().empty())
574 for (
const ParmVarDecl *Param : AbstractCall->parameters()) {
580 if (RequiredNullability != Nullability::Nullable)
583 const VarRegion *ParamRegion = State->getRegion(Param, LCtx);
584 const MemRegion *ParamPointeeRegion =
585 State->getSVal(ParamRegion).getAsRegion();
586 if (!ParamPointeeRegion)
589 State = State->set<NullabilityMap>(ParamPointeeRegion,
590 NullabilityState(RequiredNullability));
592 C.addTransition(State);
608void NullabilityChecker::checkLocation(SVal Location,
bool IsLoad,
610 CheckerContext &Context)
const {
619 dyn_cast_or_null<TypedValueRegion>(Location.
getAsRegion());
625 auto StoredVal = State->getSVal(Region).getAs<loc::MemRegionVal>();
632 if (NullabilityOfTheLoadedValue == Nullability::Nonnull) {
636 Context.addTransition(NewState);
651void NullabilityChecker::checkPreStmt(
const ReturnStmt *S,
652 CheckerContext &
C)
const {
661 if (State->get<InvariantViolated>())
664 auto RetSVal =
C.getSVal(S).getAs<DefinedOrUnknownSVal>();
668 bool InSuppressedMethodFamily =
false;
670 QualType RequiredRetType;
671 AnalysisDeclContext *DeclCtxt =
672 C.getLocationContext()->getAnalysisDeclContext();
674 if (
auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
681 InSuppressedMethodFamily =
true;
683 RequiredRetType = MD->getReturnType();
684 }
else if (
auto *FD = dyn_cast<FunctionDecl>(D)) {
685 RequiredRetType = FD->getReturnType();
693 if (
const auto *FunDecl =
C.getLocationContext()->getDecl();
694 FunDecl && FunDecl->getAttr<ReturnsNonNullAttr>() &&
695 (RequiredNullability == Nullability::Unspecified ||
696 RequiredNullability == Nullability::Nullable)) {
699 RequiredNullability = Nullability::Nonnull;
710 if (RequiredNullability == Nullability::Nonnull &&
712 if (NullReturnedFromNonnull.
isEnabled() &&
713 RetExprTypeLevelNullability != Nullability::Nonnull &&
714 !InSuppressedMethodFamily) {
715 ExplodedNode *N =
C.generateErrorNode(State);
719 SmallString<256> SBuf;
720 llvm::raw_svector_ostream
OS(SBuf);
721 OS << (RetExpr->getType()->isObjCObjectPointerType() ?
"nil" :
"Null");
722 OS <<
" returned from a " <<
C.getDeclDescription(D)
723 <<
" that is expected to return a non-null value";
724 reportBugIfInvariantHolds(
OS.str(), ErrorKind::NilReturnedToNonnull,
725 NullReturnedFromNonnull, N,
nullptr,
C,
732 State = State->set<InvariantViolated>(
true);
733 C.addTransition(State);
737 const MemRegion *Region = getTrackRegion(*RetSVal);
741 const NullabilityState *TrackedNullability =
742 State->get<NullabilityMap>(Region);
743 if (TrackedNullability) {
744 Nullability TrackedNullabValue = TrackedNullability->getValue();
745 if (NullableReturnedFromNonnull.
isEnabled() &&
747 TrackedNullabValue == Nullability::Nullable &&
748 RequiredNullability == Nullability::Nonnull) {
749 ExplodedNode *N =
C.addTransition(State,
C.getPredecessor());
751 SmallString<256> SBuf;
752 llvm::raw_svector_ostream
OS(SBuf);
753 OS <<
"Nullable pointer is returned from a " <<
C.getDeclDescription(D) <<
754 " that is expected to return a non-null value";
756 reportBugIfInvariantHolds(
OS.str(), ErrorKind::NullableReturnedToNonnull,
757 NullableReturnedFromNonnull, N, Region,
C);
761 if (RequiredNullability == Nullability::Nullable) {
762 State = State->set<NullabilityMap>(Region,
763 NullabilityState(RequiredNullability,
765 C.addTransition(State);
771void NullabilityChecker::checkPreCall(
const CallEvent &
Call,
772 CheckerContext &
C)
const {
777 if (State->get<InvariantViolated>())
783 for (
const ParmVarDecl *Param :
Call.parameters()) {
784 if (Param->isParameterPack())
787 if (Idx >=
Call.getNumArgs())
790 const Expr *ArgExpr =
Call.getArgExpr(Idx);
791 auto ArgSVal =
Call.getArgSVal(Idx++).getAs<DefinedOrUnknownSVal>();
796 !Param->getType()->isReferenceType())
806 unsigned ParamIdx = Param->getFunctionScopeIndex() + 1;
809 ArgExprTypeLevelNullability != Nullability::Nonnull &&
810 RequiredNullability == Nullability::Nonnull &&
811 isDiagnosableCall(
Call)) {
812 ExplodedNode *N =
C.generateErrorNode(State);
816 SmallString<256> SBuf;
817 llvm::raw_svector_ostream
OS(SBuf);
818 OS << (Param->getType()->isObjCObjectPointerType() ?
"nil" :
"Null");
819 OS <<
" passed to a callee that requires a non-null " << ParamIdx
820 << llvm::getOrdinalSuffix(ParamIdx) <<
" parameter";
821 reportBugIfInvariantHolds(
OS.str(), ErrorKind::NilPassedToNonnull,
822 NullPassedToNonnull, N,
nullptr,
C, ArgExpr,
827 const MemRegion *Region = getTrackRegion(*ArgSVal);
831 const NullabilityState *TrackedNullability =
832 State->get<NullabilityMap>(Region);
834 if (TrackedNullability) {
836 TrackedNullability->getValue() != Nullability::Nullable)
839 if (NullablePassedToNonnull.isEnabled() &&
840 RequiredNullability == Nullability::Nonnull &&
841 isDiagnosableCall(
Call)) {
842 ExplodedNode *N =
C.addTransition(State);
843 SmallString<256> SBuf;
844 llvm::raw_svector_ostream
OS(SBuf);
845 OS <<
"Nullable pointer is passed to a callee that requires a non-null "
846 << ParamIdx << llvm::getOrdinalSuffix(ParamIdx) <<
" parameter";
847 reportBugIfInvariantHolds(
OS.str(), ErrorKind::NullablePassedToNonnull,
848 NullablePassedToNonnull, N, Region,
C,
852 if (NullableDereferenced.isEnabled() &&
853 Param->getType()->isReferenceType()) {
854 ExplodedNode *N =
C.addTransition(State);
855 reportBugIfInvariantHolds(
856 "Nullable pointer is dereferenced", ErrorKind::NullableDereferenced,
857 NullableDereferenced, N, Region,
C, ArgExpr,
true);
863 if (State != OrigState)
864 C.addTransition(State);
868void NullabilityChecker::checkPostCall(
const CallEvent &
Call,
869 CheckerContext &
C)
const {
876 const FunctionType *FuncType =
Decl->getFunctionType();
883 if (State->get<InvariantViolated>())
886 const MemRegion *Region = getTrackRegion(
Call.getReturnValue());
892 const SourceManager &
SM =
C.getSourceManager();
893 StringRef FilePath =
SM.getFilename(
SM.getSpellingLoc(
Decl->getBeginLoc()));
894 if (llvm::sys::path::filename(FilePath).starts_with(
"CG")) {
895 State = State->set<NullabilityMap>(Region, Nullability::Contradicted);
896 C.addTransition(State);
900 const NullabilityState *TrackedNullability =
901 State->get<NullabilityMap>(Region);
908 if (
const Expr *E =
Call.getOriginExpr())
909 ReturnType = E->getType();
911 if (!TrackedNullability &&
913 State = State->set<NullabilityMap>(Region, Nullability::Nullable);
914 C.addTransition(State);
923 return Nullability::Nonnull;
932 return Nullability::Nonnull;
935 if (ValueRegionSVal) {
936 const MemRegion *SelfRegion = ValueRegionSVal->getRegion();
939 const NullabilityState *TrackedSelfNullability =
940 State->get<NullabilityMap>(SelfRegion);
941 if (TrackedSelfNullability)
942 return TrackedSelfNullability->getValue();
944 return Nullability::Unspecified;
952 bool Assumption)
const {
953 PropertyAccessesMapTy PropertyAccesses = State->get<PropertyAccessesMap>();
954 for (
auto [PropKey, PropVal] : PropertyAccesses) {
955 if (!PropVal.isConstrainedNonnull) {
956 ConditionTruthVal
IsNonNull = State->isNonNull(PropVal.Value);
958 ConstrainedPropertyVal Replacement = PropVal;
959 Replacement.isConstrainedNonnull =
true;
960 State = State->set<PropertyAccessesMap>(PropKey, Replacement);
961 }
else if (
IsNonNull.isConstrainedFalse()) {
963 State = State->remove<PropertyAccessesMap>(PropKey);
974void NullabilityChecker::checkPostObjCMessage(
const ObjCMethodCall &M,
975 CheckerContext &
C)
const {
979 QualType RetType =
Decl->getReturnType();
984 if (State->get<InvariantViolated>())
987 const MemRegion *ReturnRegion = getTrackRegion(M.
getReturnValue());
996 if (Name.starts_with(
"NS")) {
1007 State->set<NullabilityMap>(ReturnRegion, Nullability::Contradicted);
1008 C.addTransition(State);
1013 if (Name.contains(
"Array") &&
1014 (FirstSelectorSlot ==
"firstObject" ||
1015 FirstSelectorSlot ==
"lastObject")) {
1017 State->set<NullabilityMap>(ReturnRegion, Nullability::Contradicted);
1018 C.addTransition(State);
1026 if (Name.contains(
"String")) {
1028 if (Param->getName() ==
"encoding") {
1029 State = State->set<NullabilityMap>(ReturnRegion,
1030 Nullability::Contradicted);
1031 C.addTransition(State);
1041 const NullabilityState *NullabilityOfReturn =
1042 State->get<NullabilityMap>(ReturnRegion);
1044 if (NullabilityOfReturn) {
1048 Nullability RetValTracked = NullabilityOfReturn->getValue();
1050 getMostNullable(RetValTracked, SelfNullability);
1051 if (ComputedNullab != RetValTracked &&
1052 ComputedNullab != Nullability::Unspecified) {
1053 const Stmt *NullabilitySource =
1054 ComputedNullab == RetValTracked
1055 ? NullabilityOfReturn->getNullabilitySource()
1056 :
Message->getInstanceReceiver();
1057 State = State->set<NullabilityMap>(
1058 ReturnRegion, NullabilityState(ComputedNullab, NullabilitySource));
1059 C.addTransition(State);
1082 if (RetNullability != Nullability::Nonnull &&
1084 bool LookupResolved =
false;
1085 if (
const MemRegion *ReceiverRegion = getTrackRegion(M.
getReceiverSVal())) {
1086 if (
const IdentifierInfo *Ident =
1088 LookupResolved =
true;
1090 const ConstrainedPropertyVal *PrevPropVal =
1091 State->get<PropertyAccessesMap>(Key);
1092 if (PrevPropVal && PrevPropVal->isConstrainedNonnull) {
1093 RetNullability = Nullability::Nonnull;
1101 if (
auto ReturnSVal =
1103 State = State->set<PropertyAccessesMap>(
1104 Key, ConstrainedPropertyVal(*ReturnSVal));
1110 if (!LookupResolved) {
1112 RetNullability = Nullability::Nonnull;
1116 Nullability ComputedNullab = getMostNullable(RetNullability, SelfNullability);
1117 if (ComputedNullab == Nullability::Nullable) {
1118 const Stmt *NullabilitySource = ComputedNullab == RetNullability
1120 :
Message->getInstanceReceiver();
1121 State = State->set<NullabilityMap>(
1122 ReturnRegion, NullabilityState(ComputedNullab, NullabilitySource));
1123 C.addTransition(State);
1131void NullabilityChecker::checkPostStmt(
const ExplicitCastExpr *CE,
1132 CheckerContext &
C)
const {
1134 QualType DestType = CE->
getType();
1141 if (State->get<InvariantViolated>())
1148 if (DestNullability == Nullability::Unspecified)
1151 auto RegionSVal =
C.getSVal(CE).getAs<DefinedOrUnknownSVal>();
1152 const MemRegion *Region = getTrackRegion(*RegionSVal);
1157 if (DestNullability == Nullability::Nonnull) {
1160 State = State->set<NullabilityMap>(Region, Nullability::Contradicted);
1161 C.addTransition(State);
1166 const NullabilityState *TrackedNullability =
1167 State->get<NullabilityMap>(Region);
1169 if (!TrackedNullability) {
1170 if (DestNullability != Nullability::Nullable)
1172 State = State->set<NullabilityMap>(Region,
1173 NullabilityState(DestNullability, CE));
1174 C.addTransition(State);
1178 if (TrackedNullability->getValue() != DestNullability &&
1179 TrackedNullability->getValue() != Nullability::Contradicted) {
1180 State = State->set<NullabilityMap>(Region, Nullability::Contradicted);
1181 C.addTransition(State);
1189 if (
auto *BinOp = dyn_cast<BinaryOperator>(S)) {
1190 if (BinOp->getOpcode() == BO_Assign)
1191 return BinOp->getRHS();
1195 if (
auto *DS = dyn_cast<DeclStmt>(S)) {
1196 if (DS->isSingleDecl()) {
1197 auto *VD = dyn_cast<VarDecl>(DS->getSingleDecl());
1201 if (
const Expr *
Init = VD->getInit())
1226 if (!
C.getASTContext().getLangOpts().ObjCAutoRefCount)
1229 auto *DS = dyn_cast<DeclStmt>(S);
1230 if (!DS || !DS->isSingleDecl())
1233 auto *VD = dyn_cast<VarDecl>(DS->getSingleDecl());
1238 if(!VD->getType().getQualifiers().hasObjCLifetime())
1242 assert(
Init &&
"ObjC local under ARC without initializer");
1253void NullabilityChecker::checkBind(SVal L, SVal
V,
const Stmt *S,
1254 bool AtDeclInit, CheckerContext &
C)
const {
1255 const TypedValueRegion *TVR =
1256 dyn_cast_or_null<TypedValueRegion>(L.
getAsRegion());
1265 if (State->get<InvariantViolated>())
1268 auto ValDefOrUnknown =
V.getAs<DefinedOrUnknownSVal>();
1269 if (!ValDefOrUnknown)
1274 Nullability ValNullability = Nullability::Unspecified;
1275 if (
SymbolRef Sym = ValDefOrUnknown->getAsSymbol())
1282 Nullability ValueExprTypeLevelNullability = Nullability::Unspecified;
1285 ValueExprTypeLevelNullability =
1289 bool NullAssignedToNonNull = (LocNullability == Nullability::Nonnull &&
1291 if (NullPassedToNonnull.
isEnabled() && NullAssignedToNonNull &&
1292 ValNullability != Nullability::Nonnull &&
1293 ValueExprTypeLevelNullability != Nullability::Nonnull &&
1295 ExplodedNode *N =
C.generateErrorNode(State);
1300 const Stmt *ValueStmt = S;
1302 ValueStmt = ValueExpr;
1304 SmallString<256> SBuf;
1305 llvm::raw_svector_ostream
OS(SBuf);
1307 OS <<
" assigned to a pointer which is expected to have non-null value";
1308 reportBugIfInvariantHolds(
OS.str(), ErrorKind::NilAssignedToNonnull,
1309 NullPassedToNonnull, N,
nullptr,
C, ValueStmt);
1315 if (NullAssignedToNonNull) {
1316 State = State->set<InvariantViolated>(
true);
1317 C.addTransition(State);
1324 const MemRegion *ValueRegion = getTrackRegion(*ValDefOrUnknown);
1328 const NullabilityState *TrackedNullability =
1329 State->get<NullabilityMap>(ValueRegion);
1331 if (TrackedNullability) {
1333 TrackedNullability->getValue() != Nullability::Nullable)
1335 if (NullablePassedToNonnull.isEnabled() &&
1336 LocNullability == Nullability::Nonnull) {
1337 ExplodedNode *N =
C.addTransition(State,
C.getPredecessor());
1338 reportBugIfInvariantHolds(
"Nullable pointer is assigned to a pointer "
1339 "which is expected to have non-null value",
1340 ErrorKind::NullableAssignedToNonnull,
1341 NullablePassedToNonnull, N, ValueRegion,
C);
1346 const auto *BinOp = dyn_cast<BinaryOperator>(S);
1348 if (ValNullability == Nullability::Nullable) {
1351 const Stmt *NullabilitySource = BinOp ? BinOp->getRHS() : S;
1352 State = State->set<NullabilityMap>(
1353 ValueRegion, NullabilityState(ValNullability, NullabilitySource));
1354 C.addTransition(State);
1358 if (LocNullability == Nullability::Nullable) {
1359 const Stmt *NullabilitySource = BinOp ? BinOp->getLHS() : S;
1360 State = State->set<NullabilityMap>(
1361 ValueRegion, NullabilityState(LocNullability, NullabilitySource));
1362 C.addTransition(State);
1366void NullabilityChecker::printState(raw_ostream &Out,
ProgramStateRef State,
1367 const char *NL,
const char *Sep)
const {
1369 NullabilityMapTy B = State->get<NullabilityMap>();
1371 if (State->get<InvariantViolated>())
1373 <<
"Nullability invariant was violated, warnings suppressed." << NL;
1378 if (!State->get<InvariantViolated>())
1381 for (
auto [Region, State] : B) {
1382 Out << Region <<
" : ";
1395constexpr llvm::StringLiteral
GroupOptName =
"NoDiagnoseCallsToSystemHeaders";
1397#define REGISTER_CHECKER(NAME, TRACKING_REQUIRED) \
1398 void ento::register##NAME##Checker(CheckerManager &Mgr) { \
1399 NullabilityChecker *Chk = Mgr.getChecker<NullabilityChecker>(); \
1400 Chk->NAME.enable(Mgr); \
1401 Chk->NeedTracking = Chk->NeedTracking || TRACKING_REQUIRED; \
1402 Chk->NoDiagnoseCallsToSystemHeaders = \
1403 Mgr.getAnalyzerOptions().getCheckerBooleanOption(GroupName, \
1404 GroupOptName, true); \
1407 bool ento::shouldRegister##NAME##Checker(const CheckerManager &) { \
#define REGISTER_CHECKER(name)
static void print(llvm::raw_ostream &OS, const T &V, ASTContext &ASTCtx, QualType Ty)
static bool isValidPointerType(QualType T)
static NullConstraint getNullConstraint(DefinedOrUnknownSVal Val, ProgramStateRef State)
static bool isARCNilInitializedLocal(CheckerContext &C, const Stmt *S)
Returns true if.
constexpr llvm::StringLiteral GroupOptName
static bool checkValueAtLValForInvariantViolation(ProgramStateRef State, SVal LV, QualType T)
Returns true when the value stored at the given location has been constrained to null after being pas...
static const Expr * matchValueExprForBind(const Stmt *S)
For a given statement performing a bind, attempt to syntactically match the expression resulting in t...
static bool checkSelfIvarsForInvariantViolation(ProgramStateRef State, const LocationContext *LocCtxt)
static bool checkInvariantViolation(ProgramStateRef State, ExplodedNode *N, CheckerContext &C)
constexpr llvm::StringLiteral GroupName
static const Expr * lookThroughImplicitCasts(const Expr *E)
Find the outermost subexpression of E that is not an implicit cast.
static bool checkParamsForPreconditionViolation(ArrayRef< ParmVarDecl * > Params, ProgramStateRef State, const LocationContext *LocCtxt)
static Nullability getReceiverNullability(const ObjCMethodCall &M, ProgramStateRef State)
#define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value)
Declares an immutable map of type NameTy, suitable for placement into the ProgramState.
#define REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, Type)
Declares a program state trait for type Type called Name, and introduce a type named NameTy.
const Decl * getDecl() const
static std::optional< AnyCall > forDecl(const Decl *D)
If D is a callable (Objective-C method or a function), return a constructed AnyCall object.
Decl - This represents one declaration (or definition), e.g.
This represents one expression.
Expr * IgnoreImpCasts() LLVM_READONLY
Skip past any implicit casts which might surround this expression until reaching a fixed point.
QualType getReturnType() const
It wraps the AnalysisDeclContext to represent both the call stack with the help of StackFrameContext ...
const Decl * getDecl() const
const ImplicitParamDecl * getSelfDecl() const
Represents an ObjC class declaration.
Represents a pointer to an Objective C object.
ObjCInterfaceDecl * getInterfaceDecl() const
If this pointer points to an Objective @interface type, gets the declaration for that interface.
A (possibly-)qualified type.
StringRef getNameForSlot(unsigned argIndex) const
Retrieve the name at a given position in the selector.
const IdentifierInfo * getIdentifierInfoForSlot(unsigned argIndex) const
Retrieve the identifier at a given position in the selector.
Stmt - This represents one statement.
SourceLocation getBeginLoc() const LLVM_READONLY
bool isObjCObjectPointerType() const
const SourceManager & getSourceManager() const
virtual void emitReport(std::unique_ptr< BugReport > R)
Add the given report to the set of reports tracked by BugReporter.
SVal getReturnValue() const
Returns the return value of the call.
Checker families (where a single backend class implements multiple related frontends) should derive f...
bool isConstrainedFalse() const
Return true if the constraint is perfectly constrained to 'false'.
bool isConstrainedTrue() const
Return true if the constraint is perfectly constrained to 'true'.
const ProgramStateRef & getState() const
const Stmt * getStmtForDiagnostics() const
If the node's program point corresponds to a statement, retrieve that statement.
const LocationContext * getLocationContext() const
ExplodedNode * getFirstPred()
MemRegion - The root abstract class for all memory regions.
const RegionTy * getAs() const
Represents any expression that calls an Objective-C method.
const ObjCMethodDecl * getDecl() const override
Returns the declaration of the function or method that will be called.
bool isInstanceMessage() const
ObjCMessageKind getMessageKind() const
Returns how the message was written in the source (property access, subscript, or explicit message se...
const ObjCMessageExpr * getOriginExpr() const override
Returns the expression whose value will be the result of this call.
ArrayRef< ParmVarDecl * > parameters() const override
Return call's formal parameters.
SVal getReceiverSVal() const
Returns the value of the receiver at the time of this call.
bool isReceiverSelfOrSuper() const
Checks if the receiver refers to 'self' or 'super'.
Selector getSelector() const
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
std::optional< T > getAs() const
Convert to the specified SVal type, returning std::nullopt if this SVal is not of the desired type.
QualType getType(const ASTContext &) const
Try to get a reasonable type for the given value.
const MemRegion * getAsRegion() const
bool isDead(SymbolRef sym)
Returns whether or not a symbol has been confirmed dead.
bool isLiveRegion(const MemRegion *region)
SymbolicRegion - A special, "non-concrete" region.
virtual QualType getValueType() const =0
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.
const char *const MemoryError
Nullability getNullabilityAnnotation(QualType Type)
Get nullability annotation for a given type.
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
const SymExpr * SymbolRef
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
std::shared_ptr< PathDiagnosticPiece > PathDiagnosticPieceRef
bool IsNonNull(InterpState &S, CodePtr OpPC)
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.
bool isa(CodeGen::Address addr)
bool operator==(const CallGraphNode::CallRecord &LHS, const CallGraphNode::CallRecord &RHS)
ObjCMethodFamily
A family of Objective-C methods.
const FunctionProtoType * T
@ Interface
The "__interface" keyword introduces the elaborated-type-specifier.