1cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks//== ObjCContainersASTChecker.cpp - CoreFoundation containers API *- C++ -*-==//
2cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks//
3cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks//                     The LLVM Compiler Infrastructure
4cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks//
5cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks// This file is distributed under the University of Illinois Open Source
6cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks// License. See LICENSE.TXT for details.
7cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks//
8cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks//===----------------------------------------------------------------------===//
9cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks//
10cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks// An AST checker that looks for common pitfalls when using 'CFArray',
11cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks// 'CFDictionary', 'CFSet' APIs.
12cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks//
13cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks//===----------------------------------------------------------------------===//
14cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks#include "ClangSACheckers.h"
15cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks#include "clang/AST/StmtVisitor.h"
1655fc873017f10f6f566b182b70f6fc22aefa3464Chandler Carruth#include "clang/Analysis/AnalysisContext.h"
17cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks#include "clang/Basic/TargetInfo.h"
18cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
1955fc873017f10f6f566b182b70f6fc22aefa3464Chandler Carruth#include "clang/StaticAnalyzer/Core/Checker.h"
20cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
218fe83e1df954d72c0f4ffc15d20a5222ec151c21Benjamin Kramer#include "llvm/ADT/SmallString.h"
22cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks#include "llvm/Support/raw_ostream.h"
23cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks
24cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaksusing namespace clang;
25cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaksusing namespace ento;
26cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks
27cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaksnamespace {
28cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaksclass WalkAST : public StmtVisitor<WalkAST> {
29cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks  BugReporter &BR;
30cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks  AnalysisDeclContext* AC;
31cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks  ASTContext &ASTC;
32cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks  uint64_t PtrWidth;
33cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks
34cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks  /// Check if the type has pointer size (very conservative).
35cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks  inline bool isPointerSize(const Type *T) {
36cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks    if (!T)
37cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks      return true;
38cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks    if (T->isIncompleteType())
39cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks      return true;
40cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks    return (ASTC.getTypeSize(T) == PtrWidth);
41cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks  }
42cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks
43cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks  /// Check if the type is a pointer/array to pointer sized values.
44cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks  inline bool hasPointerToPointerSizedType(const Expr *E) {
45cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks    QualType T = E->getType();
46cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks
47cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks    // The type could be either a pointer or array.
48cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks    const Type *TP = T.getTypePtr();
49cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks    QualType PointeeT = TP->getPointeeType();
50f196a90b26479a2c67959c6715491763cbc8ade1Anna Zaks    if (!PointeeT.isNull()) {
51f196a90b26479a2c67959c6715491763cbc8ade1Anna Zaks      // If the type is a pointer to an array, check the size of the array
52f196a90b26479a2c67959c6715491763cbc8ade1Anna Zaks      // elements. To avoid false positives coming from assumption that the
53f196a90b26479a2c67959c6715491763cbc8ade1Anna Zaks      // values x and &x are equal when x is an array.
54f196a90b26479a2c67959c6715491763cbc8ade1Anna Zaks      if (const Type *TElem = PointeeT->getArrayElementTypeNoTypeQual())
55f196a90b26479a2c67959c6715491763cbc8ade1Anna Zaks        if (isPointerSize(TElem))
56f196a90b26479a2c67959c6715491763cbc8ade1Anna Zaks          return true;
57f196a90b26479a2c67959c6715491763cbc8ade1Anna Zaks
58f196a90b26479a2c67959c6715491763cbc8ade1Anna Zaks      // Else, check the pointee size.
59cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks      return isPointerSize(PointeeT.getTypePtr());
60f196a90b26479a2c67959c6715491763cbc8ade1Anna Zaks    }
61cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks
62cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks    if (const Type *TElem = TP->getArrayElementTypeNoTypeQual())
63cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks      return isPointerSize(TElem);
64cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks
65cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks    // The type must be an array/pointer type.
66cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks
67cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks    // This could be a null constant, which is allowed.
68cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks    if (E->isNullPointerConstant(ASTC, Expr::NPC_ValueDependentIsNull))
69cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks      return true;
70cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks    return false;
71cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks  }
72cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks
73cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zakspublic:
74cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks  WalkAST(BugReporter &br, AnalysisDeclContext* ac)
75cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks  : BR(br), AC(ac), ASTC(AC->getASTContext()),
76cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks    PtrWidth(ASTC.getTargetInfo().getPointerWidth(0)) {}
77cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks
78cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks  // Statement visitor methods.
79cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks  void VisitChildren(Stmt *S);
80cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks  void VisitStmt(Stmt *S) { VisitChildren(S); }
81cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks  void VisitCallExpr(CallExpr *CE);
82cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks};
83cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks} // end anonymous namespace
84cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks
85cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaksstatic StringRef getCalleeName(CallExpr *CE) {
86cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks  const FunctionDecl *FD = CE->getDirectCallee();
87cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks  if (!FD)
88cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks    return StringRef();
89cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks
90cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks  IdentifierInfo *II = FD->getIdentifier();
91cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks  if (!II)   // if no identifier, not a simple C function
92cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks    return StringRef();
93cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks
94cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks  return II->getName();
95cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks}
96cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks
97cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaksvoid WalkAST::VisitCallExpr(CallExpr *CE) {
98cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks  StringRef Name = getCalleeName(CE);
99cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks  if (Name.empty())
100cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks    return;
101cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks
102cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks  const Expr *Arg = 0;
103bc9e5ffb0d0757238c071764e4bc1fc8a1521097Jordan Rose  unsigned ArgNum;
104cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks
105cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks  if (Name.equals("CFArrayCreate") || Name.equals("CFSetCreate")) {
106441ee1dfa5ff8d904ad07dc3b7837c44d9f173ebTed Kremenek    if (CE->getNumArgs() != 4)
107441ee1dfa5ff8d904ad07dc3b7837c44d9f173ebTed Kremenek      return;
108cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks    ArgNum = 1;
109cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks    Arg = CE->getArg(ArgNum)->IgnoreParenCasts();
110cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks    if (hasPointerToPointerSizedType(Arg))
111cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks        return;
112bc9e5ffb0d0757238c071764e4bc1fc8a1521097Jordan Rose  } else if (Name.equals("CFDictionaryCreate")) {
113441ee1dfa5ff8d904ad07dc3b7837c44d9f173ebTed Kremenek    if (CE->getNumArgs() != 6)
114441ee1dfa5ff8d904ad07dc3b7837c44d9f173ebTed Kremenek      return;
115cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks    // Check first argument.
116cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks    ArgNum = 1;
117cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks    Arg = CE->getArg(ArgNum)->IgnoreParenCasts();
118cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks    if (hasPointerToPointerSizedType(Arg)) {
119cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks      // Check second argument.
120cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks      ArgNum = 2;
121cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks      Arg = CE->getArg(ArgNum)->IgnoreParenCasts();
122cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks      if (hasPointerToPointerSizedType(Arg))
123cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks        // Both are good, return.
124cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks        return;
125cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks    }
126cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks  }
127cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks
128bc9e5ffb0d0757238c071764e4bc1fc8a1521097Jordan Rose  if (Arg) {
129cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks    assert(ArgNum == 1 || ArgNum == 2);
130cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks
131bc9e5ffb0d0757238c071764e4bc1fc8a1521097Jordan Rose    SmallString<64> BufName;
132cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks    llvm::raw_svector_ostream OsName(BufName);
133cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks    OsName << " Invalid use of '" << Name << "'" ;
134cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks
135f7ccbad5d9949e7ddd1cbef43d482553b811e026Dylan Noblesmith    SmallString<256> Buf;
136cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks    llvm::raw_svector_ostream Os(Buf);
1372ab012a6de2b2769ec7ad99c4b61788cc5175d17Ted Kremenek    // Use "second" and "third" since users will expect 1-based indexing
1382ab012a6de2b2769ec7ad99c4b61788cc5175d17Ted Kremenek    // for parameter names when mentioned in prose.
1392ab012a6de2b2769ec7ad99c4b61788cc5175d17Ted Kremenek    Os << " The "<< ((ArgNum == 1) ? "second" : "third") << " argument to '"
140cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks        << Name << "' must be a C array of pointer-sized values, not '"
141cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks        << Arg->getType().getAsString() << "'";
142cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks
143cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks    SourceRange R = Arg->getSourceRange();
144cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks    PathDiagnosticLocation CELoc =
145cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks        PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
14607189521a15d9c088216b943649cb9fe231cbb57Ted Kremenek    BR.EmitBasicReport(AC->getDecl(),
1476fd4505ad67a186da8cc26fdb493c93fe4937555Ted Kremenek                       OsName.str(), categories::CoreFoundationObjectiveC,
148cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks                       Os.str(), CELoc, &R, 1);
149cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks  }
150cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks
151cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks  // Recurse and check children.
152cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks  VisitChildren(CE);
153cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks}
154cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks
155cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaksvoid WalkAST::VisitChildren(Stmt *S) {
156cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks  for (Stmt::child_iterator I = S->child_begin(), E = S->child_end(); I!=E; ++I)
157cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks    if (Stmt *child = *I)
158cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks      Visit(child);
159cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks}
160cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks
161cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaksnamespace {
162cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaksclass ObjCContainersASTChecker : public Checker<check::ASTCodeBody> {
163cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zakspublic:
164cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks
165cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks  void checkASTCodeBody(const Decl *D, AnalysisManager& Mgr,
166cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks                        BugReporter &BR) const {
167cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks    WalkAST walker(BR, Mgr.getAnalysisDeclContext(D));
168cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks    walker.Visit(D->getBody());
169cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks  }
170cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks};
171cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks}
172cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks
173cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaksvoid ento::registerObjCContainersASTChecker(CheckerManager &mgr) {
174cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks  mgr.registerChecker<ObjCContainersASTChecker>();
175cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks}
176