ObjCContainersASTChecker.cpp revision 8fe83e1df954d72c0f4ffc15d20a5222ec151c21
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/Analysis/AnalysisContext.h" 16cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks#include "clang/AST/StmtVisitor.h" 17cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks#include "clang/Basic/TargetInfo.h" 18cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks#include "clang/StaticAnalyzer/Core/Checker.h" 19cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.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 static const unsigned InvalidArgIndex = UINT_MAX; 35cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks 36cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks /// Check if the type has pointer size (very conservative). 37cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks inline bool isPointerSize(const Type *T) { 38cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks if (!T) 39cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks return true; 40cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks if (T->isIncompleteType()) 41cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks return true; 42cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks return (ASTC.getTypeSize(T) == PtrWidth); 43cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks } 44cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks 45cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks /// Check if the type is a pointer/array to pointer sized values. 46cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks inline bool hasPointerToPointerSizedType(const Expr *E) { 47cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks QualType T = E->getType(); 48cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks 49cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks // The type could be either a pointer or array. 50cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks const Type *TP = T.getTypePtr(); 51cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks QualType PointeeT = TP->getPointeeType(); 52f196a90b26479a2c67959c6715491763cbc8ade1Anna Zaks if (!PointeeT.isNull()) { 53f196a90b26479a2c67959c6715491763cbc8ade1Anna Zaks // If the type is a pointer to an array, check the size of the array 54f196a90b26479a2c67959c6715491763cbc8ade1Anna Zaks // elements. To avoid false positives coming from assumption that the 55f196a90b26479a2c67959c6715491763cbc8ade1Anna Zaks // values x and &x are equal when x is an array. 56f196a90b26479a2c67959c6715491763cbc8ade1Anna Zaks if (const Type *TElem = PointeeT->getArrayElementTypeNoTypeQual()) 57f196a90b26479a2c67959c6715491763cbc8ade1Anna Zaks if (isPointerSize(TElem)) 58f196a90b26479a2c67959c6715491763cbc8ade1Anna Zaks return true; 59f196a90b26479a2c67959c6715491763cbc8ade1Anna Zaks 60f196a90b26479a2c67959c6715491763cbc8ade1Anna Zaks // Else, check the pointee size. 61cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks return isPointerSize(PointeeT.getTypePtr()); 62f196a90b26479a2c67959c6715491763cbc8ade1Anna Zaks } 63cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks 64cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks if (const Type *TElem = TP->getArrayElementTypeNoTypeQual()) 65cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks return isPointerSize(TElem); 66cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks 67cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks // The type must be an array/pointer type. 68cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks 69cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks // This could be a null constant, which is allowed. 70cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks if (E->isNullPointerConstant(ASTC, Expr::NPC_ValueDependentIsNull)) 71cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks return true; 72cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks return false; 73cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks } 74cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks 75cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zakspublic: 76cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks WalkAST(BugReporter &br, AnalysisDeclContext* ac) 77cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks : BR(br), AC(ac), ASTC(AC->getASTContext()), 78cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks PtrWidth(ASTC.getTargetInfo().getPointerWidth(0)) {} 79cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks 80cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks // Statement visitor methods. 81cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks void VisitChildren(Stmt *S); 82cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks void VisitStmt(Stmt *S) { VisitChildren(S); } 83cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks void VisitCallExpr(CallExpr *CE); 84cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks}; 85cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks} // end anonymous namespace 86cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks 87cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaksstatic StringRef getCalleeName(CallExpr *CE) { 88cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks const FunctionDecl *FD = CE->getDirectCallee(); 89cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks if (!FD) 90cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks return StringRef(); 91cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks 92cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks IdentifierInfo *II = FD->getIdentifier(); 93cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks if (!II) // if no identifier, not a simple C function 94cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks return StringRef(); 95cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks 96cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks return II->getName(); 97cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks} 98cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks 99cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaksvoid WalkAST::VisitCallExpr(CallExpr *CE) { 100cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks StringRef Name = getCalleeName(CE); 101cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks if (Name.empty()) 102cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks return; 103cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks 104cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks const Expr *Arg = 0; 105cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks unsigned ArgNum = InvalidArgIndex; 106cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks 107cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks if (Name.equals("CFArrayCreate") || Name.equals("CFSetCreate")) { 108cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks ArgNum = 1; 109cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks Arg = CE->getArg(ArgNum)->IgnoreParenCasts(); 110cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks if (hasPointerToPointerSizedType(Arg)) 111cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks return; 112cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks } 113cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks 114cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks if (Arg == 0 && Name.equals("CFDictionaryCreate")) { 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 128cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks if (ArgNum != InvalidArgIndex) { 129cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks assert(ArgNum == 1 || ArgNum == 2); 130cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks 131cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks llvm::SmallString<256> BufName; 132cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks llvm::raw_svector_ostream OsName(BufName); 133cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks assert(ArgNum == 1 || ArgNum == 2); 134cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks OsName << " Invalid use of '" << Name << "'" ; 135cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks 136cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks llvm::SmallString<256> Buf; 137cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks llvm::raw_svector_ostream Os(Buf); 138cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks Os << " The "<< ((ArgNum == 1) ? "first" : "second") << " argument to '" 139cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks << Name << "' must be a C array of pointer-sized values, not '" 140cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks << Arg->getType().getAsString() << "'"; 141cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks 142cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks SourceRange R = Arg->getSourceRange(); 143cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks PathDiagnosticLocation CELoc = 144cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); 1451efcc42c922204d6797a70d90d3c350882f3c098Anna Zaks BR.EmitBasicReport(OsName.str(), "Core Foundation/Objective-C", 146cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks Os.str(), CELoc, &R, 1); 147cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks } 148cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks 149cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks // Recurse and check children. 150cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks VisitChildren(CE); 151cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks} 152cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks 153cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaksvoid WalkAST::VisitChildren(Stmt *S) { 154cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks for (Stmt::child_iterator I = S->child_begin(), E = S->child_end(); I!=E; ++I) 155cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks if (Stmt *child = *I) 156cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks Visit(child); 157cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks} 158cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks 159cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaksnamespace { 160cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaksclass ObjCContainersASTChecker : public Checker<check::ASTCodeBody> { 161cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zakspublic: 162cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks 163cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks void checkASTCodeBody(const Decl *D, AnalysisManager& Mgr, 164cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks BugReporter &BR) const { 165cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks WalkAST walker(BR, Mgr.getAnalysisDeclContext(D)); 166cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks walker.Visit(D->getBody()); 167cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks } 168cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks}; 169cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks} 170cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks 171cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaksvoid ento::registerObjCContainersASTChecker(CheckerManager &mgr) { 172cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks mgr.registerChecker<ObjCContainersASTChecker>(); 173cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks} 174