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