MacOSXAPIChecker.cpp revision 226633
119026Sjulian// MacOSXAPIChecker.h - Checks proper use of various MacOS X APIs --*- C++ -*-// 267627Sasmodai// 319026Sjulian// The LLVM Compiler Infrastructure 419026Sjulian// 519026Sjulian// This file is distributed under the University of Illinois Open Source 619026Sjulian// License. See LICENSE.TXT for details. 719026Sjulian// 819026Sjulian//===----------------------------------------------------------------------===// 919026Sjulian// 1019026Sjulian// This defines MacOSXAPIChecker, which is an assortment of checks on calls 1119026Sjulian// to various, widely used Mac OS X functions. 1219026Sjulian// 1319026Sjulian// FIXME: What's currently in BasicObjCFoundationChecks.cpp should be migrated 1419026Sjulian// to here, using the new Checker interface. 1519026Sjulian// 1619026Sjulian//===----------------------------------------------------------------------===// 1719026Sjulian 1819026Sjulian#include "ClangSACheckers.h" 1919026Sjulian#include "clang/StaticAnalyzer/Core/Checker.h" 2019026Sjulian#include "clang/StaticAnalyzer/Core/CheckerManager.h" 2119026Sjulian#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 2219026Sjulian#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 2319026Sjulian#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" 2419026Sjulian#include "clang/Basic/TargetInfo.h" 2519026Sjulian#include "llvm/ADT/SmallString.h" 2660446Sphantom#include "llvm/ADT/StringSwitch.h" 27236712Smav#include "llvm/Support/raw_ostream.h" 28204704Smav 2979538Sruusing namespace clang; 305884Sdgusing namespace ento; 3140439Sken 32204704Smavnamespace { 335884Sdgclass MacOSXAPIChecker : public Checker< check::PreStmt<CallExpr> > { 3456467Sasmodai mutable llvm::OwningPtr<BugType> BT_dispatchOnce; 35204704Smav 3656467Sasmodaipublic: 3756467Sasmodai void checkPreStmt(const CallExpr *CE, CheckerContext &C) const; 3856467Sasmodai 3956467Sasmodai void CheckDispatchOnce(CheckerContext &C, const CallExpr *CE, 4056467Sasmodai const IdentifierInfo *FI) const; 4156467Sasmodai 4270466Sru typedef void (MacOSXAPIChecker::*SubChecker)(CheckerContext &, 4370466Sru const CallExpr *, 4470466Sru const IdentifierInfo *) const; 4570466Sru}; 46236712Smav} //end anonymous namespace 4770466Sru 4870466Sru//===----------------------------------------------------------------------===// 4970466Sru// dispatch_once and dispatch_once_f 5070466Sru//===----------------------------------------------------------------------===// 5170466Sru 525884Sdgvoid MacOSXAPIChecker::CheckDispatchOnce(CheckerContext &C, const CallExpr *CE, 53204704Smav const IdentifierInfo *FI) const { 54204704Smav if (CE->getNumArgs() < 1) 5540439Sken return; 5640439Sken 5740439Sken // Check if the first argument is stack allocated. If so, issue a warning 58204704Smav // because that's likely to be bad news. 59204704Smav const ProgramState *state = C.getState(); 6040439Sken const MemRegion *R = state->getSVal(CE->getArg(0)).getAsRegion(); 6140439Sken if (!R || !isa<StackSpaceRegion>(R->getMemorySpace())) 62204704Smav return; 63204704Smav 6457676Ssheldonh ExplodedNode *N = C.generateSink(state); 65204704Smav if (!N) 66204704Smav return; 67117011Sru 6840439Sken if (!BT_dispatchOnce) 69204704Smav BT_dispatchOnce.reset(new BugType("Improper use of 'dispatch_once'", 705884Sdg "Mac OS X API")); 7140439Sken 72204704Smav llvm::SmallString<256> S; 7340439Sken llvm::raw_svector_ostream os(S); 7440439Sken os << "Call to '" << FI->getName() << "' uses"; 7540439Sken if (const VarRegion *VR = dyn_cast<VarRegion>(R)) 76236712Smav os << " the local variable '" << VR->getDecl()->getName() << '\''; 77204704Smav else 78204704Smav os << " stack allocated memory"; 79141846Sru os << " for the predicate value. Using such transient memory for " 8040439Sken "the predicate is potentially dangerous."; 81117011Sru if (isa<VarRegion>(R) && isa<StackLocalsSpaceRegion>(R->getMemorySpace())) 8240439Sken os << " Perhaps you intended to declare the variable as 'static'?"; 8340439Sken 8440439Sken BugReport *report = new BugReport(*BT_dispatchOnce, os.str(), N); 85117011Sru report->addRange(CE->getArg(0)->getSourceRange()); 86204704Smav C.EmitReport(report); 8740439Sken} 88117011Sru 89204704Smav//===----------------------------------------------------------------------===// 90204704Smav// Central dispatch function. 91117011Sru//===----------------------------------------------------------------------===// 9240439Sken 9340439Skenvoid MacOSXAPIChecker::checkPreStmt(const CallExpr *CE, 9440439Sken CheckerContext &C) const { 9540439Sken // FIXME: This sort of logic is common to several checkers, including 9640439Sken // UnixAPIChecker, PthreadLockChecker, and CStringChecker. Should refactor. 97117011Sru const ProgramState *state = C.getState(); 98117011Sru const Expr *Callee = CE->getCallee(); 9940439Sken const FunctionDecl *Fn = state->getSVal(Callee).getAsFunctionDecl(); 100117011Sru 101117011Sru if (!Fn) 102117011Sru return; 103117011Sru 10440439Sken const IdentifierInfo *FI = Fn->getIdentifier(); 10540439Sken if (!FI) 106131530Sru return; 107141846Sru 10840439Sken SubChecker SC = 10940439Sken llvm::StringSwitch<SubChecker>(FI->getName()) 11040439Sken .Cases("dispatch_once", "dispatch_once_f", 11140439Sken &MacOSXAPIChecker::CheckDispatchOnce) 112117011Sru .Default(NULL); 113117011Sru 11440439Sken if (SC) 115141846Sru (this->*SC)(C, CE, FI); 11640439Sken} 11740439Sken 11840439Sken//===----------------------------------------------------------------------===// 11940439Sken// Registration. 12040439Sken//===----------------------------------------------------------------------===// 12140439Sken 122117011Sruvoid ento::registerMacOSXAPIChecker(CheckerManager &mgr) { 123204704Smav mgr.registerChecker<MacOSXAPIChecker>(); 124204704Smav} 125204704Smav