[analyzer] Pass CheckerManager to the registration functions.
[clang.git] / lib / StaticAnalyzer / Checkers / MacOSXAPIChecker.cpp
blob358be124b9e4dd938108a2a316e5fd60797cb359
1 // MacOSXAPIChecker.h - Checks proper use of various MacOS X APIs --*- C++ -*-//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This defines MacOSXAPIChecker, which is an assortment of checks on calls
11 // to various, widely used Mac OS X functions.
13 // FIXME: What's currently in BasicObjCFoundationChecks.cpp should be migrated
14 // to here, using the new Checker interface.
16 //===----------------------------------------------------------------------===//
18 #include "ClangSACheckers.h"
19 #include "clang/Basic/TargetInfo.h"
20 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
21 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
22 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
23 #include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h"
24 #include "llvm/ADT/SmallString.h"
25 #include "llvm/ADT/StringSwitch.h"
26 #include "llvm/Support/raw_ostream.h"
28 using namespace clang;
29 using namespace ento;
31 namespace {
32 class MacOSXAPIChecker : public CheckerVisitor<MacOSXAPIChecker> {
33 enum SubChecks {
34 DispatchOnce = 0,
35 DispatchOnceF,
36 NumChecks
39 BugType *BTypes[NumChecks];
41 public:
42 MacOSXAPIChecker() { memset(BTypes, 0, sizeof(*BTypes) * NumChecks); }
43 static void *getTag() { static unsigned tag = 0; return &tag; }
45 void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
47 } //end anonymous namespace
49 static void RegisterMacOSXAPIChecker(ExprEngine &Eng) {
50 Eng.registerCheck(new MacOSXAPIChecker());
53 void ento::registerMacOSXAPIChecker(CheckerManager &mgr) {
54 mgr.addCheckerRegisterFunction(RegisterMacOSXAPIChecker);
57 //===----------------------------------------------------------------------===//
58 // dispatch_once and dispatch_once_f
59 //===----------------------------------------------------------------------===//
61 static void CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
62 BugType *&BT, const IdentifierInfo *FI) {
64 if (!BT) {
65 llvm::SmallString<128> S;
66 llvm::raw_svector_ostream os(S);
67 os << "Improper use of '" << FI->getName() << '\'';
68 BT = new BugType(os.str(), "Mac OS X API");
71 if (CE->getNumArgs() < 1)
72 return;
74 // Check if the first argument is stack allocated. If so, issue a warning
75 // because that's likely to be bad news.
76 const GRState *state = C.getState();
77 const MemRegion *R = state->getSVal(CE->getArg(0)).getAsRegion();
78 if (!R || !isa<StackSpaceRegion>(R->getMemorySpace()))
79 return;
81 ExplodedNode *N = C.generateSink(state);
82 if (!N)
83 return;
85 llvm::SmallString<256> S;
86 llvm::raw_svector_ostream os(S);
87 os << "Call to '" << FI->getName() << "' uses";
88 if (const VarRegion *VR = dyn_cast<VarRegion>(R))
89 os << " the local variable '" << VR->getDecl()->getName() << '\'';
90 else
91 os << " stack allocated memory";
92 os << " for the predicate value. Using such transient memory for "
93 "the predicate is potentially dangerous.";
94 if (isa<VarRegion>(R) && isa<StackLocalsSpaceRegion>(R->getMemorySpace()))
95 os << " Perhaps you intended to declare the variable as 'static'?";
97 EnhancedBugReport *report = new EnhancedBugReport(*BT, os.str(), N);
98 report->addRange(CE->getArg(0)->getSourceRange());
99 C.EmitReport(report);
102 //===----------------------------------------------------------------------===//
103 // Central dispatch function.
104 //===----------------------------------------------------------------------===//
106 typedef void (*SubChecker)(CheckerContext &C, const CallExpr *CE, BugType *&BT,
107 const IdentifierInfo *FI);
108 namespace {
109 class SubCheck {
110 SubChecker SC;
111 BugType **BT;
112 public:
113 SubCheck(SubChecker sc, BugType *& bt) : SC(sc), BT(&bt) {}
114 SubCheck() : SC(NULL), BT(NULL) {}
116 void run(CheckerContext &C, const CallExpr *CE,
117 const IdentifierInfo *FI) const {
118 if (SC)
119 SC(C, CE, *BT, FI);
122 } // end anonymous namespace
124 void MacOSXAPIChecker::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) {
125 // FIXME: Mostly copy and paste from UnixAPIChecker. Should refactor.
126 const GRState *state = C.getState();
127 const Expr *Callee = CE->getCallee();
128 const FunctionTextRegion *Fn =
129 dyn_cast_or_null<FunctionTextRegion>(state->getSVal(Callee).getAsRegion());
131 if (!Fn)
132 return;
134 const IdentifierInfo *FI = Fn->getDecl()->getIdentifier();
135 if (!FI)
136 return;
138 const SubCheck &SC =
139 llvm::StringSwitch<SubCheck>(FI->getName())
140 .Case("dispatch_once", SubCheck(CheckDispatchOnce, BTypes[DispatchOnce]))
141 .Case("dispatch_once_f", SubCheck(CheckDispatchOnce,
142 BTypes[DispatchOnceF]))
143 .Default(SubCheck());
145 SC.run(C, CE, FI);