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