1421 lines · cpp
1//===-- NullabilityChecker.cpp - Nullability checker ----------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This checker tries to find nullability violations. There are several kinds of10// possible violations:11// * Null pointer is passed to a pointer which has a _Nonnull type.12// * Null pointer is returned from a function which has a _Nonnull return type.13// * Nullable pointer is passed to a pointer which has a _Nonnull type.14// * Nullable pointer is returned from a function which has a _Nonnull return15// type.16// * Nullable pointer is dereferenced.17//18// This checker propagates the nullability information of the pointers and looks19// for the patterns that are described above. Explicit casts are trusted and are20// considered a way to suppress false positives for this checker. The other way21// to suppress warnings would be to add asserts or guarding if statements to the22// code. In addition to the nullability propagation this checker also uses some23// heuristics to suppress potential false positives.24//25//===----------------------------------------------------------------------===//26 27#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"28 29#include "clang/Analysis/AnyCall.h"30#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"31#include "clang/StaticAnalyzer/Core/Checker.h"32#include "clang/StaticAnalyzer/Core/CheckerManager.h"33#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"34#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"35#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h"36 37#include "llvm/ADT/STLExtras.h"38#include "llvm/ADT/StringExtras.h"39#include "llvm/Support/Path.h"40 41using namespace clang;42using namespace ento;43 44namespace {45 46/// Returns the most nullable nullability. This is used for message expressions47/// like [receiver method], where the nullability of this expression is either48/// the nullability of the receiver or the nullability of the return type of the49/// method, depending on which is more nullable. Contradicted is considered to50/// be the most nullable, to avoid false positive results.51Nullability getMostNullable(Nullability Lhs, Nullability Rhs) {52 return static_cast<Nullability>(53 std::min(static_cast<char>(Lhs), static_cast<char>(Rhs)));54}55 56const char *getNullabilityString(Nullability Nullab) {57 switch (Nullab) {58 case Nullability::Contradicted:59 return "contradicted";60 case Nullability::Nullable:61 return "nullable";62 case Nullability::Unspecified:63 return "unspecified";64 case Nullability::Nonnull:65 return "nonnull";66 }67 llvm_unreachable("Unexpected enumeration.");68 return "";69}70 71// These enums are used as an index to ErrorMessages array.72// FIXME: ErrorMessages no longer exists, perhaps remove this as well?73enum class ErrorKind : int {74 NilAssignedToNonnull,75 NilPassedToNonnull,76 NilReturnedToNonnull,77 NullableAssignedToNonnull,78 NullableReturnedToNonnull,79 NullableDereferenced,80 NullablePassedToNonnull81};82 83class NullabilityChecker84 : public CheckerFamily<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> {90 91public:92 // If true, the checker will not diagnose nullabilility issues for calls93 // to system headers. This option is motivated by the observation that large94 // projects may have many nullability warnings. These projects may95 // find warnings about nullability annotations that they have explicitly96 // added themselves higher priority to fix than warnings on calls to system97 // libraries.98 bool NoDiagnoseCallsToSystemHeaders = false;99 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;112 ProgramStateRef evalAssume(ProgramStateRef State, SVal Cond,113 bool Assumption) const;114 115 void printState(raw_ostream &Out, ProgramStateRef State, const char *NL,116 const char *Sep) const override;117 118 StringRef getDebugTag() const override { return "NullabilityChecker"; }119 120 // FIXME: All bug types share the same Description ("Nullability") since the121 // creation of this checker. We should write more descriptive descriptions...122 // or just eliminate the Description field if it is meaningless?123 CheckerFrontendWithBugType NullPassedToNonnull{"Nullability",124 categories::MemoryError};125 CheckerFrontendWithBugType NullReturnedFromNonnull{"Nullability",126 categories::MemoryError};127 CheckerFrontendWithBugType NullableDereferenced{"Nullability",128 categories::MemoryError};129 CheckerFrontendWithBugType NullablePassedToNonnull{"Nullability",130 categories::MemoryError};131 CheckerFrontendWithBugType NullableReturnedFromNonnull{132 "Nullability", categories::MemoryError};133 134 // When set to false no nullability information will be tracked in135 // NullabilityMap. It is possible to catch errors like passing a null pointer136 // to a callee that expects nonnull argument without the information that is137 // stored in the NullabilityMap. This is an optimization.138 bool NeedTracking = false;139 140private:141 class NullabilityBugVisitor : public BugReporterVisitor {142 public:143 NullabilityBugVisitor(const MemRegion *M) : Region(M) {}144 145 void Profile(llvm::FoldingSetNodeID &ID) const override {146 static int X = 0;147 ID.AddPointer(&X);148 ID.AddPointer(Region);149 }150 151 PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,152 BugReporterContext &BRC,153 PathSensitiveBugReport &BR) override;154 155 private:156 // The tracked region.157 const MemRegion *Region;158 };159 160 /// When any of the nonnull arguments of the analyzed function is null, do not161 /// report anything and turn off the check.162 ///163 /// When \p SuppressPath is set to true, no more bugs will be reported on this164 /// path by this checker.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;170 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);175 if (Region) {176 R->markInteresting(Region);177 R->addVisitor<NullabilityBugVisitor>(Region);178 }179 if (ValueExpr) {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))185 bugreporter::trackExpressionValue(N, Ex, *R);186 }187 BR.emitReport(std::move(R));188 }189 190 /// If an SVal wraps a region that should be tracked, it will return a pointer191 /// to the wrapped region. Otherwise it will return a nullptr.192 const SymbolicRegion *getTrackRegion(SVal Val,193 bool CheckSuperRegion = false) const;194 195 /// Returns true if the call is diagnosable in the current analyzer196 /// configuration.197 bool isDiagnosableCall(const CallEvent &Call) const {198 if (NoDiagnoseCallsToSystemHeaders && Call.isInSystemHeader())199 return false;200 201 return true;202 }203};204 205class NullabilityState {206public:207 NullabilityState(Nullability Nullab, const Stmt *Source = nullptr)208 : Nullab(Nullab), Source(Source) {}209 210 const Stmt *getNullabilitySource() const { return Source; }211 212 Nullability getValue() const { return Nullab; }213 214 void Profile(llvm::FoldingSetNodeID &ID) const {215 ID.AddInteger(static_cast<char>(Nullab));216 ID.AddPointer(Source);217 }218 219 void print(raw_ostream &Out) const {220 Out << getNullabilityString(Nullab) << "\n";221 }222 223private:224 Nullability Nullab;225 // Source is the expression which determined the nullability. For example in a226 // message like [nullable nonnull_returning] has nullable nullability, because227 // the receiver is nullable. Here the receiver will be the source of the228 // nullability. This is useful information when the diagnostics are generated.229 const Stmt *Source;230};231 232bool operator==(NullabilityState Lhs, NullabilityState Rhs) {233 return Lhs.getValue() == Rhs.getValue() &&234 Lhs.getNullabilitySource() == Rhs.getNullabilitySource();235}236 237// For the purpose of tracking historical property accesses, the key for lookup238// is an object pointer (could be an instance or a class) paired with the unique239// identifier for the property being invoked on that object.240using ObjectPropPair = std::pair<const MemRegion *, const IdentifierInfo *>;241 242// Metadata associated with the return value from a recorded property access.243struct ConstrainedPropertyVal {244 // This will reference the conjured return SVal for some call245 // of the form [object property]246 DefinedOrUnknownSVal Value;247 248 // If the SVal has been determined to be nonnull, that is recorded here249 bool isConstrainedNonnull;250 251 ConstrainedPropertyVal(DefinedOrUnknownSVal SV)252 : Value(SV), isConstrainedNonnull(false) {}253 254 void Profile(llvm::FoldingSetNodeID &ID) const {255 Value.Profile(ID);256 ID.AddInteger(isConstrainedNonnull ? 1 : 0);257 }258};259 260bool operator==(const ConstrainedPropertyVal &Lhs,261 const ConstrainedPropertyVal &Rhs) {262 return Lhs.Value == Rhs.Value &&263 Lhs.isConstrainedNonnull == Rhs.isConstrainedNonnull;264}265 266} // end anonymous namespace267 268REGISTER_MAP_WITH_PROGRAMSTATE(NullabilityMap, const MemRegion *,269 NullabilityState)270REGISTER_MAP_WITH_PROGRAMSTATE(PropertyAccessesMap, ObjectPropPair,271 ConstrainedPropertyVal)272 273// We say "the nullability type invariant is violated" when a location with a274// non-null type contains NULL or a function with a non-null return type returns275// NULL. Violations of the nullability type invariant can be detected either276// directly (for example, when NULL is passed as an argument to a nonnull277// parameter) or indirectly (for example, when, inside a function, the278// programmer defensively checks whether a nonnull parameter contains NULL and279// finds that it does).280//281// As a matter of policy, the nullability checker typically warns on direct282// violations of the nullability invariant (although it uses various283// heuristics to suppress warnings in some cases) but will not warn if the284// invariant has already been violated along the path (either directly or285// indirectly). As a practical matter, this prevents the analyzer from286// (1) warning on defensive code paths where a nullability precondition is287// determined to have been violated, (2) warning additional times after an288// initial direct violation has been discovered, and (3) warning after a direct289// violation that has been implicitly or explicitly suppressed (for290// example, with a cast of NULL to _Nonnull). In essence, once an invariant291// violation is detected on a path, this checker will be essentially turned off292// for the rest of the analysis293//294// The analyzer takes this approach (rather than generating a sink node) to295// ensure coverage of defensive paths, which may be important for backwards296// compatibility in codebases that were developed without nullability in mind.297REGISTER_TRAIT_WITH_PROGRAMSTATE(InvariantViolated, bool)298 299enum class NullConstraint { IsNull, IsNotNull, Unknown };300 301static NullConstraint getNullConstraint(DefinedOrUnknownSVal Val,302 ProgramStateRef State) {303 ConditionTruthVal Nullness = State->isNull(Val);304 if (Nullness.isConstrainedFalse())305 return NullConstraint::IsNotNull;306 if (Nullness.isConstrainedTrue())307 return NullConstraint::IsNull;308 return NullConstraint::Unknown;309}310 311static bool isValidPointerType(QualType T) {312 return T->isAnyPointerType() || T->isBlockPointerType();313}314 315const SymbolicRegion *316NullabilityChecker::getTrackRegion(SVal Val, bool CheckSuperRegion) const {317 if (!NeedTracking)318 return nullptr;319 320 auto RegionSVal = Val.getAs<loc::MemRegionVal>();321 if (!RegionSVal)322 return nullptr;323 324 const MemRegion *Region = RegionSVal->getRegion();325 326 if (CheckSuperRegion) {327 if (const SubRegion *FieldReg = Region->getAs<FieldRegion>()) {328 if (const auto *ER = dyn_cast<ElementRegion>(FieldReg->getSuperRegion()))329 FieldReg = ER;330 return dyn_cast<SymbolicRegion>(FieldReg->getSuperRegion());331 }332 if (auto ElementReg = Region->getAs<ElementRegion>())333 return dyn_cast<SymbolicRegion>(ElementReg->getSuperRegion());334 }335 336 return dyn_cast<SymbolicRegion>(Region);337}338 339PathDiagnosticPieceRef NullabilityChecker::NullabilityBugVisitor::VisitNode(340 const ExplodedNode *N, BugReporterContext &BRC,341 PathSensitiveBugReport &BR) {342 ProgramStateRef State = N->getState();343 ProgramStateRef StatePrev = N->getFirstPred()->getState();344 345 const NullabilityState *TrackedNullab = State->get<NullabilityMap>(Region);346 const NullabilityState *TrackedNullabPrev =347 StatePrev->get<NullabilityMap>(Region);348 if (!TrackedNullab)349 return nullptr;350 351 if (TrackedNullabPrev &&352 TrackedNullabPrev->getValue() == TrackedNullab->getValue())353 return nullptr;354 355 // Retrieve the associated statement.356 const Stmt *S = TrackedNullab->getNullabilitySource();357 if (!S || S->getBeginLoc().isInvalid()) {358 S = N->getStmtForDiagnostics();359 }360 361 if (!S)362 return nullptr;363 364 std::string InfoText =365 (llvm::Twine("Nullability '") +366 getNullabilityString(TrackedNullab->getValue()) + "' is inferred")367 .str();368 369 // Generate the extra diagnostic.370 PathDiagnosticLocation Pos(S, BRC.getSourceManager(),371 N->getLocationContext());372 return std::make_shared<PathDiagnosticEventPiece>(Pos, InfoText, true);373}374 375/// Returns true when the value stored at the given location has been376/// constrained to null after being passed through an object of nonnnull type.377static bool checkValueAtLValForInvariantViolation(ProgramStateRef State,378 SVal LV, QualType T) {379 if (getNullabilityAnnotation(T) != Nullability::Nonnull)380 return false;381 382 auto RegionVal = LV.getAs<loc::MemRegionVal>();383 if (!RegionVal)384 return false;385 386 // If the value was constrained to null *after* it was passed through that387 // location, it could not have been a concrete pointer *when* it was passed.388 // In that case we would have handled the situation when the value was389 // bound to that location, by emitting (or not emitting) a report.390 // Therefore we are only interested in symbolic regions that can be either391 // null or non-null depending on the value of their respective symbol.392 auto StoredVal = State->getSVal(*RegionVal).getAs<loc::MemRegionVal>();393 if (!StoredVal || !isa<SymbolicRegion>(StoredVal->getRegion()))394 return false;395 396 if (getNullConstraint(*StoredVal, State) == NullConstraint::IsNull)397 return true;398 399 return false;400}401 402static bool403checkParamsForPreconditionViolation(ArrayRef<ParmVarDecl *> Params,404 ProgramStateRef State,405 const LocationContext *LocCtxt) {406 for (const auto *ParamDecl : Params) {407 if (ParamDecl->isParameterPack())408 break;409 410 SVal LV = State->getLValue(ParamDecl, LocCtxt);411 if (checkValueAtLValForInvariantViolation(State, LV,412 ParamDecl->getType())) {413 return true;414 }415 }416 return false;417}418 419static bool420checkSelfIvarsForInvariantViolation(ProgramStateRef State,421 const LocationContext *LocCtxt) {422 auto *MD = dyn_cast<ObjCMethodDecl>(LocCtxt->getDecl());423 if (!MD || !MD->isInstanceMethod())424 return false;425 426 const ImplicitParamDecl *SelfDecl = LocCtxt->getSelfDecl();427 if (!SelfDecl)428 return false;429 430 SVal SelfVal = State->getSVal(State->getRegion(SelfDecl, LocCtxt));431 432 const ObjCObjectPointerType *SelfType =433 dyn_cast<ObjCObjectPointerType>(SelfDecl->getType());434 if (!SelfType)435 return false;436 437 const ObjCInterfaceDecl *ID = SelfType->getInterfaceDecl();438 if (!ID)439 return false;440 441 for (const auto *IvarDecl : ID->ivars()) {442 SVal LV = State->getLValue(IvarDecl, SelfVal);443 if (checkValueAtLValForInvariantViolation(State, LV, IvarDecl->getType())) {444 return true;445 }446 }447 return false;448}449 450static bool checkInvariantViolation(ProgramStateRef State, ExplodedNode *N,451 CheckerContext &C) {452 if (State->get<InvariantViolated>())453 return true;454 455 const LocationContext *LocCtxt = C.getLocationContext();456 const Decl *D = LocCtxt->getDecl();457 if (!D)458 return false;459 460 ArrayRef<ParmVarDecl*> Params;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();467 else468 return false;469 470 if (checkParamsForPreconditionViolation(Params, State, LocCtxt) ||471 checkSelfIvarsForInvariantViolation(State, LocCtxt)) {472 if (!N->isSink())473 C.addTransition(State->set<InvariantViolated>(true), N);474 return true;475 }476 return false;477}478 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 {483 ProgramStateRef OriginalState = N->getState();484 485 if (checkInvariantViolation(OriginalState, N, C))486 return;487 if (SuppressPath) {488 OriginalState = OriginalState->set<InvariantViolated>(true);489 N = C.addTransition(OriginalState, N);490 }491 492 reportBug(Msg, Error, BT, N, Region, C.getBugReporter(), ValueExpr);493}494 495/// Cleaning up the program state.496void NullabilityChecker::checkDeadSymbols(SymbolReaper &SR,497 CheckerContext &C) const {498 ProgramStateRef State = C.getState();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);505 }506 }507 508 // When an object goes out of scope, we can free the history associated509 // with any property accesses on that object510 PropertyAccessesMapTy PropertyAccesses = State->get<PropertyAccessesMap>();511 for (ObjectPropPair PropKey : llvm::make_first_range(PropertyAccesses)) {512 const MemRegion *ReceiverRegion = PropKey.first;513 if (!SR.isLiveRegion(ReceiverRegion)) {514 State = State->remove<PropertyAccessesMap>(PropKey);515 }516 }517 518 // When one of the nonnull arguments are constrained to be null, nullability519 // preconditions are violated. It is not enough to check this only when we520 // actually report an error, because at that time interesting symbols might be521 // reaped.522 if (checkInvariantViolation(State, C.getPredecessor(), C))523 return;524 C.addTransition(State);525}526 527/// This callback triggers when a pointer is dereferenced and the analyzer does528/// not know anything about the value of that pointer. When that pointer is529/// nullable, this code emits a warning.530void NullabilityChecker::checkEvent(ImplicitNullDerefEvent Event) const {531 if (Event.SinkNode->getState()->get<InvariantViolated>())532 return;533 534 const MemRegion *Region =535 getTrackRegion(Event.Location, /*CheckSuperRegion=*/true);536 if (!Region)537 return;538 539 ProgramStateRef State = Event.SinkNode->getState();540 const NullabilityState *TrackedNullability =541 State->get<NullabilityMap>(Region);542 543 if (!TrackedNullability)544 return;545 546 if (NullableDereferenced.isEnabled() &&547 TrackedNullability->getValue() == Nullability::Nullable) {548 BugReporter &BR = *Event.BR;549 // Do not suppress errors on defensive code paths, because dereferencing550 // a nullable pointer is always an error.551 if (Event.IsDirectDereference)552 reportBug("Nullable pointer is dereferenced",553 ErrorKind::NullableDereferenced, NullableDereferenced,554 Event.SinkNode, Region, BR);555 else {556 reportBug("Nullable pointer is passed to a callee that requires a "557 "non-null",558 ErrorKind::NullablePassedToNonnull, NullableDereferenced,559 Event.SinkNode, Region, BR);560 }561 }562}563 564void NullabilityChecker::checkBeginFunction(CheckerContext &C) const {565 if (!C.inTopFrame())566 return;567 568 const LocationContext *LCtx = C.getLocationContext();569 auto AbstractCall = AnyCall::forDecl(LCtx->getDecl());570 if (!AbstractCall || AbstractCall->parameters().empty())571 return;572 573 ProgramStateRef State = C.getState();574 for (const ParmVarDecl *Param : AbstractCall->parameters()) {575 if (!isValidPointerType(Param->getType()))576 continue;577 578 Nullability RequiredNullability =579 getNullabilityAnnotation(Param->getType());580 if (RequiredNullability != Nullability::Nullable)581 continue;582 583 const VarRegion *ParamRegion = State->getRegion(Param, LCtx);584 const MemRegion *ParamPointeeRegion =585 State->getSVal(ParamRegion).getAsRegion();586 if (!ParamPointeeRegion)587 continue;588 589 State = State->set<NullabilityMap>(ParamPointeeRegion,590 NullabilityState(RequiredNullability));591 }592 C.addTransition(State);593}594 595// Whenever we see a load from a typed memory region that's been annotated as596// 'nonnull', we want to trust the user on that and assume that it is is indeed597// non-null.598//599// We do so even if the value is known to have been assigned to null.600// The user should be warned on assigning the null value to a non-null pointer601// as opposed to warning on the later dereference of this pointer.602//603// \code604// int * _Nonnull var = 0; // we want to warn the user here...605// // . . .606// *var = 42; // ...and not here607// \endcode608void NullabilityChecker::checkLocation(SVal Location, bool IsLoad,609 const Stmt *S,610 CheckerContext &Context) const {611 // We should care only about loads.612 // The main idea is to add a constraint whenever we're loading a value from613 // an annotated pointer type.614 if (!IsLoad)615 return;616 617 // Annotations that we want to consider make sense only for types.618 const auto *Region =619 dyn_cast_or_null<TypedValueRegion>(Location.getAsRegion());620 if (!Region)621 return;622 623 ProgramStateRef State = Context.getState();624 625 auto StoredVal = State->getSVal(Region).getAs<loc::MemRegionVal>();626 if (!StoredVal)627 return;628 629 Nullability NullabilityOfTheLoadedValue =630 getNullabilityAnnotation(Region->getValueType());631 632 if (NullabilityOfTheLoadedValue == Nullability::Nonnull) {633 // It doesn't matter what we think about this particular pointer, it should634 // be considered non-null as annotated by the developer.635 if (ProgramStateRef NewState = State->assume(*StoredVal, true)) {636 Context.addTransition(NewState);637 }638 }639}640 641/// Find the outermost subexpression of E that is not an implicit cast.642/// This looks through the implicit casts to _Nonnull that ARC adds to643/// return expressions of ObjC types when the return type of the function or644/// method is non-null but the express is not.645static const Expr *lookThroughImplicitCasts(const Expr *E) {646 return E->IgnoreImpCasts();647}648 649/// This method check when nullable pointer or null value is returned from a650/// function that has nonnull return type.651void NullabilityChecker::checkPreStmt(const ReturnStmt *S,652 CheckerContext &C) const {653 auto RetExpr = S->getRetValue();654 if (!RetExpr)655 return;656 657 if (!isValidPointerType(RetExpr->getType()))658 return;659 660 ProgramStateRef State = C.getState();661 if (State->get<InvariantViolated>())662 return;663 664 auto RetSVal = C.getSVal(S).getAs<DefinedOrUnknownSVal>();665 if (!RetSVal)666 return;667 668 bool InSuppressedMethodFamily = false;669 670 QualType RequiredRetType;671 AnalysisDeclContext *DeclCtxt =672 C.getLocationContext()->getAnalysisDeclContext();673 const Decl *D = DeclCtxt->getDecl();674 if (auto *MD = dyn_cast<ObjCMethodDecl>(D)) {675 // HACK: This is a big hammer to avoid warning when there are defensive676 // nil checks in -init and -copy methods. We should add more sophisticated677 // logic here to suppress on common defensive idioms but still678 // warn when there is a likely problem.679 ObjCMethodFamily Family = MD->getMethodFamily();680 if (OMF_init == Family || OMF_copy == Family || OMF_mutableCopy == Family)681 InSuppressedMethodFamily = true;682 683 RequiredRetType = MD->getReturnType();684 } else if (auto *FD = dyn_cast<FunctionDecl>(D)) {685 RequiredRetType = FD->getReturnType();686 } else {687 return;688 }689 690 NullConstraint Nullness = getNullConstraint(*RetSVal, State);691 692 Nullability RequiredNullability = getNullabilityAnnotation(RequiredRetType);693 if (const auto *FunDecl = C.getLocationContext()->getDecl();694 FunDecl && FunDecl->getAttr<ReturnsNonNullAttr>() &&695 (RequiredNullability == Nullability::Unspecified ||696 RequiredNullability == Nullability::Nullable)) {697 // If a function is marked with the returns_nonnull attribute,698 // the return value must be non-null.699 RequiredNullability = Nullability::Nonnull;700 }701 702 // If the returned value is null but the type of the expression703 // generating it is nonnull then we will suppress the diagnostic.704 // This enables explicit suppression when returning a nil literal in a705 // function with a _Nonnull return type:706 // return (NSString * _Nonnull)0;707 Nullability RetExprTypeLevelNullability =708 getNullabilityAnnotation(lookThroughImplicitCasts(RetExpr)->getType());709 710 if (RequiredNullability == Nullability::Nonnull &&711 Nullness == NullConstraint::IsNull) {712 if (NullReturnedFromNonnull.isEnabled() &&713 RetExprTypeLevelNullability != Nullability::Nonnull &&714 !InSuppressedMethodFamily) {715 ExplodedNode *N = C.generateErrorNode(State);716 if (!N)717 return;718 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,726 RetExpr);727 return;728 }729 730 // If null was returned from a non-null function, mark the nullability731 // invariant as violated even if the diagnostic was suppressed.732 State = State->set<InvariantViolated>(true);733 C.addTransition(State);734 return;735 }736 737 const MemRegion *Region = getTrackRegion(*RetSVal);738 if (!Region)739 return;740 741 const NullabilityState *TrackedNullability =742 State->get<NullabilityMap>(Region);743 if (TrackedNullability) {744 Nullability TrackedNullabValue = TrackedNullability->getValue();745 if (NullableReturnedFromNonnull.isEnabled() &&746 Nullness != NullConstraint::IsNotNull &&747 TrackedNullabValue == Nullability::Nullable &&748 RequiredNullability == Nullability::Nonnull) {749 ExplodedNode *N = C.addTransition(State, C.getPredecessor());750 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";755 756 reportBugIfInvariantHolds(OS.str(), ErrorKind::NullableReturnedToNonnull,757 NullableReturnedFromNonnull, N, Region, C);758 }759 return;760 }761 if (RequiredNullability == Nullability::Nullable) {762 State = State->set<NullabilityMap>(Region,763 NullabilityState(RequiredNullability,764 S));765 C.addTransition(State);766 }767}768 769/// This callback warns when a nullable pointer or a null value is passed to a770/// function that expects its argument to be nonnull.771void NullabilityChecker::checkPreCall(const CallEvent &Call,772 CheckerContext &C) const {773 if (!Call.getDecl())774 return;775 776 ProgramStateRef State = C.getState();777 if (State->get<InvariantViolated>())778 return;779 780 ProgramStateRef OrigState = State;781 782 unsigned Idx = 0;783 for (const ParmVarDecl *Param : Call.parameters()) {784 if (Param->isParameterPack())785 break;786 787 if (Idx >= Call.getNumArgs())788 break;789 790 const Expr *ArgExpr = Call.getArgExpr(Idx);791 auto ArgSVal = Call.getArgSVal(Idx++).getAs<DefinedOrUnknownSVal>();792 if (!ArgSVal)793 continue;794 795 if (!isValidPointerType(Param->getType()) &&796 !Param->getType()->isReferenceType())797 continue;798 799 NullConstraint Nullness = getNullConstraint(*ArgSVal, State);800 801 Nullability RequiredNullability =802 getNullabilityAnnotation(Param->getType());803 Nullability ArgExprTypeLevelNullability =804 getNullabilityAnnotation(lookThroughImplicitCasts(ArgExpr)->getType());805 806 unsigned ParamIdx = Param->getFunctionScopeIndex() + 1;807 808 if (NullPassedToNonnull.isEnabled() && Nullness == NullConstraint::IsNull &&809 ArgExprTypeLevelNullability != Nullability::Nonnull &&810 RequiredNullability == Nullability::Nonnull &&811 isDiagnosableCall(Call)) {812 ExplodedNode *N = C.generateErrorNode(State);813 if (!N)814 return;815 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 " << ParamIdx820 << llvm::getOrdinalSuffix(ParamIdx) << " parameter";821 reportBugIfInvariantHolds(OS.str(), ErrorKind::NilPassedToNonnull,822 NullPassedToNonnull, N, nullptr, C, ArgExpr,823 /*SuppressPath=*/false);824 return;825 }826 827 const MemRegion *Region = getTrackRegion(*ArgSVal);828 if (!Region)829 continue;830 831 const NullabilityState *TrackedNullability =832 State->get<NullabilityMap>(Region);833 834 if (TrackedNullability) {835 if (Nullness == NullConstraint::IsNotNull ||836 TrackedNullability->getValue() != Nullability::Nullable)837 continue;838 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,849 ArgExpr, /*SuppressPath=*/true);850 return;851 }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, /*SuppressPath=*/true);858 return;859 }860 continue;861 }862 }863 if (State != OrigState)864 C.addTransition(State);865}866 867/// Suppress the nullability warnings for some functions.868void NullabilityChecker::checkPostCall(const CallEvent &Call,869 CheckerContext &C) const {870 auto Decl = Call.getDecl();871 if (!Decl)872 return;873 // ObjC Messages handles in a different callback.874 if (Call.getKind() == CE_ObjCMessage)875 return;876 const FunctionType *FuncType = Decl->getFunctionType();877 if (!FuncType)878 return;879 QualType ReturnType = FuncType->getReturnType();880 if (!isValidPointerType(ReturnType))881 return;882 ProgramStateRef State = C.getState();883 if (State->get<InvariantViolated>())884 return;885 886 const MemRegion *Region = getTrackRegion(Call.getReturnValue());887 if (!Region)888 return;889 890 // CG headers are misannotated. Do not warn for symbols that are the results891 // of CG calls.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);897 return;898 }899 900 const NullabilityState *TrackedNullability =901 State->get<NullabilityMap>(Region);902 903 // ObjCMessageExpr gets the actual type through904 // Sema::getMessageSendResultType, instead of using the return type of905 // MethodDecl directly. The final type is generated by considering the906 // nullability of receiver and MethodDecl together. Thus, The type of907 // ObjCMessageExpr is prefer.908 if (const Expr *E = Call.getOriginExpr())909 ReturnType = E->getType();910 911 if (!TrackedNullability &&912 getNullabilityAnnotation(ReturnType) == Nullability::Nullable) {913 State = State->set<NullabilityMap>(Region, Nullability::Nullable);914 C.addTransition(State);915 }916}917 918static Nullability getReceiverNullability(const ObjCMethodCall &M,919 ProgramStateRef State) {920 if (M.isReceiverSelfOrSuper()) {921 // For super and super class receivers we assume that the receiver is922 // nonnull.923 return Nullability::Nonnull;924 }925 // Otherwise look up nullability in the state.926 SVal Receiver = M.getReceiverSVal();927 if (auto DefOrUnknown = Receiver.getAs<DefinedOrUnknownSVal>()) {928 // If the receiver is constrained to be nonnull, assume that it is nonnull929 // regardless of its type.930 NullConstraint Nullness = getNullConstraint(*DefOrUnknown, State);931 if (Nullness == NullConstraint::IsNotNull)932 return Nullability::Nonnull;933 }934 auto ValueRegionSVal = Receiver.getAs<loc::MemRegionVal>();935 if (ValueRegionSVal) {936 const MemRegion *SelfRegion = ValueRegionSVal->getRegion();937 assert(SelfRegion);938 939 const NullabilityState *TrackedSelfNullability =940 State->get<NullabilityMap>(SelfRegion);941 if (TrackedSelfNullability)942 return TrackedSelfNullability->getValue();943 }944 return Nullability::Unspecified;945}946 947// The return value of a property access is typically a temporary value which948// will not be tracked in a persistent manner by the analyzer. We use949// evalAssume() in order to immediately record constraints on those temporaries950// at the time they are imposed (e.g. by a nil-check conditional).951ProgramStateRef NullabilityChecker::evalAssume(ProgramStateRef State, SVal Cond,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);957 if (IsNonNull.isConstrainedTrue()) {958 ConstrainedPropertyVal Replacement = PropVal;959 Replacement.isConstrainedNonnull = true;960 State = State->set<PropertyAccessesMap>(PropKey, Replacement);961 } else if (IsNonNull.isConstrainedFalse()) {962 // Space optimization: no point in tracking constrained-null cases963 State = State->remove<PropertyAccessesMap>(PropKey);964 }965 }966 }967 968 return State;969}970 971/// Calculate the nullability of the result of a message expr based on the972/// nullability of the receiver, the nullability of the return value, and the973/// constraints.974void NullabilityChecker::checkPostObjCMessage(const ObjCMethodCall &M,975 CheckerContext &C) const {976 auto Decl = M.getDecl();977 if (!Decl)978 return;979 QualType RetType = Decl->getReturnType();980 if (!isValidPointerType(RetType))981 return;982 983 ProgramStateRef State = C.getState();984 if (State->get<InvariantViolated>())985 return;986 987 const MemRegion *ReturnRegion = getTrackRegion(M.getReturnValue());988 if (!ReturnRegion)989 return;990 991 auto Interface = Decl->getClassInterface();992 auto Name = Interface ? Interface->getName() : "";993 // In order to reduce the noise in the diagnostics generated by this checker,994 // some framework and programming style based heuristics are used. These995 // heuristics are for Cocoa APIs which have NS prefix.996 if (Name.starts_with("NS")) {997 // Developers rely on dynamic invariants such as an item should be available998 // in a collection, or a collection is not empty often. Those invariants can999 // not be inferred by any static analysis tool. To not to bother the users1000 // with too many false positives, every item retrieval function should be1001 // ignored for collections. The instance methods of dictionaries in Cocoa1002 // are either item retrieval related or not interesting nullability wise.1003 // Using this fact, to keep the code easier to read just ignore the return1004 // value of every instance method of dictionaries.1005 if (M.isInstanceMessage() && Name.contains("Dictionary")) {1006 State =1007 State->set<NullabilityMap>(ReturnRegion, Nullability::Contradicted);1008 C.addTransition(State);1009 return;1010 }1011 // For similar reasons ignore some methods of Cocoa arrays.1012 StringRef FirstSelectorSlot = M.getSelector().getNameForSlot(0);1013 if (Name.contains("Array") &&1014 (FirstSelectorSlot == "firstObject" ||1015 FirstSelectorSlot == "lastObject")) {1016 State =1017 State->set<NullabilityMap>(ReturnRegion, Nullability::Contradicted);1018 C.addTransition(State);1019 return;1020 }1021 1022 // Encoding related methods of string should not fail when lossless1023 // encodings are used. Using lossless encodings is so frequent that ignoring1024 // this class of methods reduced the emitted diagnostics by about 30% on1025 // some projects (and all of that was false positives).1026 if (Name.contains("String")) {1027 for (auto *Param : M.parameters()) {1028 if (Param->getName() == "encoding") {1029 State = State->set<NullabilityMap>(ReturnRegion,1030 Nullability::Contradicted);1031 C.addTransition(State);1032 return;1033 }1034 }1035 }1036 }1037 1038 const ObjCMessageExpr *Message = M.getOriginExpr();1039 Nullability SelfNullability = getReceiverNullability(M, State);1040 1041 const NullabilityState *NullabilityOfReturn =1042 State->get<NullabilityMap>(ReturnRegion);1043 1044 if (NullabilityOfReturn) {1045 // When we have a nullability tracked for the return value, the nullability1046 // of the expression will be the most nullable of the receiver and the1047 // return value.1048 Nullability RetValTracked = NullabilityOfReturn->getValue();1049 Nullability ComputedNullab =1050 getMostNullable(RetValTracked, SelfNullability);1051 if (ComputedNullab != RetValTracked &&1052 ComputedNullab != Nullability::Unspecified) {1053 const Stmt *NullabilitySource =1054 ComputedNullab == RetValTracked1055 ? NullabilityOfReturn->getNullabilitySource()1056 : Message->getInstanceReceiver();1057 State = State->set<NullabilityMap>(1058 ReturnRegion, NullabilityState(ComputedNullab, NullabilitySource));1059 C.addTransition(State);1060 }1061 return;1062 }1063 1064 // No tracked information. Use static type information for return value.1065 Nullability RetNullability = getNullabilityAnnotation(Message->getType());1066 1067 // Properties might be computed, which means the property value could1068 // theoretically change between calls even in commonly-observed cases like1069 // this:1070 //1071 // if (foo.prop) { // ok, it's nonnull here...1072 // [bar doStuffWithNonnullVal:foo.prop]; // ...but what about1073 // here?1074 // }1075 //1076 // If the property is nullable-annotated, a naive analysis would lead to many1077 // false positives despite the presence of probably-correct nil-checks. To1078 // reduce the false positive rate, we maintain a history of the most recently1079 // observed property value. For each property access, if the prior value has1080 // been constrained to be not nil then we will conservatively assume that the1081 // next access can be inferred as nonnull.1082 if (RetNullability != Nullability::Nonnull &&1083 M.getMessageKind() == OCM_PropertyAccess && !C.wasInlined) {1084 bool LookupResolved = false;1085 if (const MemRegion *ReceiverRegion = getTrackRegion(M.getReceiverSVal())) {1086 if (const IdentifierInfo *Ident =1087 M.getSelector().getIdentifierInfoForSlot(0)) {1088 LookupResolved = true;1089 ObjectPropPair Key = std::make_pair(ReceiverRegion, Ident);1090 const ConstrainedPropertyVal *PrevPropVal =1091 State->get<PropertyAccessesMap>(Key);1092 if (PrevPropVal && PrevPropVal->isConstrainedNonnull) {1093 RetNullability = Nullability::Nonnull;1094 } else {1095 // If a previous property access was constrained as nonnull, we hold1096 // on to that constraint (effectively inferring that all subsequent1097 // accesses on that code path can be inferred as nonnull). If the1098 // previous property access was *not* constrained as nonnull, then1099 // let's throw it away in favor of keeping the SVal associated with1100 // this more recent access.1101 if (auto ReturnSVal =1102 M.getReturnValue().getAs<DefinedOrUnknownSVal>()) {1103 State = State->set<PropertyAccessesMap>(1104 Key, ConstrainedPropertyVal(*ReturnSVal));1105 }1106 }1107 }1108 }1109 1110 if (!LookupResolved) {1111 // Fallback: err on the side of suppressing the false positive.1112 RetNullability = Nullability::Nonnull;1113 }1114 }1115 1116 Nullability ComputedNullab = getMostNullable(RetNullability, SelfNullability);1117 if (ComputedNullab == Nullability::Nullable) {1118 const Stmt *NullabilitySource = ComputedNullab == RetNullability1119 ? Message1120 : Message->getInstanceReceiver();1121 State = State->set<NullabilityMap>(1122 ReturnRegion, NullabilityState(ComputedNullab, NullabilitySource));1123 C.addTransition(State);1124 }1125}1126 1127/// Explicit casts are trusted. If there is a disagreement in the nullability1128/// annotations in the destination and the source or '0' is casted to nonnull1129/// track the value as having contraditory nullability. This will allow users to1130/// suppress warnings.1131void NullabilityChecker::checkPostStmt(const ExplicitCastExpr *CE,1132 CheckerContext &C) const {1133 QualType OriginType = CE->getSubExpr()->getType();1134 QualType DestType = CE->getType();1135 if (!isValidPointerType(OriginType))1136 return;1137 if (!isValidPointerType(DestType))1138 return;1139 1140 ProgramStateRef State = C.getState();1141 if (State->get<InvariantViolated>())1142 return;1143 1144 Nullability DestNullability = getNullabilityAnnotation(DestType);1145 1146 // No explicit nullability in the destination type, so this cast does not1147 // change the nullability.1148 if (DestNullability == Nullability::Unspecified)1149 return;1150 1151 auto RegionSVal = C.getSVal(CE).getAs<DefinedOrUnknownSVal>();1152 const MemRegion *Region = getTrackRegion(*RegionSVal);1153 if (!Region)1154 return;1155 1156 // When 0 is converted to nonnull mark it as contradicted.1157 if (DestNullability == Nullability::Nonnull) {1158 NullConstraint Nullness = getNullConstraint(*RegionSVal, State);1159 if (Nullness == NullConstraint::IsNull) {1160 State = State->set<NullabilityMap>(Region, Nullability::Contradicted);1161 C.addTransition(State);1162 return;1163 }1164 }1165 1166 const NullabilityState *TrackedNullability =1167 State->get<NullabilityMap>(Region);1168 1169 if (!TrackedNullability) {1170 if (DestNullability != Nullability::Nullable)1171 return;1172 State = State->set<NullabilityMap>(Region,1173 NullabilityState(DestNullability, CE));1174 C.addTransition(State);1175 return;1176 }1177 1178 if (TrackedNullability->getValue() != DestNullability &&1179 TrackedNullability->getValue() != Nullability::Contradicted) {1180 State = State->set<NullabilityMap>(Region, Nullability::Contradicted);1181 C.addTransition(State);1182 }1183}1184 1185/// For a given statement performing a bind, attempt to syntactically1186/// match the expression resulting in the bound value.1187static const Expr * matchValueExprForBind(const Stmt *S) {1188 // For `x = e` the value expression is the right-hand side.1189 if (auto *BinOp = dyn_cast<BinaryOperator>(S)) {1190 if (BinOp->getOpcode() == BO_Assign)1191 return BinOp->getRHS();1192 }1193 1194 // For `int x = e` the value expression is the initializer.1195 if (auto *DS = dyn_cast<DeclStmt>(S)) {1196 if (DS->isSingleDecl()) {1197 auto *VD = dyn_cast<VarDecl>(DS->getSingleDecl());1198 if (!VD)1199 return nullptr;1200 1201 if (const Expr *Init = VD->getInit())1202 return Init;1203 }1204 }1205 1206 return nullptr;1207}1208 1209/// Returns true if \param S is a DeclStmt for a local variable that1210/// ObjC automated reference counting initialized with zero.1211static bool isARCNilInitializedLocal(CheckerContext &C, const Stmt *S) {1212 // We suppress diagnostics for ARC zero-initialized _Nonnull locals. This1213 // prevents false positives when a _Nonnull local variable cannot be1214 // initialized with an initialization expression:1215 // NSString * _Nonnull s; // no-warning1216 // @autoreleasepool {1217 // s = ...1218 // }1219 //1220 // FIXME: We should treat implicitly zero-initialized _Nonnull locals as1221 // uninitialized in Sema's UninitializedValues analysis to warn when a use of1222 // the zero-initialized definition will unexpectedly yield nil.1223 1224 // Locals are only zero-initialized when automated reference counting1225 // is turned on.1226 if (!C.getASTContext().getLangOpts().ObjCAutoRefCount)1227 return false;1228 1229 auto *DS = dyn_cast<DeclStmt>(S);1230 if (!DS || !DS->isSingleDecl())1231 return false;1232 1233 auto *VD = dyn_cast<VarDecl>(DS->getSingleDecl());1234 if (!VD)1235 return false;1236 1237 // Sema only zero-initializes locals with ObjCLifetimes.1238 if(!VD->getType().getQualifiers().hasObjCLifetime())1239 return false;1240 1241 const Expr *Init = VD->getInit();1242 assert(Init && "ObjC local under ARC without initializer");1243 1244 // Return false if the local is explicitly initialized (e.g., with '= nil').1245 if (!isa<ImplicitValueInitExpr>(Init))1246 return false;1247 1248 return true;1249}1250 1251/// Propagate the nullability information through binds and warn when nullable1252/// pointer or null symbol is assigned to a pointer with a nonnull type.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());1257 if (!TVR)1258 return;1259 1260 QualType LocType = TVR->getValueType();1261 if (!isValidPointerType(LocType))1262 return;1263 1264 ProgramStateRef State = C.getState();1265 if (State->get<InvariantViolated>())1266 return;1267 1268 auto ValDefOrUnknown = V.getAs<DefinedOrUnknownSVal>();1269 if (!ValDefOrUnknown)1270 return;1271 1272 NullConstraint RhsNullness = getNullConstraint(*ValDefOrUnknown, State);1273 1274 Nullability ValNullability = Nullability::Unspecified;1275 if (SymbolRef Sym = ValDefOrUnknown->getAsSymbol())1276 ValNullability = getNullabilityAnnotation(Sym->getType());1277 1278 Nullability LocNullability = getNullabilityAnnotation(LocType);1279 1280 // If the type of the RHS expression is nonnull, don't warn. This1281 // enables explicit suppression with a cast to nonnull.1282 Nullability ValueExprTypeLevelNullability = Nullability::Unspecified;1283 const Expr *ValueExpr = matchValueExprForBind(S);1284 if (ValueExpr) {1285 ValueExprTypeLevelNullability =1286 getNullabilityAnnotation(lookThroughImplicitCasts(ValueExpr)->getType());1287 }1288 1289 bool NullAssignedToNonNull = (LocNullability == Nullability::Nonnull &&1290 RhsNullness == NullConstraint::IsNull);1291 if (NullPassedToNonnull.isEnabled() && NullAssignedToNonNull &&1292 ValNullability != Nullability::Nonnull &&1293 ValueExprTypeLevelNullability != Nullability::Nonnull &&1294 !isARCNilInitializedLocal(C, S)) {1295 ExplodedNode *N = C.generateErrorNode(State);1296 if (!N)1297 return;1298 1299 1300 const Stmt *ValueStmt = S;1301 if (ValueExpr)1302 ValueStmt = ValueExpr;1303 1304 SmallString<256> SBuf;1305 llvm::raw_svector_ostream OS(SBuf);1306 OS << (LocType->isObjCObjectPointerType() ? "nil" : "Null");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);1310 return;1311 }1312 1313 // If null was returned from a non-null function, mark the nullability1314 // invariant as violated even if the diagnostic was suppressed.1315 if (NullAssignedToNonNull) {1316 State = State->set<InvariantViolated>(true);1317 C.addTransition(State);1318 return;1319 }1320 1321 // Intentionally missing case: '0' is bound to a reference. It is handled by1322 // the DereferenceChecker.1323 1324 const MemRegion *ValueRegion = getTrackRegion(*ValDefOrUnknown);1325 if (!ValueRegion)1326 return;1327 1328 const NullabilityState *TrackedNullability =1329 State->get<NullabilityMap>(ValueRegion);1330 1331 if (TrackedNullability) {1332 if (RhsNullness == NullConstraint::IsNotNull ||1333 TrackedNullability->getValue() != Nullability::Nullable)1334 return;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);1342 }1343 return;1344 }1345 1346 const auto *BinOp = dyn_cast<BinaryOperator>(S);1347 1348 if (ValNullability == Nullability::Nullable) {1349 // Trust the static information of the value more than the static1350 // information on the location.1351 const Stmt *NullabilitySource = BinOp ? BinOp->getRHS() : S;1352 State = State->set<NullabilityMap>(1353 ValueRegion, NullabilityState(ValNullability, NullabilitySource));1354 C.addTransition(State);1355 return;1356 }1357 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);1363 }1364}1365 1366void NullabilityChecker::printState(raw_ostream &Out, ProgramStateRef State,1367 const char *NL, const char *Sep) const {1368 1369 NullabilityMapTy B = State->get<NullabilityMap>();1370 1371 if (State->get<InvariantViolated>())1372 Out << Sep << NL1373 << "Nullability invariant was violated, warnings suppressed." << NL;1374 1375 if (B.isEmpty())1376 return;1377 1378 if (!State->get<InvariantViolated>())1379 Out << Sep << NL;1380 1381 for (auto [Region, State] : B) {1382 Out << Region << " : ";1383 State.print(Out);1384 Out << NL;1385 }1386}1387 1388// The checker group "nullability" (which consists of the checkers that are1389// implemented in this file) has a group-level configuration option which1390// affects all the checkers in the group. As this is a completely unique1391// remnant of old design (this is the only group option in the analyzer), there1392// is no machinery to inject the group name from `Checkers.td`, so it is simply1393// hardcoded here:1394constexpr llvm::StringLiteral GroupName = "nullability";1395constexpr llvm::StringLiteral GroupOptName = "NoDiagnoseCallsToSystemHeaders";1396 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); \1405 } \1406 \1407 bool ento::shouldRegister##NAME##Checker(const CheckerManager &) { \1408 return true; \1409 }1410 1411// The checks are likely to be turned on by default and it is possible to do1412// them without tracking any nullability related information. As an optimization1413// no nullability information will be tracked when only these two checks are1414// enables.1415REGISTER_CHECKER(NullPassedToNonnull, false)1416REGISTER_CHECKER(NullReturnedFromNonnull, false)1417 1418REGISTER_CHECKER(NullableDereferenced, true)1419REGISTER_CHECKER(NullablePassedToNonnull, true)1420REGISTER_CHECKER(NullableReturnedFromNonnull, true)1421