clang  6.0.0svn
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.
69  return static_cast<bool>(
71  }
72 
73 public:
74  WalkAST(BugReporter &br, const CheckerBase *checker, AnalysisDeclContext *ac)
75  : BR(br), Checker(checker), AC(ac), ASTC(AC->getASTContext()),
76  PtrWidth(ASTC.getTargetInfo().getPointerWidth(0)) {}
77 
78  // Statement visitor methods.
79  void VisitChildren(Stmt *S);
80  void VisitStmt(Stmt *S) { VisitChildren(S); }
81  void VisitCallExpr(CallExpr *CE);
82 };
83 } // end anonymous namespace
84 
85 static StringRef getCalleeName(CallExpr *CE) {
86  const FunctionDecl *FD = CE->getDirectCallee();
87  if (!FD)
88  return StringRef();
89 
90  IdentifierInfo *II = FD->getIdentifier();
91  if (!II) // if no identifier, not a simple C function
92  return StringRef();
93 
94  return II->getName();
95 }
96 
97 void WalkAST::VisitCallExpr(CallExpr *CE) {
98  StringRef Name = getCalleeName(CE);
99  if (Name.empty())
100  return;
101 
102  const Expr *Arg = nullptr;
103  unsigned ArgNum;
104 
105  if (Name.equals("CFArrayCreate") || Name.equals("CFSetCreate")) {
106  if (CE->getNumArgs() != 4)
107  return;
108  ArgNum = 1;
109  Arg = CE->getArg(ArgNum)->IgnoreParenCasts();
110  if (hasPointerToPointerSizedType(Arg))
111  return;
112  } else if (Name.equals("CFDictionaryCreate")) {
113  if (CE->getNumArgs() != 6)
114  return;
115  // Check first argument.
116  ArgNum = 1;
117  Arg = CE->getArg(ArgNum)->IgnoreParenCasts();
118  if (hasPointerToPointerSizedType(Arg)) {
119  // Check second argument.
120  ArgNum = 2;
121  Arg = CE->getArg(ArgNum)->IgnoreParenCasts();
122  if (hasPointerToPointerSizedType(Arg))
123  // Both are good, return.
124  return;
125  }
126  }
127 
128  if (Arg) {
129  assert(ArgNum == 1 || ArgNum == 2);
130 
131  SmallString<64> BufName;
132  llvm::raw_svector_ostream OsName(BufName);
133  OsName << " Invalid use of '" << Name << "'" ;
134 
135  SmallString<256> Buf;
136  llvm::raw_svector_ostream Os(Buf);
137  // Use "second" and "third" since users will expect 1-based indexing
138  // for parameter names when mentioned in prose.
139  Os << " The "<< ((ArgNum == 1) ? "second" : "third") << " argument to '"
140  << Name << "' must be a C array of pointer-sized values, not '"
141  << Arg->getType().getAsString() << "'";
142 
143  PathDiagnosticLocation CELoc =
145  BR.EmitBasicReport(AC->getDecl(), Checker, OsName.str(),
146  categories::CoreFoundationObjectiveC, Os.str(), CELoc,
147  Arg->getSourceRange());
148  }
149 
150  // Recurse and check children.
151  VisitChildren(CE);
152 }
153 
154 void WalkAST::VisitChildren(Stmt *S) {
155  for (Stmt *Child : S->children())
156  if (Child)
157  Visit(Child);
158 }
159 
160 namespace {
161 class ObjCContainersASTChecker : public Checker<check::ASTCodeBody> {
162 public:
163 
164  void checkASTCodeBody(const Decl *D, AnalysisManager& Mgr,
165  BugReporter &BR) const {
166  WalkAST walker(BR, this, Mgr.getAnalysisDeclContext(D));
167  walker.Visit(D->getBody());
168  }
169 };
170 }
171 
172 void ento::registerObjCContainersASTChecker(CheckerManager &mgr) {
173  mgr.registerChecker<ObjCContainersASTChecker>();
174 }
An instance of this class is created to represent a function declaration or definition.
Definition: Decl.h:1697
const char *const CoreFoundationObjectiveC
A (possibly-)qualified type.
Definition: Type.h:653
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition: Expr.h:2278
virtual Stmt * getBody() const
getBody - If this Decl represents a declaration for a body of code, such as a function or method defi...
Definition: DeclBase.h:974
Stmt - This represents one statement.
Definition: Stmt.h:66
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
Definition: Expr.h:2266
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee...
Definition: Type.cpp:456
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:86
The base class of the type hierarchy.
Definition: Type.h:1353
IdentifierInfo * getIdentifier() const
getIdentifier - Get the identifier that names this declaration, if there is one.
Definition: Decl.h:265
One of these records is kept for each identifier that is lexed.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:149
AnalysisDeclContext contains the context data for the function or method under analysis.
child_range children()
Definition: Stmt.cpp:226
std::string getAsString() const
Definition: Type.h:979
Expr * IgnoreParenCasts() LLVM_READONLY
IgnoreParenCasts - Ignore parentheses and casts.
Definition: Expr.cpp:2465
const Type * getTypePtr() const
Retrieves a pointer to the underlying (unqualified) type.
Definition: Type.h:5720
AnalysisDeclContext * getAnalysisDeclContext(const Decl *D)
Expr - This represents one expression.
Definition: Expr.h:106
const FunctionProtoType * T
Specifies that a value-dependent expression of integral or dependent type should be considered a null...
Definition: Expr.h:702
QualType getType() const
Definition: Expr.h:128
bool isNull() const
Return true if this QualType doesn&#39;t point to a type yet.
Definition: Type.h:719
BugReporter is a utility class for generating PathDiagnostics for analysis.
Definition: BugReporter.h:403
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.
NullPointerConstantKind isNullPointerConstant(ASTContext &Ctx, NullPointerConstantValueDependence NPC) const
isNullPointerConstant - C99 6.3.2.3p3 - Test if this reduces down to a Null pointer constant...
Definition: Expr.cpp:3275
void EmitBasicReport(const Decl *DeclWithIssue, const CheckerBase *Checker, StringRef BugName, StringRef BugCategory, StringRef BugStr, PathDiagnosticLocation Loc, ArrayRef< SourceRange > Ranges=None)
StmtVisitor - This class implements a simple visitor for Stmt subclasses.
Definition: StmtVisitor.h:186
const Decl * getDecl() const
StringRef getName() const
Return the actual identifier string.
Dataflow Directional Tag Classes.
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return 0.
Definition: Expr.cpp:1216
const Type * getArrayElementTypeNoTypeQual() const
If this is an array type, return the element type of the array, potentially with type qualifiers miss...
Definition: Type.cpp:229
uint64_t getTypeSize(QualType T) const
Return the size of the specified (complete) type T, in bits.
Definition: ASTContext.h:2007
bool isIncompleteType(NamedDecl **Def=nullptr) const
Types are partitioned into 3 broad categories (C99 6.2.5p1): object types, function types...
Definition: Type.cpp:1986
SourceManager & getSourceManager()
Definition: BugReporter.h:463
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition: Stmt.cpp:265
Defines the clang::TargetInfo interface.
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition: Expr.h:2209