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