1*67e74705SXin Li // MacOSXAPIChecker.h - Checks proper use of various MacOS X APIs --*- C++ -*-//
2*67e74705SXin Li //
3*67e74705SXin Li // The LLVM Compiler Infrastructure
4*67e74705SXin Li //
5*67e74705SXin Li // This file is distributed under the University of Illinois Open Source
6*67e74705SXin Li // License. See LICENSE.TXT for details.
7*67e74705SXin Li //
8*67e74705SXin Li //===----------------------------------------------------------------------===//
9*67e74705SXin Li //
10*67e74705SXin Li // This defines MacOSXAPIChecker, which is an assortment of checks on calls
11*67e74705SXin Li // to various, widely used Apple APIs.
12*67e74705SXin Li //
13*67e74705SXin Li // FIXME: What's currently in BasicObjCFoundationChecks.cpp should be migrated
14*67e74705SXin Li // to here, using the new Checker interface.
15*67e74705SXin Li //
16*67e74705SXin Li //===----------------------------------------------------------------------===//
17*67e74705SXin Li
18*67e74705SXin Li #include "ClangSACheckers.h"
19*67e74705SXin Li #include "clang/Basic/TargetInfo.h"
20*67e74705SXin Li #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
21*67e74705SXin Li #include "clang/StaticAnalyzer/Core/Checker.h"
22*67e74705SXin Li #include "clang/StaticAnalyzer/Core/CheckerManager.h"
23*67e74705SXin Li #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
24*67e74705SXin Li #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
25*67e74705SXin Li #include "llvm/ADT/SmallString.h"
26*67e74705SXin Li #include "llvm/ADT/StringSwitch.h"
27*67e74705SXin Li #include "llvm/Support/raw_ostream.h"
28*67e74705SXin Li
29*67e74705SXin Li using namespace clang;
30*67e74705SXin Li using namespace ento;
31*67e74705SXin Li
32*67e74705SXin Li namespace {
33*67e74705SXin Li class MacOSXAPIChecker : public Checker< check::PreStmt<CallExpr> > {
34*67e74705SXin Li mutable std::unique_ptr<BugType> BT_dispatchOnce;
35*67e74705SXin Li
36*67e74705SXin Li public:
37*67e74705SXin Li void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
38*67e74705SXin Li
39*67e74705SXin Li void CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
40*67e74705SXin Li StringRef FName) const;
41*67e74705SXin Li
42*67e74705SXin Li typedef void (MacOSXAPIChecker::*SubChecker)(CheckerContext &,
43*67e74705SXin Li const CallExpr *,
44*67e74705SXin Li StringRef FName) const;
45*67e74705SXin Li };
46*67e74705SXin Li } //end anonymous namespace
47*67e74705SXin Li
48*67e74705SXin Li //===----------------------------------------------------------------------===//
49*67e74705SXin Li // dispatch_once and dispatch_once_f
50*67e74705SXin Li //===----------------------------------------------------------------------===//
51*67e74705SXin Li
CheckDispatchOnce(CheckerContext & C,const CallExpr * CE,StringRef FName) const52*67e74705SXin Li void MacOSXAPIChecker::CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
53*67e74705SXin Li StringRef FName) const {
54*67e74705SXin Li if (CE->getNumArgs() < 1)
55*67e74705SXin Li return;
56*67e74705SXin Li
57*67e74705SXin Li // Check if the first argument is stack allocated. If so, issue a warning
58*67e74705SXin Li // because that's likely to be bad news.
59*67e74705SXin Li ProgramStateRef state = C.getState();
60*67e74705SXin Li const MemRegion *R =
61*67e74705SXin Li state->getSVal(CE->getArg(0), C.getLocationContext()).getAsRegion();
62*67e74705SXin Li if (!R || !isa<StackSpaceRegion>(R->getMemorySpace()))
63*67e74705SXin Li return;
64*67e74705SXin Li
65*67e74705SXin Li ExplodedNode *N = C.generateErrorNode(state);
66*67e74705SXin Li if (!N)
67*67e74705SXin Li return;
68*67e74705SXin Li
69*67e74705SXin Li if (!BT_dispatchOnce)
70*67e74705SXin Li BT_dispatchOnce.reset(new BugType(this, "Improper use of 'dispatch_once'",
71*67e74705SXin Li "API Misuse (Apple)"));
72*67e74705SXin Li
73*67e74705SXin Li // Handle _dispatch_once. In some versions of the OS X SDK we have the case
74*67e74705SXin Li // that dispatch_once is a macro that wraps a call to _dispatch_once.
75*67e74705SXin Li // _dispatch_once is then a function which then calls the real dispatch_once.
76*67e74705SXin Li // Users do not care; they just want the warning at the top-level call.
77*67e74705SXin Li if (CE->getLocStart().isMacroID()) {
78*67e74705SXin Li StringRef TrimmedFName = FName.ltrim('_');
79*67e74705SXin Li if (TrimmedFName != FName)
80*67e74705SXin Li FName = TrimmedFName;
81*67e74705SXin Li }
82*67e74705SXin Li
83*67e74705SXin Li SmallString<256> S;
84*67e74705SXin Li llvm::raw_svector_ostream os(S);
85*67e74705SXin Li os << "Call to '" << FName << "' uses";
86*67e74705SXin Li if (const VarRegion *VR = dyn_cast<VarRegion>(R))
87*67e74705SXin Li os << " the local variable '" << VR->getDecl()->getName() << '\'';
88*67e74705SXin Li else
89*67e74705SXin Li os << " stack allocated memory";
90*67e74705SXin Li os << " for the predicate value. Using such transient memory for "
91*67e74705SXin Li "the predicate is potentially dangerous.";
92*67e74705SXin Li if (isa<VarRegion>(R) && isa<StackLocalsSpaceRegion>(R->getMemorySpace()))
93*67e74705SXin Li os << " Perhaps you intended to declare the variable as 'static'?";
94*67e74705SXin Li
95*67e74705SXin Li auto report = llvm::make_unique<BugReport>(*BT_dispatchOnce, os.str(), N);
96*67e74705SXin Li report->addRange(CE->getArg(0)->getSourceRange());
97*67e74705SXin Li C.emitReport(std::move(report));
98*67e74705SXin Li }
99*67e74705SXin Li
100*67e74705SXin Li //===----------------------------------------------------------------------===//
101*67e74705SXin Li // Central dispatch function.
102*67e74705SXin Li //===----------------------------------------------------------------------===//
103*67e74705SXin Li
checkPreStmt(const CallExpr * CE,CheckerContext & C) const104*67e74705SXin Li void MacOSXAPIChecker::checkPreStmt(const CallExpr *CE,
105*67e74705SXin Li CheckerContext &C) const {
106*67e74705SXin Li StringRef Name = C.getCalleeName(CE);
107*67e74705SXin Li if (Name.empty())
108*67e74705SXin Li return;
109*67e74705SXin Li
110*67e74705SXin Li SubChecker SC =
111*67e74705SXin Li llvm::StringSwitch<SubChecker>(Name)
112*67e74705SXin Li .Cases("dispatch_once",
113*67e74705SXin Li "_dispatch_once",
114*67e74705SXin Li "dispatch_once_f",
115*67e74705SXin Li &MacOSXAPIChecker::CheckDispatchOnce)
116*67e74705SXin Li .Default(nullptr);
117*67e74705SXin Li
118*67e74705SXin Li if (SC)
119*67e74705SXin Li (this->*SC)(C, CE, Name);
120*67e74705SXin Li }
121*67e74705SXin Li
122*67e74705SXin Li //===----------------------------------------------------------------------===//
123*67e74705SXin Li // Registration.
124*67e74705SXin Li //===----------------------------------------------------------------------===//
125*67e74705SXin Li
registerMacOSXAPIChecker(CheckerManager & mgr)126*67e74705SXin Li void ento::registerMacOSXAPIChecker(CheckerManager &mgr) {
127*67e74705SXin Li mgr.registerChecker<MacOSXAPIChecker>();
128*67e74705SXin Li }
129