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")
371 return std::make_shared<PathDiagnosticEventPiece>(Pos, InfoText,
true);
404 for (
const auto *ParamDecl : Params) {
405 if (ParamDecl->isParameterPack())
408 SVal LV = State->getLValue(ParamDecl, SF);
419 auto *MD = dyn_cast<ObjCMethodDecl>(SF->
getDecl());
420 if (!MD || !MD->isInstanceMethod())
427 SVal SelfVal = State->getSVal(State->getRegion(SelfDecl, SF));
430 dyn_cast<ObjCObjectPointerType>(SelfDecl->
getType());
438 for (
const auto *IvarDecl : ID->ivars()) {
439 SVal LV = State->getLValue(IvarDecl, SelfVal);
449 if (State->get<InvariantViolated>())
458 if (
const auto *BD = dyn_cast<BlockDecl>(D))
459 Params = BD->parameters();
460 else if (
const auto *FD = dyn_cast<FunctionDecl>(D))
461 Params = FD->parameters();
462 else if (
const auto *MD = dyn_cast<ObjCMethodDecl>(D))
463 Params = MD->parameters();
470 C.addTransition(State->set<InvariantViolated>(
true), N);
476void NullabilityChecker::reportBugIfInvariantHolds(
477 StringRef Msg, ErrorKind
Error,
const BugType &BT, ExplodedNode *N,
478 const MemRegion *Region, CheckerContext &
C,
const Stmt *ValueExpr,
479 bool SuppressPath)
const {
485 OriginalState = OriginalState->set<InvariantViolated>(
true);
486 N =
C.addTransition(OriginalState, N);
489 reportBug(Msg,
Error, BT, N, Region,
C.getBugReporter(), ValueExpr);
493void NullabilityChecker::checkDeadSymbols(SymbolReaper &SR,
494 CheckerContext &
C)
const {
496 NullabilityMapTy Nullabilities = State->get<NullabilityMap>();
497 for (
const MemRegion *Reg : llvm::make_first_range(Nullabilities)) {
498 const auto *Region = Reg->
getAs<SymbolicRegion>();
499 assert(Region &&
"Non-symbolic region is tracked.");
500 if (SR.
isDead(Region->getSymbol())) {
501 State = State->remove<NullabilityMap>(Reg);
507 PropertyAccessesMapTy PropertyAccesses = State->get<PropertyAccessesMap>();
508 for (
ObjectPropPair PropKey : llvm::make_first_range(PropertyAccesses)) {
509 const MemRegion *ReceiverRegion = PropKey.first;
511 State = State->remove<PropertyAccessesMap>(PropKey);
521 C.addTransition(State);
527void NullabilityChecker::checkEvent(ImplicitNullDerefEvent Event)
const {
531 const MemRegion *Region =
532 getTrackRegion(Event.
Location,
true);
537 const NullabilityState *TrackedNullability =
538 State->get<NullabilityMap>(Region);
540 if (!TrackedNullability)
543 if (NullableDereferenced.isEnabled() &&
544 TrackedNullability->getValue() == Nullability::Nullable) {
545 BugReporter &BR = *Event.
BR;
549 reportBug(
"Nullable pointer is dereferenced",
550 ErrorKind::NullableDereferenced, NullableDereferenced,
553 reportBug(
"Nullable pointer is passed to a callee that requires a "
555 ErrorKind::NullablePassedToNonnull, NullableDereferenced,
561void NullabilityChecker::checkBeginFunction(CheckerContext &
C)
const {
565 const StackFrame *SF =
C.getStackFrame();
567 if (!AbstractCall || AbstractCall->parameters().empty())
571 for (
const ParmVarDecl *Param : AbstractCall->parameters()) {
577 if (RequiredNullability != Nullability::Nullable)
580 const VarRegion *ParamRegion = State->getRegion(Param, SF);
581 const MemRegion *ParamPointeeRegion =
582 State->getSVal(ParamRegion).getAsRegion();
583 if (!ParamPointeeRegion)
586 State = State->set<NullabilityMap>(ParamPointeeRegion,
587 NullabilityState(RequiredNullability));
589 C.addTransition(State);
605void NullabilityChecker::checkLocation(SVal Location,
bool IsLoad,
607 CheckerContext &Context)
const {
616 dyn_cast_or_null<TypedValueRegion>(Location.
getAsRegion());
622 auto StoredVal = State->getSVal(Region).getAs<loc::MemRegionVal>();
629 if (NullabilityOfTheLoadedValue == Nullability::Nonnull) {
633 Context.addTransition(NewState);
648void NullabilityChecker::checkPreStmt(
const ReturnStmt *S,
649 CheckerContext &
C)
const {
658 if (State->get<InvariantViolated>())
661 auto RetSVal =
C.getSVal(RetExpr).getAs<DefinedOrUnknownSVal>();
665 bool InSuppressedMethodFamily =
false;
667 QualType RequiredRetType;
668 AnalysisDeclContext *DeclCtxt =
C.getStackFrame()->getAnalysisDeclContext();
670 if (
auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
677 InSuppressedMethodFamily =
true;
679 RequiredRetType = MD->getReturnType();
680 }
else if (
auto *FD = dyn_cast<FunctionDecl>(D)) {
681 RequiredRetType = FD->getReturnType();
689 if (
const auto *FunDecl =
C.getStackFrame()->getDecl();
690 FunDecl && FunDecl->getAttr<ReturnsNonNullAttr>() &&
691 (RequiredNullability == Nullability::Unspecified ||
692 RequiredNullability == Nullability::Nullable)) {
695 RequiredNullability = Nullability::Nonnull;
706 if (RequiredNullability == Nullability::Nonnull &&
708 if (NullReturnedFromNonnull.
isEnabled() &&
709 RetExprTypeLevelNullability != Nullability::Nonnull &&
710 !InSuppressedMethodFamily) {
711 ExplodedNode *N =
C.generateErrorNode(State);
715 SmallString<256> SBuf;
716 llvm::raw_svector_ostream
OS(SBuf);
717 OS << (RetExpr->getType()->isObjCObjectPointerType() ?
"nil" :
"Null");
718 OS <<
" returned from a " <<
C.getDeclDescription(D)
719 <<
" that is expected to return a non-null value";
720 reportBugIfInvariantHolds(
OS.str(), ErrorKind::NilReturnedToNonnull,
721 NullReturnedFromNonnull, N,
nullptr,
C,
728 State = State->set<InvariantViolated>(
true);
729 C.addTransition(State);
733 const MemRegion *Region = getTrackRegion(*RetSVal);
737 const NullabilityState *TrackedNullability =
738 State->get<NullabilityMap>(Region);
739 if (TrackedNullability) {
740 Nullability TrackedNullabValue = TrackedNullability->getValue();
741 if (NullableReturnedFromNonnull.
isEnabled() &&
743 TrackedNullabValue == Nullability::Nullable &&
744 RequiredNullability == Nullability::Nonnull) {
745 ExplodedNode *N =
C.addTransition(State,
C.getPredecessor());
747 SmallString<256> SBuf;
748 llvm::raw_svector_ostream
OS(SBuf);
749 OS <<
"Nullable pointer is returned from a " <<
C.getDeclDescription(D) <<
750 " that is expected to return a non-null value";
752 reportBugIfInvariantHolds(
OS.str(), ErrorKind::NullableReturnedToNonnull,
753 NullableReturnedFromNonnull, N, Region,
C);
757 if (RequiredNullability == Nullability::Nullable) {
758 State = State->set<NullabilityMap>(Region,
759 NullabilityState(RequiredNullability,
761 C.addTransition(State);
767void NullabilityChecker::checkPreCall(
const CallEvent &
Call,
768 CheckerContext &
C)
const {
773 if (State->get<InvariantViolated>())
779 for (
const ParmVarDecl *Param :
Call.parameters()) {
780 if (Param->isParameterPack())
783 if (Idx >=
Call.getNumArgs())
786 const Expr *ArgExpr =
Call.getArgExpr(Idx);
787 auto ArgSVal =
Call.getArgSVal(Idx++).getAs<DefinedOrUnknownSVal>();
792 !Param->getType()->isReferenceType())
802 unsigned ParamIdx = Param->getFunctionScopeIndex() + 1;
805 ArgExprTypeLevelNullability != Nullability::Nonnull &&
806 RequiredNullability == Nullability::Nonnull &&
807 isDiagnosableCall(
Call)) {
808 ExplodedNode *N =
C.generateErrorNode(State);
812 SmallString<256> SBuf;
813 llvm::raw_svector_ostream
OS(SBuf);
814 OS << (Param->getType()->isObjCObjectPointerType() ?
"nil" :
"Null");
815 OS <<
" passed to a callee that requires a non-null " << ParamIdx
816 << llvm::getOrdinalSuffix(ParamIdx) <<
" parameter";
817 reportBugIfInvariantHolds(
OS.str(), ErrorKind::NilPassedToNonnull,
818 NullPassedToNonnull, N,
nullptr,
C, ArgExpr,
823 const MemRegion *Region = getTrackRegion(*ArgSVal);
827 const NullabilityState *TrackedNullability =
828 State->get<NullabilityMap>(Region);
830 if (TrackedNullability) {
832 TrackedNullability->getValue() != Nullability::Nullable)
835 if (NullablePassedToNonnull.isEnabled() &&
836 RequiredNullability == Nullability::Nonnull &&
837 isDiagnosableCall(
Call)) {
838 ExplodedNode *N =
C.addTransition(State);
839 SmallString<256> SBuf;
840 llvm::raw_svector_ostream
OS(SBuf);
841 OS <<
"Nullable pointer is passed to a callee that requires a non-null "
842 << ParamIdx << llvm::getOrdinalSuffix(ParamIdx) <<
" parameter";
843 reportBugIfInvariantHolds(
OS.str(), ErrorKind::NullablePassedToNonnull,
844 NullablePassedToNonnull, N, Region,
C,
848 if (NullableDereferenced.isEnabled() &&
849 Param->getType()->isReferenceType()) {
850 ExplodedNode *N =
C.addTransition(State);
851 reportBugIfInvariantHolds(
852 "Nullable pointer is dereferenced", ErrorKind::NullableDereferenced,
853 NullableDereferenced, N, Region,
C, ArgExpr,
true);
859 if (State != OrigState)
860 C.addTransition(State);
864void NullabilityChecker::checkPostCall(
const CallEvent &
Call,
865 CheckerContext &
C)
const {
872 const FunctionType *FuncType =
Decl->getFunctionType();
879 if (State->get<InvariantViolated>())
882 const MemRegion *Region = getTrackRegion(
Call.getReturnValue());
888 const SourceManager &
SM =
C.getSourceManager();
889 StringRef FilePath =
SM.getFilename(
SM.getSpellingLoc(
Decl->getBeginLoc()));
890 if (llvm::sys::path::filename(FilePath).starts_with(
"CG")) {
891 State = State->set<NullabilityMap>(Region, Nullability::Contradicted);
892 C.addTransition(State);
896 const NullabilityState *TrackedNullability =
897 State->get<NullabilityMap>(Region);
904 if (
const Expr *E =
Call.getOriginExpr())
905 ReturnType = E->getType();
907 if (!TrackedNullability &&
909 State = State->set<NullabilityMap>(Region, Nullability::Nullable);
910 C.addTransition(State);
919 return Nullability::Nonnull;
928 return Nullability::Nonnull;
931 if (ValueRegionSVal) {
932 const MemRegion *SelfRegion = ValueRegionSVal->getRegion();
935 const NullabilityState *TrackedSelfNullability =
936 State->get<NullabilityMap>(SelfRegion);
937 if (TrackedSelfNullability)
938 return TrackedSelfNullability->getValue();
940 return Nullability::Unspecified;
948 bool Assumption)
const {
949 PropertyAccessesMapTy PropertyAccesses = State->get<PropertyAccessesMap>();
950 for (
auto [PropKey, PropVal] : PropertyAccesses) {
951 if (!PropVal.isConstrainedNonnull) {
952 ConditionTruthVal
IsNonNull = State->isNonNull(PropVal.Value);
954 ConstrainedPropertyVal Replacement = PropVal;
955 Replacement.isConstrainedNonnull =
true;
956 State = State->set<PropertyAccessesMap>(PropKey, Replacement);
957 }
else if (
IsNonNull.isConstrainedFalse()) {
959 State = State->remove<PropertyAccessesMap>(PropKey);
970void NullabilityChecker::checkPostObjCMessage(
const ObjCMethodCall &M,
971 CheckerContext &
C)
const {
975 QualType RetType =
Decl->getReturnType();
980 if (State->get<InvariantViolated>())
983 const MemRegion *ReturnRegion = getTrackRegion(M.
getReturnValue());
992 if (Name.starts_with(
"NS")) {
1003 State->set<NullabilityMap>(ReturnRegion, Nullability::Contradicted);
1004 C.addTransition(State);
1009 if (Name.contains(
"Array") &&
1010 (FirstSelectorSlot ==
"firstObject" ||
1011 FirstSelectorSlot ==
"lastObject")) {
1013 State->set<NullabilityMap>(ReturnRegion, Nullability::Contradicted);
1014 C.addTransition(State);
1022 if (Name.contains(
"String")) {
1024 if (Param->getName() ==
"encoding") {
1025 State = State->set<NullabilityMap>(ReturnRegion,
1026 Nullability::Contradicted);
1027 C.addTransition(State);
1037 const NullabilityState *NullabilityOfReturn =
1038 State->get<NullabilityMap>(ReturnRegion);
1040 if (NullabilityOfReturn) {
1044 Nullability RetValTracked = NullabilityOfReturn->getValue();
1046 getMostNullable(RetValTracked, SelfNullability);
1047 if (ComputedNullab != RetValTracked &&
1048 ComputedNullab != Nullability::Unspecified) {
1049 const Stmt *NullabilitySource =
1050 ComputedNullab == RetValTracked
1051 ? NullabilityOfReturn->getNullabilitySource()
1052 :
Message->getInstanceReceiver();
1053 State = State->set<NullabilityMap>(
1054 ReturnRegion, NullabilityState(ComputedNullab, NullabilitySource));
1055 C.addTransition(State);
1078 if (RetNullability != Nullability::Nonnull &&
1080 bool LookupResolved =
false;
1081 if (
const MemRegion *ReceiverRegion = getTrackRegion(M.
getReceiverSVal())) {
1082 if (
const IdentifierInfo *Ident =
1084 LookupResolved =
true;
1086 const ConstrainedPropertyVal *PrevPropVal =
1087 State->get<PropertyAccessesMap>(Key);
1088 if (PrevPropVal && PrevPropVal->isConstrainedNonnull) {
1089 RetNullability = Nullability::Nonnull;
1097 if (
auto ReturnSVal =
1099 State = State->set<PropertyAccessesMap>(
1100 Key, ConstrainedPropertyVal(*ReturnSVal));
1106 if (!LookupResolved) {
1108 RetNullability = Nullability::Nonnull;
1112 Nullability ComputedNullab = getMostNullable(RetNullability, SelfNullability);
1113 if (ComputedNullab == Nullability::Nullable) {
1114 const Stmt *NullabilitySource = ComputedNullab == RetNullability
1116 :
Message->getInstanceReceiver();
1117 State = State->set<NullabilityMap>(
1118 ReturnRegion, NullabilityState(ComputedNullab, NullabilitySource));
1119 C.addTransition(State);
1127void NullabilityChecker::checkPostStmt(
const ExplicitCastExpr *CE,
1128 CheckerContext &
C)
const {
1130 QualType DestType = CE->
getType();
1137 if (State->get<InvariantViolated>())
1144 if (DestNullability == Nullability::Unspecified)
1147 auto RegionSVal =
C.getSVal(CE).getAs<DefinedOrUnknownSVal>();
1148 const MemRegion *Region = getTrackRegion(*RegionSVal);
1153 if (DestNullability == Nullability::Nonnull) {
1156 State = State->set<NullabilityMap>(Region, Nullability::Contradicted);
1157 C.addTransition(State);
1162 const NullabilityState *TrackedNullability =
1163 State->get<NullabilityMap>(Region);
1165 if (!TrackedNullability) {
1166 if (DestNullability != Nullability::Nullable)
1168 State = State->set<NullabilityMap>(Region,
1169 NullabilityState(DestNullability, CE));
1170 C.addTransition(State);
1174 if (TrackedNullability->getValue() != DestNullability &&
1175 TrackedNullability->getValue() != Nullability::Contradicted) {
1176 State = State->set<NullabilityMap>(Region, Nullability::Contradicted);
1177 C.addTransition(State);
1185 if (
auto *BinOp = dyn_cast<BinaryOperator>(S)) {
1186 if (BinOp->getOpcode() == BO_Assign)
1187 return BinOp->getRHS();
1191 if (
auto *DS = dyn_cast<DeclStmt>(S)) {
1192 if (DS->isSingleDecl()) {
1193 auto *VD = dyn_cast<VarDecl>(DS->getSingleDecl());
1197 if (
const Expr *
Init = VD->getInit())
1222 if (!
C.getASTContext().getLangOpts().ObjCAutoRefCount)
1225 auto *DS = dyn_cast<DeclStmt>(S);
1226 if (!DS || !DS->isSingleDecl())
1229 auto *VD = dyn_cast<VarDecl>(DS->getSingleDecl());
1234 if(!VD->getType().getQualifiers().hasObjCLifetime())
1238 assert(
Init &&
"ObjC local under ARC without initializer");
1249void NullabilityChecker::checkBind(SVal L, SVal
V,
const Stmt *S,
1250 bool AtDeclInit, CheckerContext &
C)
const {
1251 const TypedValueRegion *TVR =
1252 dyn_cast_or_null<TypedValueRegion>(L.
getAsRegion());
1261 if (State->get<InvariantViolated>())
1264 auto ValDefOrUnknown =
V.getAs<DefinedOrUnknownSVal>();
1265 if (!ValDefOrUnknown)
1270 Nullability ValNullability = Nullability::Unspecified;
1271 if (
SymbolRef Sym = ValDefOrUnknown->getAsSymbol())
1278 Nullability ValueExprTypeLevelNullability = Nullability::Unspecified;
1281 ValueExprTypeLevelNullability =
1285 bool NullAssignedToNonNull = (LocNullability == Nullability::Nonnull &&
1287 if (NullPassedToNonnull.
isEnabled() && NullAssignedToNonNull &&
1288 ValNullability != Nullability::Nonnull &&
1289 ValueExprTypeLevelNullability != Nullability::Nonnull &&
1291 ExplodedNode *N =
C.generateErrorNode(State);
1296 const Stmt *ValueStmt = S;
1298 ValueStmt = ValueExpr;
1300 SmallString<256> SBuf;
1301 llvm::raw_svector_ostream
OS(SBuf);
1303 OS <<
" assigned to a pointer which is expected to have non-null value";
1304 reportBugIfInvariantHolds(
OS.str(), ErrorKind::NilAssignedToNonnull,
1305 NullPassedToNonnull, N,
nullptr,
C, ValueStmt);
1311 if (NullAssignedToNonNull) {
1312 State = State->set<InvariantViolated>(
true);
1313 C.addTransition(State);
1320 const MemRegion *ValueRegion = getTrackRegion(*ValDefOrUnknown);
1324 const NullabilityState *TrackedNullability =
1325 State->get<NullabilityMap>(ValueRegion);
1327 if (TrackedNullability) {
1329 TrackedNullability->getValue() != Nullability::Nullable)
1331 if (NullablePassedToNonnull.isEnabled() &&
1332 LocNullability == Nullability::Nonnull) {
1333 ExplodedNode *N =
C.addTransition(State,
C.getPredecessor());
1334 reportBugIfInvariantHolds(
"Nullable pointer is assigned to a pointer "
1335 "which is expected to have non-null value",
1336 ErrorKind::NullableAssignedToNonnull,
1337 NullablePassedToNonnull, N, ValueRegion,
C);
1342 const auto *BinOp = dyn_cast<BinaryOperator>(S);
1344 if (ValNullability == Nullability::Nullable) {
1347 const Stmt *NullabilitySource = BinOp ? BinOp->getRHS() : S;
1348 State = State->set<NullabilityMap>(
1349 ValueRegion, NullabilityState(ValNullability, NullabilitySource));
1350 C.addTransition(State);
1354 if (LocNullability == Nullability::Nullable) {
1355 const Stmt *NullabilitySource = BinOp ? BinOp->getLHS() : S;
1356 State = State->set<NullabilityMap>(
1357 ValueRegion, NullabilityState(LocNullability, NullabilitySource));
1358 C.addTransition(State);
1362void NullabilityChecker::printState(raw_ostream &Out,
ProgramStateRef State,
1363 const char *NL,
const char *Sep)
const {
1365 NullabilityMapTy B = State->get<NullabilityMap>();
1367 if (State->get<InvariantViolated>())
1369 <<
"Nullability invariant was violated, warnings suppressed." << NL;
1374 if (!State->get<InvariantViolated>())
1377 for (
auto [Region, State] : B) {
1378 Out << Region <<
" : ";
1391constexpr llvm::StringLiteral
GroupOptName =
"NoDiagnoseCallsToSystemHeaders";
1393#define REGISTER_CHECKER(NAME, TRACKING_REQUIRED) \
1394 void ento::register##NAME##Checker(CheckerManager &Mgr) { \
1395 NullabilityChecker *Chk = Mgr.getChecker<NullabilityChecker>(); \
1396 Chk->NAME.enable(Mgr); \
1397 Chk->NeedTracking = Chk->NeedTracking || TRACKING_REQUIRED; \
1398 Chk->NoDiagnoseCallsToSystemHeaders = \
1399 Mgr.getAnalyzerOptions().getCheckerBooleanOption(GroupName, \
1400 GroupOptName, true); \
1403 bool ento::shouldRegister##NAME##Checker(const CheckerManager &) { \
1418#undef REGISTER_CHECKER
#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 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 StackFrame *SF)
static bool checkSelfIvarsForInvariantViolation(ProgramStateRef State, const StackFrame *SF)
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
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.
It represents a stack frame of the call stack.
const Decl * getDecl() const
const ImplicitParamDecl * getSelfDecl() const
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.
ExplodedNode * getFirstPred()
const StackFrame * getStackFrame() const
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.
@ Interface
The "__interface" keyword introduces the elaborated-type-specifier.