BasicObjCFoundationChecks.cpp revision 50e837b3cbc9315b6808daabb96c5c7cccf11ea7
1dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block//== BasicObjCFoundationChecks.cpp - Simple Apple-Foundation checks -*- C++ -*--
2dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block//
3dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block//                     The LLVM Compiler Infrastructure
4dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block//
5dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block// This file is distributed under the University of Illinois Open Source
6dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block// License. See LICENSE.TXT for details.
7dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block//
8dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block//===----------------------------------------------------------------------===//
9dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block//
10dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block//  This file defines BasicObjCFoundationChecks, a class that encapsulates
11dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block//  a set of simple checks to run on Objective-C code using Apple's Foundation
12dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block//  classes.
13dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block//
14dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block//===----------------------------------------------------------------------===//
15dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
16dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#include "BasicObjCFoundationChecks.h"
17dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
18dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#include "clang/Analysis/PathSensitive/ExplodedGraph.h"
19dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#include "clang/Analysis/PathSensitive/GRSimpleAPICheck.h"
20dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#include "clang/Analysis/PathSensitive/GRExprEngine.h"
21dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#include "clang/Analysis/PathSensitive/GRState.h"
22dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#include "clang/Analysis/PathSensitive/BugReporter.h"
23dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#include "clang/Analysis/PathSensitive/MemRegion.h"
24dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#include "clang/Analysis/PathDiagnostic.h"
25dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
26dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#include "clang/Analysis/LocalCheckers.h"
27dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#include "clang/AST/DeclObjC.h"
28dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#include "clang/AST/Expr.h"
29f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick#include "clang/AST/ExprObjC.h"
30dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#include "clang/AST/ASTContext.h"
31dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#include "llvm/Support/Compiler.h"
32dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
33dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockusing namespace clang;
34dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
35dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockstatic const ObjCInterfaceType* GetReceiverType(const ObjCMessageExpr* ME) {
36f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick  const Expr* Receiver = ME->getReceiver();
37dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
38dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block  if (!Receiver)
39dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    return NULL;
40dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
41dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block  if (const ObjCObjectPointerType *PT =
42dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block      Receiver->getType()->getAs<ObjCObjectPointerType>())
43dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    return PT->getInterfaceType();
44dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
45dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block  return NULL;
46dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block}
47dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
48dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockstatic const char* GetReceiverNameType(const ObjCMessageExpr* ME) {
49dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block  if (const ObjCInterfaceType *ReceiverType = GetReceiverType(ME))
50dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    return ReceiverType->getDecl()->getIdentifier()->getNameStart();
51dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block  return NULL;
52dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block}
53dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
54dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blocknamespace {
55dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
56dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockclass VISIBILITY_HIDDEN APIMisuse : public BugType {
57dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockpublic:
58dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block  APIMisuse(const char* name) : BugType(name, "API Misuse (Apple)") {}
59f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick};
60dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
61dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockclass VISIBILITY_HIDDEN BasicObjCFoundationChecks : public GRSimpleAPICheck {
626c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen  APIMisuse *BT;
636c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen  BugReporter& BR;
646c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen  ASTContext &Ctx;
656c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen
666c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen  bool isNSString(const ObjCInterfaceType *T, llvm::StringRef suffix);
676c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen  bool AuditNSString(ExplodedNode* N, const ObjCMessageExpr* ME);
686c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen
696c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen  void Warn(ExplodedNode* N, const Expr* E, const std::string& s);
706c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen  void WarnNilArg(ExplodedNode* N, const Expr* E);
716c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen
726c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen  bool CheckNilArg(ExplodedNode* N, unsigned Arg);
736c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen
746c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsenpublic:
756c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen  BasicObjCFoundationChecks(ASTContext& ctx, BugReporter& br)
766c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    : BT(0), BR(br), Ctx(ctx) {}
776c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen
786c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen  bool Audit(ExplodedNode* N, GRStateManager&);
79dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
806c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsenprivate:
816c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen  void WarnNilArg(ExplodedNode* N, const ObjCMessageExpr* ME, unsigned Arg) {
826c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    std::string sbuf;
836c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    llvm::raw_string_ostream os(sbuf);
846c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    os << "Argument to '" << GetReceiverNameType(ME) << "' method '"
85dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block       << ME->getSelector().getAsString() << "' cannot be nil.";
86dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
87dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // Lazily create the BugType object for NilArg.  This will be owned
88dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // by the BugReporter object 'BR' once we call BR.EmitWarning.
89dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    if (!BT) BT = new APIMisuse("nil argument");
90dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
916c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    RangedBugReport *R = new RangedBugReport(*BT, os.str().c_str(), N);
92dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    R->addRange(ME->getArg(Arg)->getSourceRange());
93dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    BR.EmitReport(R);
94dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block  }
95dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block};
96dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
97dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block} // end anonymous namespace
98
99
100GRSimpleAPICheck*
101clang::CreateBasicObjCFoundationChecks(ASTContext& Ctx, BugReporter& BR) {
102  return new BasicObjCFoundationChecks(Ctx, BR);
103}
104
105
106
107bool BasicObjCFoundationChecks::Audit(ExplodedNode* N,
108                                      GRStateManager&) {
109
110  const ObjCMessageExpr* ME =
111    cast<ObjCMessageExpr>(cast<PostStmt>(N->getLocation()).getStmt());
112
113  const ObjCInterfaceType *ReceiverType = GetReceiverType(ME);
114
115  if (!ReceiverType)
116    return false;
117
118  if (isNSString(ReceiverType,
119                 ReceiverType->getDecl()->getIdentifier()->getName()))
120    return AuditNSString(N, ME);
121
122  return false;
123}
124
125static inline bool isNil(SVal X) {
126  return isa<loc::ConcreteInt>(X);
127}
128
129//===----------------------------------------------------------------------===//
130// Error reporting.
131//===----------------------------------------------------------------------===//
132
133bool BasicObjCFoundationChecks::CheckNilArg(ExplodedNode* N, unsigned Arg) {
134  const ObjCMessageExpr* ME =
135    cast<ObjCMessageExpr>(cast<PostStmt>(N->getLocation()).getStmt());
136
137  const Expr * E = ME->getArg(Arg);
138
139  if (isNil(N->getState()->getSVal(E))) {
140    WarnNilArg(N, ME, Arg);
141    return true;
142  }
143
144  return false;
145}
146
147//===----------------------------------------------------------------------===//
148// NSString checking.
149//===----------------------------------------------------------------------===//
150
151bool BasicObjCFoundationChecks::isNSString(const ObjCInterfaceType *T,
152                                           llvm::StringRef ClassName) {
153  return ClassName == "NSString" || ClassName == "NSMutableString";
154}
155
156bool BasicObjCFoundationChecks::AuditNSString(ExplodedNode* N,
157                                              const ObjCMessageExpr* ME) {
158
159  Selector S = ME->getSelector();
160
161  if (S.isUnarySelector())
162    return false;
163
164  // FIXME: This is going to be really slow doing these checks with
165  //  lexical comparisons.
166
167  std::string name = S.getAsString();
168  assert (!name.empty());
169  const char* cstr = &name[0];
170  unsigned len = name.size();
171
172  switch (len) {
173    default:
174      break;
175    case 8:
176      if (!strcmp(cstr, "compare:"))
177        return CheckNilArg(N, 0);
178
179      break;
180
181    case 15:
182      // FIXME: Checking for initWithFormat: will not work in most cases
183      //  yet because [NSString alloc] returns id, not NSString*.  We will
184      //  need support for tracking expected-type information in the analyzer
185      //  to find these errors.
186      if (!strcmp(cstr, "initWithFormat:"))
187        return CheckNilArg(N, 0);
188
189      break;
190
191    case 16:
192      if (!strcmp(cstr, "compare:options:"))
193        return CheckNilArg(N, 0);
194
195      break;
196
197    case 22:
198      if (!strcmp(cstr, "compare:options:range:"))
199        return CheckNilArg(N, 0);
200
201      break;
202
203    case 23:
204
205      if (!strcmp(cstr, "caseInsensitiveCompare:"))
206        return CheckNilArg(N, 0);
207
208      break;
209
210    case 29:
211      if (!strcmp(cstr, "compare:options:range:locale:"))
212        return CheckNilArg(N, 0);
213
214      break;
215
216    case 37:
217    if (!strcmp(cstr, "componentsSeparatedByCharactersInSet:"))
218      return CheckNilArg(N, 0);
219
220    break;
221  }
222
223  return false;
224}
225
226//===----------------------------------------------------------------------===//
227// Error reporting.
228//===----------------------------------------------------------------------===//
229
230namespace {
231
232class VISIBILITY_HIDDEN AuditCFNumberCreate : public GRSimpleAPICheck {
233  APIMisuse* BT;
234
235  // FIXME: Either this should be refactored into GRSimpleAPICheck, or
236  //   it should always be passed with a call to Audit.  The latter
237  //   approach makes this class more stateless.
238  ASTContext& Ctx;
239  IdentifierInfo* II;
240  BugReporter& BR;
241
242public:
243  AuditCFNumberCreate(ASTContext& ctx, BugReporter& br)
244  : BT(0), Ctx(ctx), II(&Ctx.Idents.get("CFNumberCreate")), BR(br){}
245
246  ~AuditCFNumberCreate() {}
247
248  bool Audit(ExplodedNode* N, GRStateManager&);
249
250private:
251  void AddError(const TypedRegion* R, const Expr* Ex, ExplodedNode *N,
252                uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind);
253};
254} // end anonymous namespace
255
256enum CFNumberType {
257  kCFNumberSInt8Type = 1,
258  kCFNumberSInt16Type = 2,
259  kCFNumberSInt32Type = 3,
260  kCFNumberSInt64Type = 4,
261  kCFNumberFloat32Type = 5,
262  kCFNumberFloat64Type = 6,
263  kCFNumberCharType = 7,
264  kCFNumberShortType = 8,
265  kCFNumberIntType = 9,
266  kCFNumberLongType = 10,
267  kCFNumberLongLongType = 11,
268  kCFNumberFloatType = 12,
269  kCFNumberDoubleType = 13,
270  kCFNumberCFIndexType = 14,
271  kCFNumberNSIntegerType = 15,
272  kCFNumberCGFloatType = 16
273};
274
275namespace {
276  template<typename T>
277  class Optional {
278    bool IsKnown;
279    T Val;
280  public:
281    Optional() : IsKnown(false), Val(0) {}
282    Optional(const T& val) : IsKnown(true), Val(val) {}
283
284    bool isKnown() const { return IsKnown; }
285
286    const T& getValue() const {
287      assert (isKnown());
288      return Val;
289    }
290
291    operator const T&() const {
292      return getValue();
293    }
294  };
295}
296
297static Optional<uint64_t> GetCFNumberSize(ASTContext& Ctx, uint64_t i) {
298  static unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 };
299
300  if (i < kCFNumberCharType)
301    return FixedSize[i-1];
302
303  QualType T;
304
305  switch (i) {
306    case kCFNumberCharType:     T = Ctx.CharTy;     break;
307    case kCFNumberShortType:    T = Ctx.ShortTy;    break;
308    case kCFNumberIntType:      T = Ctx.IntTy;      break;
309    case kCFNumberLongType:     T = Ctx.LongTy;     break;
310    case kCFNumberLongLongType: T = Ctx.LongLongTy; break;
311    case kCFNumberFloatType:    T = Ctx.FloatTy;    break;
312    case kCFNumberDoubleType:   T = Ctx.DoubleTy;   break;
313    case kCFNumberCFIndexType:
314    case kCFNumberNSIntegerType:
315    case kCFNumberCGFloatType:
316      // FIXME: We need a way to map from names to Type*.
317    default:
318      return Optional<uint64_t>();
319  }
320
321  return Ctx.getTypeSize(T);
322}
323
324#if 0
325static const char* GetCFNumberTypeStr(uint64_t i) {
326  static const char* Names[] = {
327    "kCFNumberSInt8Type",
328    "kCFNumberSInt16Type",
329    "kCFNumberSInt32Type",
330    "kCFNumberSInt64Type",
331    "kCFNumberFloat32Type",
332    "kCFNumberFloat64Type",
333    "kCFNumberCharType",
334    "kCFNumberShortType",
335    "kCFNumberIntType",
336    "kCFNumberLongType",
337    "kCFNumberLongLongType",
338    "kCFNumberFloatType",
339    "kCFNumberDoubleType",
340    "kCFNumberCFIndexType",
341    "kCFNumberNSIntegerType",
342    "kCFNumberCGFloatType"
343  };
344
345  return i <= kCFNumberCGFloatType ? Names[i-1] : "Invalid CFNumberType";
346}
347#endif
348
349bool AuditCFNumberCreate::Audit(ExplodedNode* N,GRStateManager&){
350  const CallExpr* CE =
351    cast<CallExpr>(cast<PostStmt>(N->getLocation()).getStmt());
352  const Expr* Callee = CE->getCallee();
353  SVal CallV = N->getState()->getSVal(Callee);
354  const FunctionDecl* FD = CallV.getAsFunctionDecl();
355
356  if (!FD || FD->getIdentifier() != II || CE->getNumArgs()!=3)
357    return false;
358
359  // Get the value of the "theType" argument.
360  SVal TheTypeVal = N->getState()->getSVal(CE->getArg(1));
361
362    // FIXME: We really should allow ranges of valid theType values, and
363    //   bifurcate the state appropriately.
364  nonloc::ConcreteInt* V = dyn_cast<nonloc::ConcreteInt>(&TheTypeVal);
365
366  if (!V)
367    return false;
368
369  uint64_t NumberKind = V->getValue().getLimitedValue();
370  Optional<uint64_t> TargetSize = GetCFNumberSize(Ctx, NumberKind);
371
372  // FIXME: In some cases we can emit an error.
373  if (!TargetSize.isKnown())
374    return false;
375
376  // Look at the value of the integer being passed by reference.  Essentially
377  // we want to catch cases where the value passed in is not equal to the
378  // size of the type being created.
379  SVal TheValueExpr = N->getState()->getSVal(CE->getArg(2));
380
381  // FIXME: Eventually we should handle arbitrary locations.  We can do this
382  //  by having an enhanced memory model that does low-level typing.
383  loc::MemRegionVal* LV = dyn_cast<loc::MemRegionVal>(&TheValueExpr);
384
385  if (!LV)
386    return false;
387
388  const TypedRegion* R = dyn_cast<TypedRegion>(LV->StripCasts());
389
390  if (!R)
391    return false;
392
393  QualType T = Ctx.getCanonicalType(R->getValueType(Ctx));
394
395  // FIXME: If the pointee isn't an integer type, should we flag a warning?
396  //  People can do weird stuff with pointers.
397
398  if (!T->isIntegerType())
399    return false;
400
401  uint64_t SourceSize = Ctx.getTypeSize(T);
402
403  // CHECK: is SourceSize == TargetSize
404
405  if (SourceSize == TargetSize)
406    return false;
407
408  AddError(R, CE->getArg(2), N, SourceSize, TargetSize, NumberKind);
409
410  // FIXME: We can actually create an abstract "CFNumber" object that has
411  //  the bits initialized to the provided values.
412  return SourceSize < TargetSize;
413}
414
415void AuditCFNumberCreate::AddError(const TypedRegion* R, const Expr* Ex,
416                                   ExplodedNode *N,
417                                   uint64_t SourceSize, uint64_t TargetSize,
418                                   uint64_t NumberKind) {
419
420  std::string sbuf;
421  llvm::raw_string_ostream os(sbuf);
422
423  os << (SourceSize == 8 ? "An " : "A ")
424     << SourceSize << " bit integer is used to initialize a CFNumber "
425        "object that represents "
426     << (TargetSize == 8 ? "an " : "a ")
427     << TargetSize << " bit integer. ";
428
429  if (SourceSize < TargetSize)
430    os << (TargetSize - SourceSize)
431       << " bits of the CFNumber value will be garbage." ;
432  else
433    os << (SourceSize - TargetSize)
434       << " bits of the input integer will be lost.";
435
436  // Lazily create the BugType object.  This will be owned
437  // by the BugReporter object 'BR' once we call BR.EmitWarning.
438  if (!BT) BT = new APIMisuse("Bad use of CFNumberCreate");
439  RangedBugReport *report = new RangedBugReport(*BT, os.str().c_str(), N);
440  report->addRange(Ex->getSourceRange());
441  BR.EmitReport(report);
442}
443
444GRSimpleAPICheck*
445clang::CreateAuditCFNumberCreate(ASTContext& Ctx, BugReporter& BR) {
446  return new AuditCFNumberCreate(Ctx, BR);
447}
448
449//===----------------------------------------------------------------------===//
450// CFRetain/CFRelease auditing for null arguments.
451//===----------------------------------------------------------------------===//
452
453namespace {
454class VISIBILITY_HIDDEN AuditCFRetainRelease : public GRSimpleAPICheck {
455  APIMisuse *BT;
456
457  // FIXME: Either this should be refactored into GRSimpleAPICheck, or
458  //   it should always be passed with a call to Audit.  The latter
459  //   approach makes this class more stateless.
460  ASTContext& Ctx;
461  IdentifierInfo *Retain, *Release;
462  BugReporter& BR;
463
464public:
465  AuditCFRetainRelease(ASTContext& ctx, BugReporter& br)
466  : BT(0), Ctx(ctx),
467    Retain(&Ctx.Idents.get("CFRetain")), Release(&Ctx.Idents.get("CFRelease")),
468    BR(br){}
469
470  ~AuditCFRetainRelease() {}
471
472  bool Audit(ExplodedNode* N, GRStateManager&);
473};
474} // end anonymous namespace
475
476
477bool AuditCFRetainRelease::Audit(ExplodedNode* N, GRStateManager&) {
478  const CallExpr* CE = cast<CallExpr>(cast<PostStmt>(N->getLocation()).getStmt());
479
480  // If the CallExpr doesn't have exactly 1 argument just give up checking.
481  if (CE->getNumArgs() != 1)
482    return false;
483
484  // Check if we called CFRetain/CFRelease.
485  const GRState* state = N->getState();
486  SVal X = state->getSVal(CE->getCallee());
487  const FunctionDecl* FD = X.getAsFunctionDecl();
488
489  if (!FD)
490    return false;
491
492  const IdentifierInfo *FuncII = FD->getIdentifier();
493  if (!(FuncII == Retain || FuncII == Release))
494    return false;
495
496  // Finally, check if the argument is NULL.
497  // FIXME: We should be able to bifurcate the state here, as a successful
498  // check will result in the value not being NULL afterwards.
499  // FIXME: Need a way to register vistors for the BugReporter.  Would like
500  // to benefit from the same diagnostics that regular null dereference
501  // reporting has.
502  if (state->getStateManager().isEqual(state, CE->getArg(0), 0)) {
503    if (!BT)
504      BT = new APIMisuse("null passed to CFRetain/CFRelease");
505
506    const char *description = (FuncII == Retain)
507                            ? "Null pointer argument in call to CFRetain"
508                            : "Null pointer argument in call to CFRelease";
509
510    RangedBugReport *report = new RangedBugReport(*BT, description, N);
511    report->addRange(CE->getArg(0)->getSourceRange());
512    BR.EmitReport(report);
513    return true;
514  }
515
516  return false;
517}
518
519
520GRSimpleAPICheck*
521clang::CreateAuditCFRetainRelease(ASTContext& Ctx, BugReporter& BR) {
522  return new AuditCFRetainRelease(Ctx, BR);
523}
524
525//===----------------------------------------------------------------------===//
526// Check for sending 'retain', 'release', or 'autorelease' directly to a Class.
527//===----------------------------------------------------------------------===//
528
529namespace {
530class VISIBILITY_HIDDEN ClassReleaseChecker :
531    public CheckerVisitor<ClassReleaseChecker> {
532  Selector releaseS;
533  Selector retainS;
534  Selector autoreleaseS;
535  Selector drainS;
536  BugType *BT;
537public:
538  ClassReleaseChecker(ASTContext &Ctx)
539    : releaseS(GetNullarySelector("release", Ctx)),
540      retainS(GetNullarySelector("retain", Ctx)),
541      autoreleaseS(GetNullarySelector("autorelease", Ctx)),
542      drainS(GetNullarySelector("drain", Ctx)),
543      BT(0) {}
544
545  static void *getTag() { static int x = 0; return &x; }
546
547  void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME);
548};
549}
550
551void ClassReleaseChecker::PreVisitObjCMessageExpr(CheckerContext &C,
552                                                  const ObjCMessageExpr *ME) {
553
554  const IdentifierInfo *ClsName = ME->getClassName();
555  if (!ClsName)
556    return;
557
558  Selector S = ME->getSelector();
559  if (!(S == releaseS || S == retainS || S == autoreleaseS | S == drainS))
560    return;
561
562  if (!BT)
563    BT = new APIMisuse("message incorrectly sent to class instead of class "
564                       "instance");
565
566  ExplodedNode *N = C.GenerateNode(ME, C.getState(), false);
567  if (!N)
568    return;
569
570  C.addTransition(N);
571
572  llvm::SmallString<200> buf;
573  llvm::raw_svector_ostream os(buf);
574
575  os << "The '" << S.getAsString() << "' message should be sent to instances "
576        "of class '" << ClsName->getName()
577     << "' and not the class directly";
578
579  RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
580  report->addRange(ME->getSourceRange());
581  C.EmitReport(report);
582}
583
584//===----------------------------------------------------------------------===//
585// Check registration.
586//===----------------------------------------------------------------------===//
587
588void clang::RegisterAppleChecks(GRExprEngine& Eng, const Decl &D) {
589  ASTContext& Ctx = Eng.getContext();
590  BugReporter &BR = Eng.getBugReporter();
591
592  Eng.AddCheck(CreateBasicObjCFoundationChecks(Ctx, BR),
593               Stmt::ObjCMessageExprClass);
594  Eng.AddCheck(CreateAuditCFNumberCreate(Ctx, BR), Stmt::CallExprClass);
595  Eng.AddCheck(CreateAuditCFRetainRelease(Ctx, BR), Stmt::CallExprClass);
596
597  RegisterNSErrorChecks(BR, Eng, D);
598  RegisterNSAutoreleasePoolChecks(Eng);
599  Eng.registerCheck(new ClassReleaseChecker(Ctx));
600}
601