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