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-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This checker tries to find nullability violations. There are several kinds of
10// 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 return
15// type.
16// * Nullable pointer is dereferenced.
17//
18// This checker propagates the nullability information of the pointers and looks
19// for the patterns that are described above. Explicit casts are trusted and are
20// considered a way to suppress false positives for this checker. The other way
21// to suppress warnings would be to add asserts or guarding if statements to the
22// code. In addition to the nullability propagation this checker also uses some
23// 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 expressions
47/// like [receiver method], where the nullability of this expression is either
48/// the nullability of the receiver or the nullability of the return type of the
49/// method, depending on which is more nullable. Contradicted is considered to
50/// be the most nullable, to avoid false positive results.
51Nullability getMostNullable(Nullability Lhs, Nullability Rhs) {
52 return static_cast<Nullability>(
53 std::min(a: static_cast<char>(Lhs), b: 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 NullablePassedToNonnull
81};
82
83class NullabilityChecker
84 : 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 calls
93 // to system headers. This option is motivated by the observation that large
94 // projects may have many nullability warnings. These projects may
95 // find warnings about nullability annotations that they have explicitly
96 // added themselves higher priority to fix than warnings on calls to system
97 // 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 the
121 // 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 in
135 // NullabilityMap. It is possible to catch errors like passing a null pointer
136 // to a callee that expects nonnull argument without the information that is
137 // 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(Ptr: &X);
148 ID.AddPointer(Ptr: 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 not
161 /// report anything and turn off the check.
162 ///
163 /// When \p SuppressPath is set to true, no more bugs will be reported on this
164 /// 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>(args: BT, args&: Msg, args&: N);
175 if (Region) {
176 R->markInteresting(R: Region);
177 R->addVisitor<NullabilityBugVisitor>(ConstructorArgs&: Region);
178 }
179 if (ValueExpr) {
180 R->addRange(R: ValueExpr->getSourceRange());
181 if (Error == ErrorKind::NilAssignedToNonnull ||
182 Error == ErrorKind::NilPassedToNonnull ||
183 Error == ErrorKind::NilReturnedToNonnull)
184 if (const auto *Ex = dyn_cast<Expr>(Val: ValueExpr))
185 bugreporter::trackExpressionValue(N, E: Ex, R&: *R);
186 }
187 BR.emitReport(R: std::move(R));
188 }
189
190 /// If an SVal wraps a region that should be tracked, it will return a pointer
191 /// 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 analyzer
196 /// 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(I: static_cast<char>(Nullab));
216 ID.AddPointer(Ptr: 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 a
226 // message like [nullable nonnull_returning] has nullable nullability, because
227 // the receiver is nullable. Here the receiver will be the source of the
228 // 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 lookup
238// is an object pointer (could be an instance or a class) paired with the unique
239// 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 call
245 // of the form [object property]
246 DefinedOrUnknownSVal Value;
247
248 // If the SVal has been determined to be nonnull, that is recorded here
249 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(I: 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 namespace
267
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 a
274// non-null type contains NULL or a function with a non-null return type returns
275// NULL. Violations of the nullability type invariant can be detected either
276// directly (for example, when NULL is passed as an argument to a nonnull
277// parameter) or indirectly (for example, when, inside a function, the
278// programmer defensively checks whether a nonnull parameter contains NULL and
279// finds that it does).
280//
281// As a matter of policy, the nullability checker typically warns on direct
282// violations of the nullability invariant (although it uses various
283// heuristics to suppress warnings in some cases) but will not warn if the
284// invariant has already been violated along the path (either directly or
285// indirectly). As a practical matter, this prevents the analyzer from
286// (1) warning on defensive code paths where a nullability precondition is
287// determined to have been violated, (2) warning additional times after an
288// initial direct violation has been discovered, and (3) warning after a direct
289// violation that has been implicitly or explicitly suppressed (for
290// example, with a cast of NULL to _Nonnull). In essence, once an invariant
291// violation is detected on a path, this checker will be essentially turned off
292// for the rest of the analysis
293//
294// The analyzer takes this approach (rather than generating a sink node) to
295// ensure coverage of defensive paths, which may be important for backwards
296// 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(V: 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>(Val: FieldReg->getSuperRegion()))
329 FieldReg = ER;
330 return dyn_cast<SymbolicRegion>(Val: FieldReg->getSuperRegion());
331 }
332 if (auto ElementReg = Region->getAs<ElementRegion>())
333 return dyn_cast<SymbolicRegion>(Val: ElementReg->getSuperRegion());
334 }
335
336 return dyn_cast<SymbolicRegion>(Val: 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>(key: Region);
346 const NullabilityState *TrackedNullabPrev =
347 StatePrev->get<NullabilityMap>(key: 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(Nullab: TrackedNullab->getValue()) + "' is inferred")
367 .str();
368
369 // Generate the extra diagnostic.
370 PathDiagnosticLocation Pos(S, BRC.getSourceManager(), N->getStackFrame());
371 return std::make_shared<PathDiagnosticEventPiece>(args&: Pos, args&: InfoText, args: true);
372}
373
374/// Returns true when the value stored at the given location has been
375/// constrained to null after being passed through an object of nonnnull type.
376static bool checkValueAtLValForInvariantViolation(ProgramStateRef State,
377 SVal LV, QualType T) {
378 if (getNullabilityAnnotation(Type: T) != Nullability::Nonnull)
379 return false;
380
381 auto RegionVal = LV.getAs<loc::MemRegionVal>();
382 if (!RegionVal)
383 return false;
384
385 // If the value was constrained to null *after* it was passed through that
386 // location, it could not have been a concrete pointer *when* it was passed.
387 // In that case we would have handled the situation when the value was
388 // bound to that location, by emitting (or not emitting) a report.
389 // Therefore we are only interested in symbolic regions that can be either
390 // null or non-null depending on the value of their respective symbol.
391 auto StoredVal = State->getSVal(LV: *RegionVal).getAs<loc::MemRegionVal>();
392 if (!StoredVal || !isa<SymbolicRegion>(Val: StoredVal->getRegion()))
393 return false;
394
395 if (getNullConstraint(Val: *StoredVal, State) == NullConstraint::IsNull)
396 return true;
397
398 return false;
399}
400
401static bool checkParamsForPreconditionViolation(ArrayRef<ParmVarDecl *> Params,
402 ProgramStateRef State,
403 const StackFrame *SF) {
404 for (const auto *ParamDecl : Params) {
405 if (ParamDecl->isParameterPack())
406 break;
407
408 SVal LV = State->getLValue(VD: ParamDecl, SF);
409 if (checkValueAtLValForInvariantViolation(State, LV,
410 T: ParamDecl->getType())) {
411 return true;
412 }
413 }
414 return false;
415}
416
417static bool checkSelfIvarsForInvariantViolation(ProgramStateRef State,
418 const StackFrame *SF) {
419 auto *MD = dyn_cast<ObjCMethodDecl>(Val: SF->getDecl());
420 if (!MD || !MD->isInstanceMethod())
421 return false;
422
423 const ImplicitParamDecl *SelfDecl = SF->getSelfDecl();
424 if (!SelfDecl)
425 return false;
426
427 SVal SelfVal = State->getSVal(R: State->getRegion(D: SelfDecl, SF));
428
429 const ObjCObjectPointerType *SelfType =
430 dyn_cast<ObjCObjectPointerType>(Val: SelfDecl->getType());
431 if (!SelfType)
432 return false;
433
434 const ObjCInterfaceDecl *ID = SelfType->getInterfaceDecl();
435 if (!ID)
436 return false;
437
438 for (const auto *IvarDecl : ID->ivars()) {
439 SVal LV = State->getLValue(D: IvarDecl, Base: SelfVal);
440 if (checkValueAtLValForInvariantViolation(State, LV, T: IvarDecl->getType())) {
441 return true;
442 }
443 }
444 return false;
445}
446
447static bool checkInvariantViolation(ProgramStateRef State, ExplodedNode *N,
448 CheckerContext &C) {
449 if (State->get<InvariantViolated>())
450 return true;
451
452 const StackFrame *SF = C.getStackFrame();
453 const Decl *D = SF->getDecl();
454 if (!D)
455 return false;
456
457 ArrayRef<ParmVarDecl*> Params;
458 if (const auto *BD = dyn_cast<BlockDecl>(Val: D))
459 Params = BD->parameters();
460 else if (const auto *FD = dyn_cast<FunctionDecl>(Val: D))
461 Params = FD->parameters();
462 else if (const auto *MD = dyn_cast<ObjCMethodDecl>(Val: D))
463 Params = MD->parameters();
464 else
465 return false;
466
467 if (checkParamsForPreconditionViolation(Params, State, SF) ||
468 checkSelfIvarsForInvariantViolation(State, SF)) {
469 if (!N->isSink())
470 C.addTransition(State: State->set<InvariantViolated>(true), Pred: N);
471 return true;
472 }
473 return false;
474}
475
476void NullabilityChecker::reportBugIfInvariantHolds(
477 StringRef Msg, ErrorKind Error, const BugType &BT, ExplodedNode *N,
478 const MemRegion *Region, CheckerContext &C, const Stmt *ValueExpr,
479 bool SuppressPath) const {
480 ProgramStateRef OriginalState = N->getState();
481
482 if (checkInvariantViolation(State: OriginalState, N, C))
483 return;
484 if (SuppressPath) {
485 OriginalState = OriginalState->set<InvariantViolated>(true);
486 N = C.addTransition(State: OriginalState, Pred: N);
487 }
488
489 reportBug(Msg, Error, BT, N, Region, BR&: C.getBugReporter(), ValueExpr);
490}
491
492/// Cleaning up the program state.
493void NullabilityChecker::checkDeadSymbols(SymbolReaper &SR,
494 CheckerContext &C) const {
495 ProgramStateRef State = C.getState();
496 NullabilityMapTy Nullabilities = State->get<NullabilityMap>();
497 for (const MemRegion *Reg : llvm::make_first_range(c&: Nullabilities)) {
498 const auto *Region = Reg->getAs<SymbolicRegion>();
499 assert(Region && "Non-symbolic region is tracked.");
500 if (SR.isDead(sym: Region->getSymbol())) {
501 State = State->remove<NullabilityMap>(K: Reg);
502 }
503 }
504
505 // When an object goes out of scope, we can free the history associated
506 // with any property accesses on that object
507 PropertyAccessesMapTy PropertyAccesses = State->get<PropertyAccessesMap>();
508 for (ObjectPropPair PropKey : llvm::make_first_range(c&: PropertyAccesses)) {
509 const MemRegion *ReceiverRegion = PropKey.first;
510 if (!SR.isLiveRegion(region: ReceiverRegion)) {
511 State = State->remove<PropertyAccessesMap>(K: PropKey);
512 }
513 }
514
515 // When one of the nonnull arguments are constrained to be null, nullability
516 // preconditions are violated. It is not enough to check this only when we
517 // actually report an error, because at that time interesting symbols might be
518 // reaped.
519 if (checkInvariantViolation(State, N: C.getPredecessor(), C))
520 return;
521 C.addTransition(State);
522}
523
524/// This callback triggers when a pointer is dereferenced and the analyzer does
525/// not know anything about the value of that pointer. When that pointer is
526/// nullable, this code emits a warning.
527void NullabilityChecker::checkEvent(ImplicitNullDerefEvent Event) const {
528 if (Event.SinkNode->getState()->get<InvariantViolated>())
529 return;
530
531 const MemRegion *Region =
532 getTrackRegion(Val: Event.Location, /*CheckSuperRegion=*/true);
533 if (!Region)
534 return;
535
536 ProgramStateRef State = Event.SinkNode->getState();
537 const NullabilityState *TrackedNullability =
538 State->get<NullabilityMap>(key: Region);
539
540 if (!TrackedNullability)
541 return;
542
543 if (NullableDereferenced.isEnabled() &&
544 TrackedNullability->getValue() == Nullability::Nullable) {
545 BugReporter &BR = *Event.BR;
546 // Do not suppress errors on defensive code paths, because dereferencing
547 // a nullable pointer is always an error.
548 if (Event.IsDirectDereference)
549 reportBug(Msg: "Nullable pointer is dereferenced",
550 Error: ErrorKind::NullableDereferenced, BT: NullableDereferenced,
551 N: Event.SinkNode, Region, BR);
552 else {
553 reportBug(Msg: "Nullable pointer is passed to a callee that requires a "
554 "non-null",
555 Error: ErrorKind::NullablePassedToNonnull, BT: NullableDereferenced,
556 N: Event.SinkNode, Region, BR);
557 }
558 }
559}
560
561void NullabilityChecker::checkBeginFunction(CheckerContext &C) const {
562 if (!C.inTopFrame())
563 return;
564
565 const StackFrame *SF = C.getStackFrame();
566 auto AbstractCall = AnyCall::forDecl(D: SF->getDecl());
567 if (!AbstractCall || AbstractCall->parameters().empty())
568 return;
569
570 ProgramStateRef State = C.getState();
571 for (const ParmVarDecl *Param : AbstractCall->parameters()) {
572 if (!isValidPointerType(T: Param->getType()))
573 continue;
574
575 Nullability RequiredNullability =
576 getNullabilityAnnotation(Type: Param->getType());
577 if (RequiredNullability != Nullability::Nullable)
578 continue;
579
580 const VarRegion *ParamRegion = State->getRegion(D: Param, SF);
581 const MemRegion *ParamPointeeRegion =
582 State->getSVal(R: ParamRegion).getAsRegion();
583 if (!ParamPointeeRegion)
584 continue;
585
586 State = State->set<NullabilityMap>(K: ParamPointeeRegion,
587 E: NullabilityState(RequiredNullability));
588 }
589 C.addTransition(State);
590}
591
592// Whenever we see a load from a typed memory region that's been annotated as
593// 'nonnull', we want to trust the user on that and assume that it is is indeed
594// non-null.
595//
596// We do so even if the value is known to have been assigned to null.
597// The user should be warned on assigning the null value to a non-null pointer
598// as opposed to warning on the later dereference of this pointer.
599//
600// \code
601// int * _Nonnull var = 0; // we want to warn the user here...
602// // . . .
603// *var = 42; // ...and not here
604// \endcode
605void NullabilityChecker::checkLocation(SVal Location, bool IsLoad,
606 const Stmt *S,
607 CheckerContext &Context) const {
608 // We should care only about loads.
609 // The main idea is to add a constraint whenever we're loading a value from
610 // an annotated pointer type.
611 if (!IsLoad)
612 return;
613
614 // Annotations that we want to consider make sense only for types.
615 const auto *Region =
616 dyn_cast_or_null<TypedValueRegion>(Val: Location.getAsRegion());
617 if (!Region)
618 return;
619
620 ProgramStateRef State = Context.getState();
621
622 auto StoredVal = State->getSVal(R: Region).getAs<loc::MemRegionVal>();
623 if (!StoredVal)
624 return;
625
626 Nullability NullabilityOfTheLoadedValue =
627 getNullabilityAnnotation(Type: Region->getValueType());
628
629 if (NullabilityOfTheLoadedValue == Nullability::Nonnull) {
630 // It doesn't matter what we think about this particular pointer, it should
631 // be considered non-null as annotated by the developer.
632 if (ProgramStateRef NewState = State->assume(Cond: *StoredVal, Assumption: true)) {
633 Context.addTransition(State: NewState);
634 }
635 }
636}
637
638/// Find the outermost subexpression of E that is not an implicit cast.
639/// This looks through the implicit casts to _Nonnull that ARC adds to
640/// return expressions of ObjC types when the return type of the function or
641/// method is non-null but the express is not.
642static const Expr *lookThroughImplicitCasts(const Expr *E) {
643 return E->IgnoreImpCasts();
644}
645
646/// This method check when nullable pointer or null value is returned from a
647/// function that has nonnull return type.
648void NullabilityChecker::checkPreStmt(const ReturnStmt *S,
649 CheckerContext &C) const {
650 auto RetExpr = S->getRetValue();
651 if (!RetExpr)
652 return;
653
654 if (!isValidPointerType(T: RetExpr->getType()))
655 return;
656
657 ProgramStateRef State = C.getState();
658 if (State->get<InvariantViolated>())
659 return;
660
661 auto RetSVal = C.getSVal(E: RetExpr).getAs<DefinedOrUnknownSVal>();
662 if (!RetSVal)
663 return;
664
665 bool InSuppressedMethodFamily = false;
666
667 QualType RequiredRetType;
668 AnalysisDeclContext *DeclCtxt = C.getStackFrame()->getAnalysisDeclContext();
669 const Decl *D = DeclCtxt->getDecl();
670 if (auto *MD = dyn_cast<ObjCMethodDecl>(Val: D)) {
671 // HACK: This is a big hammer to avoid warning when there are defensive
672 // nil checks in -init and -copy methods. We should add more sophisticated
673 // logic here to suppress on common defensive idioms but still
674 // warn when there is a likely problem.
675 ObjCMethodFamily Family = MD->getMethodFamily();
676 if (OMF_init == Family || OMF_copy == Family || OMF_mutableCopy == Family)
677 InSuppressedMethodFamily = true;
678
679 RequiredRetType = MD->getReturnType();
680 } else if (auto *FD = dyn_cast<FunctionDecl>(Val: D)) {
681 RequiredRetType = FD->getReturnType();
682 } else {
683 return;
684 }
685
686 NullConstraint Nullness = getNullConstraint(Val: *RetSVal, State);
687
688 Nullability RequiredNullability = getNullabilityAnnotation(Type: RequiredRetType);
689 if (const auto *FunDecl = C.getStackFrame()->getDecl();
690 FunDecl && FunDecl->getAttr<ReturnsNonNullAttr>() &&
691 (RequiredNullability == Nullability::Unspecified ||
692 RequiredNullability == Nullability::Nullable)) {
693 // If a function is marked with the returns_nonnull attribute,
694 // the return value must be non-null.
695 RequiredNullability = Nullability::Nonnull;
696 }
697
698 // If the returned value is null but the type of the expression
699 // generating it is nonnull then we will suppress the diagnostic.
700 // This enables explicit suppression when returning a nil literal in a
701 // function with a _Nonnull return type:
702 // return (NSString * _Nonnull)0;
703 Nullability RetExprTypeLevelNullability =
704 getNullabilityAnnotation(Type: lookThroughImplicitCasts(E: RetExpr)->getType());
705
706 if (RequiredNullability == Nullability::Nonnull &&
707 Nullness == NullConstraint::IsNull) {
708 if (NullReturnedFromNonnull.isEnabled() &&
709 RetExprTypeLevelNullability != Nullability::Nonnull &&
710 !InSuppressedMethodFamily) {
711 ExplodedNode *N = C.generateErrorNode(State);
712 if (!N)
713 return;
714
715 SmallString<256> SBuf;
716 llvm::raw_svector_ostream OS(SBuf);
717 OS << (RetExpr->getType()->isObjCObjectPointerType() ? "nil" : "Null");
718 OS << " returned from a " << C.getDeclDescription(D)
719 << " that is expected to return a non-null value";
720 reportBugIfInvariantHolds(Msg: OS.str(), Error: ErrorKind::NilReturnedToNonnull,
721 BT: NullReturnedFromNonnull, N, Region: nullptr, C,
722 ValueExpr: RetExpr);
723 return;
724 }
725
726 // If null was returned from a non-null function, mark the nullability
727 // invariant as violated even if the diagnostic was suppressed.
728 State = State->set<InvariantViolated>(true);
729 C.addTransition(State);
730 return;
731 }
732
733 const MemRegion *Region = getTrackRegion(Val: *RetSVal);
734 if (!Region)
735 return;
736
737 const NullabilityState *TrackedNullability =
738 State->get<NullabilityMap>(key: Region);
739 if (TrackedNullability) {
740 Nullability TrackedNullabValue = TrackedNullability->getValue();
741 if (NullableReturnedFromNonnull.isEnabled() &&
742 Nullness != NullConstraint::IsNotNull &&
743 TrackedNullabValue == Nullability::Nullable &&
744 RequiredNullability == Nullability::Nonnull) {
745 ExplodedNode *N = C.addTransition(State, Pred: C.getPredecessor());
746
747 SmallString<256> SBuf;
748 llvm::raw_svector_ostream OS(SBuf);
749 OS << "Nullable pointer is returned from a " << C.getDeclDescription(D) <<
750 " that is expected to return a non-null value";
751
752 reportBugIfInvariantHolds(Msg: OS.str(), Error: ErrorKind::NullableReturnedToNonnull,
753 BT: NullableReturnedFromNonnull, N, Region, C);
754 }
755 return;
756 }
757 if (RequiredNullability == Nullability::Nullable) {
758 State = State->set<NullabilityMap>(K: Region,
759 E: NullabilityState(RequiredNullability,
760 S));
761 C.addTransition(State);
762 }
763}
764
765/// This callback warns when a nullable pointer or a null value is passed to a
766/// function that expects its argument to be nonnull.
767void NullabilityChecker::checkPreCall(const CallEvent &Call,
768 CheckerContext &C) const {
769 if (!Call.getDecl())
770 return;
771
772 ProgramStateRef State = C.getState();
773 if (State->get<InvariantViolated>())
774 return;
775
776 ProgramStateRef OrigState = State;
777
778 unsigned Idx = 0;
779 for (const ParmVarDecl *Param : Call.parameters()) {
780 if (Param->isParameterPack())
781 break;
782
783 if (Idx >= Call.getNumArgs())
784 break;
785
786 const Expr *ArgExpr = Call.getArgExpr(Index: Idx);
787 auto ArgSVal = Call.getArgSVal(Index: Idx++).getAs<DefinedOrUnknownSVal>();
788 if (!ArgSVal)
789 continue;
790
791 if (!isValidPointerType(T: Param->getType()) &&
792 !Param->getType()->isReferenceType())
793 continue;
794
795 NullConstraint Nullness = getNullConstraint(Val: *ArgSVal, State);
796
797 Nullability RequiredNullability =
798 getNullabilityAnnotation(Type: Param->getType());
799 Nullability ArgExprTypeLevelNullability =
800 getNullabilityAnnotation(Type: lookThroughImplicitCasts(E: ArgExpr)->getType());
801
802 unsigned ParamIdx = Param->getFunctionScopeIndex() + 1;
803
804 if (NullPassedToNonnull.isEnabled() && Nullness == NullConstraint::IsNull &&
805 ArgExprTypeLevelNullability != Nullability::Nonnull &&
806 RequiredNullability == Nullability::Nonnull &&
807 isDiagnosableCall(Call)) {
808 ExplodedNode *N = C.generateErrorNode(State);
809 if (!N)
810 return;
811
812 SmallString<256> SBuf;
813 llvm::raw_svector_ostream OS(SBuf);
814 OS << (Param->getType()->isObjCObjectPointerType() ? "nil" : "Null");
815 OS << " passed to a callee that requires a non-null " << ParamIdx
816 << llvm::getOrdinalSuffix(Val: ParamIdx) << " parameter";
817 reportBugIfInvariantHolds(Msg: OS.str(), Error: ErrorKind::NilPassedToNonnull,
818 BT: NullPassedToNonnull, N, Region: nullptr, C, ValueExpr: ArgExpr,
819 /*SuppressPath=*/false);
820 return;
821 }
822
823 const MemRegion *Region = getTrackRegion(Val: *ArgSVal);
824 if (!Region)
825 continue;
826
827 const NullabilityState *TrackedNullability =
828 State->get<NullabilityMap>(key: Region);
829
830 if (TrackedNullability) {
831 if (Nullness == NullConstraint::IsNotNull ||
832 TrackedNullability->getValue() != Nullability::Nullable)
833 continue;
834
835 if (NullablePassedToNonnull.isEnabled() &&
836 RequiredNullability == Nullability::Nonnull &&
837 isDiagnosableCall(Call)) {
838 ExplodedNode *N = C.addTransition(State);
839 SmallString<256> SBuf;
840 llvm::raw_svector_ostream OS(SBuf);
841 OS << "Nullable pointer is passed to a callee that requires a non-null "
842 << ParamIdx << llvm::getOrdinalSuffix(Val: ParamIdx) << " parameter";
843 reportBugIfInvariantHolds(Msg: OS.str(), Error: ErrorKind::NullablePassedToNonnull,
844 BT: NullablePassedToNonnull, N, Region, C,
845 ValueExpr: ArgExpr, /*SuppressPath=*/true);
846 return;
847 }
848 if (NullableDereferenced.isEnabled() &&
849 Param->getType()->isReferenceType()) {
850 ExplodedNode *N = C.addTransition(State);
851 reportBugIfInvariantHolds(
852 Msg: "Nullable pointer is dereferenced", Error: ErrorKind::NullableDereferenced,
853 BT: NullableDereferenced, N, Region, C, ValueExpr: ArgExpr, /*SuppressPath=*/true);
854 return;
855 }
856 continue;
857 }
858 }
859 if (State != OrigState)
860 C.addTransition(State);
861}
862
863/// Suppress the nullability warnings for some functions.
864void NullabilityChecker::checkPostCall(const CallEvent &Call,
865 CheckerContext &C) const {
866 auto Decl = Call.getDecl();
867 if (!Decl)
868 return;
869 // ObjC Messages handles in a different callback.
870 if (Call.getKind() == CE_ObjCMessage)
871 return;
872 const FunctionType *FuncType = Decl->getFunctionType();
873 if (!FuncType)
874 return;
875 QualType ReturnType = FuncType->getReturnType();
876 if (!isValidPointerType(T: ReturnType))
877 return;
878 ProgramStateRef State = C.getState();
879 if (State->get<InvariantViolated>())
880 return;
881
882 const MemRegion *Region = getTrackRegion(Val: Call.getReturnValue());
883 if (!Region)
884 return;
885
886 // CG headers are misannotated. Do not warn for symbols that are the results
887 // of CG calls.
888 const SourceManager &SM = C.getSourceManager();
889 StringRef FilePath = SM.getFilename(SpellingLoc: SM.getSpellingLoc(Loc: Decl->getBeginLoc()));
890 if (llvm::sys::path::filename(path: FilePath).starts_with(Prefix: "CG")) {
891 State = State->set<NullabilityMap>(K: Region, E: Nullability::Contradicted);
892 C.addTransition(State);
893 return;
894 }
895
896 const NullabilityState *TrackedNullability =
897 State->get<NullabilityMap>(key: Region);
898
899 // ObjCMessageExpr gets the actual type through
900 // Sema::getMessageSendResultType, instead of using the return type of
901 // MethodDecl directly. The final type is generated by considering the
902 // nullability of receiver and MethodDecl together. Thus, The type of
903 // ObjCMessageExpr is prefer.
904 if (const Expr *E = Call.getOriginExpr())
905 ReturnType = E->getType();
906
907 if (!TrackedNullability &&
908 getNullabilityAnnotation(Type: ReturnType) == Nullability::Nullable) {
909 State = State->set<NullabilityMap>(K: Region, E: Nullability::Nullable);
910 C.addTransition(State);
911 }
912}
913
914static Nullability getReceiverNullability(const ObjCMethodCall &M,
915 ProgramStateRef State) {
916 if (M.isReceiverSelfOrSuper()) {
917 // For super and super class receivers we assume that the receiver is
918 // nonnull.
919 return Nullability::Nonnull;
920 }
921 // Otherwise look up nullability in the state.
922 SVal Receiver = M.getReceiverSVal();
923 if (auto DefOrUnknown = Receiver.getAs<DefinedOrUnknownSVal>()) {
924 // If the receiver is constrained to be nonnull, assume that it is nonnull
925 // regardless of its type.
926 NullConstraint Nullness = getNullConstraint(Val: *DefOrUnknown, State);
927 if (Nullness == NullConstraint::IsNotNull)
928 return Nullability::Nonnull;
929 }
930 auto ValueRegionSVal = Receiver.getAs<loc::MemRegionVal>();
931 if (ValueRegionSVal) {
932 const MemRegion *SelfRegion = ValueRegionSVal->getRegion();
933 assert(SelfRegion);
934
935 const NullabilityState *TrackedSelfNullability =
936 State->get<NullabilityMap>(key: SelfRegion);
937 if (TrackedSelfNullability)
938 return TrackedSelfNullability->getValue();
939 }
940 return Nullability::Unspecified;
941}
942
943// The return value of a property access is typically a temporary value which
944// will not be tracked in a persistent manner by the analyzer. We use
945// evalAssume() in order to immediately record constraints on those temporaries
946// at the time they are imposed (e.g. by a nil-check conditional).
947ProgramStateRef NullabilityChecker::evalAssume(ProgramStateRef State, SVal Cond,
948 bool Assumption) const {
949 PropertyAccessesMapTy PropertyAccesses = State->get<PropertyAccessesMap>();
950 for (auto [PropKey, PropVal] : PropertyAccesses) {
951 if (!PropVal.isConstrainedNonnull) {
952 ConditionTruthVal IsNonNull = State->isNonNull(V: PropVal.Value);
953 if (IsNonNull.isConstrainedTrue()) {
954 ConstrainedPropertyVal Replacement = PropVal;
955 Replacement.isConstrainedNonnull = true;
956 State = State->set<PropertyAccessesMap>(K: PropKey, E: Replacement);
957 } else if (IsNonNull.isConstrainedFalse()) {
958 // Space optimization: no point in tracking constrained-null cases
959 State = State->remove<PropertyAccessesMap>(K: PropKey);
960 }
961 }
962 }
963
964 return State;
965}
966
967/// Calculate the nullability of the result of a message expr based on the
968/// nullability of the receiver, the nullability of the return value, and the
969/// constraints.
970void NullabilityChecker::checkPostObjCMessage(const ObjCMethodCall &M,
971 CheckerContext &C) const {
972 auto Decl = M.getDecl();
973 if (!Decl)
974 return;
975 QualType RetType = Decl->getReturnType();
976 if (!isValidPointerType(T: RetType))
977 return;
978
979 ProgramStateRef State = C.getState();
980 if (State->get<InvariantViolated>())
981 return;
982
983 const MemRegion *ReturnRegion = getTrackRegion(Val: M.getReturnValue());
984 if (!ReturnRegion)
985 return;
986
987 auto Interface = Decl->getClassInterface();
988 auto Name = Interface ? Interface->getName() : "";
989 // In order to reduce the noise in the diagnostics generated by this checker,
990 // some framework and programming style based heuristics are used. These
991 // heuristics are for Cocoa APIs which have NS prefix.
992 if (Name.starts_with(Prefix: "NS")) {
993 // Developers rely on dynamic invariants such as an item should be available
994 // in a collection, or a collection is not empty often. Those invariants can
995 // not be inferred by any static analysis tool. To not to bother the users
996 // with too many false positives, every item retrieval function should be
997 // ignored for collections. The instance methods of dictionaries in Cocoa
998 // are either item retrieval related or not interesting nullability wise.
999 // Using this fact, to keep the code easier to read just ignore the return
1000 // value of every instance method of dictionaries.
1001 if (M.isInstanceMessage() && Name.contains(Other: "Dictionary")) {
1002 State =
1003 State->set<NullabilityMap>(K: ReturnRegion, E: Nullability::Contradicted);
1004 C.addTransition(State);
1005 return;
1006 }
1007 // For similar reasons ignore some methods of Cocoa arrays.
1008 StringRef FirstSelectorSlot = M.getSelector().getNameForSlot(argIndex: 0);
1009 if (Name.contains(Other: "Array") &&
1010 (FirstSelectorSlot == "firstObject" ||
1011 FirstSelectorSlot == "lastObject")) {
1012 State =
1013 State->set<NullabilityMap>(K: ReturnRegion, E: Nullability::Contradicted);
1014 C.addTransition(State);
1015 return;
1016 }
1017
1018 // Encoding related methods of string should not fail when lossless
1019 // encodings are used. Using lossless encodings is so frequent that ignoring
1020 // this class of methods reduced the emitted diagnostics by about 30% on
1021 // some projects (and all of that was false positives).
1022 if (Name.contains(Other: "String")) {
1023 for (auto *Param : M.parameters()) {
1024 if (Param->getName() == "encoding") {
1025 State = State->set<NullabilityMap>(K: ReturnRegion,
1026 E: Nullability::Contradicted);
1027 C.addTransition(State);
1028 return;
1029 }
1030 }
1031 }
1032 }
1033
1034 const ObjCMessageExpr *Message = M.getOriginExpr();
1035 Nullability SelfNullability = getReceiverNullability(M, State);
1036
1037 const NullabilityState *NullabilityOfReturn =
1038 State->get<NullabilityMap>(key: ReturnRegion);
1039
1040 if (NullabilityOfReturn) {
1041 // When we have a nullability tracked for the return value, the nullability
1042 // of the expression will be the most nullable of the receiver and the
1043 // return value.
1044 Nullability RetValTracked = NullabilityOfReturn->getValue();
1045 Nullability ComputedNullab =
1046 getMostNullable(Lhs: RetValTracked, Rhs: SelfNullability);
1047 if (ComputedNullab != RetValTracked &&
1048 ComputedNullab != Nullability::Unspecified) {
1049 const Stmt *NullabilitySource =
1050 ComputedNullab == RetValTracked
1051 ? NullabilityOfReturn->getNullabilitySource()
1052 : Message->getInstanceReceiver();
1053 State = State->set<NullabilityMap>(
1054 K: ReturnRegion, E: NullabilityState(ComputedNullab, NullabilitySource));
1055 C.addTransition(State);
1056 }
1057 return;
1058 }
1059
1060 // No tracked information. Use static type information for return value.
1061 Nullability RetNullability = getNullabilityAnnotation(Type: Message->getType());
1062
1063 // Properties might be computed, which means the property value could
1064 // theoretically change between calls even in commonly-observed cases like
1065 // this:
1066 //
1067 // if (foo.prop) { // ok, it's nonnull here...
1068 // [bar doStuffWithNonnullVal:foo.prop]; // ...but what about
1069 // here?
1070 // }
1071 //
1072 // If the property is nullable-annotated, a naive analysis would lead to many
1073 // false positives despite the presence of probably-correct nil-checks. To
1074 // reduce the false positive rate, we maintain a history of the most recently
1075 // observed property value. For each property access, if the prior value has
1076 // been constrained to be not nil then we will conservatively assume that the
1077 // next access can be inferred as nonnull.
1078 if (RetNullability != Nullability::Nonnull &&
1079 M.getMessageKind() == OCM_PropertyAccess && !C.wasInlined) {
1080 bool LookupResolved = false;
1081 if (const MemRegion *ReceiverRegion = getTrackRegion(Val: M.getReceiverSVal())) {
1082 if (const IdentifierInfo *Ident =
1083 M.getSelector().getIdentifierInfoForSlot(argIndex: 0)) {
1084 LookupResolved = true;
1085 ObjectPropPair Key = std::make_pair(x&: ReceiverRegion, y&: Ident);
1086 const ConstrainedPropertyVal *PrevPropVal =
1087 State->get<PropertyAccessesMap>(key: Key);
1088 if (PrevPropVal && PrevPropVal->isConstrainedNonnull) {
1089 RetNullability = Nullability::Nonnull;
1090 } else {
1091 // If a previous property access was constrained as nonnull, we hold
1092 // on to that constraint (effectively inferring that all subsequent
1093 // accesses on that code path can be inferred as nonnull). If the
1094 // previous property access was *not* constrained as nonnull, then
1095 // let's throw it away in favor of keeping the SVal associated with
1096 // this more recent access.
1097 if (auto ReturnSVal =
1098 M.getReturnValue().getAs<DefinedOrUnknownSVal>()) {
1099 State = State->set<PropertyAccessesMap>(
1100 K: Key, E: ConstrainedPropertyVal(*ReturnSVal));
1101 }
1102 }
1103 }
1104 }
1105
1106 if (!LookupResolved) {
1107 // Fallback: err on the side of suppressing the false positive.
1108 RetNullability = Nullability::Nonnull;
1109 }
1110 }
1111
1112 Nullability ComputedNullab = getMostNullable(Lhs: RetNullability, Rhs: SelfNullability);
1113 if (ComputedNullab == Nullability::Nullable) {
1114 const Stmt *NullabilitySource = ComputedNullab == RetNullability
1115 ? Message
1116 : Message->getInstanceReceiver();
1117 State = State->set<NullabilityMap>(
1118 K: ReturnRegion, E: NullabilityState(ComputedNullab, NullabilitySource));
1119 C.addTransition(State);
1120 }
1121}
1122
1123/// Explicit casts are trusted. If there is a disagreement in the nullability
1124/// annotations in the destination and the source or '0' is casted to nonnull
1125/// track the value as having contraditory nullability. This will allow users to
1126/// suppress warnings.
1127void NullabilityChecker::checkPostStmt(const ExplicitCastExpr *CE,
1128 CheckerContext &C) const {
1129 QualType OriginType = CE->getSubExpr()->getType();
1130 QualType DestType = CE->getType();
1131 if (!isValidPointerType(T: OriginType))
1132 return;
1133 if (!isValidPointerType(T: DestType))
1134 return;
1135
1136 ProgramStateRef State = C.getState();
1137 if (State->get<InvariantViolated>())
1138 return;
1139
1140 Nullability DestNullability = getNullabilityAnnotation(Type: DestType);
1141
1142 // No explicit nullability in the destination type, so this cast does not
1143 // change the nullability.
1144 if (DestNullability == Nullability::Unspecified)
1145 return;
1146
1147 auto RegionSVal = C.getSVal(E: CE).getAs<DefinedOrUnknownSVal>();
1148 const MemRegion *Region = getTrackRegion(Val: *RegionSVal);
1149 if (!Region)
1150 return;
1151
1152 // When 0 is converted to nonnull mark it as contradicted.
1153 if (DestNullability == Nullability::Nonnull) {
1154 NullConstraint Nullness = getNullConstraint(Val: *RegionSVal, State);
1155 if (Nullness == NullConstraint::IsNull) {
1156 State = State->set<NullabilityMap>(K: Region, E: Nullability::Contradicted);
1157 C.addTransition(State);
1158 return;
1159 }
1160 }
1161
1162 const NullabilityState *TrackedNullability =
1163 State->get<NullabilityMap>(key: Region);
1164
1165 if (!TrackedNullability) {
1166 if (DestNullability != Nullability::Nullable)
1167 return;
1168 State = State->set<NullabilityMap>(K: Region,
1169 E: NullabilityState(DestNullability, CE));
1170 C.addTransition(State);
1171 return;
1172 }
1173
1174 if (TrackedNullability->getValue() != DestNullability &&
1175 TrackedNullability->getValue() != Nullability::Contradicted) {
1176 State = State->set<NullabilityMap>(K: Region, E: Nullability::Contradicted);
1177 C.addTransition(State);
1178 }
1179}
1180
1181/// For a given statement performing a bind, attempt to syntactically
1182/// match the expression resulting in the bound value.
1183static const Expr * matchValueExprForBind(const Stmt *S) {
1184 // For `x = e` the value expression is the right-hand side.
1185 if (auto *BinOp = dyn_cast<BinaryOperator>(Val: S)) {
1186 if (BinOp->getOpcode() == BO_Assign)
1187 return BinOp->getRHS();
1188 }
1189
1190 // For `int x = e` the value expression is the initializer.
1191 if (auto *DS = dyn_cast<DeclStmt>(Val: S)) {
1192 if (DS->isSingleDecl()) {
1193 auto *VD = dyn_cast<VarDecl>(Val: DS->getSingleDecl());
1194 if (!VD)
1195 return nullptr;
1196
1197 if (const Expr *Init = VD->getInit())
1198 return Init;
1199 }
1200 }
1201
1202 return nullptr;
1203}
1204
1205/// Returns true if \param S is a DeclStmt for a local variable that
1206/// ObjC automated reference counting initialized with zero.
1207static bool isARCNilInitializedLocal(CheckerContext &C, const Stmt *S) {
1208 // We suppress diagnostics for ARC zero-initialized _Nonnull locals. This
1209 // prevents false positives when a _Nonnull local variable cannot be
1210 // initialized with an initialization expression:
1211 // NSString * _Nonnull s; // no-warning
1212 // @autoreleasepool {
1213 // s = ...
1214 // }
1215 //
1216 // FIXME: We should treat implicitly zero-initialized _Nonnull locals as
1217 // uninitialized in Sema's UninitializedValues analysis to warn when a use of
1218 // the zero-initialized definition will unexpectedly yield nil.
1219
1220 // Locals are only zero-initialized when automated reference counting
1221 // is turned on.
1222 if (!C.getASTContext().getLangOpts().ObjCAutoRefCount)
1223 return false;
1224
1225 auto *DS = dyn_cast<DeclStmt>(Val: S);
1226 if (!DS || !DS->isSingleDecl())
1227 return false;
1228
1229 auto *VD = dyn_cast<VarDecl>(Val: DS->getSingleDecl());
1230 if (!VD)
1231 return false;
1232
1233 // Sema only zero-initializes locals with ObjCLifetimes.
1234 if(!VD->getType().getQualifiers().hasObjCLifetime())
1235 return false;
1236
1237 const Expr *Init = VD->getInit();
1238 assert(Init && "ObjC local under ARC without initializer");
1239
1240 // Return false if the local is explicitly initialized (e.g., with '= nil').
1241 if (!isa<ImplicitValueInitExpr>(Val: Init))
1242 return false;
1243
1244 return true;
1245}
1246
1247/// Propagate the nullability information through binds and warn when nullable
1248/// pointer or null symbol is assigned to a pointer with a nonnull type.
1249void NullabilityChecker::checkBind(SVal L, SVal V, const Stmt *S,
1250 bool AtDeclInit, CheckerContext &C) const {
1251 const TypedValueRegion *TVR =
1252 dyn_cast_or_null<TypedValueRegion>(Val: L.getAsRegion());
1253 if (!TVR)
1254 return;
1255
1256 QualType LocType = TVR->getValueType();
1257 if (!isValidPointerType(T: LocType))
1258 return;
1259
1260 ProgramStateRef State = C.getState();
1261 if (State->get<InvariantViolated>())
1262 return;
1263
1264 auto ValDefOrUnknown = V.getAs<DefinedOrUnknownSVal>();
1265 if (!ValDefOrUnknown)
1266 return;
1267
1268 NullConstraint RhsNullness = getNullConstraint(Val: *ValDefOrUnknown, State);
1269
1270 Nullability ValNullability = Nullability::Unspecified;
1271 if (SymbolRef Sym = ValDefOrUnknown->getAsSymbol())
1272 ValNullability = getNullabilityAnnotation(Type: Sym->getType());
1273
1274 Nullability LocNullability = getNullabilityAnnotation(Type: LocType);
1275
1276 // If the type of the RHS expression is nonnull, don't warn. This
1277 // enables explicit suppression with a cast to nonnull.
1278 Nullability ValueExprTypeLevelNullability = Nullability::Unspecified;
1279 const Expr *ValueExpr = matchValueExprForBind(S);
1280 if (ValueExpr) {
1281 ValueExprTypeLevelNullability =
1282 getNullabilityAnnotation(Type: lookThroughImplicitCasts(E: ValueExpr)->getType());
1283 }
1284
1285 bool NullAssignedToNonNull = (LocNullability == Nullability::Nonnull &&
1286 RhsNullness == NullConstraint::IsNull);
1287 if (NullPassedToNonnull.isEnabled() && NullAssignedToNonNull &&
1288 ValNullability != Nullability::Nonnull &&
1289 ValueExprTypeLevelNullability != Nullability::Nonnull &&
1290 !isARCNilInitializedLocal(C, S)) {
1291 ExplodedNode *N = C.generateErrorNode(State);
1292 if (!N)
1293 return;
1294
1295
1296 const Stmt *ValueStmt = S;
1297 if (ValueExpr)
1298 ValueStmt = ValueExpr;
1299
1300 SmallString<256> SBuf;
1301 llvm::raw_svector_ostream OS(SBuf);
1302 OS << (LocType->isObjCObjectPointerType() ? "nil" : "Null");
1303 OS << " assigned to a pointer which is expected to have non-null value";
1304 reportBugIfInvariantHolds(Msg: OS.str(), Error: ErrorKind::NilAssignedToNonnull,
1305 BT: NullPassedToNonnull, N, Region: nullptr, C, ValueExpr: ValueStmt);
1306 return;
1307 }
1308
1309 // If null was returned from a non-null function, mark the nullability
1310 // invariant as violated even if the diagnostic was suppressed.
1311 if (NullAssignedToNonNull) {
1312 State = State->set<InvariantViolated>(true);
1313 C.addTransition(State);
1314 return;
1315 }
1316
1317 // Intentionally missing case: '0' is bound to a reference. It is handled by
1318 // the DereferenceChecker.
1319
1320 const MemRegion *ValueRegion = getTrackRegion(Val: *ValDefOrUnknown);
1321 if (!ValueRegion)
1322 return;
1323
1324 const NullabilityState *TrackedNullability =
1325 State->get<NullabilityMap>(key: ValueRegion);
1326
1327 if (TrackedNullability) {
1328 if (RhsNullness == NullConstraint::IsNotNull ||
1329 TrackedNullability->getValue() != Nullability::Nullable)
1330 return;
1331 if (NullablePassedToNonnull.isEnabled() &&
1332 LocNullability == Nullability::Nonnull) {
1333 ExplodedNode *N = C.addTransition(State, Pred: C.getPredecessor());
1334 reportBugIfInvariantHolds(Msg: "Nullable pointer is assigned to a pointer "
1335 "which is expected to have non-null value",
1336 Error: ErrorKind::NullableAssignedToNonnull,
1337 BT: NullablePassedToNonnull, N, Region: ValueRegion, C);
1338 }
1339 return;
1340 }
1341
1342 const auto *BinOp = dyn_cast<BinaryOperator>(Val: S);
1343
1344 if (ValNullability == Nullability::Nullable) {
1345 // Trust the static information of the value more than the static
1346 // information on the location.
1347 const Stmt *NullabilitySource = BinOp ? BinOp->getRHS() : S;
1348 State = State->set<NullabilityMap>(
1349 K: ValueRegion, E: NullabilityState(ValNullability, NullabilitySource));
1350 C.addTransition(State);
1351 return;
1352 }
1353
1354 if (LocNullability == Nullability::Nullable) {
1355 const Stmt *NullabilitySource = BinOp ? BinOp->getLHS() : S;
1356 State = State->set<NullabilityMap>(
1357 K: ValueRegion, E: NullabilityState(LocNullability, NullabilitySource));
1358 C.addTransition(State);
1359 }
1360}
1361
1362void NullabilityChecker::printState(raw_ostream &Out, ProgramStateRef State,
1363 const char *NL, const char *Sep) const {
1364
1365 NullabilityMapTy B = State->get<NullabilityMap>();
1366
1367 if (State->get<InvariantViolated>())
1368 Out << Sep << NL
1369 << "Nullability invariant was violated, warnings suppressed." << NL;
1370
1371 if (B.isEmpty())
1372 return;
1373
1374 if (!State->get<InvariantViolated>())
1375 Out << Sep << NL;
1376
1377 for (auto [Region, State] : B) {
1378 Out << Region << " : ";
1379 State.print(Out);
1380 Out << NL;
1381 }
1382}
1383
1384// The checker group "nullability" (which consists of the checkers that are
1385// implemented in this file) has a group-level configuration option which
1386// affects all the checkers in the group. As this is a completely unique
1387// remnant of old design (this is the only group option in the analyzer), there
1388// is no machinery to inject the group name from `Checkers.td`, so it is simply
1389// hardcoded here:
1390constexpr llvm::StringLiteral GroupName = "nullability";
1391constexpr llvm::StringLiteral GroupOptName = "NoDiagnoseCallsToSystemHeaders";
1392
1393#define REGISTER_CHECKER(NAME, TRACKING_REQUIRED) \
1394 void ento::register##NAME##Checker(CheckerManager &Mgr) { \
1395 NullabilityChecker *Chk = Mgr.getChecker<NullabilityChecker>(); \
1396 Chk->NAME.enable(Mgr); \
1397 Chk->NeedTracking = Chk->NeedTracking || TRACKING_REQUIRED; \
1398 Chk->NoDiagnoseCallsToSystemHeaders = \
1399 Mgr.getAnalyzerOptions().getCheckerBooleanOption(GroupName, \
1400 GroupOptName, true); \
1401 } \
1402 \
1403 bool ento::shouldRegister##NAME##Checker(const CheckerManager &) { \
1404 return true; \
1405 }
1406
1407// The checks are likely to be turned on by default and it is possible to do
1408// them without tracking any nullability related information. As an optimization
1409// no nullability information will be tracked when only these two checks are
1410// enables.
1411REGISTER_CHECKER(NullPassedToNonnull, false)
1412REGISTER_CHECKER(NullReturnedFromNonnull, false)
1413
1414REGISTER_CHECKER(NullableDereferenced, true)
1415REGISTER_CHECKER(NullablePassedToNonnull, true)
1416REGISTER_CHECKER(NullableReturnedFromNonnull, true)
1417
1418#undef REGISTER_CHECKER
1419