1 // MacOSXAPIChecker.h - Checks proper use of various MacOS X APIs --*- C++ -*-//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
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
;
32 class MacOSXAPIChecker
: public CheckerVisitor
<MacOSXAPIChecker
> {
39 BugType
*BTypes
[NumChecks
];
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
) {
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)
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()))
81 ExplodedNode
*N
= C
.generateSink(state
);
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() << '\'';
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());
102 //===----------------------------------------------------------------------===//
103 // Central dispatch function.
104 //===----------------------------------------------------------------------===//
106 typedef void (*SubChecker
)(CheckerContext
&C
, const CallExpr
*CE
, BugType
*&BT
,
107 const IdentifierInfo
*FI
);
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 {
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());
134 const IdentifierInfo
*FI
= Fn
->getDecl()->getIdentifier();
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());