blob: 78b4beda87339790c68a41b041422f81eff9563f [file] [log] [blame]
Gabor Horvath28690922015-08-26 23:17:43 +00001//== 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);
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
Gabor Horvathb47128a2015-09-03 23:16:21 +0000164 /// When any of the nonnull arguments of the analyzed function is null, do not
165 /// report anything and turn off the check.
166 ///
167 /// When \p SuppressPath is set to true, no more bugs will be reported on this
168 /// path by this checker.
169 void reportBugIfPreconditionHolds(ErrorKind Error, ExplodedNode *N,
170 const MemRegion *Region, CheckerContext &C,
171 const Stmt *ValueExpr = nullptr,
172 bool SuppressPath = false) const;
173
Gabor Horvath28690922015-08-26 23:17:43 +0000174 void reportBug(ErrorKind Error, ExplodedNode *N, const MemRegion *Region,
175 BugReporter &BR, const Stmt *ValueExpr = nullptr) const {
176 if (!BT)
177 BT.reset(new BugType(this, "Nullability", "Memory error"));
178 const char *Msg = ErrorMessages[static_cast<int>(Error)];
179 assert(Msg);
180 std::unique_ptr<BugReport> R(new BugReport(*BT, Msg, N));
181 if (Region) {
182 R->markInteresting(Region);
183 R->addVisitor(llvm::make_unique<NullabilityBugVisitor>(Region));
184 }
185 if (ValueExpr) {
186 R->addRange(ValueExpr->getSourceRange());
187 if (Error == ErrorKind::NilAssignedToNonnull ||
188 Error == ErrorKind::NilPassedToNonnull ||
189 Error == ErrorKind::NilReturnedToNonnull)
190 bugreporter::trackNullOrUndefValue(N, ValueExpr, *R);
191 }
192 BR.emitReport(std::move(R));
193 }
194};
195
196class NullabilityState {
197public:
198 NullabilityState(Nullability Nullab, const Stmt *Source = nullptr)
199 : Nullab(Nullab), Source(Source) {}
200
201 const Stmt *getNullabilitySource() const { return Source; }
202
203 Nullability getValue() const { return Nullab; }
204
205 void Profile(llvm::FoldingSetNodeID &ID) const {
206 ID.AddInteger(static_cast<char>(Nullab));
207 ID.AddPointer(Source);
208 }
209
210 void print(raw_ostream &Out) const {
211 Out << getNullabilityString(Nullab) << "\n";
212 }
213
214private:
215 Nullability Nullab;
216 // Source is the expression which determined the nullability. For example in a
217 // message like [nullable nonnull_returning] has nullable nullability, because
218 // the receiver is nullable. Here the receiver will be the source of the
219 // nullability. This is useful information when the diagnostics are generated.
220 const Stmt *Source;
221};
222
223bool operator==(NullabilityState Lhs, NullabilityState Rhs) {
224 return Lhs.getValue() == Rhs.getValue() &&
225 Lhs.getNullabilitySource() == Rhs.getNullabilitySource();
226}
227
228} // end anonymous namespace
229
230REGISTER_MAP_WITH_PROGRAMSTATE(NullabilityMap, const MemRegion *,
231 NullabilityState)
232
Gabor Horvathb47128a2015-09-03 23:16:21 +0000233// If the nullability precondition of a function is violated, we should not
234// report nullability related issues on that path. For this reason once a
235// precondition is not met on a path, this checker will be esentially turned off
236// for the rest of the analysis. We do not want to generate a sink node however,
237// so this checker would not lead to reduced coverage.
238REGISTER_TRAIT_WITH_PROGRAMSTATE(PreconditionViolated, bool)
239
Gabor Horvath28690922015-08-26 23:17:43 +0000240enum class NullConstraint { IsNull, IsNotNull, Unknown };
241
242static NullConstraint getNullConstraint(DefinedOrUnknownSVal Val,
243 ProgramStateRef State) {
244 ConditionTruthVal Nullness = State->isNull(Val);
245 if (Nullness.isConstrainedFalse())
246 return NullConstraint::IsNotNull;
247 if (Nullness.isConstrainedTrue())
248 return NullConstraint::IsNull;
249 return NullConstraint::Unknown;
250}
251
252// If an SVal wraps a region that should be tracked, it will return a pointer
253// to the wrapped region. Otherwise it will return a nullptr.
254static const SymbolicRegion *getTrackRegion(SVal Val,
255 bool CheckSuperRegion = false) {
256 auto RegionSVal = Val.getAs<loc::MemRegionVal>();
257 if (!RegionSVal)
258 return nullptr;
259
260 const MemRegion *Region = RegionSVal->getRegion();
261
262 if (CheckSuperRegion) {
263 if (auto FieldReg = Region->getAs<FieldRegion>())
264 return dyn_cast<SymbolicRegion>(FieldReg->getSuperRegion());
265 else if (auto ElementReg = Region->getAs<ElementRegion>())
266 return dyn_cast<SymbolicRegion>(ElementReg->getSuperRegion());
267 }
268
269 return dyn_cast<SymbolicRegion>(Region);
270}
271
272PathDiagnosticPiece *NullabilityChecker::NullabilityBugVisitor::VisitNode(
273 const ExplodedNode *N, const ExplodedNode *PrevN, BugReporterContext &BRC,
274 BugReport &BR) {
275 ProgramStateRef state = N->getState();
276 ProgramStateRef statePrev = PrevN->getState();
277
278 const NullabilityState *TrackedNullab = state->get<NullabilityMap>(Region);
279 const NullabilityState *TrackedNullabPrev =
280 statePrev->get<NullabilityMap>(Region);
281 if (!TrackedNullab)
282 return nullptr;
283
284 if (TrackedNullabPrev &&
285 TrackedNullabPrev->getValue() == TrackedNullab->getValue())
286 return nullptr;
287
288 // Retrieve the associated statement.
289 const Stmt *S = TrackedNullab->getNullabilitySource();
290 if (!S) {
291 ProgramPoint ProgLoc = N->getLocation();
292 if (Optional<StmtPoint> SP = ProgLoc.getAs<StmtPoint>()) {
293 S = SP->getStmt();
294 }
295 }
296
297 if (!S)
298 return nullptr;
299
300 std::string InfoText =
301 (llvm::Twine("Nullability '") +
302 getNullabilityString(TrackedNullab->getValue()) + "' is infered")
303 .str();
304
305 // Generate the extra diagnostic.
306 PathDiagnosticLocation Pos(S, BRC.getSourceManager(),
307 N->getLocationContext());
308 return new PathDiagnosticEventPiece(Pos, InfoText, true, nullptr);
309}
310
311static Nullability getNullabilityAnnotation(QualType Type) {
312 const auto *AttrType = Type->getAs<AttributedType>();
313 if (!AttrType)
314 return Nullability::Unspecified;
315 if (AttrType->getAttrKind() == AttributedType::attr_nullable)
316 return Nullability::Nullable;
317 else if (AttrType->getAttrKind() == AttributedType::attr_nonnull)
318 return Nullability::Nonnull;
319 return Nullability::Unspecified;
320}
321
Gabor Horvathb47128a2015-09-03 23:16:21 +0000322template <typename ParamVarDeclRange>
323static bool
324checkParamsForPreconditionViolation(const ParamVarDeclRange &Params,
325 ProgramStateRef State,
326 const LocationContext *LocCtxt) {
327 for (const auto *ParamDecl : Params) {
328 if (ParamDecl->isParameterPack())
329 break;
330
331 if (getNullabilityAnnotation(ParamDecl->getType()) != Nullability::Nonnull)
332 continue;
333
334 auto RegVal = State->getLValue(ParamDecl, LocCtxt)
335 .template getAs<loc::MemRegionVal>();
336 if (!RegVal)
337 continue;
338
339 auto ParamValue = State->getSVal(RegVal->getRegion())
340 .template getAs<DefinedOrUnknownSVal>();
341 if (!ParamValue)
342 continue;
343
344 if (getNullConstraint(*ParamValue, State) == NullConstraint::IsNull) {
345 return true;
346 }
347 }
348 return false;
349}
350
351static bool checkPreconditionViolation(ProgramStateRef State, ExplodedNode *N,
352 CheckerContext &C) {
353 if (State->get<PreconditionViolated>())
354 return true;
355
356 const LocationContext *LocCtxt = C.getLocationContext();
357 const Decl *D = LocCtxt->getDecl();
358 if (!D)
359 return false;
360
361 if (const auto *BlockD = dyn_cast<BlockDecl>(D)) {
362 if (checkParamsForPreconditionViolation(BlockD->parameters(), State,
363 LocCtxt)) {
364 if (!N->isSink())
365 C.addTransition(State->set<PreconditionViolated>(true), N);
366 return true;
367 }
368 return false;
369 }
370
371 if (const auto *FuncDecl = dyn_cast<FunctionDecl>(D)) {
372 if (checkParamsForPreconditionViolation(FuncDecl->parameters(), State,
373 LocCtxt)) {
374 if (!N->isSink())
375 C.addTransition(State->set<PreconditionViolated>(true), N);
376 return true;
377 }
378 return false;
379 }
380 return false;
381}
382
383void NullabilityChecker::reportBugIfPreconditionHolds(
384 ErrorKind Error, ExplodedNode *N, const MemRegion *Region,
385 CheckerContext &C, const Stmt *ValueExpr, bool SuppressPath) const {
386 ProgramStateRef OriginalState = N->getState();
387
388 if (checkPreconditionViolation(OriginalState, N, C))
389 return;
390 if (SuppressPath) {
391 OriginalState = OriginalState->set<PreconditionViolated>(true);
392 N = C.addTransition(OriginalState, N);
393 }
394
395 reportBug(Error, N, Region, C.getBugReporter(), ValueExpr);
396}
397
Gabor Horvath28690922015-08-26 23:17:43 +0000398/// Cleaning up the program state.
399void NullabilityChecker::checkDeadSymbols(SymbolReaper &SR,
400 CheckerContext &C) const {
401 ProgramStateRef State = C.getState();
402 NullabilityMapTy Nullabilities = State->get<NullabilityMap>();
403 for (NullabilityMapTy::iterator I = Nullabilities.begin(),
404 E = Nullabilities.end();
405 I != E; ++I) {
406 if (!SR.isLiveRegion(I->first)) {
407 State = State->remove<NullabilityMap>(I->first);
408 }
409 }
Gabor Horvathb47128a2015-09-03 23:16:21 +0000410 // When one of the nonnull arguments are constrained to be null, nullability
411 // preconditions are violated. It is not enough to check this only when we
412 // actually report an error, because at that time interesting symbols might be
413 // reaped.
414 if (checkPreconditionViolation(State, C.getPredecessor(), C))
415 return;
416 C.addTransition(State);
Gabor Horvath28690922015-08-26 23:17:43 +0000417}
418
419/// This callback triggers when a pointer is dereferenced and the analyzer does
420/// not know anything about the value of that pointer. When that pointer is
421/// nullable, this code emits a warning.
422void NullabilityChecker::checkEvent(ImplicitNullDerefEvent Event) const {
Gabor Horvathb47128a2015-09-03 23:16:21 +0000423 if (Event.SinkNode->getState()->get<PreconditionViolated>())
424 return;
425
Gabor Horvath28690922015-08-26 23:17:43 +0000426 const MemRegion *Region =
427 getTrackRegion(Event.Location, /*CheckSuperregion=*/true);
428 if (!Region)
429 return;
430
431 ProgramStateRef State = Event.SinkNode->getState();
432 const NullabilityState *TrackedNullability =
433 State->get<NullabilityMap>(Region);
434
435 if (!TrackedNullability)
436 return;
437
438 if (Filter.CheckNullableDereferenced &&
439 TrackedNullability->getValue() == Nullability::Nullable) {
440 BugReporter &BR = *Event.BR;
Gabor Horvathb47128a2015-09-03 23:16:21 +0000441 // Do not suppress errors on defensive code paths, because dereferencing
442 // a nullable pointer is always an error.
Gabor Horvath8d3ad6b2015-08-27 18:49:07 +0000443 if (Event.IsDirectDereference)
444 reportBug(ErrorKind::NullableDereferenced, Event.SinkNode, Region, BR);
445 else
446 reportBug(ErrorKind::NullablePassedToNonnull, Event.SinkNode, Region, BR);
Gabor Horvath28690922015-08-26 23:17:43 +0000447 }
448}
449
450/// This method check when nullable pointer or null value is returned from a
451/// function that has nonnull return type.
452///
453/// TODO: when nullability preconditons are violated, it is ok to violate the
454/// nullability postconditons (i.e.: when one of the nonnull parameters are null
455/// this check should not report any nullability related issue).
456void NullabilityChecker::checkPreStmt(const ReturnStmt *S,
457 CheckerContext &C) const {
458 auto RetExpr = S->getRetValue();
459 if (!RetExpr)
460 return;
461
462 if (!RetExpr->getType()->isAnyPointerType())
463 return;
464
465 ProgramStateRef State = C.getState();
Gabor Horvathb47128a2015-09-03 23:16:21 +0000466 if (State->get<PreconditionViolated>())
467 return;
468
Gabor Horvath28690922015-08-26 23:17:43 +0000469 auto RetSVal =
470 State->getSVal(S, C.getLocationContext()).getAs<DefinedOrUnknownSVal>();
471 if (!RetSVal)
472 return;
473
474 AnalysisDeclContext *DeclCtxt =
475 C.getLocationContext()->getAnalysisDeclContext();
476 const FunctionType *FuncType = DeclCtxt->getDecl()->getFunctionType();
477 if (!FuncType)
478 return;
479
480 NullConstraint Nullness = getNullConstraint(*RetSVal, State);
481
482 Nullability StaticNullability =
483 getNullabilityAnnotation(FuncType->getReturnType());
484
485 if (Filter.CheckNullReturnedFromNonnull &&
486 Nullness == NullConstraint::IsNull &&
487 StaticNullability == Nullability::Nonnull) {
488 static CheckerProgramPointTag Tag(this, "NullReturnedFromNonnull");
Gabor Horvathb47128a2015-09-03 23:16:21 +0000489 ExplodedNode *N = C.generateSink(State, C.getPredecessor(), &Tag);
490 reportBugIfPreconditionHolds(ErrorKind::NilReturnedToNonnull, N, nullptr, C,
491 RetExpr);
Gabor Horvath28690922015-08-26 23:17:43 +0000492 return;
493 }
494
495 const MemRegion *Region = getTrackRegion(*RetSVal);
496 if (!Region)
497 return;
498
499 const NullabilityState *TrackedNullability =
500 State->get<NullabilityMap>(Region);
501 if (TrackedNullability) {
502 Nullability TrackedNullabValue = TrackedNullability->getValue();
503 if (Filter.CheckNullableReturnedFromNonnull &&
504 Nullness != NullConstraint::IsNotNull &&
505 TrackedNullabValue == Nullability::Nullable &&
506 StaticNullability == Nullability::Nonnull) {
507 static CheckerProgramPointTag Tag(this, "NullableReturnedFromNonnull");
508 ExplodedNode *N = C.addTransition(State, C.getPredecessor(), &Tag);
Gabor Horvathb47128a2015-09-03 23:16:21 +0000509 reportBugIfPreconditionHolds(ErrorKind::NullableReturnedToNonnull, N,
510 Region, C);
Gabor Horvath28690922015-08-26 23:17:43 +0000511 }
512 return;
513 }
514 if (StaticNullability == Nullability::Nullable) {
515 State = State->set<NullabilityMap>(Region,
516 NullabilityState(StaticNullability, S));
517 C.addTransition(State);
518 }
519}
520
521/// This callback warns when a nullable pointer or a null value is passed to a
522/// function that expects its argument to be nonnull.
523void NullabilityChecker::checkPreCall(const CallEvent &Call,
524 CheckerContext &C) const {
525 if (!Call.getDecl())
526 return;
527
528 ProgramStateRef State = C.getState();
Gabor Horvathb47128a2015-09-03 23:16:21 +0000529 if (State->get<PreconditionViolated>())
530 return;
531
Gabor Horvath28690922015-08-26 23:17:43 +0000532 ProgramStateRef OrigState = State;
533
534 unsigned Idx = 0;
535 for (const ParmVarDecl *Param : Call.parameters()) {
536 if (Param->isParameterPack())
537 break;
538
539 const Expr *ArgExpr = nullptr;
540 if (Idx < Call.getNumArgs())
541 ArgExpr = Call.getArgExpr(Idx);
542 auto ArgSVal = Call.getArgSVal(Idx++).getAs<DefinedOrUnknownSVal>();
543 if (!ArgSVal)
544 continue;
545
546 if (!Param->getType()->isAnyPointerType() &&
547 !Param->getType()->isReferenceType())
548 continue;
549
550 NullConstraint Nullness = getNullConstraint(*ArgSVal, State);
551
552 Nullability ParamNullability = getNullabilityAnnotation(Param->getType());
553 Nullability ArgStaticNullability =
554 getNullabilityAnnotation(ArgExpr->getType());
555
556 if (Filter.CheckNullPassedToNonnull && Nullness == NullConstraint::IsNull &&
557 ArgStaticNullability != Nullability::Nonnull &&
558 ParamNullability == Nullability::Nonnull) {
Gabor Horvathb47128a2015-09-03 23:16:21 +0000559 ExplodedNode *N = C.generateSink(State);
560 reportBugIfPreconditionHolds(ErrorKind::NilPassedToNonnull, N, nullptr, C,
561 ArgExpr);
Gabor Horvath28690922015-08-26 23:17:43 +0000562 return;
563 }
564
565 const MemRegion *Region = getTrackRegion(*ArgSVal);
566 if (!Region)
567 continue;
568
569 const NullabilityState *TrackedNullability =
570 State->get<NullabilityMap>(Region);
571
572 if (TrackedNullability) {
573 if (Nullness == NullConstraint::IsNotNull ||
574 TrackedNullability->getValue() != Nullability::Nullable)
575 continue;
576
577 if (Filter.CheckNullablePassedToNonnull &&
578 ParamNullability == Nullability::Nonnull) {
Gabor Horvathb47128a2015-09-03 23:16:21 +0000579 ExplodedNode *N = C.addTransition(State);
580 reportBugIfPreconditionHolds(ErrorKind::NullablePassedToNonnull, N,
581 Region, C, ArgExpr, /*SuppressPath=*/true);
Gabor Horvath28690922015-08-26 23:17:43 +0000582 return;
583 }
584 if (Filter.CheckNullableDereferenced &&
585 Param->getType()->isReferenceType()) {
Gabor Horvathb47128a2015-09-03 23:16:21 +0000586 ExplodedNode *N = C.addTransition(State);
587 reportBugIfPreconditionHolds(ErrorKind::NullableDereferenced, N, Region,
588 C, ArgExpr, /*SuppressPath=*/true);
Gabor Horvath28690922015-08-26 23:17:43 +0000589 return;
590 }
591 continue;
592 }
593 // No tracked nullability yet.
594 if (ArgStaticNullability != Nullability::Nullable)
595 continue;
596 State = State->set<NullabilityMap>(
597 Region, NullabilityState(ArgStaticNullability, ArgExpr));
598 }
599 if (State != OrigState)
600 C.addTransition(State);
601}
602
603/// Suppress the nullability warnings for some functions.
604void NullabilityChecker::checkPostCall(const CallEvent &Call,
605 CheckerContext &C) const {
606 auto Decl = Call.getDecl();
607 if (!Decl)
608 return;
609 // ObjC Messages handles in a different callback.
610 if (Call.getKind() == CE_ObjCMessage)
611 return;
612 const FunctionType *FuncType = Decl->getFunctionType();
613 if (!FuncType)
614 return;
615 QualType ReturnType = FuncType->getReturnType();
616 if (!ReturnType->isAnyPointerType())
617 return;
Gabor Horvathb47128a2015-09-03 23:16:21 +0000618 ProgramStateRef State = C.getState();
619 if (State->get<PreconditionViolated>())
620 return;
621
Gabor Horvath28690922015-08-26 23:17:43 +0000622 const MemRegion *Region = getTrackRegion(Call.getReturnValue());
623 if (!Region)
624 return;
Gabor Horvath28690922015-08-26 23:17:43 +0000625
626 // CG headers are misannotated. Do not warn for symbols that are the results
627 // of CG calls.
628 const SourceManager &SM = C.getSourceManager();
629 StringRef FilePath = SM.getFilename(SM.getSpellingLoc(Decl->getLocStart()));
630 if (llvm::sys::path::filename(FilePath).startswith("CG")) {
631 State = State->set<NullabilityMap>(Region, Nullability::Contradicted);
632 C.addTransition(State);
633 return;
634 }
635
636 const NullabilityState *TrackedNullability =
637 State->get<NullabilityMap>(Region);
638
639 if (!TrackedNullability &&
640 getNullabilityAnnotation(ReturnType) == Nullability::Nullable) {
641 State = State->set<NullabilityMap>(Region, Nullability::Nullable);
642 C.addTransition(State);
643 }
644}
645
646static Nullability getReceiverNullability(const ObjCMethodCall &M,
647 ProgramStateRef State) {
648 Nullability RetNullability = Nullability::Unspecified;
649 if (M.isReceiverSelfOrSuper()) {
650 // For super and super class receivers we assume that the receiver is
651 // nonnull.
652 RetNullability = Nullability::Nonnull;
653 } else {
654 // Otherwise look up nullability in the state.
655 SVal Receiver = M.getReceiverSVal();
656 auto ValueRegionSVal = Receiver.getAs<loc::MemRegionVal>();
657 if (ValueRegionSVal) {
658 const MemRegion *SelfRegion = ValueRegionSVal->getRegion();
659 assert(SelfRegion);
660
661 const NullabilityState *TrackedSelfNullability =
662 State->get<NullabilityMap>(SelfRegion);
663 if (TrackedSelfNullability) {
664 RetNullability = TrackedSelfNullability->getValue();
665 }
666 }
667 if (auto DefOrUnknown = Receiver.getAs<DefinedOrUnknownSVal>()) {
668 // If the receiver is constrained to be nonnull, assume that it is nonnull
669 // regardless of its type.
670 NullConstraint Nullness = getNullConstraint(*DefOrUnknown, State);
671 if (Nullness == NullConstraint::IsNotNull)
672 RetNullability = Nullability::Nonnull;
673 }
674 }
675 return RetNullability;
676}
677
678/// Calculate the nullability of the result of a message expr based on the
679/// nullability of the receiver, the nullability of the return value, and the
680/// constraints.
681void NullabilityChecker::checkPostObjCMessage(const ObjCMethodCall &M,
682 CheckerContext &C) const {
683 auto Decl = M.getDecl();
684 if (!Decl)
685 return;
686 QualType RetType = Decl->getReturnType();
687 if (!RetType->isAnyPointerType())
688 return;
689
Gabor Horvathb47128a2015-09-03 23:16:21 +0000690 ProgramStateRef State = C.getState();
691 if (State->get<PreconditionViolated>())
692 return;
693
Gabor Horvath28690922015-08-26 23:17:43 +0000694 const MemRegion *ReturnRegion = getTrackRegion(M.getReturnValue());
695 if (!ReturnRegion)
696 return;
697
Gabor Horvath28690922015-08-26 23:17:43 +0000698 auto Interface = Decl->getClassInterface();
699 auto Name = Interface ? Interface->getName() : "";
700 // In order to reduce the noise in the diagnostics generated by this checker,
701 // some framework and programming style based heuristics are used. These
702 // heuristics are for Cocoa APIs which have NS prefix.
703 if (Name.startswith("NS")) {
704 // Developers rely on dynamic invariants such as an item should be available
705 // in a collection, or a collection is not empty often. Those invariants can
706 // not be inferred by any static analysis tool. To not to bother the users
707 // with too many false positives, every item retrieval function should be
708 // ignored for collections. The instance methods of dictionaries in Cocoa
709 // are either item retrieval related or not interesting nullability wise.
710 // Using this fact, to keep the code easier to read just ignore the return
711 // value of every instance method of dictionaries.
712 if (M.isInstanceMessage() && Name.find("Dictionary") != StringRef::npos) {
713 State =
714 State->set<NullabilityMap>(ReturnRegion, Nullability::Contradicted);
715 C.addTransition(State);
716 return;
717 }
718 // For similar reasons ignore some methods of Cocoa arrays.
719 StringRef FirstSelectorSlot = M.getSelector().getNameForSlot(0);
720 if (Name.find("Array") != StringRef::npos &&
721 (FirstSelectorSlot == "firstObject" ||
722 FirstSelectorSlot == "lastObject")) {
723 State =
724 State->set<NullabilityMap>(ReturnRegion, Nullability::Contradicted);
725 C.addTransition(State);
726 return;
727 }
728
729 // Encoding related methods of string should not fail when lossless
730 // encodings are used. Using lossless encodings is so frequent that ignoring
731 // this class of methods reduced the emitted diagnostics by about 30% on
732 // some projects (and all of that was false positives).
733 if (Name.find("String") != StringRef::npos) {
734 for (auto Param : M.parameters()) {
735 if (Param->getName() == "encoding") {
736 State = State->set<NullabilityMap>(ReturnRegion,
737 Nullability::Contradicted);
738 C.addTransition(State);
739 return;
740 }
741 }
742 }
743 }
744
745 const ObjCMessageExpr *Message = M.getOriginExpr();
746 Nullability SelfNullability = getReceiverNullability(M, State);
747
748 const NullabilityState *NullabilityOfReturn =
749 State->get<NullabilityMap>(ReturnRegion);
750
751 if (NullabilityOfReturn) {
752 // When we have a nullability tracked for the return value, the nullability
753 // of the expression will be the most nullable of the receiver and the
754 // return value.
755 Nullability RetValTracked = NullabilityOfReturn->getValue();
756 Nullability ComputedNullab =
757 getMostNullable(RetValTracked, SelfNullability);
758 if (ComputedNullab != RetValTracked &&
759 ComputedNullab != Nullability::Unspecified) {
760 const Stmt *NullabilitySource =
761 ComputedNullab == RetValTracked
762 ? NullabilityOfReturn->getNullabilitySource()
763 : Message->getInstanceReceiver();
764 State = State->set<NullabilityMap>(
765 ReturnRegion, NullabilityState(ComputedNullab, NullabilitySource));
766 C.addTransition(State);
767 }
768 return;
769 }
770
771 // No tracked information. Use static type information for return value.
772 Nullability RetNullability = getNullabilityAnnotation(RetType);
773
774 // Properties might be computed. For this reason the static analyzer creates a
775 // new symbol each time an unknown property is read. To avoid false pozitives
776 // do not treat unknown properties as nullable, even when they explicitly
777 // marked nullable.
778 if (M.getMessageKind() == OCM_PropertyAccess && !C.wasInlined)
779 RetNullability = Nullability::Nonnull;
780
781 Nullability ComputedNullab = getMostNullable(RetNullability, SelfNullability);
782 if (ComputedNullab == Nullability::Nullable) {
783 const Stmt *NullabilitySource = ComputedNullab == RetNullability
784 ? Message
785 : Message->getInstanceReceiver();
786 State = State->set<NullabilityMap>(
787 ReturnRegion, NullabilityState(ComputedNullab, NullabilitySource));
788 C.addTransition(State);
789 }
790}
791
792/// Explicit casts are trusted. If there is a disagreement in the nullability
793/// annotations in the destination and the source or '0' is casted to nonnull
794/// track the value as having contraditory nullability. This will allow users to
795/// suppress warnings.
796void NullabilityChecker::checkPostStmt(const ExplicitCastExpr *CE,
797 CheckerContext &C) const {
798 QualType OriginType = CE->getSubExpr()->getType();
799 QualType DestType = CE->getType();
800 if (!OriginType->isAnyPointerType())
801 return;
802 if (!DestType->isAnyPointerType())
803 return;
804
Gabor Horvathb47128a2015-09-03 23:16:21 +0000805 ProgramStateRef State = C.getState();
806 if (State->get<PreconditionViolated>())
807 return;
808
Gabor Horvath28690922015-08-26 23:17:43 +0000809 Nullability DestNullability = getNullabilityAnnotation(DestType);
810
811 // No explicit nullability in the destination type, so this cast does not
812 // change the nullability.
813 if (DestNullability == Nullability::Unspecified)
814 return;
815
Gabor Horvath28690922015-08-26 23:17:43 +0000816 auto RegionSVal =
817 State->getSVal(CE, C.getLocationContext()).getAs<DefinedOrUnknownSVal>();
818 const MemRegion *Region = getTrackRegion(*RegionSVal);
819 if (!Region)
820 return;
821
822 // When 0 is converted to nonnull mark it as contradicted.
823 if (DestNullability == Nullability::Nonnull) {
824 NullConstraint Nullness = getNullConstraint(*RegionSVal, State);
825 if (Nullness == NullConstraint::IsNull) {
826 State = State->set<NullabilityMap>(Region, Nullability::Contradicted);
827 C.addTransition(State);
828 return;
829 }
830 }
831
832 const NullabilityState *TrackedNullability =
833 State->get<NullabilityMap>(Region);
834
835 if (!TrackedNullability) {
836 if (DestNullability != Nullability::Nullable)
837 return;
838 State = State->set<NullabilityMap>(Region,
839 NullabilityState(DestNullability, CE));
840 C.addTransition(State);
841 return;
842 }
843
844 if (TrackedNullability->getValue() != DestNullability &&
845 TrackedNullability->getValue() != Nullability::Contradicted) {
846 State = State->set<NullabilityMap>(Region, Nullability::Contradicted);
847 C.addTransition(State);
848 }
849}
850
851/// Propagate the nullability information through binds and warn when nullable
852/// pointer or null symbol is assigned to a pointer with a nonnull type.
853void NullabilityChecker::checkBind(SVal L, SVal V, const Stmt *S,
854 CheckerContext &C) const {
855 const TypedValueRegion *TVR =
856 dyn_cast_or_null<TypedValueRegion>(L.getAsRegion());
857 if (!TVR)
858 return;
859
860 QualType LocType = TVR->getValueType();
861 if (!LocType->isAnyPointerType())
862 return;
863
Gabor Horvathb47128a2015-09-03 23:16:21 +0000864 ProgramStateRef State = C.getState();
865 if (State->get<PreconditionViolated>())
866 return;
867
Gabor Horvath28690922015-08-26 23:17:43 +0000868 auto ValDefOrUnknown = V.getAs<DefinedOrUnknownSVal>();
869 if (!ValDefOrUnknown)
870 return;
871
Gabor Horvath28690922015-08-26 23:17:43 +0000872 NullConstraint RhsNullness = getNullConstraint(*ValDefOrUnknown, State);
873
874 Nullability ValNullability = Nullability::Unspecified;
875 if (SymbolRef Sym = ValDefOrUnknown->getAsSymbol())
876 ValNullability = getNullabilityAnnotation(Sym->getType());
877
878 Nullability LocNullability = getNullabilityAnnotation(LocType);
879 if (Filter.CheckNullPassedToNonnull &&
880 RhsNullness == NullConstraint::IsNull &&
881 ValNullability != Nullability::Nonnull &&
882 LocNullability == Nullability::Nonnull) {
883 static CheckerProgramPointTag Tag(this, "NullPassedToNonnull");
Gabor Horvathb47128a2015-09-03 23:16:21 +0000884 ExplodedNode *N = C.generateSink(State, C.getPredecessor(), &Tag);
885 reportBugIfPreconditionHolds(ErrorKind::NilAssignedToNonnull, N, nullptr, C,
886 S);
Gabor Horvath28690922015-08-26 23:17:43 +0000887 return;
888 }
889 // Intentionally missing case: '0' is bound to a reference. It is handled by
890 // the DereferenceChecker.
891
892 const MemRegion *ValueRegion = getTrackRegion(*ValDefOrUnknown);
893 if (!ValueRegion)
894 return;
895
896 const NullabilityState *TrackedNullability =
897 State->get<NullabilityMap>(ValueRegion);
898
899 if (TrackedNullability) {
900 if (RhsNullness == NullConstraint::IsNotNull ||
901 TrackedNullability->getValue() != Nullability::Nullable)
902 return;
903 if (Filter.CheckNullablePassedToNonnull &&
904 LocNullability == Nullability::Nonnull) {
905 static CheckerProgramPointTag Tag(this, "NullablePassedToNonnull");
906 ExplodedNode *N = C.addTransition(State, C.getPredecessor(), &Tag);
Gabor Horvathb47128a2015-09-03 23:16:21 +0000907 reportBugIfPreconditionHolds(ErrorKind::NullableAssignedToNonnull, N,
908 ValueRegion, C);
Gabor Horvath28690922015-08-26 23:17:43 +0000909 }
910 return;
911 }
912
913 const auto *BinOp = dyn_cast<BinaryOperator>(S);
914
915 if (ValNullability == Nullability::Nullable) {
916 // Trust the static information of the value more than the static
917 // information on the location.
918 const Stmt *NullabilitySource = BinOp ? BinOp->getRHS() : S;
919 State = State->set<NullabilityMap>(
920 ValueRegion, NullabilityState(ValNullability, NullabilitySource));
921 C.addTransition(State);
922 return;
923 }
924
925 if (LocNullability == Nullability::Nullable) {
926 const Stmt *NullabilitySource = BinOp ? BinOp->getLHS() : S;
927 State = State->set<NullabilityMap>(
928 ValueRegion, NullabilityState(LocNullability, NullabilitySource));
929 C.addTransition(State);
930 }
931}
932
933void NullabilityChecker::printState(raw_ostream &Out, ProgramStateRef State,
934 const char *NL, const char *Sep) const {
935
936 NullabilityMapTy B = State->get<NullabilityMap>();
937
938 if (B.isEmpty())
939 return;
940
941 Out << Sep << NL;
942
943 for (NullabilityMapTy::iterator I = B.begin(), E = B.end(); I != E; ++I) {
944 Out << I->first << " : ";
945 I->second.print(Out);
946 Out << NL;
947 }
948}
949
950#define REGISTER_CHECKER(name) \
951 void ento::register##name##Checker(CheckerManager &mgr) { \
952 NullabilityChecker *checker = mgr.registerChecker<NullabilityChecker>(); \
953 checker->Filter.Check##name = true; \
954 checker->Filter.CheckName##name = mgr.getCurrentCheckName(); \
955 }
956
957REGISTER_CHECKER(NullPassedToNonnull)
958REGISTER_CHECKER(NullReturnedFromNonnull)
959REGISTER_CHECKER(NullableDereferenced)
960REGISTER_CHECKER(NullablePassedToNonnull)
961REGISTER_CHECKER(NullableReturnedFromNonnull)