BasicObjCFoundationChecks.cpp revision 04badcf84c8d504d8491c7c7e29b58f52cb16640
199c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek//== BasicObjCFoundationChecks.cpp - Simple Apple-Foundation checks -*- C++ -*--
299c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek//
399c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek//                     The LLVM Compiler Infrastructure
499c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek//
599c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek// This file is distributed under the University of Illinois Open Source
699c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek// License. See LICENSE.TXT for details.
799c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek//
899c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek//===----------------------------------------------------------------------===//
999c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek//
1099c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek//  This file defines BasicObjCFoundationChecks, a class that encapsulates
1199c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek//  a set of simple checks to run on Objective-C code using Apple's Foundation
1299c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek//  classes.
1399c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek//
1499c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek//===----------------------------------------------------------------------===//
1599c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek
16527556184b276c545be1355ad596fce29a0400fbTed Kremenek#include "BasicObjCFoundationChecks.h"
17527556184b276c545be1355ad596fce29a0400fbTed Kremenek
181309f9a3b225ea846e5822691c39a77423125505Ted Kremenek#include "clang/Checker/PathSensitive/ExplodedGraph.h"
191309f9a3b225ea846e5822691c39a77423125505Ted Kremenek#include "clang/Checker/PathSensitive/GRSimpleAPICheck.h"
201309f9a3b225ea846e5822691c39a77423125505Ted Kremenek#include "clang/Checker/PathSensitive/GRExprEngine.h"
211309f9a3b225ea846e5822691c39a77423125505Ted Kremenek#include "clang/Checker/PathSensitive/GRState.h"
225e2d2c2ee3cf410643e0f9a5701708e51409d973Benjamin Kramer#include "clang/Checker/BugReporter/BugType.h"
231309f9a3b225ea846e5822691c39a77423125505Ted Kremenek#include "clang/Checker/PathSensitive/MemRegion.h"
241309f9a3b225ea846e5822691c39a77423125505Ted Kremenek#include "clang/Checker/PathSensitive/CheckerVisitor.h"
2597053091c0e4df12ffb662b284b6ab329ca1c40fTed Kremenek#include "clang/Checker/Checkers/LocalCheckers.h"
26c4a1dea2dc56bd1357ec91b829a0b9e68229a13eDaniel Dunbar#include "clang/AST/DeclObjC.h"
2799c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek#include "clang/AST/Expr.h"
28f494b579b22f9950f5af021f0bf9879a91bb8b41Steve Naroff#include "clang/AST/ExprObjC.h"
2999c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek#include "clang/AST/ASTContext.h"
3099c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek
3199c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenekusing namespace clang;
32f1ae705460552655fe7275327804444c62e86baeTed Kremenek
3314108da7f7fc059772711e4ffee1322a27b152a7Steve Naroffstatic const ObjCInterfaceType* GetReceiverType(const ObjCMessageExpr* ME) {
3404badcf84c8d504d8491c7c7e29b58f52cb16640Douglas Gregor  QualType T;
3504badcf84c8d504d8491c7c7e29b58f52cb16640Douglas Gregor  switch (ME->getReceiverKind()) {
3604badcf84c8d504d8491c7c7e29b58f52cb16640Douglas Gregor  case ObjCMessageExpr::Instance:
3704badcf84c8d504d8491c7c7e29b58f52cb16640Douglas Gregor    T = ME->getInstanceReceiver()->getType();
3804badcf84c8d504d8491c7c7e29b58f52cb16640Douglas Gregor    break;
3904badcf84c8d504d8491c7c7e29b58f52cb16640Douglas Gregor
4004badcf84c8d504d8491c7c7e29b58f52cb16640Douglas Gregor  case ObjCMessageExpr::SuperInstance:
4104badcf84c8d504d8491c7c7e29b58f52cb16640Douglas Gregor    T = ME->getSuperType();
4204badcf84c8d504d8491c7c7e29b58f52cb16640Douglas Gregor    break;
4304badcf84c8d504d8491c7c7e29b58f52cb16640Douglas Gregor
4404badcf84c8d504d8491c7c7e29b58f52cb16640Douglas Gregor  case ObjCMessageExpr::Class:
4504badcf84c8d504d8491c7c7e29b58f52cb16640Douglas Gregor  case ObjCMessageExpr::SuperClass:
4604badcf84c8d504d8491c7c7e29b58f52cb16640Douglas Gregor    return 0;
4704badcf84c8d504d8491c7c7e29b58f52cb16640Douglas Gregor  }
481eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
4904badcf84c8d504d8491c7c7e29b58f52cb16640Douglas Gregor  if (const ObjCObjectPointerType *PT = T->getAs<ObjCObjectPointerType>())
5014108da7f7fc059772711e4ffee1322a27b152a7Steve Naroff    return PT->getInterfaceType();
51c1ff3cd5fe4436bb14309fdc5ee7e1c2b702b7c3Ted Kremenek
52c1ff3cd5fe4436bb14309fdc5ee7e1c2b702b7c3Ted Kremenek  return NULL;
53f1ae705460552655fe7275327804444c62e86baeTed Kremenek}
54f1ae705460552655fe7275327804444c62e86baeTed Kremenek
5514108da7f7fc059772711e4ffee1322a27b152a7Steve Naroffstatic const char* GetReceiverNameType(const ObjCMessageExpr* ME) {
56e013d685c6689ac7ae103ee88acf573422d1ed6aDaniel Dunbar  if (const ObjCInterfaceType *ReceiverType = GetReceiverType(ME))
57e013d685c6689ac7ae103ee88acf573422d1ed6aDaniel Dunbar    return ReceiverType->getDecl()->getIdentifier()->getNameStart();
58e013d685c6689ac7ae103ee88acf573422d1ed6aDaniel Dunbar  return NULL;
59f1ae705460552655fe7275327804444c62e86baeTed Kremenek}
60f1ae705460552655fe7275327804444c62e86baeTed Kremenek
6199c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremeneknamespace {
62b344f91f00021b88e365a4a38502090c3b0cef12Ted Kremenek
63ba5fb5a955c896815c439289fc51c03cf0635129Kovarththanan Rajaratnamclass APIMisuse : public BugType {
64f1ae705460552655fe7275327804444c62e86baeTed Kremenekpublic:
65cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek  APIMisuse(const char* name) : BugType(name, "API Misuse (Apple)") {}
66f1ae705460552655fe7275327804444c62e86baeTed Kremenek};
671eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
68ba5fb5a955c896815c439289fc51c03cf0635129Kovarththanan Rajaratnamclass BasicObjCFoundationChecks : public GRSimpleAPICheck {
69cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek  APIMisuse *BT;
70cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek  BugReporter& BR;
71e5d5c204c761cc3b2a6374a15b035420f207c7afTed Kremenek  ASTContext &Ctx;
721eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
73d777d58714fc26c645e061ed7aa43ecb05ab41a8Daniel Dunbar  bool isNSString(const ObjCInterfaceType *T, llvm::StringRef suffix);
74031ccc0555a82afc2e8afe29e19dd57ff204e2deZhongxing Xu  bool AuditNSString(ExplodedNode* N, const ObjCMessageExpr* ME);
751eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
761eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump  void Warn(ExplodedNode* N, const Expr* E, const std::string& s);
77031ccc0555a82afc2e8afe29e19dd57ff204e2deZhongxing Xu  void WarnNilArg(ExplodedNode* N, const Expr* E);
781eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
79031ccc0555a82afc2e8afe29e19dd57ff204e2deZhongxing Xu  bool CheckNilArg(ExplodedNode* N, unsigned Arg);
8099c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek
8199c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenekpublic:
821eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump  BasicObjCFoundationChecks(ASTContext& ctx, BugReporter& br)
8323ec48cd3369c8d7d1ab3c3f2226cfcffd2cd3d3Ted Kremenek    : BT(0), BR(br), Ctx(ctx) {}
841eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
85c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xu  bool Audit(ExplodedNode* N, GRStateManager&);
861eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
871eb4433ac451dc16f4133a88af2d002ac26c58efMike Stumpprivate:
881eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump  void WarnNilArg(ExplodedNode* N, const ObjCMessageExpr* ME, unsigned Arg) {
89cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek    std::string sbuf;
90cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek    llvm::raw_string_ostream os(sbuf);
91cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek    os << "Argument to '" << GetReceiverNameType(ME) << "' method '"
92cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek       << ME->getSelector().getAsString() << "' cannot be nil.";
931eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
94cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek    // Lazily create the BugType object for NilArg.  This will be owned
95cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek    // by the BugReporter object 'BR' once we call BR.EmitWarning.
96cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek    if (!BT) BT = new APIMisuse("nil argument");
971eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
984988a9a278c50fddf46d38331e4a136a91487b7dBenjamin Kramer    RangedBugReport *R = new RangedBugReport(*BT, os.str(), N);
99cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek    R->addRange(ME->getArg(Arg)->getSourceRange());
100cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek    BR.EmitReport(R);
101f1ae705460552655fe7275327804444c62e86baeTed Kremenek  }
10299c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek};
1031eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
10499c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek} // end anonymous namespace
10599c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek
10699c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek
107527556184b276c545be1355ad596fce29a0400fbTed KremenekGRSimpleAPICheck*
10823ec48cd3369c8d7d1ab3c3f2226cfcffd2cd3d3Ted Kremenekclang::CreateBasicObjCFoundationChecks(ASTContext& Ctx, BugReporter& BR) {
1091eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump  return new BasicObjCFoundationChecks(Ctx, BR);
110527556184b276c545be1355ad596fce29a0400fbTed Kremenek}
111527556184b276c545be1355ad596fce29a0400fbTed Kremenek
1124ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek
11399c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek
114c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xubool BasicObjCFoundationChecks::Audit(ExplodedNode* N,
1154adc81e540b874bafa15715fd2c5cb662463debdTed Kremenek                                      GRStateManager&) {
1161eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
1175f85e17df3f5b0a8021443f2b590daecfb2cbd17Ted Kremenek  const ObjCMessageExpr* ME =
1184ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek    cast<ObjCMessageExpr>(cast<PostStmt>(N->getLocation()).getStmt());
1194ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek
12014108da7f7fc059772711e4ffee1322a27b152a7Steve Naroff  const ObjCInterfaceType *ReceiverType = GetReceiverType(ME);
1211eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
12299c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek  if (!ReceiverType)
123f74279447d4ad0a0c0f2e6e6740d5a0f4c242e0cNuno Lopes    return false;
1241eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
125d777d58714fc26c645e061ed7aa43ecb05ab41a8Daniel Dunbar  if (isNSString(ReceiverType,
12601eb9b9683535d8a65c704ad2c545903409e2d36Daniel Dunbar                 ReceiverType->getDecl()->getIdentifier()->getName()))
12799c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek    return AuditNSString(N, ME);
12899c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek
129f74279447d4ad0a0c0f2e6e6740d5a0f4c242e0cNuno Lopes  return false;
13099c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek}
13199c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek
1321c96b24285d05c0eac455ae96d7c9ff43d42bc96Zhongxing Xustatic inline bool isNil(SVal X) {
1331eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump  return isa<loc::ConcreteInt>(X);
134e5d5c204c761cc3b2a6374a15b035420f207c7afTed Kremenek}
135e5d5c204c761cc3b2a6374a15b035420f207c7afTed Kremenek
13699c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek//===----------------------------------------------------------------------===//
13799c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek// Error reporting.
13899c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek//===----------------------------------------------------------------------===//
13999c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek
140031ccc0555a82afc2e8afe29e19dd57ff204e2deZhongxing Xubool BasicObjCFoundationChecks::CheckNilArg(ExplodedNode* N, unsigned Arg) {
1415f85e17df3f5b0a8021443f2b590daecfb2cbd17Ted Kremenek  const ObjCMessageExpr* ME =
1424ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek    cast<ObjCMessageExpr>(cast<PostStmt>(N->getLocation()).getStmt());
1431eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
1445f85e17df3f5b0a8021443f2b590daecfb2cbd17Ted Kremenek  const Expr * E = ME->getArg(Arg);
1451eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
1461397663af9dbcc24dbf0e11de43931b3dc08fdbbTed Kremenek  if (isNil(N->getState()->getSVal(E))) {
147f1ae705460552655fe7275327804444c62e86baeTed Kremenek    WarnNilArg(N, ME, Arg);
1484ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek    return true;
1494ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek  }
1501eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
1514ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek  return false;
1524ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek}
1534ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek
15499c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek//===----------------------------------------------------------------------===//
15599c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek// NSString checking.
15699c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek//===----------------------------------------------------------------------===//
15799c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek
15814108da7f7fc059772711e4ffee1322a27b152a7Steve Naroffbool BasicObjCFoundationChecks::isNSString(const ObjCInterfaceType *T,
159d777d58714fc26c645e061ed7aa43ecb05ab41a8Daniel Dunbar                                           llvm::StringRef ClassName) {
160d777d58714fc26c645e061ed7aa43ecb05ab41a8Daniel Dunbar  return ClassName == "NSString" || ClassName == "NSMutableString";
16199c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek}
16299c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek
1631eb4433ac451dc16f4133a88af2d002ac26c58efMike Stumpbool BasicObjCFoundationChecks::AuditNSString(ExplodedNode* N,
1645f85e17df3f5b0a8021443f2b590daecfb2cbd17Ted Kremenek                                              const ObjCMessageExpr* ME) {
1651eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
16699c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek  Selector S = ME->getSelector();
1671eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
16899c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek  if (S.isUnarySelector())
16999c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek    return false;
17099c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek
17199c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek  // FIXME: This is going to be really slow doing these checks with
17299c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek  //  lexical comparisons.
1731eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
174064fb20e7a29d00f29bf10f9d7f54d36456a2449Benjamin Kramer  std::string NameStr = S.getAsString();
175064fb20e7a29d00f29bf10f9d7f54d36456a2449Benjamin Kramer  llvm::StringRef Name(NameStr);
176064fb20e7a29d00f29bf10f9d7f54d36456a2449Benjamin Kramer  assert(!Name.empty());
177064fb20e7a29d00f29bf10f9d7f54d36456a2449Benjamin Kramer
178064fb20e7a29d00f29bf10f9d7f54d36456a2449Benjamin Kramer  // FIXME: Checking for initWithFormat: will not work in most cases
179064fb20e7a29d00f29bf10f9d7f54d36456a2449Benjamin Kramer  //  yet because [NSString alloc] returns id, not NSString*.  We will
180064fb20e7a29d00f29bf10f9d7f54d36456a2449Benjamin Kramer  //  need support for tracking expected-type information in the analyzer
181064fb20e7a29d00f29bf10f9d7f54d36456a2449Benjamin Kramer  //  to find these errors.
182064fb20e7a29d00f29bf10f9d7f54d36456a2449Benjamin Kramer  if (Name == "caseInsensitiveCompare:" ||
183064fb20e7a29d00f29bf10f9d7f54d36456a2449Benjamin Kramer      Name == "compare:" ||
184064fb20e7a29d00f29bf10f9d7f54d36456a2449Benjamin Kramer      Name == "compare:options:" ||
185064fb20e7a29d00f29bf10f9d7f54d36456a2449Benjamin Kramer      Name == "compare:options:range:" ||
186064fb20e7a29d00f29bf10f9d7f54d36456a2449Benjamin Kramer      Name == "compare:options:range:locale:" ||
187064fb20e7a29d00f29bf10f9d7f54d36456a2449Benjamin Kramer      Name == "componentsSeparatedByCharactersInSet:" ||
188064fb20e7a29d00f29bf10f9d7f54d36456a2449Benjamin Kramer      Name == "initWithFormat:")
189064fb20e7a29d00f29bf10f9d7f54d36456a2449Benjamin Kramer    return CheckNilArg(N, 0);
1901eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
19199c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek  return false;
19299c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek}
19304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek
19404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek//===----------------------------------------------------------------------===//
19504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek// Error reporting.
19604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek//===----------------------------------------------------------------------===//
19704bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek
19804bc87683acacce119967dfa5f7c35b4ecef012aTed Kremeneknamespace {
19904bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek
200ba5fb5a955c896815c439289fc51c03cf0635129Kovarththanan Rajaratnamclass AuditCFNumberCreate : public GRSimpleAPICheck {
201cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek  APIMisuse* BT;
2021eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
20304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek  // FIXME: Either this should be refactored into GRSimpleAPICheck, or
20404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek  //   it should always be passed with a call to Audit.  The latter
20504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek  //   approach makes this class more stateless.
20604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek  ASTContext& Ctx;
20704bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek  IdentifierInfo* II;
208cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek  BugReporter& BR;
20923ec48cd3369c8d7d1ab3c3f2226cfcffd2cd3d3Ted Kremenek
21004bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenekpublic:
2111eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump  AuditCFNumberCreate(ASTContext& ctx, BugReporter& br)
21223ec48cd3369c8d7d1ab3c3f2226cfcffd2cd3d3Ted Kremenek  : BT(0), Ctx(ctx), II(&Ctx.Idents.get("CFNumberCreate")), BR(br){}
2131eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
214cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek  ~AuditCFNumberCreate() {}
2151eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
216c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xu  bool Audit(ExplodedNode* N, GRStateManager&);
2171eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
21804bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenekprivate:
219c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xu  void AddError(const TypedRegion* R, const Expr* Ex, ExplodedNode *N,
2201eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump                uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind);
22104bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek};
22204bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek} // end anonymous namespace
22304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek
22404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenekenum CFNumberType {
22504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek  kCFNumberSInt8Type = 1,
22604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek  kCFNumberSInt16Type = 2,
22704bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek  kCFNumberSInt32Type = 3,
22804bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek  kCFNumberSInt64Type = 4,
22904bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek  kCFNumberFloat32Type = 5,
23004bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek  kCFNumberFloat64Type = 6,
23104bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek  kCFNumberCharType = 7,
23204bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek  kCFNumberShortType = 8,
23304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek  kCFNumberIntType = 9,
23404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek  kCFNumberLongType = 10,
23504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek  kCFNumberLongLongType = 11,
23604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek  kCFNumberFloatType = 12,
23704bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek  kCFNumberDoubleType = 13,
23804bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek  kCFNumberCFIndexType = 14,
23904bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek  kCFNumberNSIntegerType = 15,
24004bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek  kCFNumberCGFloatType = 16
24104bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek};
24204bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek
24304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremeneknamespace {
24404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek  template<typename T>
24504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek  class Optional {
24604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek    bool IsKnown;
24704bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek    T Val;
24804bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek  public:
24904bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek    Optional() : IsKnown(false), Val(0) {}
25004bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek    Optional(const T& val) : IsKnown(true), Val(val) {}
2511eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
25204bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek    bool isKnown() const { return IsKnown; }
25304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek
25404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek    const T& getValue() const {
25504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek      assert (isKnown());
25604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek      return Val;
25704bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek    }
25804bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek
25904bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek    operator const T&() const {
26004bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek      return getValue();
26104bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek    }
26204bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek  };
26304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek}
26404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek
26504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenekstatic Optional<uint64_t> GetCFNumberSize(ASTContext& Ctx, uint64_t i) {
2662550d70aabb5f603e8f74cc5fb6a69a7af5b51f3Nuno Lopes  static const unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 };
2671eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
26804bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek  if (i < kCFNumberCharType)
26904bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek    return FixedSize[i-1];
2701eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
27104bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek  QualType T;
2721eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
27304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek  switch (i) {
27404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek    case kCFNumberCharType:     T = Ctx.CharTy;     break;
27504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek    case kCFNumberShortType:    T = Ctx.ShortTy;    break;
27604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek    case kCFNumberIntType:      T = Ctx.IntTy;      break;
27704bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek    case kCFNumberLongType:     T = Ctx.LongTy;     break;
27804bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek    case kCFNumberLongLongType: T = Ctx.LongLongTy; break;
27904bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek    case kCFNumberFloatType:    T = Ctx.FloatTy;    break;
28004bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek    case kCFNumberDoubleType:   T = Ctx.DoubleTy;   break;
28104bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek    case kCFNumberCFIndexType:
28204bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek    case kCFNumberNSIntegerType:
28304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek    case kCFNumberCGFloatType:
2841eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump      // FIXME: We need a way to map from names to Type*.
28504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek    default:
28604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek      return Optional<uint64_t>();
28704bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek  }
2881eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
28904bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek  return Ctx.getTypeSize(T);
29004bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek}
29104bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek
29204bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek#if 0
29304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenekstatic const char* GetCFNumberTypeStr(uint64_t i) {
29404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek  static const char* Names[] = {
29504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek    "kCFNumberSInt8Type",
29604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek    "kCFNumberSInt16Type",
29704bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek    "kCFNumberSInt32Type",
29804bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek    "kCFNumberSInt64Type",
29904bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek    "kCFNumberFloat32Type",
30004bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek    "kCFNumberFloat64Type",
30104bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek    "kCFNumberCharType",
30204bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek    "kCFNumberShortType",
30304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek    "kCFNumberIntType",
30404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek    "kCFNumberLongType",
30504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek    "kCFNumberLongLongType",
30604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek    "kCFNumberFloatType",
30704bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek    "kCFNumberDoubleType",
30804bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek    "kCFNumberCFIndexType",
30904bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek    "kCFNumberNSIntegerType",
31004bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek    "kCFNumberCGFloatType"
31104bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek  };
3121eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
31304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek  return i <= kCFNumberCGFloatType ? Names[i-1] : "Invalid CFNumberType";
31404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek}
31504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek#endif
31604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek
3171eb4433ac451dc16f4133a88af2d002ac26c58efMike Stumpbool AuditCFNumberCreate::Audit(ExplodedNode* N,GRStateManager&){
3185f85e17df3f5b0a8021443f2b590daecfb2cbd17Ted Kremenek  const CallExpr* CE =
3195f85e17df3f5b0a8021443f2b590daecfb2cbd17Ted Kremenek    cast<CallExpr>(cast<PostStmt>(N->getLocation()).getStmt());
3201eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump  const Expr* Callee = CE->getCallee();
3211397663af9dbcc24dbf0e11de43931b3dc08fdbbTed Kremenek  SVal CallV = N->getState()->getSVal(Callee);
322369f447eded97e6048ced02c0c2be3842f61fc1cZhongxing Xu  const FunctionDecl* FD = CallV.getAsFunctionDecl();
32304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek
324369f447eded97e6048ced02c0c2be3842f61fc1cZhongxing Xu  if (!FD || FD->getIdentifier() != II || CE->getNumArgs()!=3)
32504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek    return false;
3261eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
32704bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek  // Get the value of the "theType" argument.
3281397663af9dbcc24dbf0e11de43931b3dc08fdbbTed Kremenek  SVal TheTypeVal = N->getState()->getSVal(CE->getArg(1));
3291eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
33004bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek    // FIXME: We really should allow ranges of valid theType values, and
33104bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek    //   bifurcate the state appropriately.
3321c96b24285d05c0eac455ae96d7c9ff43d42bc96Zhongxing Xu  nonloc::ConcreteInt* V = dyn_cast<nonloc::ConcreteInt>(&TheTypeVal);
3331eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
33404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek  if (!V)
33504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek    return false;
3361eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
33704bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek  uint64_t NumberKind = V->getValue().getLimitedValue();
33804bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek  Optional<uint64_t> TargetSize = GetCFNumberSize(Ctx, NumberKind);
3391eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
34004bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek  // FIXME: In some cases we can emit an error.
34104bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek  if (!TargetSize.isKnown())
34204bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek    return false;
3431eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
34404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek  // Look at the value of the integer being passed by reference.  Essentially
34504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek  // we want to catch cases where the value passed in is not equal to the
34604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek  // size of the type being created.
3471397663af9dbcc24dbf0e11de43931b3dc08fdbbTed Kremenek  SVal TheValueExpr = N->getState()->getSVal(CE->getArg(2));
3481eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
34904bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek  // FIXME: Eventually we should handle arbitrary locations.  We can do this
35004bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek  //  by having an enhanced memory model that does low-level typing.
3511c96b24285d05c0eac455ae96d7c9ff43d42bc96Zhongxing Xu  loc::MemRegionVal* LV = dyn_cast<loc::MemRegionVal>(&TheValueExpr);
35204bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek
35304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek  if (!LV)
35404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek    return false;
3551eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
356479529e679957fbb92b56e116e3c86734429331eZhongxing Xu  const TypedRegion* R = dyn_cast<TypedRegion>(LV->StripCasts());
3575e77ebae47099d76020e84e604b33bb33c9006c3Ted Kremenek
3585e77ebae47099d76020e84e604b33bb33c9006c3Ted Kremenek  if (!R)
3595e77ebae47099d76020e84e604b33bb33c9006c3Ted Kremenek    return false;
3605e77ebae47099d76020e84e604b33bb33c9006c3Ted Kremenek
361a82d8aa5b3b3d24998b4d98b9f45a43cc84cac6fZhongxing Xu  QualType T = Ctx.getCanonicalType(R->getValueType(Ctx));
3621eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
36304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek  // FIXME: If the pointee isn't an integer type, should we flag a warning?
36404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek  //  People can do weird stuff with pointers.
3651eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
3661eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump  if (!T->isIntegerType())
36704bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek    return false;
3681eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
36904bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek  uint64_t SourceSize = Ctx.getTypeSize(T);
3701eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
37104bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek  // CHECK: is SourceSize == TargetSize
3721eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
37304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek  if (SourceSize == TargetSize)
37404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek    return false;
3751eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
3769e24049bef26b6289cce9ac9b483c5cbb096e3aeTed Kremenek  AddError(R, CE->getArg(2), N, SourceSize, TargetSize, NumberKind);
3771eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
37804bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek  // FIXME: We can actually create an abstract "CFNumber" object that has
37904bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek  //  the bits initialized to the provided values.
38004bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek  return SourceSize < TargetSize;
38104bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek}
38204bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek
3835f85e17df3f5b0a8021443f2b590daecfb2cbd17Ted Kremenekvoid AuditCFNumberCreate::AddError(const TypedRegion* R, const Expr* Ex,
384c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xu                                   ExplodedNode *N,
38504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek                                   uint64_t SourceSize, uint64_t TargetSize,
38604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek                                   uint64_t NumberKind) {
3871eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
388cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek  std::string sbuf;
389cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek  llvm::raw_string_ostream os(sbuf);
3901eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
39104bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek  os << (SourceSize == 8 ? "An " : "A ")
39204bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek     << SourceSize << " bit integer is used to initialize a CFNumber "
39304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek        "object that represents "
39404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek     << (TargetSize == 8 ? "an " : "a ")
3951eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump     << TargetSize << " bit integer. ";
39604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek
39704bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek  if (SourceSize < TargetSize)
39804bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek    os << (TargetSize - SourceSize)
3991eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump       << " bits of the CFNumber value will be garbage." ;
40004bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek  else
40104bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek    os << (SourceSize - TargetSize)
40204bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek       << " bits of the input integer will be lost.";
4031eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
404cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek  // Lazily create the BugType object.  This will be owned
405cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek  // by the BugReporter object 'BR' once we call BR.EmitWarning.
406cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek  if (!BT) BT = new APIMisuse("Bad use of CFNumberCreate");
4074988a9a278c50fddf46d38331e4a136a91487b7dBenjamin Kramer  RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
408cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek  report->addRange(Ex->getSourceRange());
409cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek  BR.EmitReport(report);
41004bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek}
41104bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek
41204bc87683acacce119967dfa5f7c35b4ecef012aTed KremenekGRSimpleAPICheck*
4131eb4433ac451dc16f4133a88af2d002ac26c58efMike Stumpclang::CreateAuditCFNumberCreate(ASTContext& Ctx, BugReporter& BR) {
41423ec48cd3369c8d7d1ab3c3f2226cfcffd2cd3d3Ted Kremenek  return new AuditCFNumberCreate(Ctx, BR);
41504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek}
41604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek
41778d46242e3351484c2b773f5610beba5d316914bTed Kremenek//===----------------------------------------------------------------------===//
41879b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek// CFRetain/CFRelease auditing for null arguments.
41979b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek//===----------------------------------------------------------------------===//
42079b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek
42179b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremeneknamespace {
422ba5fb5a955c896815c439289fc51c03cf0635129Kovarththanan Rajaratnamclass AuditCFRetainRelease : public GRSimpleAPICheck {
42379b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek  APIMisuse *BT;
4241eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
42579b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek  // FIXME: Either this should be refactored into GRSimpleAPICheck, or
42679b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek  //   it should always be passed with a call to Audit.  The latter
42779b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek  //   approach makes this class more stateless.
42879b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek  ASTContext& Ctx;
42979b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek  IdentifierInfo *Retain, *Release;
43079b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek  BugReporter& BR;
4311eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
43279b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenekpublic:
4331eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump  AuditCFRetainRelease(ASTContext& ctx, BugReporter& br)
43479b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek  : BT(0), Ctx(ctx),
43579b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek    Retain(&Ctx.Idents.get("CFRetain")), Release(&Ctx.Idents.get("CFRelease")),
43679b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek    BR(br){}
4371eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
43879b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek  ~AuditCFRetainRelease() {}
4391eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
440c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xu  bool Audit(ExplodedNode* N, GRStateManager&);
44179b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek};
44279b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek} // end anonymous namespace
44379b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek
44479b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek
445c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xubool AuditCFRetainRelease::Audit(ExplodedNode* N, GRStateManager&) {
4465f85e17df3f5b0a8021443f2b590daecfb2cbd17Ted Kremenek  const CallExpr* CE = cast<CallExpr>(cast<PostStmt>(N->getLocation()).getStmt());
4471eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
44879b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek  // If the CallExpr doesn't have exactly 1 argument just give up checking.
44979b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek  if (CE->getNumArgs() != 1)
45079b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek    return false;
4511eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
45279b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek  // Check if we called CFRetain/CFRelease.
45379b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek  const GRState* state = N->getState();
4541397663af9dbcc24dbf0e11de43931b3dc08fdbbTed Kremenek  SVal X = state->getSVal(CE->getCallee());
45579b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek  const FunctionDecl* FD = X.getAsFunctionDecl();
4561eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
45779b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek  if (!FD)
45879b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek    return false;
4591eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
4601eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump  const IdentifierInfo *FuncII = FD->getIdentifier();
46179b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek  if (!(FuncII == Retain || FuncII == Release))
46279b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek    return false;
4631eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
46479b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek  // Finally, check if the argument is NULL.
46579b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek  // FIXME: We should be able to bifurcate the state here, as a successful
46679b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek  // check will result in the value not being NULL afterwards.
46779b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek  // FIXME: Need a way to register vistors for the BugReporter.  Would like
46879b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek  // to benefit from the same diagnostics that regular null dereference
46979b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek  // reporting has.
47079b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek  if (state->getStateManager().isEqual(state, CE->getArg(0), 0)) {
47179b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek    if (!BT)
47279b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek      BT = new APIMisuse("null passed to CFRetain/CFRelease");
4731eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
47479b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek    const char *description = (FuncII == Retain)
47579b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek                            ? "Null pointer argument in call to CFRetain"
47679b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek                            : "Null pointer argument in call to CFRelease";
47779b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek
47879b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek    RangedBugReport *report = new RangedBugReport(*BT, description, N);
47979b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek    report->addRange(CE->getArg(0)->getSourceRange());
48079b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek    BR.EmitReport(report);
48179b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek    return true;
48279b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek  }
48379b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek
48479b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek  return false;
48579b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek}
4861eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
4871eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
48879b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted KremenekGRSimpleAPICheck*
4891eb4433ac451dc16f4133a88af2d002ac26c58efMike Stumpclang::CreateAuditCFRetainRelease(ASTContext& Ctx, BugReporter& BR) {
49079b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek  return new AuditCFRetainRelease(Ctx, BR);
49179b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek}
49279b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek
49379b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek//===----------------------------------------------------------------------===//
49450e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek// Check for sending 'retain', 'release', or 'autorelease' directly to a Class.
49550e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek//===----------------------------------------------------------------------===//
49650e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek
49750e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremeneknamespace {
498ba5fb5a955c896815c439289fc51c03cf0635129Kovarththanan Rajaratnamclass ClassReleaseChecker :
49950e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek    public CheckerVisitor<ClassReleaseChecker> {
50050e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek  Selector releaseS;
50150e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek  Selector retainS;
50250e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek  Selector autoreleaseS;
50350e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek  Selector drainS;
50450e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek  BugType *BT;
50550e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenekpublic:
50650e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek  ClassReleaseChecker(ASTContext &Ctx)
50750e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek    : releaseS(GetNullarySelector("release", Ctx)),
50850e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek      retainS(GetNullarySelector("retain", Ctx)),
50950e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek      autoreleaseS(GetNullarySelector("autorelease", Ctx)),
51050e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek      drainS(GetNullarySelector("drain", Ctx)),
51150e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek      BT(0) {}
51250e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek
51350e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek  static void *getTag() { static int x = 0; return &x; }
51450e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek
51550e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek  void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME);
51650e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek};
51750e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek}
51850e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek
51950e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenekvoid ClassReleaseChecker::PreVisitObjCMessageExpr(CheckerContext &C,
52050e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek                                                  const ObjCMessageExpr *ME) {
52104badcf84c8d504d8491c7c7e29b58f52cb16640Douglas Gregor  ObjCInterfaceDecl *Class = 0;
52204badcf84c8d504d8491c7c7e29b58f52cb16640Douglas Gregor  switch (ME->getReceiverKind()) {
52304badcf84c8d504d8491c7c7e29b58f52cb16640Douglas Gregor  case ObjCMessageExpr::Class:
52404badcf84c8d504d8491c7c7e29b58f52cb16640Douglas Gregor    Class = ME->getClassReceiver()->getAs<ObjCInterfaceType>()->getDecl();
52504badcf84c8d504d8491c7c7e29b58f52cb16640Douglas Gregor    break;
52604badcf84c8d504d8491c7c7e29b58f52cb16640Douglas Gregor
52704badcf84c8d504d8491c7c7e29b58f52cb16640Douglas Gregor  case ObjCMessageExpr::SuperClass:
52804badcf84c8d504d8491c7c7e29b58f52cb16640Douglas Gregor    Class = ME->getSuperType()->getAs<ObjCInterfaceType>()->getDecl();
52904badcf84c8d504d8491c7c7e29b58f52cb16640Douglas Gregor    break;
53004badcf84c8d504d8491c7c7e29b58f52cb16640Douglas Gregor
53104badcf84c8d504d8491c7c7e29b58f52cb16640Douglas Gregor  case ObjCMessageExpr::Instance:
53204badcf84c8d504d8491c7c7e29b58f52cb16640Douglas Gregor  case ObjCMessageExpr::SuperInstance:
53350e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek    return;
53404badcf84c8d504d8491c7c7e29b58f52cb16640Douglas Gregor  }
53504badcf84c8d504d8491c7c7e29b58f52cb16640Douglas Gregor
53650e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek  Selector S = ME->getSelector();
537921ddc4e7ef35d77965205d91582c356cb54f5efBenjamin Kramer  if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS))
53850e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek    return;
53950e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek
54050e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek  if (!BT)
54150e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek    BT = new APIMisuse("message incorrectly sent to class instead of class "
54250e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek                       "instance");
54350e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek
54419d67b52b73c04ef8eb663980330a1de2b47c845Ted Kremenek  ExplodedNode *N = C.GenerateNode();
54519d67b52b73c04ef8eb663980330a1de2b47c845Ted Kremenek
54650e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek  if (!N)
54750e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek    return;
54850e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek
54950e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek  llvm::SmallString<200> buf;
55050e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek  llvm::raw_svector_ostream os(buf);
55150e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek
55250e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek  os << "The '" << S.getAsString() << "' message should be sent to instances "
55304badcf84c8d504d8491c7c7e29b58f52cb16640Douglas Gregor        "of class '" << Class->getName()
55450e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek     << "' and not the class directly";
55550e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek
55650e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek  RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
55750e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek  report->addRange(ME->getSourceRange());
55850e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek  C.EmitReport(report);
55950e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek}
56050e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek
56150e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek//===----------------------------------------------------------------------===//
56278d46242e3351484c2b773f5610beba5d316914bTed Kremenek// Check registration.
56379b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek//===----------------------------------------------------------------------===//
56478d46242e3351484c2b773f5610beba5d316914bTed Kremenek
5655ab128b02d3b10413fb30738ec9f401dcfb47252Zhongxing Xuvoid clang::RegisterAppleChecks(GRExprEngine& Eng, const Decl &D) {
56678d46242e3351484c2b773f5610beba5d316914bTed Kremenek  ASTContext& Ctx = Eng.getContext();
567cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek  BugReporter &BR = Eng.getBugReporter();
56878d46242e3351484c2b773f5610beba5d316914bTed Kremenek
56923ec48cd3369c8d7d1ab3c3f2226cfcffd2cd3d3Ted Kremenek  Eng.AddCheck(CreateBasicObjCFoundationChecks(Ctx, BR),
57078d46242e3351484c2b773f5610beba5d316914bTed Kremenek               Stmt::ObjCMessageExprClass);
5711eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump  Eng.AddCheck(CreateAuditCFNumberCreate(Ctx, BR), Stmt::CallExprClass);
57279b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek  Eng.AddCheck(CreateAuditCFRetainRelease(Ctx, BR), Stmt::CallExprClass);
5731eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
5745ab128b02d3b10413fb30738ec9f401dcfb47252Zhongxing Xu  RegisterNSErrorChecks(BR, Eng, D);
57554cb7ccc769a5e81a13812e08c21daf52a781262Ted Kremenek  RegisterNSAutoreleasePoolChecks(Eng);
57650e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek  Eng.registerCheck(new ClassReleaseChecker(Ctx));
57778d46242e3351484c2b773f5610beba5d316914bTed Kremenek}
578