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