blob: bcd96e73305e6651504c7c05b243525d9cb9de48 [file] [log] [blame]
Ted Kremenekdf61b582010-02-25 05:44:09 +00001// 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.
12//
13// FIXME: What's currently in BasicObjCFoundationChecks.cpp should be migrated
14// to here, using the new Checker interface.
15//
16//===----------------------------------------------------------------------===//
17
18#include "GRExprEngineInternalChecks.h"
19#include "clang/Basic/TargetInfo.h"
Benjamin Kramer5e2d2c22010-03-27 21:19:47 +000020#include "clang/Checker/BugReporter/BugType.h"
Ted Kremenekdf61b582010-02-25 05:44:09 +000021#include "clang/Checker/PathSensitive/CheckerVisitor.h"
22#include "clang/Checker/PathSensitive/GRStateTrait.h"
23#include "llvm/ADT/SmallString.h"
24#include "llvm/ADT/StringSwitch.h"
25#include "llvm/Support/raw_ostream.h"
26
27using namespace clang;
28
29namespace {
30class MacOSXAPIChecker : public CheckerVisitor<MacOSXAPIChecker> {
31 enum SubChecks {
32 DispatchOnce = 0,
33 DispatchOnceF,
34 NumChecks
35 };
36
37 BugType *BTypes[NumChecks];
38
39public:
40 MacOSXAPIChecker() { memset(BTypes, 0, sizeof(*BTypes) * NumChecks); }
41 static void *getTag() { static unsigned tag = 0; return &tag; }
42
43 void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
44};
45} //end anonymous namespace
46
47void clang::RegisterMacOSXAPIChecker(GRExprEngine &Eng) {
48 if (Eng.getContext().Target.getTriple().getVendor() == llvm::Triple::Apple)
49 Eng.registerCheck(new MacOSXAPIChecker());
50}
51
52//===----------------------------------------------------------------------===//
53// dispatch_once and dispatch_once_f
54//===----------------------------------------------------------------------===//
55
56static void CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
57 BugType *&BT, const IdentifierInfo *FI) {
58
59 if (!BT) {
60 llvm::SmallString<128> S;
61 llvm::raw_svector_ostream os(S);
62 os << "Improper use of '" << FI->getName() << '\'';
63 BT = new BugType(os.str(), "Mac OS X API");
64 }
65
66 if (CE->getNumArgs() < 1)
67 return;
68
69 // Check if the first argument is stack allocated. If so, issue a warning
70 // because that's likely to be bad news.
71 const GRState *state = C.getState();
72 const MemRegion *R = state->getSVal(CE->getArg(0)).getAsRegion();
73 if (!R || !isa<StackSpaceRegion>(R->getMemorySpace()))
74 return;
75
76 ExplodedNode *N = C.GenerateSink(state);
77 if (!N)
78 return;
79
80 llvm::SmallString<256> S;
81 llvm::raw_svector_ostream os(S);
82 os << "Call to '" << FI->getName() << "' uses";
83 if (const VarRegion *VR = dyn_cast<VarRegion>(R))
84 os << " the local variable '" << VR->getDecl()->getName() << '\'';
85 else
86 os << " stack allocated memory";
87 os << " for the predicate value. Using such transient memory for "
88 "the predicate is potentially dangerous.";
89 if (isa<VarRegion>(R) && isa<StackLocalsSpaceRegion>(R->getMemorySpace()))
90 os << " Perhaps you intended to declare the variable as 'static'?";
91
92 EnhancedBugReport *report = new EnhancedBugReport(*BT, os.str(), N);
93 report->addRange(CE->getArg(0)->getSourceRange());
94 C.EmitReport(report);
95}
96
97//===----------------------------------------------------------------------===//
98// Central dispatch function.
99//===----------------------------------------------------------------------===//
100
101typedef void (*SubChecker)(CheckerContext &C, const CallExpr *CE, BugType *&BT,
102 const IdentifierInfo *FI);
103namespace {
104 class SubCheck {
105 SubChecker SC;
106 BugType **BT;
107 public:
108 SubCheck(SubChecker sc, BugType *& bt) : SC(sc), BT(&bt) {}
109 SubCheck() : SC(NULL), BT(NULL) {}
110
111 void run(CheckerContext &C, const CallExpr *CE,
112 const IdentifierInfo *FI) const {
113 if (SC)
114 SC(C, CE, *BT, FI);
115 }
116 };
117} // end anonymous namespace
118
119void MacOSXAPIChecker::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) {
120 // FIXME: Mostly copy and paste from UnixAPIChecker. Should refactor.
121 const GRState *state = C.getState();
122 const Expr *Callee = CE->getCallee();
123 const FunctionTextRegion *Fn =
124 dyn_cast_or_null<FunctionTextRegion>(state->getSVal(Callee).getAsRegion());
125
126 if (!Fn)
127 return;
128
129 const IdentifierInfo *FI = Fn->getDecl()->getIdentifier();
130 if (!FI)
131 return;
132
133 const SubCheck &SC =
134 llvm::StringSwitch<SubCheck>(FI->getName())
135 .Case("dispatch_once", SubCheck(CheckDispatchOnce, BTypes[DispatchOnce]))
136 .Case("dispatch_once_f", SubCheck(CheckDispatchOnce,
137 BTypes[DispatchOnceF]))
138 .Default(SubCheck());
139
140 SC.run(C, CE, FI);
141}