MacOSXAPIChecker.cpp revision b805c8ff133ef0c62df032fa711d6b13c5afd7f4
1df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek// MacOSXAPIChecker.h - Checks proper use of various MacOS X APIs --*- C++ -*-// 2df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek// 3df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek// The LLVM Compiler Infrastructure 4df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek// 5df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek// This file is distributed under the University of Illinois Open Source 6df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek// License. See LICENSE.TXT for details. 7df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek// 8df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek//===----------------------------------------------------------------------===// 9df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek// 10df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek// This defines MacOSXAPIChecker, which is an assortment of checks on calls 11df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek// to various, widely used Mac OS X functions. 12df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek// 13df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek// FIXME: What's currently in BasicObjCFoundationChecks.cpp should be migrated 14df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek// to here, using the new Checker interface. 15df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek// 16df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek//===----------------------------------------------------------------------===// 17df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek 18027a6abdd6cedc0b8203da72eed6d15c796dce9dArgyrios Kyrtzidis#include "ClangSACheckers.h" 19ec8605f1d7ec846dbf51047bfd5c56d32d1ff91cArgyrios Kyrtzidis#include "clang/StaticAnalyzer/Core/Checker.h" 20695fb502825a53ccd178ec1c85c77929d88acb71Argyrios Kyrtzidis#include "clang/StaticAnalyzer/Core/CheckerManager.h" 21983326f32c746f5e47161a73758e4d363263dd2cArgyrios Kyrtzidis#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 229b663716449b618ba0390b1dbebc54fa8e971124Ted Kremenek#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 2318c66fdc3c4008d335885695fe36fb5353c5f672Ted Kremenek#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" 24983326f32c746f5e47161a73758e4d363263dd2cArgyrios Kyrtzidis#include "clang/Basic/TargetInfo.h" 25df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek#include "llvm/ADT/SmallString.h" 26df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek#include "llvm/ADT/StringSwitch.h" 27df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek#include "llvm/Support/raw_ostream.h" 28df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek 29df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenekusing namespace clang; 309ef6537a894c33003359b1f9b9676e9178e028b7Ted Kremenekusing namespace ento; 31df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek 32df61b580cea757cc72723ae95c1d5da603129f2cTed Kremeneknamespace { 33ec8605f1d7ec846dbf51047bfd5c56d32d1ff91cArgyrios Kyrtzidisclass MacOSXAPIChecker : public Checker< check::PreStmt<CallExpr> > { 3457964bda54c9b1e10090cae94d776a6b9b7eca33Jordy Rose mutable llvm::OwningPtr<BugType> BT_dispatchOnce; 35df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek 36df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenekpublic: 37983326f32c746f5e47161a73758e4d363263dd2cArgyrios Kyrtzidis void checkPreStmt(const CallExpr *CE, CheckerContext &C) const; 3857964bda54c9b1e10090cae94d776a6b9b7eca33Jordy Rose 3957964bda54c9b1e10090cae94d776a6b9b7eca33Jordy Rose void CheckDispatchOnce(CheckerContext &C, const CallExpr *CE, 40b805c8ff133ef0c62df032fa711d6b13c5afd7f4Anna Zaks StringRef FName) const; 4157964bda54c9b1e10090cae94d776a6b9b7eca33Jordy Rose 4257964bda54c9b1e10090cae94d776a6b9b7eca33Jordy Rose typedef void (MacOSXAPIChecker::*SubChecker)(CheckerContext &, 4357964bda54c9b1e10090cae94d776a6b9b7eca33Jordy Rose const CallExpr *, 44b805c8ff133ef0c62df032fa711d6b13c5afd7f4Anna Zaks StringRef FName) const; 45df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek}; 46df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek} //end anonymous namespace 47df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek 48df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek//===----------------------------------------------------------------------===// 49df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek// dispatch_once and dispatch_once_f 50df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek//===----------------------------------------------------------------------===// 51df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek 5257964bda54c9b1e10090cae94d776a6b9b7eca33Jordy Rosevoid MacOSXAPIChecker::CheckDispatchOnce(CheckerContext &C, const CallExpr *CE, 53b805c8ff133ef0c62df032fa711d6b13c5afd7f4Anna Zaks StringRef FName) const { 54df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek if (CE->getNumArgs() < 1) 55df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek return; 56df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek 57df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek // Check if the first argument is stack allocated. If so, issue a warning 58df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek // because that's likely to be bad news. 5918c66fdc3c4008d335885695fe36fb5353c5f672Ted Kremenek const ProgramState *state = C.getState(); 60df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek const MemRegion *R = state->getSVal(CE->getArg(0)).getAsRegion(); 61df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek if (!R || !isa<StackSpaceRegion>(R->getMemorySpace())) 62df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek return; 63df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek 64d048c6ef5b6cfaa0cecb8cc1d4bdace32ed21d07Ted Kremenek ExplodedNode *N = C.generateSink(state); 65df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek if (!N) 66df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek return; 67df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek 6857964bda54c9b1e10090cae94d776a6b9b7eca33Jordy Rose if (!BT_dispatchOnce) 6957964bda54c9b1e10090cae94d776a6b9b7eca33Jordy Rose BT_dispatchOnce.reset(new BugType("Improper use of 'dispatch_once'", 7057964bda54c9b1e10090cae94d776a6b9b7eca33Jordy Rose "Mac OS X API")); 7157964bda54c9b1e10090cae94d776a6b9b7eca33Jordy Rose 72df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek llvm::SmallString<256> S; 73df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek llvm::raw_svector_ostream os(S); 74b805c8ff133ef0c62df032fa711d6b13c5afd7f4Anna Zaks os << "Call to '" << FName << "' uses"; 75df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek if (const VarRegion *VR = dyn_cast<VarRegion>(R)) 76df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek os << " the local variable '" << VR->getDecl()->getName() << '\''; 77df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek else 78df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek os << " stack allocated memory"; 79df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek os << " for the predicate value. Using such transient memory for " 80df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek "the predicate is potentially dangerous."; 81df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek if (isa<VarRegion>(R) && isa<StackLocalsSpaceRegion>(R->getMemorySpace())) 82df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek os << " Perhaps you intended to declare the variable as 'static'?"; 83df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek 84e172e8b9e7fc67d7d03589af7e92fe777afcf33aAnna Zaks BugReport *report = new BugReport(*BT_dispatchOnce, os.str(), N); 85df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek report->addRange(CE->getArg(0)->getSourceRange()); 86df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek C.EmitReport(report); 87df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek} 88df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek 89df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek//===----------------------------------------------------------------------===// 90df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek// Central dispatch function. 91df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek//===----------------------------------------------------------------------===// 92df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek 93983326f32c746f5e47161a73758e4d363263dd2cArgyrios Kyrtzidisvoid MacOSXAPIChecker::checkPreStmt(const CallExpr *CE, 94983326f32c746f5e47161a73758e4d363263dd2cArgyrios Kyrtzidis CheckerContext &C) const { 95b805c8ff133ef0c62df032fa711d6b13c5afd7f4Anna Zaks StringRef Name = C.getCalleeName(CE); 96b805c8ff133ef0c62df032fa711d6b13c5afd7f4Anna Zaks if (Name.empty()) 97df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek return; 98df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek 9957964bda54c9b1e10090cae94d776a6b9b7eca33Jordy Rose SubChecker SC = 100b805c8ff133ef0c62df032fa711d6b13c5afd7f4Anna Zaks llvm::StringSwitch<SubChecker>(Name) 10157964bda54c9b1e10090cae94d776a6b9b7eca33Jordy Rose .Cases("dispatch_once", "dispatch_once_f", 10257964bda54c9b1e10090cae94d776a6b9b7eca33Jordy Rose &MacOSXAPIChecker::CheckDispatchOnce) 10357964bda54c9b1e10090cae94d776a6b9b7eca33Jordy Rose .Default(NULL); 104df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek 10557964bda54c9b1e10090cae94d776a6b9b7eca33Jordy Rose if (SC) 106b805c8ff133ef0c62df032fa711d6b13c5afd7f4Anna Zaks (this->*SC)(C, CE, Name); 107df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek} 108983326f32c746f5e47161a73758e4d363263dd2cArgyrios Kyrtzidis 109983326f32c746f5e47161a73758e4d363263dd2cArgyrios Kyrtzidis//===----------------------------------------------------------------------===// 110983326f32c746f5e47161a73758e4d363263dd2cArgyrios Kyrtzidis// Registration. 111983326f32c746f5e47161a73758e4d363263dd2cArgyrios Kyrtzidis//===----------------------------------------------------------------------===// 112983326f32c746f5e47161a73758e4d363263dd2cArgyrios Kyrtzidis 113983326f32c746f5e47161a73758e4d363263dd2cArgyrios Kyrtzidisvoid ento::registerMacOSXAPIChecker(CheckerManager &mgr) { 114983326f32c746f5e47161a73758e4d363263dd2cArgyrios Kyrtzidis mgr.registerChecker<MacOSXAPIChecker>(); 115983326f32c746f5e47161a73758e4d363263dd2cArgyrios Kyrtzidis} 116