clang  3.7.0
ObjCContainersASTChecker.cpp
Go to the documentation of this file.
1 //== ObjCContainersASTChecker.cpp - CoreFoundation containers API *- C++ -*-==//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // An AST checker that looks for common pitfalls when using 'CFArray',
11 // 'CFDictionary', 'CFSet' APIs.
12 //
13 //===----------------------------------------------------------------------===//
14 #include "ClangSACheckers.h"
15 #include "clang/AST/StmtVisitor.h"
17 #include "clang/Basic/TargetInfo.h"
21 #include "llvm/ADT/SmallString.h"
22 #include "llvm/Support/raw_ostream.h"
23 
24 using namespace clang;
25 using namespace ento;
26 
27 namespace {
28 class WalkAST : public StmtVisitor<WalkAST> {
29  BugReporter &BR;
30  const CheckerBase *Checker;
32  ASTContext &ASTC;
33  uint64_t PtrWidth;
34 
35  /// Check if the type has pointer size (very conservative).
36  inline bool isPointerSize(const Type *T) {
37  if (!T)
38  return true;
39  if (T->isIncompleteType())
40  return true;
41  return (ASTC.getTypeSize(T) == PtrWidth);
42  }
43 
44  /// Check if the type is a pointer/array to pointer sized values.
45  inline bool hasPointerToPointerSizedType(const Expr *E) {
46  QualType T = E->getType();
47 
48  // The type could be either a pointer or array.
49  const Type *TP = T.getTypePtr();
50  QualType PointeeT = TP->getPointeeType();
51  if (!PointeeT.isNull()) {
52  // If the type is a pointer to an array, check the size of the array
53  // elements. To avoid false positives coming from assumption that the
54  // values x and &x are equal when x is an array.
55  if (const Type *TElem = PointeeT->getArrayElementTypeNoTypeQual())
56  if (isPointerSize(TElem))
57  return true;
58 
59  // Else, check the pointee size.
60  return isPointerSize(PointeeT.getTypePtr());
61  }
62 
63  if (const Type *TElem = TP->getArrayElementTypeNoTypeQual())
64  return isPointerSize(TElem);
65 
66  // The type must be an array/pointer type.
67 
68  // This could be a null constant, which is allowed.
70  return true;
71  return false;
72  }
73 
74 public:
75  WalkAST(BugReporter &br, const CheckerBase *checker, AnalysisDeclContext *ac)
76  : BR(br), Checker(checker), AC(ac), ASTC(AC->getASTContext()),
77  PtrWidth(ASTC.getTargetInfo().getPointerWidth(0)) {}
78 
79  // Statement visitor methods.
80  void VisitChildren(Stmt *S);
81  void VisitStmt(Stmt *S) { VisitChildren(S); }
82  void VisitCallExpr(CallExpr *CE);
83 };
84 } // end anonymous namespace
85 
86 static StringRef getCalleeName(CallExpr *CE) {
87  const FunctionDecl *FD = CE->getDirectCallee();
88  if (!FD)
89  return StringRef();
90 
91  IdentifierInfo *II = FD->getIdentifier();
92  if (!II) // if no identifier, not a simple C function
93  return StringRef();
94 
95  return II->getName();
96 }
97 
98 void WalkAST::VisitCallExpr(CallExpr *CE) {
99  StringRef Name = getCalleeName(CE);
100  if (Name.empty())
101  return;
102 
103  const Expr *Arg = nullptr;
104  unsigned ArgNum;
105 
106  if (Name.equals("CFArrayCreate") || Name.equals("CFSetCreate")) {
107  if (CE->getNumArgs() != 4)
108  return;
109  ArgNum = 1;
110  Arg = CE->getArg(ArgNum)->IgnoreParenCasts();
111  if (hasPointerToPointerSizedType(Arg))
112  return;
113  } else if (Name.equals("CFDictionaryCreate")) {
114  if (CE->getNumArgs() != 6)
115  return;
116  // Check first argument.
117  ArgNum = 1;
118  Arg = CE->getArg(ArgNum)->IgnoreParenCasts();
119  if (hasPointerToPointerSizedType(Arg)) {
120  // Check second argument.
121  ArgNum = 2;
122  Arg = CE->getArg(ArgNum)->IgnoreParenCasts();
123  if (hasPointerToPointerSizedType(Arg))
124  // Both are good, return.
125  return;
126  }
127  }
128 
129  if (Arg) {
130  assert(ArgNum == 1 || ArgNum == 2);
131 
132  SmallString<64> BufName;
133  llvm::raw_svector_ostream OsName(BufName);
134  OsName << " Invalid use of '" << Name << "'" ;
135 
136  SmallString<256> Buf;
137  llvm::raw_svector_ostream Os(Buf);
138  // Use "second" and "third" since users will expect 1-based indexing
139  // for parameter names when mentioned in prose.
140  Os << " The "<< ((ArgNum == 1) ? "second" : "third") << " argument to '"
141  << Name << "' must be a C array of pointer-sized values, not '"
142  << Arg->getType().getAsString() << "'";
143 
144  PathDiagnosticLocation CELoc =
145  PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
146  BR.EmitBasicReport(AC->getDecl(), Checker, OsName.str(),
147  categories::CoreFoundationObjectiveC, Os.str(), CELoc,
148  Arg->getSourceRange());
149  }
150 
151  // Recurse and check children.
152  VisitChildren(CE);
153 }
154 
155 void WalkAST::VisitChildren(Stmt *S) {
156  for (Stmt *Child : S->children())
157  if (Child)
158  Visit(Child);
159 }
160 
161 namespace {
162 class ObjCContainersASTChecker : public Checker<check::ASTCodeBody> {
163 public:
164 
165  void checkASTCodeBody(const Decl *D, AnalysisManager& Mgr,
166  BugReporter &BR) const {
167  WalkAST walker(BR, this, Mgr.getAnalysisDeclContext(D));
168  walker.Visit(D->getBody());
169  }
170 };
171 }
172 
173 void ento::registerObjCContainersASTChecker(CheckerManager &mgr) {
174  mgr.registerChecker<ObjCContainersASTChecker>();
175 }
const char *const CoreFoundationObjectiveC
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition: Expr.h:2216
IdentifierInfo * getIdentifier() const
Definition: Decl.h:163
std::string getAsString() const
Definition: Type.h:897
NullPointerConstantKind isNullPointerConstant(ASTContext &Ctx, NullPointerConstantValueDependence NPC) const
Definition: Expr.cpp:3225
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:89
Expr * IgnoreParenCasts() LLVM_READONLY
Definition: Expr.cpp:2439
bool isIncompleteType(NamedDecl **Def=nullptr) const
Def If non-NULL, and the type refers to some kind of declaration that can be completed (such as a C s...
Definition: Type.cpp:1869
AnalysisDeclContext * getAnalysisDeclContext(const Decl *D)
QualType getPointeeType() const
Definition: Type.cpp:414
StringRef getName() const
Return the actual identifier string.
Specifies that a value-dependent expression of integral or dependent type should be considered a null...
Definition: Expr.h:662
static StringRef getCalleeName(CallExpr *CE)
static PathDiagnosticLocation createBegin(const Decl *D, const SourceManager &SM)
Create a location for the beginning of the declaration.
CHECKER * registerChecker()
Used to register checkers.
const Type * getTypePtr() const
Definition: Type.h:5016
virtual Stmt * getBody() const
Definition: DeclBase.h:840
const Type * getArrayElementTypeNoTypeQual() const
Definition: Type.cpp:190
QualType getType() const
Definition: Expr.h:125
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return 0.
Definition: Expr.cpp:1184
unsigned getNumArgs() const
Definition: Expr.h:2205
Defines the clang::TargetInfo interface.
bool isNull() const
isNull - Return true if this QualType doesn't point to a type yet.
Definition: Type.h:633