xref: /aosp_15_r20/external/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp (revision 67e74705e28f6214e480b399dd47ea732279e315)
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