blob: c377f31d8fc15d6101137bacd60cddf314c43c8e [file] [log] [blame]
Caitlin Sadowski402aa062011-09-09 16:11:56 +00001//===- ThreadSafety.cpp ----------------------------------------*- 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// A intra-procedural analysis for thread safety (e.g. deadlocks and race
11// conditions), based off of an annotation system.
12//
Caitlin Sadowski19903462011-09-14 20:05:09 +000013// See http://clang.llvm.org/docs/LanguageExtensions.html#threadsafety for more
14// information.
Caitlin Sadowski402aa062011-09-09 16:11:56 +000015//
16//===----------------------------------------------------------------------===//
17
18#include "clang/Analysis/Analyses/ThreadSafety.h"
Caitlin Sadowskid5b16052011-09-09 23:00:59 +000019#include "clang/Analysis/AnalysisContext.h"
20#include "clang/Analysis/CFG.h"
21#include "clang/Analysis/CFGStmtMap.h"
Caitlin Sadowski402aa062011-09-09 16:11:56 +000022#include "clang/AST/DeclCXX.h"
23#include "clang/AST/ExprCXX.h"
24#include "clang/AST/StmtCXX.h"
25#include "clang/AST/StmtVisitor.h"
Caitlin Sadowskid5b16052011-09-09 23:00:59 +000026#include "clang/Basic/SourceManager.h"
27#include "clang/Basic/SourceLocation.h"
Caitlin Sadowski402aa062011-09-09 16:11:56 +000028#include "llvm/ADT/BitVector.h"
29#include "llvm/ADT/FoldingSet.h"
30#include "llvm/ADT/ImmutableMap.h"
31#include "llvm/ADT/PostOrderIterator.h"
32#include "llvm/ADT/SmallVector.h"
33#include "llvm/ADT/StringRef.h"
34#include <algorithm>
35#include <vector>
36
37using namespace clang;
38using namespace thread_safety;
39
Caitlin Sadowski19903462011-09-14 20:05:09 +000040// Key method definition
41ThreadSafetyHandler::~ThreadSafetyHandler() {}
42
Caitlin Sadowski402aa062011-09-09 16:11:56 +000043namespace {
DeLesley Hutchinsa60448d2011-10-21 16:14:33 +000044
Caitlin Sadowski402aa062011-09-09 16:11:56 +000045/// \brief Implements a set of CFGBlocks using a BitVector.
46///
47/// This class contains a minimal interface, primarily dictated by the SetType
48/// template parameter of the llvm::po_iterator template, as used with external
49/// storage. We also use this set to keep track of which CFGBlocks we visit
50/// during the analysis.
51class CFGBlockSet {
52 llvm::BitVector VisitedBlockIDs;
53
54public:
55 // po_iterator requires this iterator, but the only interface needed is the
56 // value_type typedef.
57 struct iterator {
58 typedef const CFGBlock *value_type;
59 };
60
61 CFGBlockSet() {}
62 CFGBlockSet(const CFG *G) : VisitedBlockIDs(G->getNumBlockIDs(), false) {}
63
64 /// \brief Set the bit associated with a particular CFGBlock.
65 /// This is the important method for the SetType template parameter.
66 bool insert(const CFGBlock *Block) {
67 // Note that insert() is called by po_iterator, which doesn't check to make
68 // sure that Block is non-null. Moreover, the CFGBlock iterator will
69 // occasionally hand out null pointers for pruned edges, so we catch those
70 // here.
71 if (Block == 0)
72 return false; // if an edge is trivially false.
73 if (VisitedBlockIDs.test(Block->getBlockID()))
74 return false;
75 VisitedBlockIDs.set(Block->getBlockID());
76 return true;
77 }
78
79 /// \brief Check if the bit for a CFGBlock has been already set.
80 /// This method is for tracking visited blocks in the main threadsafety loop.
81 /// Block must not be null.
82 bool alreadySet(const CFGBlock *Block) {
83 return VisitedBlockIDs.test(Block->getBlockID());
84 }
85};
86
DeLesley Hutchinsa60448d2011-10-21 16:14:33 +000087
Caitlin Sadowski402aa062011-09-09 16:11:56 +000088/// \brief We create a helper class which we use to iterate through CFGBlocks in
89/// the topological order.
90class TopologicallySortedCFG {
91 typedef llvm::po_iterator<const CFG*, CFGBlockSet, true> po_iterator;
92
93 std::vector<const CFGBlock*> Blocks;
94
95public:
96 typedef std::vector<const CFGBlock*>::reverse_iterator iterator;
97
98 TopologicallySortedCFG(const CFG *CFGraph) {
99 Blocks.reserve(CFGraph->getNumBlockIDs());
100 CFGBlockSet BSet(CFGraph);
101
102 for (po_iterator I = po_iterator::begin(CFGraph, BSet),
103 E = po_iterator::end(CFGraph, BSet); I != E; ++I) {
104 Blocks.push_back(*I);
105 }
106 }
107
108 iterator begin() {
109 return Blocks.rbegin();
110 }
111
112 iterator end() {
113 return Blocks.rend();
114 }
Caitlin Sadowskicb967512011-09-15 17:43:08 +0000115
116 bool empty() {
117 return begin() == end();
118 }
Caitlin Sadowski402aa062011-09-09 16:11:56 +0000119};
120
DeLesley Hutchinsa60448d2011-10-21 16:14:33 +0000121
Caitlin Sadowski402aa062011-09-09 16:11:56 +0000122/// \brief A MutexID object uniquely identifies a particular mutex, and
123/// is built from an Expr* (i.e. calling a lock function).
124///
125/// Thread-safety analysis works by comparing lock expressions. Within the
126/// body of a function, an expression such as "x->foo->bar.mu" will resolve to
127/// a particular mutex object at run-time. Subsequent occurrences of the same
128/// expression (where "same" means syntactic equality) will refer to the same
129/// run-time object if three conditions hold:
130/// (1) Local variables in the expression, such as "x" have not changed.
131/// (2) Values on the heap that affect the expression have not changed.
132/// (3) The expression involves only pure function calls.
133/// The current implementation assumes, but does not verify, that multiple uses
134/// of the same lock expression satisfies these criteria.
135///
136/// Clang introduces an additional wrinkle, which is that it is difficult to
137/// derive canonical expressions, or compare expressions directly for equality.
138/// Thus, we identify a mutex not by an Expr, but by the set of named
139/// declarations that are referenced by the Expr. In other words,
140/// x->foo->bar.mu will be a four element vector with the Decls for
141/// mu, bar, and foo, and x. The vector will uniquely identify the expression
142/// for all practical purposes.
143///
144/// Note we will need to perform substitution on "this" and function parameter
145/// names when constructing a lock expression.
146///
147/// For example:
148/// class C { Mutex Mu; void lock() EXCLUSIVE_LOCK_FUNCTION(this->Mu); };
149/// void myFunc(C *X) { ... X->lock() ... }
150/// The original expression for the mutex acquired by myFunc is "this->Mu", but
151/// "X" is substituted for "this" so we get X->Mu();
152///
153/// For another example:
154/// foo(MyList *L) EXCLUSIVE_LOCKS_REQUIRED(L->Mu) { ... }
155/// MyList *MyL;
156/// foo(MyL); // requires lock MyL->Mu to be held
157class MutexID {
158 SmallVector<NamedDecl*, 2> DeclSeq;
159
160 /// Build a Decl sequence representing the lock from the given expression.
161 /// Recursive function that bottoms out when the final DeclRefExpr is reached.
DeLesley Hutchins81216392011-10-17 21:38:02 +0000162 void buildMutexID(Expr *Exp, Expr *Parent, int NumArgs,
163 const NamedDecl **FunArgDecls, Expr **FunArgs) {
Caitlin Sadowski402aa062011-09-09 16:11:56 +0000164 if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Exp)) {
DeLesley Hutchins81216392011-10-17 21:38:02 +0000165 if (FunArgDecls) {
166 // Substitute call arguments for references to function parameters
167 for (int i = 0; i < NumArgs; ++i) {
168 if (DRE->getDecl() == FunArgDecls[i]) {
169 buildMutexID(FunArgs[i], 0, 0, 0, 0);
170 return;
171 }
172 }
173 }
Caitlin Sadowski402aa062011-09-09 16:11:56 +0000174 NamedDecl *ND = cast<NamedDecl>(DRE->getDecl()->getCanonicalDecl());
175 DeclSeq.push_back(ND);
176 } else if (MemberExpr *ME = dyn_cast<MemberExpr>(Exp)) {
177 NamedDecl *ND = ME->getMemberDecl();
178 DeclSeq.push_back(ND);
DeLesley Hutchins81216392011-10-17 21:38:02 +0000179 buildMutexID(ME->getBase(), Parent, NumArgs, FunArgDecls, FunArgs);
Caitlin Sadowski402aa062011-09-09 16:11:56 +0000180 } else if (isa<CXXThisExpr>(Exp)) {
Caitlin Sadowski194418f2011-09-14 20:00:24 +0000181 if (Parent)
DeLesley Hutchins81216392011-10-17 21:38:02 +0000182 buildMutexID(Parent, 0, 0, 0, 0);
Caitlin Sadowski194418f2011-09-14 20:00:24 +0000183 else
DeLesley Hutchins9f80a972011-10-17 21:33:35 +0000184 return; // mutexID is still valid in this case
Caitlin Sadowski99107eb2011-09-09 16:21:55 +0000185 } else if (CastExpr *CE = dyn_cast<CastExpr>(Exp))
DeLesley Hutchins81216392011-10-17 21:38:02 +0000186 buildMutexID(CE->getSubExpr(), Parent, NumArgs, FunArgDecls, FunArgs);
Caitlin Sadowski99107eb2011-09-09 16:21:55 +0000187 else
DeLesley Hutchins9f80a972011-10-17 21:33:35 +0000188 DeclSeq.clear(); // Mark as invalid lock expression.
189 }
190
191 /// \brief Construct a MutexID from an expression.
192 /// \param MutexExp The original mutex expression within an attribute
193 /// \param DeclExp An expression involving the Decl on which the attribute
194 /// occurs.
195 /// \param D The declaration to which the lock/unlock attribute is attached.
196 void buildMutexIDFromExp(Expr *MutexExp, Expr *DeclExp, const NamedDecl *D) {
197 Expr *Parent = 0;
DeLesley Hutchins81216392011-10-17 21:38:02 +0000198 unsigned NumArgs = 0;
199 Expr **FunArgs = 0;
200 SmallVector<const NamedDecl*, 8> FunArgDecls;
DeLesley Hutchins9f80a972011-10-17 21:33:35 +0000201
202 if (DeclExp == 0) {
DeLesley Hutchins81216392011-10-17 21:38:02 +0000203 buildMutexID(MutexExp, 0, 0, 0, 0);
DeLesley Hutchins9f80a972011-10-17 21:33:35 +0000204 return;
205 }
206
DeLesley Hutchins81216392011-10-17 21:38:02 +0000207 if (MemberExpr *ME = dyn_cast<MemberExpr>(DeclExp)) {
DeLesley Hutchins9f80a972011-10-17 21:33:35 +0000208 Parent = ME->getBase();
DeLesley Hutchins81216392011-10-17 21:38:02 +0000209 } else if (CXXMemberCallExpr *CE = dyn_cast<CXXMemberCallExpr>(DeclExp)) {
DeLesley Hutchins9f80a972011-10-17 21:33:35 +0000210 Parent = CE->getImplicitObjectArgument();
DeLesley Hutchins81216392011-10-17 21:38:02 +0000211 NumArgs = CE->getNumArgs();
212 FunArgs = CE->getArgs();
213 }
DeLesley Hutchins9f80a972011-10-17 21:33:35 +0000214
215 // If the attribute has no arguments, then assume the argument is "this".
216 if (MutexExp == 0) {
DeLesley Hutchins81216392011-10-17 21:38:02 +0000217 buildMutexID(Parent, 0, 0, 0, 0);
DeLesley Hutchins9f80a972011-10-17 21:33:35 +0000218 return;
219 }
DeLesley Hutchins81216392011-10-17 21:38:02 +0000220
221 // FIXME: handle default arguments
222 if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) {
223 for (unsigned i = 0, ni = FD->getNumParams(); i < ni && i < NumArgs; ++i) {
224 FunArgDecls.push_back(FD->getParamDecl(i));
225 }
226 }
227 buildMutexID(MutexExp, Parent, NumArgs, &FunArgDecls.front(), FunArgs);
Caitlin Sadowski402aa062011-09-09 16:11:56 +0000228 }
229
230public:
DeLesley Hutchins9f80a972011-10-17 21:33:35 +0000231 /// \param MutexExp The original mutex expression within an attribute
232 /// \param DeclExp An expression involving the Decl on which the attribute
233 /// occurs.
234 /// \param D The declaration to which the lock/unlock attribute is attached.
235 /// Caller must check isValid() after construction.
236 MutexID(Expr* MutexExp, Expr *DeclExp, const NamedDecl* D) {
237 buildMutexIDFromExp(MutexExp, DeclExp, D);
Caitlin Sadowski194418f2011-09-14 20:00:24 +0000238 }
239
DeLesley Hutchins9f80a972011-10-17 21:33:35 +0000240 /// Return true if this is a valid decl sequence.
241 /// Caller must call this by hand after construction to handle errors.
Caitlin Sadowski194418f2011-09-14 20:00:24 +0000242 bool isValid() const {
243 return !DeclSeq.empty();
Caitlin Sadowski402aa062011-09-09 16:11:56 +0000244 }
245
246 bool operator==(const MutexID &other) const {
247 return DeclSeq == other.DeclSeq;
248 }
249
250 bool operator!=(const MutexID &other) const {
251 return !(*this == other);
252 }
253
254 // SmallVector overloads Operator< to do lexicographic ordering. Note that
255 // we use pointer equality (and <) to compare NamedDecls. This means the order
256 // of MutexIDs in a lockset is nondeterministic. In order to output
257 // diagnostics in a deterministic ordering, we must order all diagnostics to
258 // output by SourceLocation when iterating through this lockset.
259 bool operator<(const MutexID &other) const {
260 return DeclSeq < other.DeclSeq;
261 }
262
263 /// \brief Returns the name of the first Decl in the list for a given MutexID;
264 /// e.g. the lock expression foo.bar() has name "bar".
265 /// The caret will point unambiguously to the lock expression, so using this
266 /// name in diagnostics is a way to get simple, and consistent, mutex names.
267 /// We do not want to output the entire expression text for security reasons.
268 StringRef getName() const {
Caitlin Sadowski194418f2011-09-14 20:00:24 +0000269 assert(isValid());
Caitlin Sadowski402aa062011-09-09 16:11:56 +0000270 return DeclSeq.front()->getName();
271 }
272
273 void Profile(llvm::FoldingSetNodeID &ID) const {
274 for (SmallVectorImpl<NamedDecl*>::const_iterator I = DeclSeq.begin(),
275 E = DeclSeq.end(); I != E; ++I) {
276 ID.AddPointer(*I);
277 }
278 }
279};
280
DeLesley Hutchinsa60448d2011-10-21 16:14:33 +0000281
Caitlin Sadowski402aa062011-09-09 16:11:56 +0000282/// \brief This is a helper class that stores info about the most recent
283/// accquire of a Lock.
284///
285/// The main body of the analysis maps MutexIDs to LockDatas.
286struct LockData {
287 SourceLocation AcquireLoc;
288
289 /// \brief LKind stores whether a lock is held shared or exclusively.
290 /// Note that this analysis does not currently support either re-entrant
291 /// locking or lock "upgrading" and "downgrading" between exclusive and
292 /// shared.
293 ///
294 /// FIXME: add support for re-entrant locking and lock up/downgrading
295 LockKind LKind;
296
297 LockData(SourceLocation AcquireLoc, LockKind LKind)
298 : AcquireLoc(AcquireLoc), LKind(LKind) {}
299
300 bool operator==(const LockData &other) const {
301 return AcquireLoc == other.AcquireLoc && LKind == other.LKind;
302 }
303
304 bool operator!=(const LockData &other) const {
305 return !(*this == other);
306 }
307
308 void Profile(llvm::FoldingSetNodeID &ID) const {
DeLesley Hutchinsa60448d2011-10-21 16:14:33 +0000309 ID.AddInteger(AcquireLoc.getRawEncoding());
310 ID.AddInteger(LKind);
311 }
Caitlin Sadowski402aa062011-09-09 16:11:56 +0000312};
313
DeLesley Hutchinsa60448d2011-10-21 16:14:33 +0000314
Caitlin Sadowski402aa062011-09-09 16:11:56 +0000315/// A Lockset maps each MutexID (defined above) to information about how it has
316/// been locked.
317typedef llvm::ImmutableMap<MutexID, LockData> Lockset;
318
319/// \brief We use this class to visit different types of expressions in
320/// CFGBlocks, and build up the lockset.
321/// An expression may cause us to add or remove locks from the lockset, or else
322/// output error messages related to missing locks.
323/// FIXME: In future, we may be able to not inherit from a visitor.
324class BuildLockset : public StmtVisitor<BuildLockset> {
325 ThreadSafetyHandler &Handler;
326 Lockset LSet;
327 Lockset::Factory &LocksetFactory;
328
329 // Helper functions
DeLesley Hutchins9f80a972011-10-17 21:33:35 +0000330 void removeLock(SourceLocation UnlockLoc, MutexID &Mutex);
331 void addLock(SourceLocation LockLoc, MutexID &Mutex, LockKind LK);
DeLesley Hutchinsa60448d2011-10-21 16:14:33 +0000332
333 template <class AttrType>
334 void addLocksToSet(LockKind LK, AttrType *Attr, CXXMemberCallExpr *Exp,
335 NamedDecl *D);
336
Caitlin Sadowski402aa062011-09-09 16:11:56 +0000337 const ValueDecl *getValueDecl(Expr *Exp);
338 void warnIfMutexNotHeld (const NamedDecl *D, Expr *Exp, AccessKind AK,
339 Expr *MutexExp, ProtectedOperationKind POK);
340 void checkAccess(Expr *Exp, AccessKind AK);
341 void checkDereference(Expr *Exp, AccessKind AK);
342
Caitlin Sadowski402aa062011-09-09 16:11:56 +0000343
344 /// \brief Returns true if the lockset contains a lock, regardless of whether
345 /// the lock is held exclusively or shared.
DeLesley Hutchinsa60448d2011-10-21 16:14:33 +0000346 bool locksetContains(const MutexID &Lock) const {
Caitlin Sadowski402aa062011-09-09 16:11:56 +0000347 return LSet.lookup(Lock);
348 }
349
350 /// \brief Returns true if the lockset contains a lock with the passed in
351 /// locktype.
DeLesley Hutchinsa60448d2011-10-21 16:14:33 +0000352 bool locksetContains(const MutexID &Lock, LockKind KindRequested) const {
Caitlin Sadowski402aa062011-09-09 16:11:56 +0000353 const LockData *LockHeld = LSet.lookup(Lock);
354 return (LockHeld && KindRequested == LockHeld->LKind);
355 }
356
357 /// \brief Returns true if the lockset contains a lock with at least the
358 /// passed in locktype. So for example, if we pass in LK_Shared, this function
359 /// returns true if the lock is held LK_Shared or LK_Exclusive. If we pass in
360 /// LK_Exclusive, this function returns true if the lock is held LK_Exclusive.
DeLesley Hutchinsa60448d2011-10-21 16:14:33 +0000361 bool locksetContainsAtLeast(const MutexID &Lock,
362 LockKind KindRequested) const {
Caitlin Sadowski402aa062011-09-09 16:11:56 +0000363 switch (KindRequested) {
364 case LK_Shared:
365 return locksetContains(Lock);
366 case LK_Exclusive:
367 return locksetContains(Lock, KindRequested);
368 }
Benjamin Kramerafc5b152011-09-10 21:52:04 +0000369 llvm_unreachable("Unknown LockKind");
Caitlin Sadowski402aa062011-09-09 16:11:56 +0000370 }
371
372public:
373 BuildLockset(ThreadSafetyHandler &Handler, Lockset LS, Lockset::Factory &F)
374 : StmtVisitor<BuildLockset>(), Handler(Handler), LSet(LS),
375 LocksetFactory(F) {}
376
377 Lockset getLockset() {
378 return LSet;
379 }
380
381 void VisitUnaryOperator(UnaryOperator *UO);
382 void VisitBinaryOperator(BinaryOperator *BO);
383 void VisitCastExpr(CastExpr *CE);
384 void VisitCXXMemberCallExpr(CXXMemberCallExpr *Exp);
385};
386
387/// \brief Add a new lock to the lockset, warning if the lock is already there.
388/// \param LockLoc The source location of the acquire
389/// \param LockExp The lock expression corresponding to the lock to be added
DeLesley Hutchins9f80a972011-10-17 21:33:35 +0000390void BuildLockset::addLock(SourceLocation LockLoc, MutexID &Mutex,
Caitlin Sadowski402aa062011-09-09 16:11:56 +0000391 LockKind LK) {
Caitlin Sadowski1748b122011-09-16 00:35:54 +0000392 // FIXME: deal with acquired before/after annotations. We can write a first
393 // pass that does the transitive lookup lazily, and refine afterwards.
Caitlin Sadowski402aa062011-09-09 16:11:56 +0000394 LockData NewLock(LockLoc, LK);
395
396 // FIXME: Don't always warn when we have support for reentrant locks.
397 if (locksetContains(Mutex))
398 Handler.handleDoubleLock(Mutex.getName(), LockLoc);
399 LSet = LocksetFactory.add(LSet, Mutex, NewLock);
400}
401
402/// \brief Remove a lock from the lockset, warning if the lock is not there.
403/// \param LockExp The lock expression corresponding to the lock to be removed
404/// \param UnlockLoc The source location of the unlock (only used in error msg)
DeLesley Hutchins9f80a972011-10-17 21:33:35 +0000405void BuildLockset::removeLock(SourceLocation UnlockLoc, MutexID &Mutex) {
Caitlin Sadowski402aa062011-09-09 16:11:56 +0000406 Lockset NewLSet = LocksetFactory.remove(LSet, Mutex);
407 if(NewLSet == LSet)
408 Handler.handleUnmatchedUnlock(Mutex.getName(), UnlockLoc);
409
410 LSet = NewLSet;
411}
412
DeLesley Hutchinsa60448d2011-10-21 16:14:33 +0000413/// \brief This function, parameterized by an attribute type, is used to add a
414/// set of locks specified as attribute arguments to the lockset.
415template <typename AttrType>
416void BuildLockset::addLocksToSet(LockKind LK, AttrType *Attr,
417 CXXMemberCallExpr *Exp,
418 NamedDecl* FunDecl) {
419 typedef typename AttrType::args_iterator iterator_type;
420
421 SourceLocation ExpLocation = Exp->getExprLoc();
422
423 if (Attr->args_size() == 0) {
424 // The mutex held is the "this" object.
425
426 MutexID Mutex(0, Exp, FunDecl);
427 if (!Mutex.isValid())
428 Handler.handleInvalidLockExp(Exp->getExprLoc());
429 else
430 addLock(ExpLocation, Mutex, LK);
431 return;
432 }
433
434 for (iterator_type I=Attr->args_begin(), E=Attr->args_end(); I != E; ++I) {
435 MutexID Mutex(*I, Exp, FunDecl);
436 if (!Mutex.isValid())
437 Handler.handleInvalidLockExp(Exp->getExprLoc());
438 else
439 addLock(ExpLocation, Mutex, LK);
440 }
441}
442
Caitlin Sadowski402aa062011-09-09 16:11:56 +0000443/// \brief Gets the value decl pointer from DeclRefExprs or MemberExprs
444const ValueDecl *BuildLockset::getValueDecl(Expr *Exp) {
445 if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Exp))
446 return DR->getDecl();
447
448 if (const MemberExpr *ME = dyn_cast<MemberExpr>(Exp))
449 return ME->getMemberDecl();
450
451 return 0;
452}
453
454/// \brief Warn if the LSet does not contain a lock sufficient to protect access
DeLesley Hutchins9f80a972011-10-17 21:33:35 +0000455/// of at least the passed in AccessKind.
Caitlin Sadowski402aa062011-09-09 16:11:56 +0000456void BuildLockset::warnIfMutexNotHeld(const NamedDecl *D, Expr *Exp,
457 AccessKind AK, Expr *MutexExp,
458 ProtectedOperationKind POK) {
459 LockKind LK = getLockKindFromAccessKind(AK);
DeLesley Hutchins9f80a972011-10-17 21:33:35 +0000460
461 MutexID Mutex(MutexExp, Exp, D);
Caitlin Sadowski194418f2011-09-14 20:00:24 +0000462 if (!Mutex.isValid())
463 Handler.handleInvalidLockExp(MutexExp->getExprLoc());
464 else if (!locksetContainsAtLeast(Mutex, LK))
Caitlin Sadowski402aa062011-09-09 16:11:56 +0000465 Handler.handleMutexNotHeld(D, POK, Mutex.getName(), LK, Exp->getExprLoc());
466}
467
Caitlin Sadowski402aa062011-09-09 16:11:56 +0000468/// \brief This method identifies variable dereferences and checks pt_guarded_by
469/// and pt_guarded_var annotations. Note that we only check these annotations
470/// at the time a pointer is dereferenced.
471/// FIXME: We need to check for other types of pointer dereferences
472/// (e.g. [], ->) and deal with them here.
473/// \param Exp An expression that has been read or written.
474void BuildLockset::checkDereference(Expr *Exp, AccessKind AK) {
475 UnaryOperator *UO = dyn_cast<UnaryOperator>(Exp);
476 if (!UO || UO->getOpcode() != clang::UO_Deref)
477 return;
478 Exp = UO->getSubExpr()->IgnoreParenCasts();
479
480 const ValueDecl *D = getValueDecl(Exp);
481 if(!D || !D->hasAttrs())
482 return;
483
484 if (D->getAttr<PtGuardedVarAttr>() && LSet.isEmpty())
485 Handler.handleNoMutexHeld(D, POK_VarDereference, AK, Exp->getExprLoc());
486
487 const AttrVec &ArgAttrs = D->getAttrs();
488 for(unsigned i = 0, Size = ArgAttrs.size(); i < Size; ++i)
489 if (PtGuardedByAttr *PGBAttr = dyn_cast<PtGuardedByAttr>(ArgAttrs[i]))
490 warnIfMutexNotHeld(D, Exp, AK, PGBAttr->getArg(), POK_VarDereference);
491}
492
493/// \brief Checks guarded_by and guarded_var attributes.
494/// Whenever we identify an access (read or write) of a DeclRefExpr or
495/// MemberExpr, we need to check whether there are any guarded_by or
496/// guarded_var attributes, and make sure we hold the appropriate mutexes.
497void BuildLockset::checkAccess(Expr *Exp, AccessKind AK) {
498 const ValueDecl *D = getValueDecl(Exp);
499 if(!D || !D->hasAttrs())
500 return;
501
502 if (D->getAttr<GuardedVarAttr>() && LSet.isEmpty())
503 Handler.handleNoMutexHeld(D, POK_VarAccess, AK, Exp->getExprLoc());
504
505 const AttrVec &ArgAttrs = D->getAttrs();
506 for(unsigned i = 0, Size = ArgAttrs.size(); i < Size; ++i)
507 if (GuardedByAttr *GBAttr = dyn_cast<GuardedByAttr>(ArgAttrs[i]))
508 warnIfMutexNotHeld(D, Exp, AK, GBAttr->getArg(), POK_VarAccess);
509}
510
511/// \brief For unary operations which read and write a variable, we need to
512/// check whether we hold any required mutexes. Reads are checked in
513/// VisitCastExpr.
514void BuildLockset::VisitUnaryOperator(UnaryOperator *UO) {
515 switch (UO->getOpcode()) {
516 case clang::UO_PostDec:
517 case clang::UO_PostInc:
518 case clang::UO_PreDec:
519 case clang::UO_PreInc: {
520 Expr *SubExp = UO->getSubExpr()->IgnoreParenCasts();
521 checkAccess(SubExp, AK_Written);
522 checkDereference(SubExp, AK_Written);
523 break;
524 }
525 default:
526 break;
527 }
528}
529
530/// For binary operations which assign to a variable (writes), we need to check
531/// whether we hold any required mutexes.
532/// FIXME: Deal with non-primitive types.
533void BuildLockset::VisitBinaryOperator(BinaryOperator *BO) {
534 if (!BO->isAssignmentOp())
535 return;
536 Expr *LHSExp = BO->getLHS()->IgnoreParenCasts();
537 checkAccess(LHSExp, AK_Written);
538 checkDereference(LHSExp, AK_Written);
539}
540
541/// Whenever we do an LValue to Rvalue cast, we are reading a variable and
542/// need to ensure we hold any required mutexes.
543/// FIXME: Deal with non-primitive types.
544void BuildLockset::VisitCastExpr(CastExpr *CE) {
545 if (CE->getCastKind() != CK_LValueToRValue)
546 return;
547 Expr *SubExp = CE->getSubExpr()->IgnoreParenCasts();
548 checkAccess(SubExp, AK_Read);
549 checkDereference(SubExp, AK_Read);
550}
551
Caitlin Sadowski402aa062011-09-09 16:11:56 +0000552/// \brief When visiting CXXMemberCallExprs we need to examine the attributes on
553/// the method that is being called and add, remove or check locks in the
554/// lockset accordingly.
555///
556/// FIXME: For classes annotated with one of the guarded annotations, we need
557/// to treat const method calls as reads and non-const method calls as writes,
558/// and check that the appropriate locks are held. Non-const method calls with
559/// the same signature as const method calls can be also treated as reads.
560///
561/// FIXME: We need to also visit CallExprs to catch/check global functions.
Caitlin Sadowski1748b122011-09-16 00:35:54 +0000562///
563/// FIXME: Do not flag an error for member variables accessed in constructors/
564/// destructors
Caitlin Sadowski402aa062011-09-09 16:11:56 +0000565void BuildLockset::VisitCXXMemberCallExpr(CXXMemberCallExpr *Exp) {
Caitlin Sadowski402aa062011-09-09 16:11:56 +0000566 SourceLocation ExpLocation = Exp->getExprLoc();
Caitlin Sadowski402aa062011-09-09 16:11:56 +0000567
DeLesley Hutchins9f80a972011-10-17 21:33:35 +0000568 NamedDecl *D = dyn_cast_or_null<NamedDecl>(Exp->getCalleeDecl());
Caitlin Sadowski402aa062011-09-09 16:11:56 +0000569 if(!D || !D->hasAttrs())
570 return;
571
572 AttrVec &ArgAttrs = D->getAttrs();
573 for(unsigned i = 0; i < ArgAttrs.size(); ++i) {
574 Attr *Attr = ArgAttrs[i];
575 switch (Attr->getKind()) {
576 // When we encounter an exclusive lock function, we need to add the lock
577 // to our lockset with kind exclusive.
DeLesley Hutchins9f80a972011-10-17 21:33:35 +0000578 case attr::ExclusiveLockFunction: {
579 ExclusiveLockFunctionAttr *A = cast<ExclusiveLockFunctionAttr>(Attr);
580 addLocksToSet(LK_Exclusive, A, Exp, D);
Caitlin Sadowski402aa062011-09-09 16:11:56 +0000581 break;
DeLesley Hutchins9f80a972011-10-17 21:33:35 +0000582 }
Caitlin Sadowski402aa062011-09-09 16:11:56 +0000583
584 // When we encounter a shared lock function, we need to add the lock
585 // to our lockset with kind shared.
DeLesley Hutchins9f80a972011-10-17 21:33:35 +0000586 case attr::SharedLockFunction: {
587 SharedLockFunctionAttr *A = cast<SharedLockFunctionAttr>(Attr);
588 addLocksToSet(LK_Shared, A, Exp, D);
Caitlin Sadowski402aa062011-09-09 16:11:56 +0000589 break;
DeLesley Hutchins9f80a972011-10-17 21:33:35 +0000590 }
Caitlin Sadowski402aa062011-09-09 16:11:56 +0000591
592 // When we encounter an unlock function, we need to remove unlocked
593 // mutexes from the lockset, and flag a warning if they are not there.
594 case attr::UnlockFunction: {
595 UnlockFunctionAttr *UFAttr = cast<UnlockFunctionAttr>(Attr);
596
597 if (UFAttr->args_size() == 0) { // The lock held is the "this" object.
DeLesley Hutchins9f80a972011-10-17 21:33:35 +0000598 MutexID Mu(0, Exp, D);
599 if (!Mu.isValid())
600 Handler.handleInvalidLockExp(Exp->getExprLoc());
601 else
602 removeLock(ExpLocation, Mu);
Caitlin Sadowski402aa062011-09-09 16:11:56 +0000603 break;
604 }
605
606 for (UnlockFunctionAttr::args_iterator I = UFAttr->args_begin(),
DeLesley Hutchins9f80a972011-10-17 21:33:35 +0000607 E = UFAttr->args_end(); I != E; ++I) {
608 MutexID Mutex(*I, Exp, D);
609 if (!Mutex.isValid())
610 Handler.handleInvalidLockExp(Exp->getExprLoc());
611 else
612 removeLock(ExpLocation, Mutex);
613 }
Caitlin Sadowski402aa062011-09-09 16:11:56 +0000614 break;
615 }
616
617 case attr::ExclusiveLocksRequired: {
Caitlin Sadowski402aa062011-09-09 16:11:56 +0000618 ExclusiveLocksRequiredAttr *ELRAttr =
619 cast<ExclusiveLocksRequiredAttr>(Attr);
620
621 for (ExclusiveLocksRequiredAttr::args_iterator
622 I = ELRAttr->args_begin(), E = ELRAttr->args_end(); I != E; ++I)
623 warnIfMutexNotHeld(D, Exp, AK_Written, *I, POK_FunctionCall);
624 break;
625 }
626
627 case attr::SharedLocksRequired: {
Caitlin Sadowski402aa062011-09-09 16:11:56 +0000628 SharedLocksRequiredAttr *SLRAttr = cast<SharedLocksRequiredAttr>(Attr);
629
630 for (SharedLocksRequiredAttr::args_iterator I = SLRAttr->args_begin(),
631 E = SLRAttr->args_end(); I != E; ++I)
632 warnIfMutexNotHeld(D, Exp, AK_Read, *I, POK_FunctionCall);
633 break;
634 }
635
636 case attr::LocksExcluded: {
637 LocksExcludedAttr *LEAttr = cast<LocksExcludedAttr>(Attr);
638 for (LocksExcludedAttr::args_iterator I = LEAttr->args_begin(),
639 E = LEAttr->args_end(); I != E; ++I) {
DeLesley Hutchins9f80a972011-10-17 21:33:35 +0000640 MutexID Mutex(*I, Exp, D);
Caitlin Sadowski194418f2011-09-14 20:00:24 +0000641 if (!Mutex.isValid())
642 Handler.handleInvalidLockExp((*I)->getExprLoc());
643 else if (locksetContains(Mutex))
Caitlin Sadowski402aa062011-09-09 16:11:56 +0000644 Handler.handleFunExcludesLock(D->getName(), Mutex.getName(),
645 ExpLocation);
646 }
647 break;
648 }
649
Caitlin Sadowski402aa062011-09-09 16:11:56 +0000650 // Ignore other (non thread-safety) attributes
651 default:
652 break;
653 }
654 }
655}
656
DeLesley Hutchinsa60448d2011-10-21 16:14:33 +0000657
658/// \brief Class which implements the core thread safety analysis routines.
659class ThreadSafetyAnalyzer {
660 ThreadSafetyHandler &Handler;
661 Lockset::Factory LocksetFactory;
662
663public:
664 ThreadSafetyAnalyzer(ThreadSafetyHandler &H) : Handler(H) {}
665
666 Lockset intersectAndWarn(const Lockset LSet1, const Lockset LSet2,
667 LockErrorKind LEK);
668
669 Lockset addLock(Lockset &LSet, Expr *MutexExp, const NamedDecl *D,
670 LockKind LK, SourceLocation Loc);
671
672 void runAnalysis(AnalysisContext &AC);
673};
Caitlin Sadowski402aa062011-09-09 16:11:56 +0000674
Caitlin Sadowski4e4bc752011-09-15 17:25:19 +0000675/// \brief Compute the intersection of two locksets and issue warnings for any
676/// locks in the symmetric difference.
677///
678/// This function is used at a merge point in the CFG when comparing the lockset
679/// of each branch being merged. For example, given the following sequence:
680/// A; if () then B; else C; D; we need to check that the lockset after B and C
681/// are the same. In the event of a difference, we use the intersection of these
682/// two locksets at the start of D.
DeLesley Hutchinsa60448d2011-10-21 16:14:33 +0000683Lockset ThreadSafetyAnalyzer::intersectAndWarn(const Lockset LSet1,
684 const Lockset LSet2,
685 LockErrorKind LEK) {
Caitlin Sadowski4e4bc752011-09-15 17:25:19 +0000686 Lockset Intersection = LSet1;
Caitlin Sadowski402aa062011-09-09 16:11:56 +0000687 for (Lockset::iterator I = LSet2.begin(), E = LSet2.end(); I != E; ++I) {
688 const MutexID &LSet2Mutex = I.getKey();
689 const LockData &LSet2LockData = I.getData();
690 if (const LockData *LD = LSet1.lookup(LSet2Mutex)) {
691 if (LD->LKind != LSet2LockData.LKind) {
692 Handler.handleExclusiveAndShared(LSet2Mutex.getName(),
693 LSet2LockData.AcquireLoc,
694 LD->AcquireLoc);
695 if (LD->LKind != LK_Exclusive)
DeLesley Hutchinsa60448d2011-10-21 16:14:33 +0000696 Intersection = LocksetFactory.add(Intersection, LSet2Mutex,
697 LSet2LockData);
Caitlin Sadowski402aa062011-09-09 16:11:56 +0000698 }
699 } else {
700 Handler.handleMutexHeldEndOfScope(LSet2Mutex.getName(),
Caitlin Sadowski4e4bc752011-09-15 17:25:19 +0000701 LSet2LockData.AcquireLoc, LEK);
Caitlin Sadowski402aa062011-09-09 16:11:56 +0000702 }
703 }
Caitlin Sadowski402aa062011-09-09 16:11:56 +0000704
705 for (Lockset::iterator I = LSet1.begin(), E = LSet1.end(); I != E; ++I) {
706 if (!LSet2.contains(I.getKey())) {
707 const MutexID &Mutex = I.getKey();
708 const LockData &MissingLock = I.getData();
709 Handler.handleMutexHeldEndOfScope(Mutex.getName(),
Caitlin Sadowski4e4bc752011-09-15 17:25:19 +0000710 MissingLock.AcquireLoc, LEK);
DeLesley Hutchinsa60448d2011-10-21 16:14:33 +0000711 Intersection = LocksetFactory.remove(Intersection, Mutex);
Caitlin Sadowski402aa062011-09-09 16:11:56 +0000712 }
713 }
714 return Intersection;
715}
716
DeLesley Hutchinsa60448d2011-10-21 16:14:33 +0000717Lockset ThreadSafetyAnalyzer::addLock(Lockset &LSet, Expr *MutexExp,
718 const NamedDecl *D,
719 LockKind LK, SourceLocation Loc) {
DeLesley Hutchins9f80a972011-10-17 21:33:35 +0000720 MutexID Mutex(MutexExp, 0, D);
Caitlin Sadowskicb967512011-09-15 17:43:08 +0000721 if (!Mutex.isValid()) {
DeLesley Hutchins9f80a972011-10-17 21:33:35 +0000722 Handler.handleInvalidLockExp(MutexExp->getExprLoc());
Caitlin Sadowskicb967512011-09-15 17:43:08 +0000723 return LSet;
724 }
725 LockData NewLock(Loc, LK);
726 return LocksetFactory.add(LSet, Mutex, NewLock);
727}
728
Caitlin Sadowski402aa062011-09-09 16:11:56 +0000729/// \brief Check a function's CFG for thread-safety violations.
730///
731/// We traverse the blocks in the CFG, compute the set of mutexes that are held
732/// at the end of each block, and issue warnings for thread safety violations.
733/// Each block in the CFG is traversed exactly once.
DeLesley Hutchinsa60448d2011-10-21 16:14:33 +0000734void ThreadSafetyAnalyzer::runAnalysis(AnalysisContext &AC) {
Caitlin Sadowski402aa062011-09-09 16:11:56 +0000735 CFG *CFGraph = AC.getCFG();
736 if (!CFGraph) return;
DeLesley Hutchins9f80a972011-10-17 21:33:35 +0000737 const NamedDecl *D = dyn_cast_or_null<NamedDecl>(AC.getDecl());
738
739 if (!D)
740 return; // Ignore anonymous functions for now.
741 if (D->getAttr<NoThreadSafetyAnalysisAttr>())
742 return;
Caitlin Sadowski402aa062011-09-09 16:11:56 +0000743
DeLesley Hutchinsa60448d2011-10-21 16:14:33 +0000744 // FIXME: Switch to SmallVector? Otherwise improve performance impact?
Caitlin Sadowski402aa062011-09-09 16:11:56 +0000745 std::vector<Lockset> EntryLocksets(CFGraph->getNumBlockIDs(),
746 LocksetFactory.getEmptyMap());
747 std::vector<Lockset> ExitLocksets(CFGraph->getNumBlockIDs(),
748 LocksetFactory.getEmptyMap());
749
750 // We need to explore the CFG via a "topological" ordering.
751 // That way, we will be guaranteed to have information about required
752 // predecessor locksets when exploring a new block.
753 TopologicallySortedCFG SortedGraph(CFGraph);
754 CFGBlockSet VisitedBlocks(CFGraph);
755
DeLesley Hutchinsa60448d2011-10-21 16:14:33 +0000756 // Add locks from exclusive_locks_required and shared_locks_required
757 // to initial lockset.
Caitlin Sadowskicb967512011-09-15 17:43:08 +0000758 if (!SortedGraph.empty() && D->hasAttrs()) {
759 const CFGBlock *FirstBlock = *SortedGraph.begin();
760 Lockset &InitialLockset = EntryLocksets[FirstBlock->getBlockID()];
761 const AttrVec &ArgAttrs = D->getAttrs();
762 for(unsigned i = 0; i < ArgAttrs.size(); ++i) {
763 Attr *Attr = ArgAttrs[i];
Caitlin Sadowski1748b122011-09-16 00:35:54 +0000764 SourceLocation AttrLoc = Attr->getLocation();
Caitlin Sadowskicb967512011-09-15 17:43:08 +0000765 if (SharedLocksRequiredAttr *SLRAttr
766 = dyn_cast<SharedLocksRequiredAttr>(Attr)) {
767 for (SharedLocksRequiredAttr::args_iterator
768 SLRIter = SLRAttr->args_begin(),
769 SLREnd = SLRAttr->args_end(); SLRIter != SLREnd; ++SLRIter)
DeLesley Hutchinsa60448d2011-10-21 16:14:33 +0000770 InitialLockset = addLock(InitialLockset,
DeLesley Hutchins9f80a972011-10-17 21:33:35 +0000771 *SLRIter, D, LK_Shared,
Caitlin Sadowski1748b122011-09-16 00:35:54 +0000772 AttrLoc);
Caitlin Sadowskicb967512011-09-15 17:43:08 +0000773 } else if (ExclusiveLocksRequiredAttr *ELRAttr
774 = dyn_cast<ExclusiveLocksRequiredAttr>(Attr)) {
775 for (ExclusiveLocksRequiredAttr::args_iterator
776 ELRIter = ELRAttr->args_begin(),
777 ELREnd = ELRAttr->args_end(); ELRIter != ELREnd; ++ELRIter)
DeLesley Hutchinsa60448d2011-10-21 16:14:33 +0000778 InitialLockset = addLock(InitialLockset,
DeLesley Hutchins9f80a972011-10-17 21:33:35 +0000779 *ELRIter, D, LK_Exclusive,
Caitlin Sadowski1748b122011-09-16 00:35:54 +0000780 AttrLoc);
Caitlin Sadowskicb967512011-09-15 17:43:08 +0000781 }
782 }
783 }
784
Caitlin Sadowski402aa062011-09-09 16:11:56 +0000785 for (TopologicallySortedCFG::iterator I = SortedGraph.begin(),
786 E = SortedGraph.end(); I!= E; ++I) {
787 const CFGBlock *CurrBlock = *I;
788 int CurrBlockID = CurrBlock->getBlockID();
789
790 VisitedBlocks.insert(CurrBlock);
791
792 // Use the default initial lockset in case there are no predecessors.
793 Lockset &Entryset = EntryLocksets[CurrBlockID];
794 Lockset &Exitset = ExitLocksets[CurrBlockID];
795
796 // Iterate through the predecessor blocks and warn if the lockset for all
797 // predecessors is not the same. We take the entry lockset of the current
798 // block to be the intersection of all previous locksets.
799 // FIXME: By keeping the intersection, we may output more errors in future
800 // for a lock which is not in the intersection, but was in the union. We
801 // may want to also keep the union in future. As an example, let's say
802 // the intersection contains Mutex L, and the union contains L and M.
803 // Later we unlock M. At this point, we would output an error because we
804 // never locked M; although the real error is probably that we forgot to
805 // lock M on all code paths. Conversely, let's say that later we lock M.
806 // In this case, we should compare against the intersection instead of the
807 // union because the real error is probably that we forgot to unlock M on
808 // all code paths.
809 bool LocksetInitialized = false;
810 for (CFGBlock::const_pred_iterator PI = CurrBlock->pred_begin(),
811 PE = CurrBlock->pred_end(); PI != PE; ++PI) {
812
813 // if *PI -> CurrBlock is a back edge
814 if (*PI == 0 || !VisitedBlocks.alreadySet(*PI))
815 continue;
816
817 int PrevBlockID = (*PI)->getBlockID();
818 if (!LocksetInitialized) {
819 Entryset = ExitLocksets[PrevBlockID];
820 LocksetInitialized = true;
821 } else {
DeLesley Hutchinsa60448d2011-10-21 16:14:33 +0000822 Entryset = intersectAndWarn(Entryset, ExitLocksets[PrevBlockID],
Caitlin Sadowski4e4bc752011-09-15 17:25:19 +0000823 LEK_LockedSomePredecessors);
Caitlin Sadowski402aa062011-09-09 16:11:56 +0000824 }
825 }
826
827 BuildLockset LocksetBuilder(Handler, Entryset, LocksetFactory);
828 for (CFGBlock::const_iterator BI = CurrBlock->begin(),
829 BE = CurrBlock->end(); BI != BE; ++BI) {
830 if (const CFGStmt *CfgStmt = dyn_cast<CFGStmt>(&*BI))
831 LocksetBuilder.Visit(const_cast<Stmt*>(CfgStmt->getStmt()));
832 }
833 Exitset = LocksetBuilder.getLockset();
834
835 // For every back edge from CurrBlock (the end of the loop) to another block
836 // (FirstLoopBlock) we need to check that the Lockset of Block is equal to
837 // the one held at the beginning of FirstLoopBlock. We can look up the
838 // Lockset held at the beginning of FirstLoopBlock in the EntryLockSets map.
839 for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(),
840 SE = CurrBlock->succ_end(); SI != SE; ++SI) {
841
842 // if CurrBlock -> *SI is *not* a back edge
843 if (*SI == 0 || !VisitedBlocks.alreadySet(*SI))
844 continue;
845
846 CFGBlock *FirstLoopBlock = *SI;
Caitlin Sadowski402aa062011-09-09 16:11:56 +0000847 Lockset PreLoop = EntryLocksets[FirstLoopBlock->getBlockID()];
848 Lockset LoopEnd = ExitLocksets[CurrBlockID];
DeLesley Hutchinsa60448d2011-10-21 16:14:33 +0000849 intersectAndWarn(LoopEnd, PreLoop, LEK_LockedSomeLoopIterations);
Caitlin Sadowski402aa062011-09-09 16:11:56 +0000850 }
851 }
852
Caitlin Sadowski4e4bc752011-09-15 17:25:19 +0000853 Lockset InitialLockset = EntryLocksets[CFGraph->getEntry().getBlockID()];
Caitlin Sadowski402aa062011-09-09 16:11:56 +0000854 Lockset FinalLockset = ExitLocksets[CFGraph->getExit().getBlockID()];
Caitlin Sadowski1748b122011-09-16 00:35:54 +0000855
856 // FIXME: Should we call this function for all blocks which exit the function?
DeLesley Hutchinsa60448d2011-10-21 16:14:33 +0000857 intersectAndWarn(InitialLockset, FinalLockset, LEK_LockedAtEndOfFunction);
858}
859
860} // end anonymous namespace
861
862
863namespace clang {
864namespace thread_safety {
865
866/// \brief Check a function's CFG for thread-safety violations.
867///
868/// We traverse the blocks in the CFG, compute the set of mutexes that are held
869/// at the end of each block, and issue warnings for thread safety violations.
870/// Each block in the CFG is traversed exactly once.
871void runThreadSafetyAnalysis(AnalysisContext &AC,
872 ThreadSafetyHandler &Handler) {
873 ThreadSafetyAnalyzer Analyzer(Handler);
874 Analyzer.runAnalysis(AC);
Caitlin Sadowski402aa062011-09-09 16:11:56 +0000875}
876
877/// \brief Helper function that returns a LockKind required for the given level
878/// of access.
879LockKind getLockKindFromAccessKind(AccessKind AK) {
880 switch (AK) {
881 case AK_Read :
882 return LK_Shared;
883 case AK_Written :
884 return LK_Exclusive;
885 }
Benjamin Kramerafc5b152011-09-10 21:52:04 +0000886 llvm_unreachable("Unknown AccessKind");
Caitlin Sadowski402aa062011-09-09 16:11:56 +0000887}
DeLesley Hutchinsa60448d2011-10-21 16:14:33 +0000888
Caitlin Sadowski402aa062011-09-09 16:11:56 +0000889}} // end namespace clang::thread_safety