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; 30651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines const CheckerBase *Checker; 31cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks AnalysisDeclContext* AC; 32cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks ASTContext &ASTC; 33cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks uint64_t PtrWidth; 34cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks 35cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks /// Check if the type has pointer size (very conservative). 36cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks inline bool isPointerSize(const Type *T) { 37cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks if (!T) 38cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks return true; 39cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks if (T->isIncompleteType()) 40cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks return true; 41cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks return (ASTC.getTypeSize(T) == PtrWidth); 42cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks } 43cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks 44cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks /// Check if the type is a pointer/array to pointer sized values. 45cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks inline bool hasPointerToPointerSizedType(const Expr *E) { 46cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks QualType T = E->getType(); 47cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks 48cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks // The type could be either a pointer or array. 49cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks const Type *TP = T.getTypePtr(); 50cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks QualType PointeeT = TP->getPointeeType(); 51f196a90b26479a2c67959c6715491763cbc8ade1Anna Zaks if (!PointeeT.isNull()) { 52f196a90b26479a2c67959c6715491763cbc8ade1Anna Zaks // If the type is a pointer to an array, check the size of the array 53f196a90b26479a2c67959c6715491763cbc8ade1Anna Zaks // elements. To avoid false positives coming from assumption that the 54f196a90b26479a2c67959c6715491763cbc8ade1Anna Zaks // values x and &x are equal when x is an array. 55f196a90b26479a2c67959c6715491763cbc8ade1Anna Zaks if (const Type *TElem = PointeeT->getArrayElementTypeNoTypeQual()) 56f196a90b26479a2c67959c6715491763cbc8ade1Anna Zaks if (isPointerSize(TElem)) 57f196a90b26479a2c67959c6715491763cbc8ade1Anna Zaks return true; 58f196a90b26479a2c67959c6715491763cbc8ade1Anna Zaks 59f196a90b26479a2c67959c6715491763cbc8ade1Anna Zaks // Else, check the pointee size. 60cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks return isPointerSize(PointeeT.getTypePtr()); 61f196a90b26479a2c67959c6715491763cbc8ade1Anna Zaks } 62cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks 63cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks if (const Type *TElem = TP->getArrayElementTypeNoTypeQual()) 64cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks return isPointerSize(TElem); 65cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks 66cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks // The type must be an array/pointer type. 67cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks 68cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks // This could be a null constant, which is allowed. 694967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return static_cast<bool>( 704967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar E->isNullPointerConstant(ASTC, Expr::NPC_ValueDependentIsNull)); 71cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks } 72cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks 73cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zakspublic: 74651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines WalkAST(BugReporter &br, const CheckerBase *checker, AnalysisDeclContext *ac) 75651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines : BR(br), Checker(checker), AC(ac), ASTC(AC->getASTContext()), 76651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines 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 1026bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines const Expr *Arg = nullptr; 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 PathDiagnosticLocation CELoc = 144cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); 145651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines BR.EmitBasicReport(AC->getDecl(), Checker, OsName.str(), 146651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines categories::CoreFoundationObjectiveC, Os.str(), CELoc, 147651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines Arg->getSourceRange()); 148cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks } 149cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks 150cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks // Recurse and check children. 151cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks VisitChildren(CE); 152cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks} 153cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks 154cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaksvoid WalkAST::VisitChildren(Stmt *S) { 15587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar for (Stmt *Child : S->children()) 15687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar if (Child) 15787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar Visit(Child); 158cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks} 159cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks 160cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaksnamespace { 161cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaksclass ObjCContainersASTChecker : public Checker<check::ASTCodeBody> { 162cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zakspublic: 163cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks 164cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks void checkASTCodeBody(const Decl *D, AnalysisManager& Mgr, 165cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks BugReporter &BR) const { 166651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines WalkAST walker(BR, this, Mgr.getAnalysisDeclContext(D)); 167cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks walker.Visit(D->getBody()); 168cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks } 169cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks}; 170cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks} 171cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks 172cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaksvoid ento::registerObjCContainersASTChecker(CheckerManager &mgr) { 173cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks mgr.registerChecker<ObjCContainersASTChecker>(); 174cbd273387a61409f179fcfe8460a8733fcf8f872Anna Zaks} 175