Bug Summary

File:tools/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
Location:line 443, column 34
Description:Called C++ object pointer is null

Annotated Source Code

1//== Nullabilityhecker.cpp - Nullability checker ----------------*- C++ -*--==//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This checker tries to find nullability violations. There are several kinds of
11// possible violations:
12// * Null pointer is passed to a pointer which has a _Nonnull type.
13// * Null pointer is returned from a function which has a _Nonnull return type.
14// * Nullable pointer is passed to a pointer which has a _Nonnull type.
15// * Nullable pointer is returned from a function which has a _Nonnull return
16// type.
17// * Nullable pointer is dereferenced.
18//
19// This checker propagates the nullability information of the pointers and looks
20// for the patterns that are described above. Explicit casts are trusted and are
21// considered a way to suppress false positives for this checker. The other way
22// to suppress warnings would be to add asserts or guarding if statements to the
23// code. In addition to the nullability propagation this checker also uses some
24// heuristics to suppress potential false positives.
25//
26//===----------------------------------------------------------------------===//
27
28#include "ClangSACheckers.h"
29#include "llvm/Support/Path.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/CheckerContext.h"
34#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
35
36using namespace clang;
37using namespace ento;
38
39namespace {
40// Do not reorder! The getMostNullable method relies on the order.
41// Optimization: Most pointers expected to be unspecified. When a symbol has an
42// unspecified or nonnull type non of the rules would indicate any problem for
43// that symbol. For this reason only nullable and contradicted nullability are
44// stored for a symbol. When a symbol is already contradicted, it can not be
45// casted back to nullable.
46enum class Nullability : char {
47 Contradicted, // Tracked nullability is contradicted by an explicit cast. Do
48 // not report any nullability related issue for this symbol.
49 // This nullability is propagated agressively to avoid false
50 // positive results. See the comment on getMostNullable method.
51 Nullable,
52 Unspecified,
53 Nonnull
54};
55
56/// Returns the most nullable nullability. This is used for message expressions
57/// like [reciever method], where the nullability of this expression is either
58/// the nullability of the receiver or the nullability of the return type of the
59/// method, depending on which is more nullable. Contradicted is considered to
60/// be the most nullable, to avoid false positive results.
61static Nullability getMostNullable(Nullability Lhs, Nullability Rhs) {
62 return static_cast<Nullability>(
63 std::min(static_cast<char>(Lhs), static_cast<char>(Rhs)));
64}
65
66static const char *getNullabilityString(Nullability Nullab) {
67 switch (Nullab) {
68 case Nullability::Contradicted:
69 return "contradicted";
70 case Nullability::Nullable:
71 return "nullable";
72 case Nullability::Unspecified:
73 return "unspecified";
74 case Nullability::Nonnull:
75 return "nonnull";
76 }
77 assert(false)((false) ? static_cast<void> (0) : __assert_fail ("false"
, "/tmp/buildd/llvm-toolchain-snapshot-3.8~svn246424/tools/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp"
, 77, __PRETTY_FUNCTION__))
;
78 return "";
79}
80
81// These enums are used as an index to ErrorMessages array.
82enum class ErrorKind : int {
83 NilAssignedToNonnull,
84 NilPassedToNonnull,
85 NilReturnedToNonnull,
86 NullableAssignedToNonnull,
87 NullableReturnedToNonnull,
88 NullableDereferenced,
89 NullablePassedToNonnull
90};
91
92const char *ErrorMessages[] = {"Null pointer is assigned to a pointer which "
93 "has _Nonnull type",
94 "Null pointer is passed to a parameter which is "
95 "marked as _Nonnull",
96 "Null pointer is returned from a function that "
97 "has _Nonnull return type",
98 "Nullable pointer is assigned to a pointer "
99 "which has _Nonnull type",
100 "Nullable pointer is returned from a function "
101 "that has _Nonnull return type",
102 "Nullable pointer is dereferenced",
103 "Nullable pointer is passed to a parameter "
104 "which is marked as _Nonnull"};
105
106class NullabilityChecker
107 : public Checker<check::Bind, check::PreCall, check::PreStmt<ReturnStmt>,
108 check::PostCall, check::PostStmt<ExplicitCastExpr>,
109 check::PostObjCMessage, check::DeadSymbols,
110 check::Event<ImplicitNullDerefEvent>> {
111 mutable std::unique_ptr<BugType> BT;
112
113public:
114 void checkBind(SVal L, SVal V, const Stmt *S, CheckerContext &C) const;
115 void checkPostStmt(const ExplicitCastExpr *CE, CheckerContext &C) const;
116 void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const;
117 void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
118 void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
119 void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
120 void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const;
121 void checkEvent(ImplicitNullDerefEvent Event) const;
122
123 void printState(raw_ostream &Out, ProgramStateRef State, const char *NL,
124 const char *Sep) const override;
125
126 struct NullabilityChecksFilter {
127 DefaultBool CheckNullPassedToNonnull;
128 DefaultBool CheckNullReturnedFromNonnull;
129 DefaultBool CheckNullableDereferenced;
130 DefaultBool CheckNullablePassedToNonnull;
131 DefaultBool CheckNullableReturnedFromNonnull;
132
133 CheckName CheckNameNullPassedToNonnull;
134 CheckName CheckNameNullReturnedFromNonnull;
135 CheckName CheckNameNullableDereferenced;
136 CheckName CheckNameNullablePassedToNonnull;
137 CheckName CheckNameNullableReturnedFromNonnull;
138 };
139
140 NullabilityChecksFilter Filter;
141
142private:
143 class NullabilityBugVisitor
144 : public BugReporterVisitorImpl<NullabilityBugVisitor> {
145 public:
146 NullabilityBugVisitor(const MemRegion *M) : Region(M) {}
147
148 void Profile(llvm::FoldingSetNodeID &ID) const override {
149 static int X = 0;
150 ID.AddPointer(&X);
151 ID.AddPointer(Region);
152 }
153
154 PathDiagnosticPiece *VisitNode(const ExplodedNode *N,
155 const ExplodedNode *PrevN,
156 BugReporterContext &BRC,
157 BugReport &BR) override;
158
159 private:
160 // The tracked region.
161 const MemRegion *Region;
162 };
163
164 void reportBug(ErrorKind Error, ExplodedNode *N, const MemRegion *Region,
165 BugReporter &BR, const Stmt *ValueExpr = nullptr) const {
166 if (!BT)
167 BT.reset(new BugType(this, "Nullability", "Memory error"));
168 const char *Msg = ErrorMessages[static_cast<int>(Error)];
169 assert(Msg)((Msg) ? static_cast<void> (0) : __assert_fail ("Msg", "/tmp/buildd/llvm-toolchain-snapshot-3.8~svn246424/tools/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp"
, 169, __PRETTY_FUNCTION__))
;
170 std::unique_ptr<BugReport> R(new BugReport(*BT, Msg, N));
171 if (Region) {
172 R->markInteresting(Region);
173 R->addVisitor(llvm::make_unique<NullabilityBugVisitor>(Region));
174 }
175 if (ValueExpr) {
176 R->addRange(ValueExpr->getSourceRange());
177 if (Error == ErrorKind::NilAssignedToNonnull ||
178 Error == ErrorKind::NilPassedToNonnull ||
179 Error == ErrorKind::NilReturnedToNonnull)
180 bugreporter::trackNullOrUndefValue(N, ValueExpr, *R);
181 }
182 BR.emitReport(std::move(R));
183 }
184};
185
186class NullabilityState {
187public:
188 NullabilityState(Nullability Nullab, const Stmt *Source = nullptr)
189 : Nullab(Nullab), Source(Source) {}
190
191 const Stmt *getNullabilitySource() const { return Source; }
192
193 Nullability getValue() const { return Nullab; }
194
195 void Profile(llvm::FoldingSetNodeID &ID) const {
196 ID.AddInteger(static_cast<char>(Nullab));
197 ID.AddPointer(Source);
198 }
199
200 void print(raw_ostream &Out) const {
201 Out << getNullabilityString(Nullab) << "\n";
202 }
203
204private:
205 Nullability Nullab;
206 // Source is the expression which determined the nullability. For example in a
207 // message like [nullable nonnull_returning] has nullable nullability, because
208 // the receiver is nullable. Here the receiver will be the source of the
209 // nullability. This is useful information when the diagnostics are generated.
210 const Stmt *Source;
211};
212
213bool operator==(NullabilityState Lhs, NullabilityState Rhs) {
214 return Lhs.getValue() == Rhs.getValue() &&
215 Lhs.getNullabilitySource() == Rhs.getNullabilitySource();
216}
217
218} // end anonymous namespace
219
220REGISTER_MAP_WITH_PROGRAMSTATE(NullabilityMap, const MemRegion *,namespace { class NullabilityMap {}; typedef llvm::ImmutableMap
<const MemRegion *, NullabilityState> NullabilityMapTy;
} namespace clang { namespace ento { template <> struct
ProgramStateTrait<NullabilityMap> : public ProgramStatePartialTrait
<NullabilityMapTy> { static void *GDMIndex() { static int
Index; return &Index; } }; } }
221 NullabilityState)namespace { class NullabilityMap {}; typedef llvm::ImmutableMap
<const MemRegion *, NullabilityState> NullabilityMapTy;
} namespace clang { namespace ento { template <> struct
ProgramStateTrait<NullabilityMap> : public ProgramStatePartialTrait
<NullabilityMapTy> { static void *GDMIndex() { static int
Index; return &Index; } }; } }
222
223enum class NullConstraint { IsNull, IsNotNull, Unknown };
224
225static NullConstraint getNullConstraint(DefinedOrUnknownSVal Val,
226 ProgramStateRef State) {
227 ConditionTruthVal Nullness = State->isNull(Val);
228 if (Nullness.isConstrainedFalse())
229 return NullConstraint::IsNotNull;
230 if (Nullness.isConstrainedTrue())
231 return NullConstraint::IsNull;
232 return NullConstraint::Unknown;
233}
234
235// If an SVal wraps a region that should be tracked, it will return a pointer
236// to the wrapped region. Otherwise it will return a nullptr.
237static const SymbolicRegion *getTrackRegion(SVal Val,
238 bool CheckSuperRegion = false) {
239 auto RegionSVal = Val.getAs<loc::MemRegionVal>();
240 if (!RegionSVal)
241 return nullptr;
242
243 const MemRegion *Region = RegionSVal->getRegion();
244
245 if (CheckSuperRegion) {
246 if (auto FieldReg = Region->getAs<FieldRegion>())
247 return dyn_cast<SymbolicRegion>(FieldReg->getSuperRegion());
248 else if (auto ElementReg = Region->getAs<ElementRegion>())
249 return dyn_cast<SymbolicRegion>(ElementReg->getSuperRegion());
250 }
251
252 return dyn_cast<SymbolicRegion>(Region);
253}
254
255PathDiagnosticPiece *NullabilityChecker::NullabilityBugVisitor::VisitNode(
256 const ExplodedNode *N, const ExplodedNode *PrevN, BugReporterContext &BRC,
257 BugReport &BR) {
258 ProgramStateRef state = N->getState();
259 ProgramStateRef statePrev = PrevN->getState();
260
261 const NullabilityState *TrackedNullab = state->get<NullabilityMap>(Region);
262 const NullabilityState *TrackedNullabPrev =
263 statePrev->get<NullabilityMap>(Region);
264 if (!TrackedNullab)
265 return nullptr;
266
267 if (TrackedNullabPrev &&
268 TrackedNullabPrev->getValue() == TrackedNullab->getValue())
269 return nullptr;
270
271 // Retrieve the associated statement.
272 const Stmt *S = TrackedNullab->getNullabilitySource();
273 if (!S) {
274 ProgramPoint ProgLoc = N->getLocation();
275 if (Optional<StmtPoint> SP = ProgLoc.getAs<StmtPoint>()) {
276 S = SP->getStmt();
277 }
278 }
279
280 if (!S)
281 return nullptr;
282
283 std::string InfoText =
284 (llvm::Twine("Nullability '") +
285 getNullabilityString(TrackedNullab->getValue()) + "' is infered")
286 .str();
287
288 // Generate the extra diagnostic.
289 PathDiagnosticLocation Pos(S, BRC.getSourceManager(),
290 N->getLocationContext());
291 return new PathDiagnosticEventPiece(Pos, InfoText, true, nullptr);
292}
293
294static Nullability getNullabilityAnnotation(QualType Type) {
295 const auto *AttrType = Type->getAs<AttributedType>();
296 if (!AttrType)
297 return Nullability::Unspecified;
298 if (AttrType->getAttrKind() == AttributedType::attr_nullable)
299 return Nullability::Nullable;
300 else if (AttrType->getAttrKind() == AttributedType::attr_nonnull)
301 return Nullability::Nonnull;
302 return Nullability::Unspecified;
303}
304
305/// Cleaning up the program state.
306void NullabilityChecker::checkDeadSymbols(SymbolReaper &SR,
307 CheckerContext &C) const {
308 ProgramStateRef State = C.getState();
309 NullabilityMapTy Nullabilities = State->get<NullabilityMap>();
310 for (NullabilityMapTy::iterator I = Nullabilities.begin(),
311 E = Nullabilities.end();
312 I != E; ++I) {
313 if (!SR.isLiveRegion(I->first)) {
314 State = State->remove<NullabilityMap>(I->first);
315 }
316 }
317}
318
319/// This callback triggers when a pointer is dereferenced and the analyzer does
320/// not know anything about the value of that pointer. When that pointer is
321/// nullable, this code emits a warning.
322void NullabilityChecker::checkEvent(ImplicitNullDerefEvent Event) const {
323 const MemRegion *Region =
324 getTrackRegion(Event.Location, /*CheckSuperregion=*/true);
325 if (!Region)
326 return;
327
328 ProgramStateRef State = Event.SinkNode->getState();
329 const NullabilityState *TrackedNullability =
330 State->get<NullabilityMap>(Region);
331
332 if (!TrackedNullability)
333 return;
334
335 if (Filter.CheckNullableDereferenced &&
336 TrackedNullability->getValue() == Nullability::Nullable) {
337 BugReporter &BR = *Event.BR;
338 if (Event.IsDirectDereference)
339 reportBug(ErrorKind::NullableDereferenced, Event.SinkNode, Region, BR);
340 else
341 reportBug(ErrorKind::NullablePassedToNonnull, Event.SinkNode, Region, BR);
342 }
343}
344
345/// This method check when nullable pointer or null value is returned from a
346/// function that has nonnull return type.
347///
348/// TODO: when nullability preconditons are violated, it is ok to violate the
349/// nullability postconditons (i.e.: when one of the nonnull parameters are null
350/// this check should not report any nullability related issue).
351void NullabilityChecker::checkPreStmt(const ReturnStmt *S,
352 CheckerContext &C) const {
353 auto RetExpr = S->getRetValue();
354 if (!RetExpr)
355 return;
356
357 if (!RetExpr->getType()->isAnyPointerType())
358 return;
359
360 ProgramStateRef State = C.getState();
361 auto RetSVal =
362 State->getSVal(S, C.getLocationContext()).getAs<DefinedOrUnknownSVal>();
363 if (!RetSVal)
364 return;
365
366 AnalysisDeclContext *DeclCtxt =
367 C.getLocationContext()->getAnalysisDeclContext();
368 const FunctionType *FuncType = DeclCtxt->getDecl()->getFunctionType();
369 if (!FuncType)
370 return;
371
372 NullConstraint Nullness = getNullConstraint(*RetSVal, State);
373
374 Nullability StaticNullability =
375 getNullabilityAnnotation(FuncType->getReturnType());
376
377 if (Filter.CheckNullReturnedFromNonnull &&
378 Nullness == NullConstraint::IsNull &&
379 StaticNullability == Nullability::Nonnull) {
380 static CheckerProgramPointTag Tag(this, "NullReturnedFromNonnull");
381 ExplodedNode *N = C.addTransition(State, C.getPredecessor(), &Tag);
382 reportBug(ErrorKind::NilReturnedToNonnull, N, nullptr, C.getBugReporter(),
383 S);
384 return;
385 }
386
387 const MemRegion *Region = getTrackRegion(*RetSVal);
388 if (!Region)
389 return;
390
391 const NullabilityState *TrackedNullability =
392 State->get<NullabilityMap>(Region);
393 if (TrackedNullability) {
394 Nullability TrackedNullabValue = TrackedNullability->getValue();
395 if (Filter.CheckNullableReturnedFromNonnull &&
396 Nullness != NullConstraint::IsNotNull &&
397 TrackedNullabValue == Nullability::Nullable &&
398 StaticNullability == Nullability::Nonnull) {
399 static CheckerProgramPointTag Tag(this, "NullableReturnedFromNonnull");
400 ExplodedNode *N = C.addTransition(State, C.getPredecessor(), &Tag);
401 reportBug(ErrorKind::NullableReturnedToNonnull, N, Region,
402 C.getBugReporter());
403 }
404 return;
405 }
406 if (StaticNullability == Nullability::Nullable) {
407 State = State->set<NullabilityMap>(Region,
408 NullabilityState(StaticNullability, S));
409 C.addTransition(State);
410 }
411}
412
413/// This callback warns when a nullable pointer or a null value is passed to a
414/// function that expects its argument to be nonnull.
415void NullabilityChecker::checkPreCall(const CallEvent &Call,
416 CheckerContext &C) const {
417 if (!Call.getDecl())
1
Taking false branch
418 return;
419
420 ProgramStateRef State = C.getState();
421 ProgramStateRef OrigState = State;
422
423 unsigned Idx = 0;
424 for (const ParmVarDecl *Param : Call.parameters()) {
2
Assuming '__begin' is not equal to '__end'
425 if (Param->isParameterPack())
3
Taking false branch
7
Taking false branch
11
Taking false branch
15
Taking false branch
426 break;
427
428 const Expr *ArgExpr = nullptr;
16
'ArgExpr' initialized to a null pointer value
429 if (Idx < Call.getNumArgs())
4
Taking false branch
8
Taking false branch
12
Taking false branch
17
Taking false branch
430 ArgExpr = Call.getArgExpr(Idx);
431 auto ArgSVal = Call.getArgSVal(Idx++).getAs<DefinedOrUnknownSVal>();
432 if (!ArgSVal)
5
Taking true branch
9
Taking true branch
13
Taking true branch
18
Taking false branch
433 continue;
6
Execution continues on line 424
10
Execution continues on line 424
14
Execution continues on line 424
434
435 if (!Param->getType()->isAnyPointerType() &&
436 !Param->getType()->isReferenceType())
437 continue;
438
439 NullConstraint Nullness = getNullConstraint(*ArgSVal, State);
440
441 Nullability ParamNullability = getNullabilityAnnotation(Param->getType());
442 Nullability ArgStaticNullability =
443 getNullabilityAnnotation(ArgExpr->getType());
19
Called C++ object pointer is null
444
445 if (Filter.CheckNullPassedToNonnull && Nullness == NullConstraint::IsNull &&
446 ArgStaticNullability != Nullability::Nonnull &&
447 ParamNullability == Nullability::Nonnull) {
448 static CheckerProgramPointTag Tag(this, "NullPassedToNonnull");
449 ExplodedNode *N = C.generateSink(State, C.getPredecessor(), &Tag);
450 reportBug(ErrorKind::NilPassedToNonnull, N, nullptr, C.getBugReporter(),
451 ArgExpr);
452 return;
453 }
454
455 const MemRegion *Region = getTrackRegion(*ArgSVal);
456 if (!Region)
457 continue;
458
459 const NullabilityState *TrackedNullability =
460 State->get<NullabilityMap>(Region);
461
462 if (TrackedNullability) {
463 if (Nullness == NullConstraint::IsNotNull ||
464 TrackedNullability->getValue() != Nullability::Nullable)
465 continue;
466
467 if (Filter.CheckNullablePassedToNonnull &&
468 ParamNullability == Nullability::Nonnull) {
469 static CheckerProgramPointTag Tag(this, "NullablePassedToNonnull");
470 ExplodedNode *N = C.generateSink(State, C.getPredecessor(), &Tag);
471 reportBug(ErrorKind::NullablePassedToNonnull, N, Region,
472 C.getBugReporter(), ArgExpr);
473 return;
474 }
475 if (Filter.CheckNullableDereferenced &&
476 Param->getType()->isReferenceType()) {
477 static CheckerProgramPointTag Tag(this, "NullableDereferenced");
478 ExplodedNode *N = C.generateSink(State, C.getPredecessor(), &Tag);
479 reportBug(ErrorKind::NullableDereferenced, N, Region,
480 C.getBugReporter(), ArgExpr);
481 return;
482 }
483 continue;
484 }
485 // No tracked nullability yet.
486 if (ArgStaticNullability != Nullability::Nullable)
487 continue;
488 State = State->set<NullabilityMap>(
489 Region, NullabilityState(ArgStaticNullability, ArgExpr));
490 }
491 if (State != OrigState)
492 C.addTransition(State);
493}
494
495/// Suppress the nullability warnings for some functions.
496void NullabilityChecker::checkPostCall(const CallEvent &Call,
497 CheckerContext &C) const {
498 auto Decl = Call.getDecl();
499 if (!Decl)
500 return;
501 // ObjC Messages handles in a different callback.
502 if (Call.getKind() == CE_ObjCMessage)
503 return;
504 const FunctionType *FuncType = Decl->getFunctionType();
505 if (!FuncType)
506 return;
507 QualType ReturnType = FuncType->getReturnType();
508 if (!ReturnType->isAnyPointerType())
509 return;
510 const MemRegion *Region = getTrackRegion(Call.getReturnValue());
511 if (!Region)
512 return;
513 ProgramStateRef State = C.getState();
514
515 // CG headers are misannotated. Do not warn for symbols that are the results
516 // of CG calls.
517 const SourceManager &SM = C.getSourceManager();
518 StringRef FilePath = SM.getFilename(SM.getSpellingLoc(Decl->getLocStart()));
519 if (llvm::sys::path::filename(FilePath).startswith("CG")) {
520 State = State->set<NullabilityMap>(Region, Nullability::Contradicted);
521 C.addTransition(State);
522 return;
523 }
524
525 const NullabilityState *TrackedNullability =
526 State->get<NullabilityMap>(Region);
527
528 if (!TrackedNullability &&
529 getNullabilityAnnotation(ReturnType) == Nullability::Nullable) {
530 State = State->set<NullabilityMap>(Region, Nullability::Nullable);
531 C.addTransition(State);
532 }
533}
534
535static Nullability getReceiverNullability(const ObjCMethodCall &M,
536 ProgramStateRef State) {
537 Nullability RetNullability = Nullability::Unspecified;
538 if (M.isReceiverSelfOrSuper()) {
539 // For super and super class receivers we assume that the receiver is
540 // nonnull.
541 RetNullability = Nullability::Nonnull;
542 } else {
543 // Otherwise look up nullability in the state.
544 SVal Receiver = M.getReceiverSVal();
545 auto ValueRegionSVal = Receiver.getAs<loc::MemRegionVal>();
546 if (ValueRegionSVal) {
547 const MemRegion *SelfRegion = ValueRegionSVal->getRegion();
548 assert(SelfRegion)((SelfRegion) ? static_cast<void> (0) : __assert_fail (
"SelfRegion", "/tmp/buildd/llvm-toolchain-snapshot-3.8~svn246424/tools/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp"
, 548, __PRETTY_FUNCTION__))
;
549
550 const NullabilityState *TrackedSelfNullability =
551 State->get<NullabilityMap>(SelfRegion);
552 if (TrackedSelfNullability) {
553 RetNullability = TrackedSelfNullability->getValue();
554 }
555 }
556 if (auto DefOrUnknown = Receiver.getAs<DefinedOrUnknownSVal>()) {
557 // If the receiver is constrained to be nonnull, assume that it is nonnull
558 // regardless of its type.
559 NullConstraint Nullness = getNullConstraint(*DefOrUnknown, State);
560 if (Nullness == NullConstraint::IsNotNull)
561 RetNullability = Nullability::Nonnull;
562 }
563 }
564 return RetNullability;
565}
566
567/// Calculate the nullability of the result of a message expr based on the
568/// nullability of the receiver, the nullability of the return value, and the
569/// constraints.
570void NullabilityChecker::checkPostObjCMessage(const ObjCMethodCall &M,
571 CheckerContext &C) const {
572 auto Decl = M.getDecl();
573 if (!Decl)
574 return;
575 QualType RetType = Decl->getReturnType();
576 if (!RetType->isAnyPointerType())
577 return;
578
579 const MemRegion *ReturnRegion = getTrackRegion(M.getReturnValue());
580 if (!ReturnRegion)
581 return;
582
583 ProgramStateRef State = C.getState();
584 auto Interface = Decl->getClassInterface();
585 auto Name = Interface ? Interface->getName() : "";
586 // In order to reduce the noise in the diagnostics generated by this checker,
587 // some framework and programming style based heuristics are used. These
588 // heuristics are for Cocoa APIs which have NS prefix.
589 if (Name.startswith("NS")) {
590 // Developers rely on dynamic invariants such as an item should be available
591 // in a collection, or a collection is not empty often. Those invariants can
592 // not be inferred by any static analysis tool. To not to bother the users
593 // with too many false positives, every item retrieval function should be
594 // ignored for collections. The instance methods of dictionaries in Cocoa
595 // are either item retrieval related or not interesting nullability wise.
596 // Using this fact, to keep the code easier to read just ignore the return
597 // value of every instance method of dictionaries.
598 if (M.isInstanceMessage() && Name.find("Dictionary") != StringRef::npos) {
599 State =
600 State->set<NullabilityMap>(ReturnRegion, Nullability::Contradicted);
601 C.addTransition(State);
602 return;
603 }
604 // For similar reasons ignore some methods of Cocoa arrays.
605 StringRef FirstSelectorSlot = M.getSelector().getNameForSlot(0);
606 if (Name.find("Array") != StringRef::npos &&
607 (FirstSelectorSlot == "firstObject" ||
608 FirstSelectorSlot == "lastObject")) {
609 State =
610 State->set<NullabilityMap>(ReturnRegion, Nullability::Contradicted);
611 C.addTransition(State);
612 return;
613 }
614
615 // Encoding related methods of string should not fail when lossless
616 // encodings are used. Using lossless encodings is so frequent that ignoring
617 // this class of methods reduced the emitted diagnostics by about 30% on
618 // some projects (and all of that was false positives).
619 if (Name.find("String") != StringRef::npos) {
620 for (auto Param : M.parameters()) {
621 if (Param->getName() == "encoding") {
622 State = State->set<NullabilityMap>(ReturnRegion,
623 Nullability::Contradicted);
624 C.addTransition(State);
625 return;
626 }
627 }
628 }
629 }
630
631 const ObjCMessageExpr *Message = M.getOriginExpr();
632 Nullability SelfNullability = getReceiverNullability(M, State);
633
634 const NullabilityState *NullabilityOfReturn =
635 State->get<NullabilityMap>(ReturnRegion);
636
637 if (NullabilityOfReturn) {
638 // When we have a nullability tracked for the return value, the nullability
639 // of the expression will be the most nullable of the receiver and the
640 // return value.
641 Nullability RetValTracked = NullabilityOfReturn->getValue();
642 Nullability ComputedNullab =
643 getMostNullable(RetValTracked, SelfNullability);
644 if (ComputedNullab != RetValTracked &&
645 ComputedNullab != Nullability::Unspecified) {
646 const Stmt *NullabilitySource =
647 ComputedNullab == RetValTracked
648 ? NullabilityOfReturn->getNullabilitySource()
649 : Message->getInstanceReceiver();
650 State = State->set<NullabilityMap>(
651 ReturnRegion, NullabilityState(ComputedNullab, NullabilitySource));
652 C.addTransition(State);
653 }
654 return;
655 }
656
657 // No tracked information. Use static type information for return value.
658 Nullability RetNullability = getNullabilityAnnotation(RetType);
659
660 // Properties might be computed. For this reason the static analyzer creates a
661 // new symbol each time an unknown property is read. To avoid false pozitives
662 // do not treat unknown properties as nullable, even when they explicitly
663 // marked nullable.
664 if (M.getMessageKind() == OCM_PropertyAccess && !C.wasInlined)
665 RetNullability = Nullability::Nonnull;
666
667 Nullability ComputedNullab = getMostNullable(RetNullability, SelfNullability);
668 if (ComputedNullab == Nullability::Nullable) {
669 const Stmt *NullabilitySource = ComputedNullab == RetNullability
670 ? Message
671 : Message->getInstanceReceiver();
672 State = State->set<NullabilityMap>(
673 ReturnRegion, NullabilityState(ComputedNullab, NullabilitySource));
674 C.addTransition(State);
675 }
676}
677
678/// Explicit casts are trusted. If there is a disagreement in the nullability
679/// annotations in the destination and the source or '0' is casted to nonnull
680/// track the value as having contraditory nullability. This will allow users to
681/// suppress warnings.
682void NullabilityChecker::checkPostStmt(const ExplicitCastExpr *CE,
683 CheckerContext &C) const {
684 QualType OriginType = CE->getSubExpr()->getType();
685 QualType DestType = CE->getType();
686 if (!OriginType->isAnyPointerType())
687 return;
688 if (!DestType->isAnyPointerType())
689 return;
690
691 Nullability DestNullability = getNullabilityAnnotation(DestType);
692
693 // No explicit nullability in the destination type, so this cast does not
694 // change the nullability.
695 if (DestNullability == Nullability::Unspecified)
696 return;
697
698 ProgramStateRef State = C.getState();
699 auto RegionSVal =
700 State->getSVal(CE, C.getLocationContext()).getAs<DefinedOrUnknownSVal>();
701 const MemRegion *Region = getTrackRegion(*RegionSVal);
702 if (!Region)
703 return;
704
705 // When 0 is converted to nonnull mark it as contradicted.
706 if (DestNullability == Nullability::Nonnull) {
707 NullConstraint Nullness = getNullConstraint(*RegionSVal, State);
708 if (Nullness == NullConstraint::IsNull) {
709 State = State->set<NullabilityMap>(Region, Nullability::Contradicted);
710 C.addTransition(State);
711 return;
712 }
713 }
714
715 const NullabilityState *TrackedNullability =
716 State->get<NullabilityMap>(Region);
717
718 if (!TrackedNullability) {
719 if (DestNullability != Nullability::Nullable)
720 return;
721 State = State->set<NullabilityMap>(Region,
722 NullabilityState(DestNullability, CE));
723 C.addTransition(State);
724 return;
725 }
726
727 if (TrackedNullability->getValue() != DestNullability &&
728 TrackedNullability->getValue() != Nullability::Contradicted) {
729 State = State->set<NullabilityMap>(Region, Nullability::Contradicted);
730 C.addTransition(State);
731 }
732}
733
734/// Propagate the nullability information through binds and warn when nullable
735/// pointer or null symbol is assigned to a pointer with a nonnull type.
736void NullabilityChecker::checkBind(SVal L, SVal V, const Stmt *S,
737 CheckerContext &C) const {
738 const TypedValueRegion *TVR =
739 dyn_cast_or_null<TypedValueRegion>(L.getAsRegion());
740 if (!TVR)
741 return;
742
743 QualType LocType = TVR->getValueType();
744 if (!LocType->isAnyPointerType())
745 return;
746
747 auto ValDefOrUnknown = V.getAs<DefinedOrUnknownSVal>();
748 if (!ValDefOrUnknown)
749 return;
750
751 ProgramStateRef State = C.getState();
752 NullConstraint RhsNullness = getNullConstraint(*ValDefOrUnknown, State);
753
754 Nullability ValNullability = Nullability::Unspecified;
755 if (SymbolRef Sym = ValDefOrUnknown->getAsSymbol())
756 ValNullability = getNullabilityAnnotation(Sym->getType());
757
758 Nullability LocNullability = getNullabilityAnnotation(LocType);
759 if (Filter.CheckNullPassedToNonnull &&
760 RhsNullness == NullConstraint::IsNull &&
761 ValNullability != Nullability::Nonnull &&
762 LocNullability == Nullability::Nonnull) {
763 static CheckerProgramPointTag Tag(this, "NullPassedToNonnull");
764 ExplodedNode *N = C.addTransition(State, C.getPredecessor(), &Tag);
765 reportBug(ErrorKind::NilAssignedToNonnull, N, nullptr, C.getBugReporter(),
766 S);
767 return;
768 }
769 // Intentionally missing case: '0' is bound to a reference. It is handled by
770 // the DereferenceChecker.
771
772 const MemRegion *ValueRegion = getTrackRegion(*ValDefOrUnknown);
773 if (!ValueRegion)
774 return;
775
776 const NullabilityState *TrackedNullability =
777 State->get<NullabilityMap>(ValueRegion);
778
779 if (TrackedNullability) {
780 if (RhsNullness == NullConstraint::IsNotNull ||
781 TrackedNullability->getValue() != Nullability::Nullable)
782 return;
783 if (Filter.CheckNullablePassedToNonnull &&
784 LocNullability == Nullability::Nonnull) {
785 static CheckerProgramPointTag Tag(this, "NullablePassedToNonnull");
786 ExplodedNode *N = C.addTransition(State, C.getPredecessor(), &Tag);
787 reportBug(ErrorKind::NullableAssignedToNonnull, N, ValueRegion,
788 C.getBugReporter());
789 }
790 return;
791 }
792
793 const auto *BinOp = dyn_cast<BinaryOperator>(S);
794
795 if (ValNullability == Nullability::Nullable) {
796 // Trust the static information of the value more than the static
797 // information on the location.
798 const Stmt *NullabilitySource = BinOp ? BinOp->getRHS() : S;
799 State = State->set<NullabilityMap>(
800 ValueRegion, NullabilityState(ValNullability, NullabilitySource));
801 C.addTransition(State);
802 return;
803 }
804
805 if (LocNullability == Nullability::Nullable) {
806 const Stmt *NullabilitySource = BinOp ? BinOp->getLHS() : S;
807 State = State->set<NullabilityMap>(
808 ValueRegion, NullabilityState(LocNullability, NullabilitySource));
809 C.addTransition(State);
810 }
811}
812
813void NullabilityChecker::printState(raw_ostream &Out, ProgramStateRef State,
814 const char *NL, const char *Sep) const {
815
816 NullabilityMapTy B = State->get<NullabilityMap>();
817
818 if (B.isEmpty())
819 return;
820
821 Out << Sep << NL;
822
823 for (NullabilityMapTy::iterator I = B.begin(), E = B.end(); I != E; ++I) {
824 Out << I->first << " : ";
825 I->second.print(Out);
826 Out << NL;
827 }
828}
829
830#define REGISTER_CHECKER(name)void ento::registernameChecker(CheckerManager &mgr) { NullabilityChecker
*checker = mgr.registerChecker<NullabilityChecker>(); checker
->Filter.Checkname = true; checker->Filter.CheckNamename
= mgr.getCurrentCheckName(); }
\
831 void ento::register##name##Checker(CheckerManager &mgr) { \
832 NullabilityChecker *checker = mgr.registerChecker<NullabilityChecker>(); \
833 checker->Filter.Check##name = true; \
834 checker->Filter.CheckName##name = mgr.getCurrentCheckName(); \
835 }
836
837REGISTER_CHECKER(NullPassedToNonnull)void ento::registerNullPassedToNonnullChecker(CheckerManager &
mgr) { NullabilityChecker *checker = mgr.registerChecker<NullabilityChecker
>(); checker->Filter.CheckNullPassedToNonnull = true; checker
->Filter.CheckNameNullPassedToNonnull = mgr.getCurrentCheckName
(); }
838REGISTER_CHECKER(NullReturnedFromNonnull)void ento::registerNullReturnedFromNonnullChecker(CheckerManager
&mgr) { NullabilityChecker *checker = mgr.registerChecker
<NullabilityChecker>(); checker->Filter.CheckNullReturnedFromNonnull
= true; checker->Filter.CheckNameNullReturnedFromNonnull =
mgr.getCurrentCheckName(); }
839REGISTER_CHECKER(NullableDereferenced)void ento::registerNullableDereferencedChecker(CheckerManager
&mgr) { NullabilityChecker *checker = mgr.registerChecker
<NullabilityChecker>(); checker->Filter.CheckNullableDereferenced
= true; checker->Filter.CheckNameNullableDereferenced = mgr
.getCurrentCheckName(); }
840REGISTER_CHECKER(NullablePassedToNonnull)void ento::registerNullablePassedToNonnullChecker(CheckerManager
&mgr) { NullabilityChecker *checker = mgr.registerChecker
<NullabilityChecker>(); checker->Filter.CheckNullablePassedToNonnull
= true; checker->Filter.CheckNameNullablePassedToNonnull =
mgr.getCurrentCheckName(); }
841REGISTER_CHECKER(NullableReturnedFromNonnull)void ento::registerNullableReturnedFromNonnullChecker(CheckerManager
&mgr) { NullabilityChecker *checker = mgr.registerChecker
<NullabilityChecker>(); checker->Filter.CheckNullableReturnedFromNonnull
= true; checker->Filter.CheckNameNullableReturnedFromNonnull
= mgr.getCurrentCheckName(); }