1 //== BasicObjCFoundationChecks.cpp - Simple Apple-Foundation checks -*- 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 file defines BasicObjCFoundationChecks, a class that encapsulates
11 // a set of simple checks to run on Objective-C code using Apple's Foundation
12 // classes.
13 //
14 //===----------------------------------------------------------------------===//
15
16 #include "ClangSACheckers.h"
17 #include "SelectorExtras.h"
18 #include "clang/AST/ASTContext.h"
19 #include "clang/AST/DeclObjC.h"
20 #include "clang/AST/Expr.h"
21 #include "clang/AST/ExprObjC.h"
22 #include "clang/AST/StmtObjC.h"
23 #include "clang/Analysis/DomainSpecific/CocoaConventions.h"
24 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
25 #include "clang/StaticAnalyzer/Core/Checker.h"
26 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
27 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
28 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
29 #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
30 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
31 #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
32 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
33 #include "llvm/ADT/SmallString.h"
34 #include "llvm/ADT/StringMap.h"
35 #include "llvm/Support/raw_ostream.h"
36
37 using namespace clang;
38 using namespace ento;
39
40 namespace {
41 class APIMisuse : public BugType {
42 public:
APIMisuse(const CheckerBase * checker,const char * name)43 APIMisuse(const CheckerBase *checker, const char *name)
44 : BugType(checker, name, "API Misuse (Apple)") {}
45 };
46 } // end anonymous namespace
47
48 //===----------------------------------------------------------------------===//
49 // Utility functions.
50 //===----------------------------------------------------------------------===//
51
GetReceiverInterfaceName(const ObjCMethodCall & msg)52 static StringRef GetReceiverInterfaceName(const ObjCMethodCall &msg) {
53 if (const ObjCInterfaceDecl *ID = msg.getReceiverInterface())
54 return ID->getIdentifier()->getName();
55 return StringRef();
56 }
57
58 enum FoundationClass {
59 FC_None,
60 FC_NSArray,
61 FC_NSDictionary,
62 FC_NSEnumerator,
63 FC_NSNull,
64 FC_NSOrderedSet,
65 FC_NSSet,
66 FC_NSString
67 };
68
findKnownClass(const ObjCInterfaceDecl * ID,bool IncludeSuperclasses=true)69 static FoundationClass findKnownClass(const ObjCInterfaceDecl *ID,
70 bool IncludeSuperclasses = true) {
71 static llvm::StringMap<FoundationClass> Classes;
72 if (Classes.empty()) {
73 Classes["NSArray"] = FC_NSArray;
74 Classes["NSDictionary"] = FC_NSDictionary;
75 Classes["NSEnumerator"] = FC_NSEnumerator;
76 Classes["NSNull"] = FC_NSNull;
77 Classes["NSOrderedSet"] = FC_NSOrderedSet;
78 Classes["NSSet"] = FC_NSSet;
79 Classes["NSString"] = FC_NSString;
80 }
81
82 // FIXME: Should we cache this at all?
83 FoundationClass result = Classes.lookup(ID->getIdentifier()->getName());
84 if (result == FC_None && IncludeSuperclasses)
85 if (const ObjCInterfaceDecl *Super = ID->getSuperClass())
86 return findKnownClass(Super);
87
88 return result;
89 }
90
91 //===----------------------------------------------------------------------===//
92 // NilArgChecker - Check for prohibited nil arguments to ObjC method calls.
93 //===----------------------------------------------------------------------===//
94
95 namespace {
96 class NilArgChecker : public Checker<check::PreObjCMessage,
97 check::PostStmt<ObjCDictionaryLiteral>,
98 check::PostStmt<ObjCArrayLiteral> > {
99 mutable std::unique_ptr<APIMisuse> BT;
100
101 mutable llvm::SmallDenseMap<Selector, unsigned, 16> StringSelectors;
102 mutable Selector ArrayWithObjectSel;
103 mutable Selector AddObjectSel;
104 mutable Selector InsertObjectAtIndexSel;
105 mutable Selector ReplaceObjectAtIndexWithObjectSel;
106 mutable Selector SetObjectAtIndexedSubscriptSel;
107 mutable Selector ArrayByAddingObjectSel;
108 mutable Selector DictionaryWithObjectForKeySel;
109 mutable Selector SetObjectForKeySel;
110 mutable Selector SetObjectForKeyedSubscriptSel;
111 mutable Selector RemoveObjectForKeySel;
112
113 void warnIfNilExpr(const Expr *E,
114 const char *Msg,
115 CheckerContext &C) const;
116
117 void warnIfNilArg(CheckerContext &C,
118 const ObjCMethodCall &msg, unsigned Arg,
119 FoundationClass Class,
120 bool CanBeSubscript = false) const;
121
122 void generateBugReport(ExplodedNode *N,
123 StringRef Msg,
124 SourceRange Range,
125 const Expr *Expr,
126 CheckerContext &C) const;
127
128 public:
129 void checkPreObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
130 void checkPostStmt(const ObjCDictionaryLiteral *DL,
131 CheckerContext &C) const;
132 void checkPostStmt(const ObjCArrayLiteral *AL,
133 CheckerContext &C) const;
134 };
135 } // end anonymous namespace
136
warnIfNilExpr(const Expr * E,const char * Msg,CheckerContext & C) const137 void NilArgChecker::warnIfNilExpr(const Expr *E,
138 const char *Msg,
139 CheckerContext &C) const {
140 ProgramStateRef State = C.getState();
141 if (State->isNull(C.getSVal(E)).isConstrainedTrue()) {
142
143 if (ExplodedNode *N = C.generateErrorNode()) {
144 generateBugReport(N, Msg, E->getSourceRange(), E, C);
145 }
146 }
147 }
148
warnIfNilArg(CheckerContext & C,const ObjCMethodCall & msg,unsigned int Arg,FoundationClass Class,bool CanBeSubscript) const149 void NilArgChecker::warnIfNilArg(CheckerContext &C,
150 const ObjCMethodCall &msg,
151 unsigned int Arg,
152 FoundationClass Class,
153 bool CanBeSubscript) const {
154 // Check if the argument is nil.
155 ProgramStateRef State = C.getState();
156 if (!State->isNull(msg.getArgSVal(Arg)).isConstrainedTrue())
157 return;
158
159 if (ExplodedNode *N = C.generateErrorNode()) {
160 SmallString<128> sbuf;
161 llvm::raw_svector_ostream os(sbuf);
162
163 if (CanBeSubscript && msg.getMessageKind() == OCM_Subscript) {
164
165 if (Class == FC_NSArray) {
166 os << "Array element cannot be nil";
167 } else if (Class == FC_NSDictionary) {
168 if (Arg == 0) {
169 os << "Value stored into '";
170 os << GetReceiverInterfaceName(msg) << "' cannot be nil";
171 } else {
172 assert(Arg == 1);
173 os << "'"<< GetReceiverInterfaceName(msg) << "' key cannot be nil";
174 }
175 } else
176 llvm_unreachable("Missing foundation class for the subscript expr");
177
178 } else {
179 if (Class == FC_NSDictionary) {
180 if (Arg == 0)
181 os << "Value argument ";
182 else {
183 assert(Arg == 1);
184 os << "Key argument ";
185 }
186 os << "to '";
187 msg.getSelector().print(os);
188 os << "' cannot be nil";
189 } else {
190 os << "Argument to '" << GetReceiverInterfaceName(msg) << "' method '";
191 msg.getSelector().print(os);
192 os << "' cannot be nil";
193 }
194 }
195
196 generateBugReport(N, os.str(), msg.getArgSourceRange(Arg),
197 msg.getArgExpr(Arg), C);
198 }
199 }
200
generateBugReport(ExplodedNode * N,StringRef Msg,SourceRange Range,const Expr * E,CheckerContext & C) const201 void NilArgChecker::generateBugReport(ExplodedNode *N,
202 StringRef Msg,
203 SourceRange Range,
204 const Expr *E,
205 CheckerContext &C) const {
206 if (!BT)
207 BT.reset(new APIMisuse(this, "nil argument"));
208
209 auto R = llvm::make_unique<BugReport>(*BT, Msg, N);
210 R->addRange(Range);
211 bugreporter::trackNullOrUndefValue(N, E, *R);
212 C.emitReport(std::move(R));
213 }
214
checkPreObjCMessage(const ObjCMethodCall & msg,CheckerContext & C) const215 void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
216 CheckerContext &C) const {
217 const ObjCInterfaceDecl *ID = msg.getReceiverInterface();
218 if (!ID)
219 return;
220
221 FoundationClass Class = findKnownClass(ID);
222
223 static const unsigned InvalidArgIndex = UINT_MAX;
224 unsigned Arg = InvalidArgIndex;
225 bool CanBeSubscript = false;
226
227 if (Class == FC_NSString) {
228 Selector S = msg.getSelector();
229
230 if (S.isUnarySelector())
231 return;
232
233 if (StringSelectors.empty()) {
234 ASTContext &Ctx = C.getASTContext();
235 Selector Sels[] = {
236 getKeywordSelector(Ctx, "caseInsensitiveCompare", nullptr),
237 getKeywordSelector(Ctx, "compare", nullptr),
238 getKeywordSelector(Ctx, "compare", "options", nullptr),
239 getKeywordSelector(Ctx, "compare", "options", "range", nullptr),
240 getKeywordSelector(Ctx, "compare", "options", "range", "locale",
241 nullptr),
242 getKeywordSelector(Ctx, "componentsSeparatedByCharactersInSet",
243 nullptr),
244 getKeywordSelector(Ctx, "initWithFormat",
245 nullptr),
246 getKeywordSelector(Ctx, "localizedCaseInsensitiveCompare", nullptr),
247 getKeywordSelector(Ctx, "localizedCompare", nullptr),
248 getKeywordSelector(Ctx, "localizedStandardCompare", nullptr),
249 };
250 for (Selector KnownSel : Sels)
251 StringSelectors[KnownSel] = 0;
252 }
253 auto I = StringSelectors.find(S);
254 if (I == StringSelectors.end())
255 return;
256 Arg = I->second;
257 } else if (Class == FC_NSArray) {
258 Selector S = msg.getSelector();
259
260 if (S.isUnarySelector())
261 return;
262
263 if (ArrayWithObjectSel.isNull()) {
264 ASTContext &Ctx = C.getASTContext();
265 ArrayWithObjectSel = getKeywordSelector(Ctx, "arrayWithObject", nullptr);
266 AddObjectSel = getKeywordSelector(Ctx, "addObject", nullptr);
267 InsertObjectAtIndexSel =
268 getKeywordSelector(Ctx, "insertObject", "atIndex", nullptr);
269 ReplaceObjectAtIndexWithObjectSel =
270 getKeywordSelector(Ctx, "replaceObjectAtIndex", "withObject", nullptr);
271 SetObjectAtIndexedSubscriptSel =
272 getKeywordSelector(Ctx, "setObject", "atIndexedSubscript", nullptr);
273 ArrayByAddingObjectSel =
274 getKeywordSelector(Ctx, "arrayByAddingObject", nullptr);
275 }
276
277 if (S == ArrayWithObjectSel || S == AddObjectSel ||
278 S == InsertObjectAtIndexSel || S == ArrayByAddingObjectSel) {
279 Arg = 0;
280 } else if (S == SetObjectAtIndexedSubscriptSel) {
281 Arg = 0;
282 CanBeSubscript = true;
283 } else if (S == ReplaceObjectAtIndexWithObjectSel) {
284 Arg = 1;
285 }
286 } else if (Class == FC_NSDictionary) {
287 Selector S = msg.getSelector();
288
289 if (S.isUnarySelector())
290 return;
291
292 if (DictionaryWithObjectForKeySel.isNull()) {
293 ASTContext &Ctx = C.getASTContext();
294 DictionaryWithObjectForKeySel =
295 getKeywordSelector(Ctx, "dictionaryWithObject", "forKey", nullptr);
296 SetObjectForKeySel =
297 getKeywordSelector(Ctx, "setObject", "forKey", nullptr);
298 SetObjectForKeyedSubscriptSel =
299 getKeywordSelector(Ctx, "setObject", "forKeyedSubscript", nullptr);
300 RemoveObjectForKeySel =
301 getKeywordSelector(Ctx, "removeObjectForKey", nullptr);
302 }
303
304 if (S == DictionaryWithObjectForKeySel || S == SetObjectForKeySel) {
305 Arg = 0;
306 warnIfNilArg(C, msg, /* Arg */1, Class);
307 } else if (S == SetObjectForKeyedSubscriptSel) {
308 CanBeSubscript = true;
309 Arg = 1;
310 } else if (S == RemoveObjectForKeySel) {
311 Arg = 0;
312 }
313 }
314
315 // If argument is '0', report a warning.
316 if ((Arg != InvalidArgIndex))
317 warnIfNilArg(C, msg, Arg, Class, CanBeSubscript);
318 }
319
checkPostStmt(const ObjCArrayLiteral * AL,CheckerContext & C) const320 void NilArgChecker::checkPostStmt(const ObjCArrayLiteral *AL,
321 CheckerContext &C) const {
322 unsigned NumOfElements = AL->getNumElements();
323 for (unsigned i = 0; i < NumOfElements; ++i) {
324 warnIfNilExpr(AL->getElement(i), "Array element cannot be nil", C);
325 }
326 }
327
checkPostStmt(const ObjCDictionaryLiteral * DL,CheckerContext & C) const328 void NilArgChecker::checkPostStmt(const ObjCDictionaryLiteral *DL,
329 CheckerContext &C) const {
330 unsigned NumOfElements = DL->getNumElements();
331 for (unsigned i = 0; i < NumOfElements; ++i) {
332 ObjCDictionaryElement Element = DL->getKeyValueElement(i);
333 warnIfNilExpr(Element.Key, "Dictionary key cannot be nil", C);
334 warnIfNilExpr(Element.Value, "Dictionary value cannot be nil", C);
335 }
336 }
337
338 //===----------------------------------------------------------------------===//
339 // Error reporting.
340 //===----------------------------------------------------------------------===//
341
342 namespace {
343 class CFNumberCreateChecker : public Checker< check::PreStmt<CallExpr> > {
344 mutable std::unique_ptr<APIMisuse> BT;
345 mutable IdentifierInfo* II;
346 public:
CFNumberCreateChecker()347 CFNumberCreateChecker() : II(nullptr) {}
348
349 void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
350
351 private:
352 void EmitError(const TypedRegion* R, const Expr *Ex,
353 uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind);
354 };
355 } // end anonymous namespace
356
357 enum CFNumberType {
358 kCFNumberSInt8Type = 1,
359 kCFNumberSInt16Type = 2,
360 kCFNumberSInt32Type = 3,
361 kCFNumberSInt64Type = 4,
362 kCFNumberFloat32Type = 5,
363 kCFNumberFloat64Type = 6,
364 kCFNumberCharType = 7,
365 kCFNumberShortType = 8,
366 kCFNumberIntType = 9,
367 kCFNumberLongType = 10,
368 kCFNumberLongLongType = 11,
369 kCFNumberFloatType = 12,
370 kCFNumberDoubleType = 13,
371 kCFNumberCFIndexType = 14,
372 kCFNumberNSIntegerType = 15,
373 kCFNumberCGFloatType = 16
374 };
375
GetCFNumberSize(ASTContext & Ctx,uint64_t i)376 static Optional<uint64_t> GetCFNumberSize(ASTContext &Ctx, uint64_t i) {
377 static const unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 };
378
379 if (i < kCFNumberCharType)
380 return FixedSize[i-1];
381
382 QualType T;
383
384 switch (i) {
385 case kCFNumberCharType: T = Ctx.CharTy; break;
386 case kCFNumberShortType: T = Ctx.ShortTy; break;
387 case kCFNumberIntType: T = Ctx.IntTy; break;
388 case kCFNumberLongType: T = Ctx.LongTy; break;
389 case kCFNumberLongLongType: T = Ctx.LongLongTy; break;
390 case kCFNumberFloatType: T = Ctx.FloatTy; break;
391 case kCFNumberDoubleType: T = Ctx.DoubleTy; break;
392 case kCFNumberCFIndexType:
393 case kCFNumberNSIntegerType:
394 case kCFNumberCGFloatType:
395 // FIXME: We need a way to map from names to Type*.
396 default:
397 return None;
398 }
399
400 return Ctx.getTypeSize(T);
401 }
402
403 #if 0
404 static const char* GetCFNumberTypeStr(uint64_t i) {
405 static const char* Names[] = {
406 "kCFNumberSInt8Type",
407 "kCFNumberSInt16Type",
408 "kCFNumberSInt32Type",
409 "kCFNumberSInt64Type",
410 "kCFNumberFloat32Type",
411 "kCFNumberFloat64Type",
412 "kCFNumberCharType",
413 "kCFNumberShortType",
414 "kCFNumberIntType",
415 "kCFNumberLongType",
416 "kCFNumberLongLongType",
417 "kCFNumberFloatType",
418 "kCFNumberDoubleType",
419 "kCFNumberCFIndexType",
420 "kCFNumberNSIntegerType",
421 "kCFNumberCGFloatType"
422 };
423
424 return i <= kCFNumberCGFloatType ? Names[i-1] : "Invalid CFNumberType";
425 }
426 #endif
427
checkPreStmt(const CallExpr * CE,CheckerContext & C) const428 void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE,
429 CheckerContext &C) const {
430 ProgramStateRef state = C.getState();
431 const FunctionDecl *FD = C.getCalleeDecl(CE);
432 if (!FD)
433 return;
434
435 ASTContext &Ctx = C.getASTContext();
436 if (!II)
437 II = &Ctx.Idents.get("CFNumberCreate");
438
439 if (FD->getIdentifier() != II || CE->getNumArgs() != 3)
440 return;
441
442 // Get the value of the "theType" argument.
443 const LocationContext *LCtx = C.getLocationContext();
444 SVal TheTypeVal = state->getSVal(CE->getArg(1), LCtx);
445
446 // FIXME: We really should allow ranges of valid theType values, and
447 // bifurcate the state appropriately.
448 Optional<nonloc::ConcreteInt> V = TheTypeVal.getAs<nonloc::ConcreteInt>();
449 if (!V)
450 return;
451
452 uint64_t NumberKind = V->getValue().getLimitedValue();
453 Optional<uint64_t> OptTargetSize = GetCFNumberSize(Ctx, NumberKind);
454
455 // FIXME: In some cases we can emit an error.
456 if (!OptTargetSize)
457 return;
458
459 uint64_t TargetSize = *OptTargetSize;
460
461 // Look at the value of the integer being passed by reference. Essentially
462 // we want to catch cases where the value passed in is not equal to the
463 // size of the type being created.
464 SVal TheValueExpr = state->getSVal(CE->getArg(2), LCtx);
465
466 // FIXME: Eventually we should handle arbitrary locations. We can do this
467 // by having an enhanced memory model that does low-level typing.
468 Optional<loc::MemRegionVal> LV = TheValueExpr.getAs<loc::MemRegionVal>();
469 if (!LV)
470 return;
471
472 const TypedValueRegion* R = dyn_cast<TypedValueRegion>(LV->stripCasts());
473 if (!R)
474 return;
475
476 QualType T = Ctx.getCanonicalType(R->getValueType());
477
478 // FIXME: If the pointee isn't an integer type, should we flag a warning?
479 // People can do weird stuff with pointers.
480
481 if (!T->isIntegralOrEnumerationType())
482 return;
483
484 uint64_t SourceSize = Ctx.getTypeSize(T);
485
486 // CHECK: is SourceSize == TargetSize
487 if (SourceSize == TargetSize)
488 return;
489
490 // Generate an error. Only generate a sink error node
491 // if 'SourceSize < TargetSize'; otherwise generate a non-fatal error node.
492 //
493 // FIXME: We can actually create an abstract "CFNumber" object that has
494 // the bits initialized to the provided values.
495 //
496 ExplodedNode *N = SourceSize < TargetSize ? C.generateErrorNode()
497 : C.generateNonFatalErrorNode();
498 if (N) {
499 SmallString<128> sbuf;
500 llvm::raw_svector_ostream os(sbuf);
501
502 os << (SourceSize == 8 ? "An " : "A ")
503 << SourceSize << " bit integer is used to initialize a CFNumber "
504 "object that represents "
505 << (TargetSize == 8 ? "an " : "a ")
506 << TargetSize << " bit integer. ";
507
508 if (SourceSize < TargetSize)
509 os << (TargetSize - SourceSize)
510 << " bits of the CFNumber value will be garbage." ;
511 else
512 os << (SourceSize - TargetSize)
513 << " bits of the input integer will be lost.";
514
515 if (!BT)
516 BT.reset(new APIMisuse(this, "Bad use of CFNumberCreate"));
517
518 auto report = llvm::make_unique<BugReport>(*BT, os.str(), N);
519 report->addRange(CE->getArg(2)->getSourceRange());
520 C.emitReport(std::move(report));
521 }
522 }
523
524 //===----------------------------------------------------------------------===//
525 // CFRetain/CFRelease/CFMakeCollectable/CFAutorelease checking for null arguments.
526 //===----------------------------------------------------------------------===//
527
528 namespace {
529 class CFRetainReleaseChecker : public Checker< check::PreStmt<CallExpr> > {
530 mutable std::unique_ptr<APIMisuse> BT;
531 mutable IdentifierInfo *Retain, *Release, *MakeCollectable, *Autorelease;
532
533 public:
CFRetainReleaseChecker()534 CFRetainReleaseChecker()
535 : Retain(nullptr), Release(nullptr), MakeCollectable(nullptr),
536 Autorelease(nullptr) {}
537 void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
538 };
539 } // end anonymous namespace
540
checkPreStmt(const CallExpr * CE,CheckerContext & C) const541 void CFRetainReleaseChecker::checkPreStmt(const CallExpr *CE,
542 CheckerContext &C) const {
543 // If the CallExpr doesn't have exactly 1 argument just give up checking.
544 if (CE->getNumArgs() != 1)
545 return;
546
547 ProgramStateRef state = C.getState();
548 const FunctionDecl *FD = C.getCalleeDecl(CE);
549 if (!FD)
550 return;
551
552 if (!BT) {
553 ASTContext &Ctx = C.getASTContext();
554 Retain = &Ctx.Idents.get("CFRetain");
555 Release = &Ctx.Idents.get("CFRelease");
556 MakeCollectable = &Ctx.Idents.get("CFMakeCollectable");
557 Autorelease = &Ctx.Idents.get("CFAutorelease");
558 BT.reset(new APIMisuse(
559 this, "null passed to CF memory management function"));
560 }
561
562 // Check if we called CFRetain/CFRelease/CFMakeCollectable/CFAutorelease.
563 const IdentifierInfo *FuncII = FD->getIdentifier();
564 if (!(FuncII == Retain || FuncII == Release || FuncII == MakeCollectable ||
565 FuncII == Autorelease))
566 return;
567
568 // FIXME: The rest of this just checks that the argument is non-null.
569 // It should probably be refactored and combined with NonNullParamChecker.
570
571 // Get the argument's value.
572 const Expr *Arg = CE->getArg(0);
573 SVal ArgVal = state->getSVal(Arg, C.getLocationContext());
574 Optional<DefinedSVal> DefArgVal = ArgVal.getAs<DefinedSVal>();
575 if (!DefArgVal)
576 return;
577
578 // Get a NULL value.
579 SValBuilder &svalBuilder = C.getSValBuilder();
580 DefinedSVal zero =
581 svalBuilder.makeZeroVal(Arg->getType()).castAs<DefinedSVal>();
582
583 // Make an expression asserting that they're equal.
584 DefinedOrUnknownSVal ArgIsNull = svalBuilder.evalEQ(state, zero, *DefArgVal);
585
586 // Are they equal?
587 ProgramStateRef stateTrue, stateFalse;
588 std::tie(stateTrue, stateFalse) = state->assume(ArgIsNull);
589
590 if (stateTrue && !stateFalse) {
591 ExplodedNode *N = C.generateErrorNode(stateTrue);
592 if (!N)
593 return;
594
595 const char *description;
596 if (FuncII == Retain)
597 description = "Null pointer argument in call to CFRetain";
598 else if (FuncII == Release)
599 description = "Null pointer argument in call to CFRelease";
600 else if (FuncII == MakeCollectable)
601 description = "Null pointer argument in call to CFMakeCollectable";
602 else if (FuncII == Autorelease)
603 description = "Null pointer argument in call to CFAutorelease";
604 else
605 llvm_unreachable("impossible case");
606
607 auto report = llvm::make_unique<BugReport>(*BT, description, N);
608 report->addRange(Arg->getSourceRange());
609 bugreporter::trackNullOrUndefValue(N, Arg, *report);
610 C.emitReport(std::move(report));
611 return;
612 }
613
614 // From here on, we know the argument is non-null.
615 C.addTransition(stateFalse);
616 }
617
618 //===----------------------------------------------------------------------===//
619 // Check for sending 'retain', 'release', or 'autorelease' directly to a Class.
620 //===----------------------------------------------------------------------===//
621
622 namespace {
623 class ClassReleaseChecker : public Checker<check::PreObjCMessage> {
624 mutable Selector releaseS;
625 mutable Selector retainS;
626 mutable Selector autoreleaseS;
627 mutable Selector drainS;
628 mutable std::unique_ptr<BugType> BT;
629
630 public:
631 void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
632 };
633 } // end anonymous namespace
634
checkPreObjCMessage(const ObjCMethodCall & msg,CheckerContext & C) const635 void ClassReleaseChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
636 CheckerContext &C) const {
637 if (!BT) {
638 BT.reset(new APIMisuse(
639 this, "message incorrectly sent to class instead of class instance"));
640
641 ASTContext &Ctx = C.getASTContext();
642 releaseS = GetNullarySelector("release", Ctx);
643 retainS = GetNullarySelector("retain", Ctx);
644 autoreleaseS = GetNullarySelector("autorelease", Ctx);
645 drainS = GetNullarySelector("drain", Ctx);
646 }
647
648 if (msg.isInstanceMessage())
649 return;
650 const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
651 assert(Class);
652
653 Selector S = msg.getSelector();
654 if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS))
655 return;
656
657 if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
658 SmallString<200> buf;
659 llvm::raw_svector_ostream os(buf);
660
661 os << "The '";
662 S.print(os);
663 os << "' message should be sent to instances "
664 "of class '" << Class->getName()
665 << "' and not the class directly";
666
667 auto report = llvm::make_unique<BugReport>(*BT, os.str(), N);
668 report->addRange(msg.getSourceRange());
669 C.emitReport(std::move(report));
670 }
671 }
672
673 //===----------------------------------------------------------------------===//
674 // Check for passing non-Objective-C types to variadic methods that expect
675 // only Objective-C types.
676 //===----------------------------------------------------------------------===//
677
678 namespace {
679 class VariadicMethodTypeChecker : public Checker<check::PreObjCMessage> {
680 mutable Selector arrayWithObjectsS;
681 mutable Selector dictionaryWithObjectsAndKeysS;
682 mutable Selector setWithObjectsS;
683 mutable Selector orderedSetWithObjectsS;
684 mutable Selector initWithObjectsS;
685 mutable Selector initWithObjectsAndKeysS;
686 mutable std::unique_ptr<BugType> BT;
687
688 bool isVariadicMessage(const ObjCMethodCall &msg) const;
689
690 public:
691 void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
692 };
693 } // end anonymous namespace
694
695 /// isVariadicMessage - Returns whether the given message is a variadic message,
696 /// where all arguments must be Objective-C types.
697 bool
isVariadicMessage(const ObjCMethodCall & msg) const698 VariadicMethodTypeChecker::isVariadicMessage(const ObjCMethodCall &msg) const {
699 const ObjCMethodDecl *MD = msg.getDecl();
700
701 if (!MD || !MD->isVariadic() || isa<ObjCProtocolDecl>(MD->getDeclContext()))
702 return false;
703
704 Selector S = msg.getSelector();
705
706 if (msg.isInstanceMessage()) {
707 // FIXME: Ideally we'd look at the receiver interface here, but that's not
708 // useful for init, because alloc returns 'id'. In theory, this could lead
709 // to false positives, for example if there existed a class that had an
710 // initWithObjects: implementation that does accept non-Objective-C pointer
711 // types, but the chance of that happening is pretty small compared to the
712 // gains that this analysis gives.
713 const ObjCInterfaceDecl *Class = MD->getClassInterface();
714
715 switch (findKnownClass(Class)) {
716 case FC_NSArray:
717 case FC_NSOrderedSet:
718 case FC_NSSet:
719 return S == initWithObjectsS;
720 case FC_NSDictionary:
721 return S == initWithObjectsAndKeysS;
722 default:
723 return false;
724 }
725 } else {
726 const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
727
728 switch (findKnownClass(Class)) {
729 case FC_NSArray:
730 return S == arrayWithObjectsS;
731 case FC_NSOrderedSet:
732 return S == orderedSetWithObjectsS;
733 case FC_NSSet:
734 return S == setWithObjectsS;
735 case FC_NSDictionary:
736 return S == dictionaryWithObjectsAndKeysS;
737 default:
738 return false;
739 }
740 }
741 }
742
checkPreObjCMessage(const ObjCMethodCall & msg,CheckerContext & C) const743 void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
744 CheckerContext &C) const {
745 if (!BT) {
746 BT.reset(new APIMisuse(this,
747 "Arguments passed to variadic method aren't all "
748 "Objective-C pointer types"));
749
750 ASTContext &Ctx = C.getASTContext();
751 arrayWithObjectsS = GetUnarySelector("arrayWithObjects", Ctx);
752 dictionaryWithObjectsAndKeysS =
753 GetUnarySelector("dictionaryWithObjectsAndKeys", Ctx);
754 setWithObjectsS = GetUnarySelector("setWithObjects", Ctx);
755 orderedSetWithObjectsS = GetUnarySelector("orderedSetWithObjects", Ctx);
756
757 initWithObjectsS = GetUnarySelector("initWithObjects", Ctx);
758 initWithObjectsAndKeysS = GetUnarySelector("initWithObjectsAndKeys", Ctx);
759 }
760
761 if (!isVariadicMessage(msg))
762 return;
763
764 // We are not interested in the selector arguments since they have
765 // well-defined types, so the compiler will issue a warning for them.
766 unsigned variadicArgsBegin = msg.getSelector().getNumArgs();
767
768 // We're not interested in the last argument since it has to be nil or the
769 // compiler would have issued a warning for it elsewhere.
770 unsigned variadicArgsEnd = msg.getNumArgs() - 1;
771
772 if (variadicArgsEnd <= variadicArgsBegin)
773 return;
774
775 // Verify that all arguments have Objective-C types.
776 Optional<ExplodedNode*> errorNode;
777
778 for (unsigned I = variadicArgsBegin; I != variadicArgsEnd; ++I) {
779 QualType ArgTy = msg.getArgExpr(I)->getType();
780 if (ArgTy->isObjCObjectPointerType())
781 continue;
782
783 // Block pointers are treaded as Objective-C pointers.
784 if (ArgTy->isBlockPointerType())
785 continue;
786
787 // Ignore pointer constants.
788 if (msg.getArgSVal(I).getAs<loc::ConcreteInt>())
789 continue;
790
791 // Ignore pointer types annotated with 'NSObject' attribute.
792 if (C.getASTContext().isObjCNSObjectType(ArgTy))
793 continue;
794
795 // Ignore CF references, which can be toll-free bridged.
796 if (coreFoundation::isCFObjectRef(ArgTy))
797 continue;
798
799 // Generate only one error node to use for all bug reports.
800 if (!errorNode.hasValue())
801 errorNode = C.generateNonFatalErrorNode();
802
803 if (!errorNode.getValue())
804 continue;
805
806 SmallString<128> sbuf;
807 llvm::raw_svector_ostream os(sbuf);
808
809 StringRef TypeName = GetReceiverInterfaceName(msg);
810 if (!TypeName.empty())
811 os << "Argument to '" << TypeName << "' method '";
812 else
813 os << "Argument to method '";
814
815 msg.getSelector().print(os);
816 os << "' should be an Objective-C pointer type, not '";
817 ArgTy.print(os, C.getLangOpts());
818 os << "'";
819
820 auto R = llvm::make_unique<BugReport>(*BT, os.str(), errorNode.getValue());
821 R->addRange(msg.getArgSourceRange(I));
822 C.emitReport(std::move(R));
823 }
824 }
825
826 //===----------------------------------------------------------------------===//
827 // Improves the modeling of loops over Cocoa collections.
828 //===----------------------------------------------------------------------===//
829
830 // The map from container symbol to the container count symbol.
831 // We currently will remember the last countainer count symbol encountered.
832 REGISTER_MAP_WITH_PROGRAMSTATE(ContainerCountMap, SymbolRef, SymbolRef)
833 REGISTER_MAP_WITH_PROGRAMSTATE(ContainerNonEmptyMap, SymbolRef, bool)
834
835 namespace {
836 class ObjCLoopChecker
837 : public Checker<check::PostStmt<ObjCForCollectionStmt>,
838 check::PostObjCMessage,
839 check::DeadSymbols,
840 check::PointerEscape > {
841 mutable IdentifierInfo *CountSelectorII;
842
843 bool isCollectionCountMethod(const ObjCMethodCall &M,
844 CheckerContext &C) const;
845
846 public:
ObjCLoopChecker()847 ObjCLoopChecker() : CountSelectorII(nullptr) {}
848 void checkPostStmt(const ObjCForCollectionStmt *FCS, CheckerContext &C) const;
849 void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
850 void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
851 ProgramStateRef checkPointerEscape(ProgramStateRef State,
852 const InvalidatedSymbols &Escaped,
853 const CallEvent *Call,
854 PointerEscapeKind Kind) const;
855 };
856 } // end anonymous namespace
857
isKnownNonNilCollectionType(QualType T)858 static bool isKnownNonNilCollectionType(QualType T) {
859 const ObjCObjectPointerType *PT = T->getAs<ObjCObjectPointerType>();
860 if (!PT)
861 return false;
862
863 const ObjCInterfaceDecl *ID = PT->getInterfaceDecl();
864 if (!ID)
865 return false;
866
867 switch (findKnownClass(ID)) {
868 case FC_NSArray:
869 case FC_NSDictionary:
870 case FC_NSEnumerator:
871 case FC_NSOrderedSet:
872 case FC_NSSet:
873 return true;
874 default:
875 return false;
876 }
877 }
878
879 /// Assumes that the collection is non-nil.
880 ///
881 /// If the collection is known to be nil, returns NULL to indicate an infeasible
882 /// path.
checkCollectionNonNil(CheckerContext & C,ProgramStateRef State,const ObjCForCollectionStmt * FCS)883 static ProgramStateRef checkCollectionNonNil(CheckerContext &C,
884 ProgramStateRef State,
885 const ObjCForCollectionStmt *FCS) {
886 if (!State)
887 return nullptr;
888
889 SVal CollectionVal = C.getSVal(FCS->getCollection());
890 Optional<DefinedSVal> KnownCollection = CollectionVal.getAs<DefinedSVal>();
891 if (!KnownCollection)
892 return State;
893
894 ProgramStateRef StNonNil, StNil;
895 std::tie(StNonNil, StNil) = State->assume(*KnownCollection);
896 if (StNil && !StNonNil) {
897 // The collection is nil. This path is infeasible.
898 return nullptr;
899 }
900
901 return StNonNil;
902 }
903
904 /// Assumes that the collection elements are non-nil.
905 ///
906 /// This only applies if the collection is one of those known not to contain
907 /// nil values.
checkElementNonNil(CheckerContext & C,ProgramStateRef State,const ObjCForCollectionStmt * FCS)908 static ProgramStateRef checkElementNonNil(CheckerContext &C,
909 ProgramStateRef State,
910 const ObjCForCollectionStmt *FCS) {
911 if (!State)
912 return nullptr;
913
914 // See if the collection is one where we /know/ the elements are non-nil.
915 if (!isKnownNonNilCollectionType(FCS->getCollection()->getType()))
916 return State;
917
918 const LocationContext *LCtx = C.getLocationContext();
919 const Stmt *Element = FCS->getElement();
920
921 // FIXME: Copied from ExprEngineObjC.
922 Optional<Loc> ElementLoc;
923 if (const DeclStmt *DS = dyn_cast<DeclStmt>(Element)) {
924 const VarDecl *ElemDecl = cast<VarDecl>(DS->getSingleDecl());
925 assert(ElemDecl->getInit() == nullptr);
926 ElementLoc = State->getLValue(ElemDecl, LCtx);
927 } else {
928 ElementLoc = State->getSVal(Element, LCtx).getAs<Loc>();
929 }
930
931 if (!ElementLoc)
932 return State;
933
934 // Go ahead and assume the value is non-nil.
935 SVal Val = State->getSVal(*ElementLoc);
936 return State->assume(Val.castAs<DefinedOrUnknownSVal>(), true);
937 }
938
939 /// Returns NULL state if the collection is known to contain elements
940 /// (or is known not to contain elements if the Assumption parameter is false.)
941 static ProgramStateRef
assumeCollectionNonEmpty(CheckerContext & C,ProgramStateRef State,SymbolRef CollectionS,bool Assumption)942 assumeCollectionNonEmpty(CheckerContext &C, ProgramStateRef State,
943 SymbolRef CollectionS, bool Assumption) {
944 if (!State || !CollectionS)
945 return State;
946
947 const SymbolRef *CountS = State->get<ContainerCountMap>(CollectionS);
948 if (!CountS) {
949 const bool *KnownNonEmpty = State->get<ContainerNonEmptyMap>(CollectionS);
950 if (!KnownNonEmpty)
951 return State->set<ContainerNonEmptyMap>(CollectionS, Assumption);
952 return (Assumption == *KnownNonEmpty) ? State : nullptr;
953 }
954
955 SValBuilder &SvalBuilder = C.getSValBuilder();
956 SVal CountGreaterThanZeroVal =
957 SvalBuilder.evalBinOp(State, BO_GT,
958 nonloc::SymbolVal(*CountS),
959 SvalBuilder.makeIntVal(0, (*CountS)->getType()),
960 SvalBuilder.getConditionType());
961 Optional<DefinedSVal> CountGreaterThanZero =
962 CountGreaterThanZeroVal.getAs<DefinedSVal>();
963 if (!CountGreaterThanZero) {
964 // The SValBuilder cannot construct a valid SVal for this condition.
965 // This means we cannot properly reason about it.
966 return State;
967 }
968
969 return State->assume(*CountGreaterThanZero, Assumption);
970 }
971
972 static ProgramStateRef
assumeCollectionNonEmpty(CheckerContext & C,ProgramStateRef State,const ObjCForCollectionStmt * FCS,bool Assumption)973 assumeCollectionNonEmpty(CheckerContext &C, ProgramStateRef State,
974 const ObjCForCollectionStmt *FCS,
975 bool Assumption) {
976 if (!State)
977 return nullptr;
978
979 SymbolRef CollectionS =
980 State->getSVal(FCS->getCollection(), C.getLocationContext()).getAsSymbol();
981 return assumeCollectionNonEmpty(C, State, CollectionS, Assumption);
982 }
983
984 /// If the fist block edge is a back edge, we are reentering the loop.
alreadyExecutedAtLeastOneLoopIteration(const ExplodedNode * N,const ObjCForCollectionStmt * FCS)985 static bool alreadyExecutedAtLeastOneLoopIteration(const ExplodedNode *N,
986 const ObjCForCollectionStmt *FCS) {
987 if (!N)
988 return false;
989
990 ProgramPoint P = N->getLocation();
991 if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) {
992 return BE->getSrc()->getLoopTarget() == FCS;
993 }
994
995 // Keep looking for a block edge.
996 for (ExplodedNode::const_pred_iterator I = N->pred_begin(),
997 E = N->pred_end(); I != E; ++I) {
998 if (alreadyExecutedAtLeastOneLoopIteration(*I, FCS))
999 return true;
1000 }
1001
1002 return false;
1003 }
1004
checkPostStmt(const ObjCForCollectionStmt * FCS,CheckerContext & C) const1005 void ObjCLoopChecker::checkPostStmt(const ObjCForCollectionStmt *FCS,
1006 CheckerContext &C) const {
1007 ProgramStateRef State = C.getState();
1008
1009 // Check if this is the branch for the end of the loop.
1010 SVal CollectionSentinel = C.getSVal(FCS);
1011 if (CollectionSentinel.isZeroConstant()) {
1012 if (!alreadyExecutedAtLeastOneLoopIteration(C.getPredecessor(), FCS))
1013 State = assumeCollectionNonEmpty(C, State, FCS, /*Assumption*/false);
1014
1015 // Otherwise, this is a branch that goes through the loop body.
1016 } else {
1017 State = checkCollectionNonNil(C, State, FCS);
1018 State = checkElementNonNil(C, State, FCS);
1019 State = assumeCollectionNonEmpty(C, State, FCS, /*Assumption*/true);
1020 }
1021
1022 if (!State)
1023 C.generateSink(C.getState(), C.getPredecessor());
1024 else if (State != C.getState())
1025 C.addTransition(State);
1026 }
1027
isCollectionCountMethod(const ObjCMethodCall & M,CheckerContext & C) const1028 bool ObjCLoopChecker::isCollectionCountMethod(const ObjCMethodCall &M,
1029 CheckerContext &C) const {
1030 Selector S = M.getSelector();
1031 // Initialize the identifiers on first use.
1032 if (!CountSelectorII)
1033 CountSelectorII = &C.getASTContext().Idents.get("count");
1034
1035 // If the method returns collection count, record the value.
1036 return S.isUnarySelector() &&
1037 (S.getIdentifierInfoForSlot(0) == CountSelectorII);
1038 }
1039
checkPostObjCMessage(const ObjCMethodCall & M,CheckerContext & C) const1040 void ObjCLoopChecker::checkPostObjCMessage(const ObjCMethodCall &M,
1041 CheckerContext &C) const {
1042 if (!M.isInstanceMessage())
1043 return;
1044
1045 const ObjCInterfaceDecl *ClassID = M.getReceiverInterface();
1046 if (!ClassID)
1047 return;
1048
1049 FoundationClass Class = findKnownClass(ClassID);
1050 if (Class != FC_NSDictionary &&
1051 Class != FC_NSArray &&
1052 Class != FC_NSSet &&
1053 Class != FC_NSOrderedSet)
1054 return;
1055
1056 SymbolRef ContainerS = M.getReceiverSVal().getAsSymbol();
1057 if (!ContainerS)
1058 return;
1059
1060 // If we are processing a call to "count", get the symbolic value returned by
1061 // a call to "count" and add it to the map.
1062 if (!isCollectionCountMethod(M, C))
1063 return;
1064
1065 const Expr *MsgExpr = M.getOriginExpr();
1066 SymbolRef CountS = C.getSVal(MsgExpr).getAsSymbol();
1067 if (CountS) {
1068 ProgramStateRef State = C.getState();
1069
1070 C.getSymbolManager().addSymbolDependency(ContainerS, CountS);
1071 State = State->set<ContainerCountMap>(ContainerS, CountS);
1072
1073 if (const bool *NonEmpty = State->get<ContainerNonEmptyMap>(ContainerS)) {
1074 State = State->remove<ContainerNonEmptyMap>(ContainerS);
1075 State = assumeCollectionNonEmpty(C, State, ContainerS, *NonEmpty);
1076 }
1077
1078 C.addTransition(State);
1079 }
1080 }
1081
getMethodReceiverIfKnownImmutable(const CallEvent * Call)1082 static SymbolRef getMethodReceiverIfKnownImmutable(const CallEvent *Call) {
1083 const ObjCMethodCall *Message = dyn_cast_or_null<ObjCMethodCall>(Call);
1084 if (!Message)
1085 return nullptr;
1086
1087 const ObjCMethodDecl *MD = Message->getDecl();
1088 if (!MD)
1089 return nullptr;
1090
1091 const ObjCInterfaceDecl *StaticClass;
1092 if (isa<ObjCProtocolDecl>(MD->getDeclContext())) {
1093 // We can't find out where the method was declared without doing more work.
1094 // Instead, see if the receiver is statically typed as a known immutable
1095 // collection.
1096 StaticClass = Message->getOriginExpr()->getReceiverInterface();
1097 } else {
1098 StaticClass = MD->getClassInterface();
1099 }
1100
1101 if (!StaticClass)
1102 return nullptr;
1103
1104 switch (findKnownClass(StaticClass, /*IncludeSuper=*/false)) {
1105 case FC_None:
1106 return nullptr;
1107 case FC_NSArray:
1108 case FC_NSDictionary:
1109 case FC_NSEnumerator:
1110 case FC_NSNull:
1111 case FC_NSOrderedSet:
1112 case FC_NSSet:
1113 case FC_NSString:
1114 break;
1115 }
1116
1117 return Message->getReceiverSVal().getAsSymbol();
1118 }
1119
1120 ProgramStateRef
checkPointerEscape(ProgramStateRef State,const InvalidatedSymbols & Escaped,const CallEvent * Call,PointerEscapeKind Kind) const1121 ObjCLoopChecker::checkPointerEscape(ProgramStateRef State,
1122 const InvalidatedSymbols &Escaped,
1123 const CallEvent *Call,
1124 PointerEscapeKind Kind) const {
1125 SymbolRef ImmutableReceiver = getMethodReceiverIfKnownImmutable(Call);
1126
1127 // Remove the invalidated symbols form the collection count map.
1128 for (InvalidatedSymbols::const_iterator I = Escaped.begin(),
1129 E = Escaped.end();
1130 I != E; ++I) {
1131 SymbolRef Sym = *I;
1132
1133 // Don't invalidate this symbol's count if we know the method being called
1134 // is declared on an immutable class. This isn't completely correct if the
1135 // receiver is also passed as an argument, but in most uses of NSArray,
1136 // NSDictionary, etc. this isn't likely to happen in a dangerous way.
1137 if (Sym == ImmutableReceiver)
1138 continue;
1139
1140 // The symbol escaped. Pessimistically, assume that the count could have
1141 // changed.
1142 State = State->remove<ContainerCountMap>(Sym);
1143 State = State->remove<ContainerNonEmptyMap>(Sym);
1144 }
1145 return State;
1146 }
1147
checkDeadSymbols(SymbolReaper & SymReaper,CheckerContext & C) const1148 void ObjCLoopChecker::checkDeadSymbols(SymbolReaper &SymReaper,
1149 CheckerContext &C) const {
1150 ProgramStateRef State = C.getState();
1151
1152 // Remove the dead symbols from the collection count map.
1153 ContainerCountMapTy Tracked = State->get<ContainerCountMap>();
1154 for (ContainerCountMapTy::iterator I = Tracked.begin(),
1155 E = Tracked.end(); I != E; ++I) {
1156 SymbolRef Sym = I->first;
1157 if (SymReaper.isDead(Sym)) {
1158 State = State->remove<ContainerCountMap>(Sym);
1159 State = State->remove<ContainerNonEmptyMap>(Sym);
1160 }
1161 }
1162
1163 C.addTransition(State);
1164 }
1165
1166 namespace {
1167 /// \class ObjCNonNilReturnValueChecker
1168 /// \brief The checker restricts the return values of APIs known to
1169 /// never (or almost never) return 'nil'.
1170 class ObjCNonNilReturnValueChecker
1171 : public Checker<check::PostObjCMessage,
1172 check::PostStmt<ObjCArrayLiteral>,
1173 check::PostStmt<ObjCDictionaryLiteral>,
1174 check::PostStmt<ObjCBoxedExpr> > {
1175 mutable bool Initialized;
1176 mutable Selector ObjectAtIndex;
1177 mutable Selector ObjectAtIndexedSubscript;
1178 mutable Selector NullSelector;
1179
1180 public:
ObjCNonNilReturnValueChecker()1181 ObjCNonNilReturnValueChecker() : Initialized(false) {}
1182
1183 ProgramStateRef assumeExprIsNonNull(const Expr *NonNullExpr,
1184 ProgramStateRef State,
1185 CheckerContext &C) const;
assumeExprIsNonNull(const Expr * E,CheckerContext & C) const1186 void assumeExprIsNonNull(const Expr *E, CheckerContext &C) const {
1187 C.addTransition(assumeExprIsNonNull(E, C.getState(), C));
1188 }
1189
checkPostStmt(const ObjCArrayLiteral * E,CheckerContext & C) const1190 void checkPostStmt(const ObjCArrayLiteral *E, CheckerContext &C) const {
1191 assumeExprIsNonNull(E, C);
1192 }
checkPostStmt(const ObjCDictionaryLiteral * E,CheckerContext & C) const1193 void checkPostStmt(const ObjCDictionaryLiteral *E, CheckerContext &C) const {
1194 assumeExprIsNonNull(E, C);
1195 }
checkPostStmt(const ObjCBoxedExpr * E,CheckerContext & C) const1196 void checkPostStmt(const ObjCBoxedExpr *E, CheckerContext &C) const {
1197 assumeExprIsNonNull(E, C);
1198 }
1199
1200 void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
1201 };
1202 } // end anonymous namespace
1203
1204 ProgramStateRef
assumeExprIsNonNull(const Expr * NonNullExpr,ProgramStateRef State,CheckerContext & C) const1205 ObjCNonNilReturnValueChecker::assumeExprIsNonNull(const Expr *NonNullExpr,
1206 ProgramStateRef State,
1207 CheckerContext &C) const {
1208 SVal Val = State->getSVal(NonNullExpr, C.getLocationContext());
1209 if (Optional<DefinedOrUnknownSVal> DV = Val.getAs<DefinedOrUnknownSVal>())
1210 return State->assume(*DV, true);
1211 return State;
1212 }
1213
checkPostObjCMessage(const ObjCMethodCall & M,CheckerContext & C) const1214 void ObjCNonNilReturnValueChecker::checkPostObjCMessage(const ObjCMethodCall &M,
1215 CheckerContext &C)
1216 const {
1217 ProgramStateRef State = C.getState();
1218
1219 if (!Initialized) {
1220 ASTContext &Ctx = C.getASTContext();
1221 ObjectAtIndex = GetUnarySelector("objectAtIndex", Ctx);
1222 ObjectAtIndexedSubscript = GetUnarySelector("objectAtIndexedSubscript", Ctx);
1223 NullSelector = GetNullarySelector("null", Ctx);
1224 }
1225
1226 // Check the receiver type.
1227 if (const ObjCInterfaceDecl *Interface = M.getReceiverInterface()) {
1228
1229 // Assume that object returned from '[self init]' or '[super init]' is not
1230 // 'nil' if we are processing an inlined function/method.
1231 //
1232 // A defensive callee will (and should) check if the object returned by
1233 // '[super init]' is 'nil' before doing it's own initialization. However,
1234 // since 'nil' is rarely returned in practice, we should not warn when the
1235 // caller to the defensive constructor uses the object in contexts where
1236 // 'nil' is not accepted.
1237 if (!C.inTopFrame() && M.getDecl() &&
1238 M.getDecl()->getMethodFamily() == OMF_init &&
1239 M.isReceiverSelfOrSuper()) {
1240 State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
1241 }
1242
1243 FoundationClass Cl = findKnownClass(Interface);
1244
1245 // Objects returned from
1246 // [NSArray|NSOrderedSet]::[ObjectAtIndex|ObjectAtIndexedSubscript]
1247 // are never 'nil'.
1248 if (Cl == FC_NSArray || Cl == FC_NSOrderedSet) {
1249 Selector Sel = M.getSelector();
1250 if (Sel == ObjectAtIndex || Sel == ObjectAtIndexedSubscript) {
1251 // Go ahead and assume the value is non-nil.
1252 State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
1253 }
1254 }
1255
1256 // Objects returned from [NSNull null] are not nil.
1257 if (Cl == FC_NSNull) {
1258 if (M.getSelector() == NullSelector) {
1259 // Go ahead and assume the value is non-nil.
1260 State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
1261 }
1262 }
1263 }
1264 C.addTransition(State);
1265 }
1266
1267 //===----------------------------------------------------------------------===//
1268 // Check registration.
1269 //===----------------------------------------------------------------------===//
1270
registerNilArgChecker(CheckerManager & mgr)1271 void ento::registerNilArgChecker(CheckerManager &mgr) {
1272 mgr.registerChecker<NilArgChecker>();
1273 }
1274
registerCFNumberCreateChecker(CheckerManager & mgr)1275 void ento::registerCFNumberCreateChecker(CheckerManager &mgr) {
1276 mgr.registerChecker<CFNumberCreateChecker>();
1277 }
1278
registerCFRetainReleaseChecker(CheckerManager & mgr)1279 void ento::registerCFRetainReleaseChecker(CheckerManager &mgr) {
1280 mgr.registerChecker<CFRetainReleaseChecker>();
1281 }
1282
registerClassReleaseChecker(CheckerManager & mgr)1283 void ento::registerClassReleaseChecker(CheckerManager &mgr) {
1284 mgr.registerChecker<ClassReleaseChecker>();
1285 }
1286
registerVariadicMethodTypeChecker(CheckerManager & mgr)1287 void ento::registerVariadicMethodTypeChecker(CheckerManager &mgr) {
1288 mgr.registerChecker<VariadicMethodTypeChecker>();
1289 }
1290
registerObjCLoopChecker(CheckerManager & mgr)1291 void ento::registerObjCLoopChecker(CheckerManager &mgr) {
1292 mgr.registerChecker<ObjCLoopChecker>();
1293 }
1294
1295 void
registerObjCNonNilReturnValueChecker(CheckerManager & mgr)1296 ento::registerObjCNonNilReturnValueChecker(CheckerManager &mgr) {
1297 mgr.registerChecker<ObjCNonNilReturnValueChecker>();
1298 }
1299