brintos

brintos / llvm-project-archived public Read only

0
0
Text · 53.6 KiB · eeb6b72 Raw
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