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" 1955fc873017f10f6f566b182b70f6fc22aefa3464Chandler Carruth#include "clang/Basic/TargetInfo.h" 2055fc873017f10f6f566b182b70f6fc22aefa3464Chandler Carruth#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 21ec8605f1d7ec846dbf51047bfd5c56d32d1ff91cArgyrios Kyrtzidis#include "clang/StaticAnalyzer/Core/Checker.h" 22695fb502825a53ccd178ec1c85c77929d88acb71Argyrios Kyrtzidis#include "clang/StaticAnalyzer/Core/CheckerManager.h" 23983326f32c746f5e47161a73758e4d363263dd2cArgyrios Kyrtzidis#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 2418c66fdc3c4008d335885695fe36fb5353c5f672Ted Kremenek#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.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> > { 346f42b62b6194f53bcbc349f5d17388e1936535d7Dylan Noblesmith mutable 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. 598bef8238181a30e52dea380789a7e2d760eac532Ted Kremenek ProgramStateRef state = C.getState(); 605eca482fe895ea57bc82410222e6426c09e63284Ted Kremenek const MemRegion *R = 615eca482fe895ea57bc82410222e6426c09e63284Ted Kremenek state->getSVal(CE->getArg(0), C.getLocationContext()).getAsRegion(); 62df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek if (!R || !isa<StackSpaceRegion>(R->getMemorySpace())) 63df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek return; 64df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek 65d048c6ef5b6cfaa0cecb8cc1d4bdace32ed21d07Ted Kremenek ExplodedNode *N = C.generateSink(state); 66df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek if (!N) 67df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek return; 68df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek 6957964bda54c9b1e10090cae94d776a6b9b7eca33Jordy Rose if (!BT_dispatchOnce) 7057964bda54c9b1e10090cae94d776a6b9b7eca33Jordy Rose BT_dispatchOnce.reset(new BugType("Improper use of 'dispatch_once'", 7157964bda54c9b1e10090cae94d776a6b9b7eca33Jordy Rose "Mac OS X API")); 7257964bda54c9b1e10090cae94d776a6b9b7eca33Jordy Rose 7345b76bad757d8b9f93df2b21ca012c309810d206Ted Kremenek // Handle _dispatch_once. In some versions of the OS X SDK we have the case 7445b76bad757d8b9f93df2b21ca012c309810d206Ted Kremenek // that dispatch_once is a macro that wraps a call to _dispatch_once. 7545b76bad757d8b9f93df2b21ca012c309810d206Ted Kremenek // _dispatch_once is then a function which then calls the real dispatch_once. 7645b76bad757d8b9f93df2b21ca012c309810d206Ted Kremenek // Users do not care; they just want the warning at the top-level call. 77be879727893994532b4a643bfae6fb656742057fTed Kremenek if (CE->getLocStart().isMacroID()) { 78be879727893994532b4a643bfae6fb656742057fTed Kremenek StringRef TrimmedFName = FName.ltrim("_"); 79be879727893994532b4a643bfae6fb656742057fTed Kremenek if (TrimmedFName != FName) 80be879727893994532b4a643bfae6fb656742057fTed Kremenek FName = TrimmedFName; 81be879727893994532b4a643bfae6fb656742057fTed Kremenek } 82be879727893994532b4a643bfae6fb656742057fTed Kremenek 83f7ccbad5d9949e7ddd1cbef43d482553b811e026Dylan Noblesmith SmallString<256> S; 84df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek llvm::raw_svector_ostream os(S); 85b805c8ff133ef0c62df032fa711d6b13c5afd7f4Anna Zaks os << "Call to '" << FName << "' uses"; 86df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek if (const VarRegion *VR = dyn_cast<VarRegion>(R)) 87df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek os << " the local variable '" << VR->getDecl()->getName() << '\''; 88df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek else 89df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek os << " stack allocated memory"; 90df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek os << " for the predicate value. Using such transient memory for " 91df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek "the predicate is potentially dangerous."; 92df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek if (isa<VarRegion>(R) && isa<StackLocalsSpaceRegion>(R->getMemorySpace())) 93df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek os << " Perhaps you intended to declare the variable as 'static'?"; 94df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek 95e172e8b9e7fc67d7d03589af7e92fe777afcf33aAnna Zaks BugReport *report = new BugReport(*BT_dispatchOnce, os.str(), N); 96df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek report->addRange(CE->getArg(0)->getSourceRange()); 97785950e59424dca7ce0081bebf13c0acd2c4fff6Jordan Rose C.emitReport(report); 98df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek} 99df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek 100df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek//===----------------------------------------------------------------------===// 101df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek// Central dispatch function. 102df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek//===----------------------------------------------------------------------===// 103df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek 104983326f32c746f5e47161a73758e4d363263dd2cArgyrios Kyrtzidisvoid MacOSXAPIChecker::checkPreStmt(const CallExpr *CE, 105983326f32c746f5e47161a73758e4d363263dd2cArgyrios Kyrtzidis CheckerContext &C) const { 106b805c8ff133ef0c62df032fa711d6b13c5afd7f4Anna Zaks StringRef Name = C.getCalleeName(CE); 107b805c8ff133ef0c62df032fa711d6b13c5afd7f4Anna Zaks if (Name.empty()) 108df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek return; 109df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek 11057964bda54c9b1e10090cae94d776a6b9b7eca33Jordy Rose SubChecker SC = 111b805c8ff133ef0c62df032fa711d6b13c5afd7f4Anna Zaks llvm::StringSwitch<SubChecker>(Name) 112be879727893994532b4a643bfae6fb656742057fTed Kremenek .Cases("dispatch_once", 113be879727893994532b4a643bfae6fb656742057fTed Kremenek "_dispatch_once", 114be879727893994532b4a643bfae6fb656742057fTed Kremenek "dispatch_once_f", 11557964bda54c9b1e10090cae94d776a6b9b7eca33Jordy Rose &MacOSXAPIChecker::CheckDispatchOnce) 11657964bda54c9b1e10090cae94d776a6b9b7eca33Jordy Rose .Default(NULL); 117df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek 11857964bda54c9b1e10090cae94d776a6b9b7eca33Jordy Rose if (SC) 119b805c8ff133ef0c62df032fa711d6b13c5afd7f4Anna Zaks (this->*SC)(C, CE, Name); 120df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek} 121983326f32c746f5e47161a73758e4d363263dd2cArgyrios Kyrtzidis 122983326f32c746f5e47161a73758e4d363263dd2cArgyrios Kyrtzidis//===----------------------------------------------------------------------===// 123983326f32c746f5e47161a73758e4d363263dd2cArgyrios Kyrtzidis// Registration. 124983326f32c746f5e47161a73758e4d363263dd2cArgyrios Kyrtzidis//===----------------------------------------------------------------------===// 125983326f32c746f5e47161a73758e4d363263dd2cArgyrios Kyrtzidis 126983326f32c746f5e47161a73758e4d363263dd2cArgyrios Kyrtzidisvoid ento::registerMacOSXAPIChecker(CheckerManager &mgr) { 127983326f32c746f5e47161a73758e4d363263dd2cArgyrios Kyrtzidis mgr.registerChecker<MacOSXAPIChecker>(); 128983326f32c746f5e47161a73758e4d363263dd2cArgyrios Kyrtzidis} 129