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