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