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

source code of clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp