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