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