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