MacOSXAPIChecker.cpp revision 18c66fdc3c4008d335885695fe36fb5353c5f672
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,
4057964bda54c9b1e10090cae94d776a6b9b7eca33Jordy Rose                         const IdentifierInfo *FI) const;
4157964bda54c9b1e10090cae94d776a6b9b7eca33Jordy Rose
4257964bda54c9b1e10090cae94d776a6b9b7eca33Jordy Rose  typedef void (MacOSXAPIChecker::*SubChecker)(CheckerContext &,
4357964bda54c9b1e10090cae94d776a6b9b7eca33Jordy Rose                                               const CallExpr *,
4457964bda54c9b1e10090cae94d776a6b9b7eca33Jordy Rose                                               const IdentifierInfo *) 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,
5357964bda54c9b1e10090cae94d776a6b9b7eca33Jordy Rose                                         const IdentifierInfo *FI) 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);
74df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek  os << "Call to '" << FI->getName() << "' 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
8457964bda54c9b1e10090cae94d776a6b9b7eca33Jordy Rose  RangedBugReport *report = new RangedBugReport(*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 {
9557964bda54c9b1e10090cae94d776a6b9b7eca33Jordy Rose  // FIXME: This sort of logic is common to several checkers, including
9657964bda54c9b1e10090cae94d776a6b9b7eca33Jordy Rose  // UnixAPIChecker, PthreadLockChecker, and CStringChecker.  Should refactor.
9718c66fdc3c4008d335885695fe36fb5353c5f672Ted Kremenek  const ProgramState *state = C.getState();
98df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek  const Expr *Callee = CE->getCallee();
9957964bda54c9b1e10090cae94d776a6b9b7eca33Jordy Rose  const FunctionDecl *Fn = state->getSVal(Callee).getAsFunctionDecl();
100df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek
101df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek  if (!Fn)
102df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek    return;
103df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek
10457964bda54c9b1e10090cae94d776a6b9b7eca33Jordy Rose  const IdentifierInfo *FI = Fn->getIdentifier();
105df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek  if (!FI)
106df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek    return;
107df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek
10857964bda54c9b1e10090cae94d776a6b9b7eca33Jordy Rose  SubChecker SC =
10957964bda54c9b1e10090cae94d776a6b9b7eca33Jordy Rose    llvm::StringSwitch<SubChecker>(FI->getName())
11057964bda54c9b1e10090cae94d776a6b9b7eca33Jordy Rose      .Cases("dispatch_once", "dispatch_once_f",
11157964bda54c9b1e10090cae94d776a6b9b7eca33Jordy Rose             &MacOSXAPIChecker::CheckDispatchOnce)
11257964bda54c9b1e10090cae94d776a6b9b7eca33Jordy Rose      .Default(NULL);
113df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek
11457964bda54c9b1e10090cae94d776a6b9b7eca33Jordy Rose  if (SC)
11557964bda54c9b1e10090cae94d776a6b9b7eca33Jordy Rose    (this->*SC)(C, CE, FI);
116df61b580cea757cc72723ae95c1d5da603129f2cTed Kremenek}
117983326f32c746f5e47161a73758e4d363263dd2cArgyrios Kyrtzidis
118983326f32c746f5e47161a73758e4d363263dd2cArgyrios Kyrtzidis//===----------------------------------------------------------------------===//
119983326f32c746f5e47161a73758e4d363263dd2cArgyrios Kyrtzidis// Registration.
120983326f32c746f5e47161a73758e4d363263dd2cArgyrios Kyrtzidis//===----------------------------------------------------------------------===//
121983326f32c746f5e47161a73758e4d363263dd2cArgyrios Kyrtzidis
122983326f32c746f5e47161a73758e4d363263dd2cArgyrios Kyrtzidisvoid ento::registerMacOSXAPIChecker(CheckerManager &mgr) {
123983326f32c746f5e47161a73758e4d363263dd2cArgyrios Kyrtzidis  mgr.registerChecker<MacOSXAPIChecker>();
124983326f32c746f5e47161a73758e4d363263dd2cArgyrios Kyrtzidis}
125