r228194 - Thread Safety Analysis: support adopting of locks, as implemented in
DeLesley Hutchins
delesley at google.com
Wed Feb 4 13:16:17 PST 2015
Author: delesley
Date: Wed Feb 4 15:16:17 2015
New Revision: 228194
URL: http://llvm.org/viewvc/llvm-project?rev=228194&view=rev
Log:
Thread Safety Analysis: support adopting of locks, as implemented in
std::lock_guard. If EXCLUSIVE_LOCKS_REQUIRED is placed on the constructor of
a SCOPED_LOCKABLE class, then that constructor is assumed to adopt the lock;
e.g. the lock must be held on construction, and will be released on destruction.
Modified:
cfe/trunk/lib/Analysis/ThreadSafety.cpp
cfe/trunk/test/SemaCXX/warn-thread-safety-analysis.cpp
Modified: cfe/trunk/lib/Analysis/ThreadSafety.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/ThreadSafety.cpp?rev=228194&r1=228193&r2=228194&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/ThreadSafety.cpp (original)
+++ cfe/trunk/lib/Analysis/ThreadSafety.cpp Wed Feb 4 15:16:17 2015
@@ -1690,8 +1690,19 @@ void BuildLockset::handleCall(Expr *Exp,
SourceLocation Loc = Exp->getExprLoc();
CapExprSet ExclusiveLocksToAdd, SharedLocksToAdd;
CapExprSet ExclusiveLocksToRemove, SharedLocksToRemove, GenericLocksToRemove;
+ CapExprSet ScopedExclusiveReqs, ScopedSharedReqs;
StringRef CapDiagKind = "mutex";
+ // Figure out if we're calling the constructor of scoped lockable class
+ bool isScopedVar = false;
+ if (VD) {
+ if (const CXXConstructorDecl *CD = dyn_cast<const CXXConstructorDecl>(D)) {
+ const CXXRecordDecl* PD = CD->getParent();
+ if (PD && PD->hasAttr<ScopedLockableAttr>())
+ isScopedVar = true;
+ }
+ }
+
for(Attr *Atconst : D->attrs()) {
Attr* At = const_cast<Attr*>(Atconst);
switch (At->getKind()) {
@@ -1751,10 +1762,17 @@ void BuildLockset::handleCall(Expr *Exp,
case attr::RequiresCapability: {
RequiresCapabilityAttr *A = cast<RequiresCapabilityAttr>(At);
- for (auto *Arg : A->args())
+ for (auto *Arg : A->args()) {
warnIfMutexNotHeld(D, Exp, A->isShared() ? AK_Read : AK_Written, Arg,
POK_FunctionCall, ClassifyDiagnostic(A),
Exp->getExprLoc());
+ // use for adopting a lock
+ if (isScopedVar) {
+ Analyzer->getMutexIDs(A->isShared() ? ScopedSharedReqs
+ : ScopedExclusiveReqs,
+ A, Exp, D, VD);
+ }
+ }
break;
}
@@ -1771,16 +1789,6 @@ void BuildLockset::handleCall(Expr *Exp,
}
}
- // Figure out if we're calling the constructor of scoped lockable class
- bool isScopedVar = false;
- if (VD) {
- if (const CXXConstructorDecl *CD = dyn_cast<const CXXConstructorDecl>(D)) {
- const CXXRecordDecl* PD = CD->getParent();
- if (PD && PD->hasAttr<ScopedLockableAttr>())
- isScopedVar = true;
- }
- }
-
// Add locks.
for (const auto &M : ExclusiveLocksToAdd)
Analyzer->addLock(FSet, llvm::make_unique<LockableFactEntry>(
@@ -1797,6 +1805,11 @@ void BuildLockset::handleCall(Expr *Exp,
DeclRefExpr DRE(VD, false, VD->getType(), VK_LValue, VD->getLocation());
// FIXME: does this store a pointer to DRE?
CapabilityExpr Scp = Analyzer->SxBuilder.translateAttrExpr(&DRE, nullptr);
+
+ std::copy(ScopedExclusiveReqs.begin(), ScopedExclusiveReqs.end(),
+ std::back_inserter(ExclusiveLocksToAdd));
+ std::copy(ScopedSharedReqs.begin(), ScopedSharedReqs.end(),
+ std::back_inserter(SharedLocksToAdd));
Analyzer->addLock(FSet,
llvm::make_unique<ScopedLockableFactEntry>(
Scp, MLoc, ExclusiveLocksToAdd, SharedLocksToAdd),
Modified: cfe/trunk/test/SemaCXX/warn-thread-safety-analysis.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/warn-thread-safety-analysis.cpp?rev=228194&r1=228193&r2=228194&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/warn-thread-safety-analysis.cpp (original)
+++ cfe/trunk/test/SemaCXX/warn-thread-safety-analysis.cpp Wed Feb 4 15:16:17 2015
@@ -3,31 +3,31 @@
// FIXME: should also run %clang_cc1 -fsyntax-only -verify -Wthread-safety -std=c++11 -Wc++98-compat %s
// FIXME: should also run %clang_cc1 -fsyntax-only -verify -Wthread-safety %s
-#define LOCKABLE __attribute__ ((lockable))
-#define SCOPED_LOCKABLE __attribute__ ((scoped_lockable))
-#define GUARDED_BY(x) __attribute__ ((guarded_by(x)))
-#define GUARDED_VAR __attribute__ ((guarded_var))
-#define PT_GUARDED_BY(x) __attribute__ ((pt_guarded_by(x)))
-#define PT_GUARDED_VAR __attribute__ ((pt_guarded_var))
-#define ACQUIRED_AFTER(...) __attribute__ ((acquired_after(__VA_ARGS__)))
-#define ACQUIRED_BEFORE(...) __attribute__ ((acquired_before(__VA_ARGS__)))
-#define EXCLUSIVE_LOCK_FUNCTION(...) __attribute__ ((exclusive_lock_function(__VA_ARGS__)))
-#define SHARED_LOCK_FUNCTION(...) __attribute__ ((shared_lock_function(__VA_ARGS__)))
-#define ASSERT_EXCLUSIVE_LOCK(...) __attribute__ ((assert_exclusive_lock(__VA_ARGS__)))
-#define ASSERT_SHARED_LOCK(...) __attribute__ ((assert_shared_lock(__VA_ARGS__)))
-#define EXCLUSIVE_TRYLOCK_FUNCTION(...) __attribute__ ((exclusive_trylock_function(__VA_ARGS__)))
-#define SHARED_TRYLOCK_FUNCTION(...) __attribute__ ((shared_trylock_function(__VA_ARGS__)))
-#define UNLOCK_FUNCTION(...) __attribute__ ((unlock_function(__VA_ARGS__)))
-#define LOCK_RETURNED(x) __attribute__ ((lock_returned(x)))
-#define LOCKS_EXCLUDED(...) __attribute__ ((locks_excluded(__VA_ARGS__)))
-#define EXCLUSIVE_LOCKS_REQUIRED(...) \
- __attribute__ ((exclusive_locks_required(__VA_ARGS__)))
-#define SHARED_LOCKS_REQUIRED(...) \
- __attribute__ ((shared_locks_required(__VA_ARGS__)))
-#define NO_THREAD_SAFETY_ANALYSIS __attribute__ ((no_thread_safety_analysis))
+#define LOCKABLE __attribute__((lockable))
+#define SCOPED_LOCKABLE __attribute__((scoped_lockable))
+#define GUARDED_BY(x) __attribute__((guarded_by(x)))
+#define GUARDED_VAR __attribute__((guarded_var))
+#define PT_GUARDED_BY(x) __attribute__((pt_guarded_by(x)))
+#define PT_GUARDED_VAR __attribute__((pt_guarded_var))
+#define ACQUIRED_AFTER(...) __attribute__((acquired_after(__VA_ARGS__)))
+#define ACQUIRED_BEFORE(...) __attribute__((acquired_before(__VA_ARGS__)))
+#define EXCLUSIVE_LOCK_FUNCTION(...) __attribute__((exclusive_lock_function(__VA_ARGS__)))
+#define SHARED_LOCK_FUNCTION(...) __attribute__((shared_lock_function(__VA_ARGS__)))
+#define ASSERT_EXCLUSIVE_LOCK(...) __attribute__((assert_exclusive_lock(__VA_ARGS__)))
+#define ASSERT_SHARED_LOCK(...) __attribute__((assert_shared_lock(__VA_ARGS__)))
+#define EXCLUSIVE_TRYLOCK_FUNCTION(...) __attribute__((exclusive_trylock_function(__VA_ARGS__)))
+#define SHARED_TRYLOCK_FUNCTION(...) __attribute__((shared_trylock_function(__VA_ARGS__)))
+#define UNLOCK_FUNCTION(...) __attribute__((unlock_function(__VA_ARGS__)))
+#define EXCLUSIVE_UNLOCK_FUNCTION(...) __attribute__((release_capability(__VA_ARGS__)))
+#define SHARED_UNLOCK_FUNCTION(...) __attribute__((release_shared_capability(__VA_ARGS__)))
+#define LOCK_RETURNED(x) __attribute__((lock_returned(x)))
+#define LOCKS_EXCLUDED(...) __attribute__((locks_excluded(__VA_ARGS__)))
+#define EXCLUSIVE_LOCKS_REQUIRED(...) __attribute__((exclusive_locks_required(__VA_ARGS__)))
+#define SHARED_LOCKS_REQUIRED(...) __attribute__((shared_locks_required(__VA_ARGS__)))
+#define NO_THREAD_SAFETY_ANALYSIS __attribute__((no_thread_safety_analysis))
-class __attribute__((lockable)) Mutex {
+class LOCKABLE Mutex {
public:
void Lock() __attribute__((exclusive_lock_function));
void ReaderLock() __attribute__((shared_lock_function));
@@ -43,16 +43,18 @@ class __attribute__((lockable)) Mutex {
void AssertReaderHeld() ASSERT_SHARED_LOCK();
};
-class __attribute__((scoped_lockable)) MutexLock {
+class SCOPED_LOCKABLE MutexLock {
public:
- MutexLock(Mutex *mu) __attribute__((exclusive_lock_function(mu)));
- ~MutexLock() __attribute__((unlock_function));
+ MutexLock(Mutex *mu) EXCLUSIVE_LOCK_FUNCTION(mu);
+ MutexLock(Mutex *mu, bool adopt) EXCLUSIVE_LOCKS_REQUIRED(mu);
+ ~MutexLock() UNLOCK_FUNCTION();
};
-class __attribute__((scoped_lockable)) ReaderMutexLock {
+class SCOPED_LOCKABLE ReaderMutexLock {
public:
- ReaderMutexLock(Mutex *mu) __attribute__((exclusive_lock_function(mu)));
- ~ReaderMutexLock() __attribute__((unlock_function));
+ ReaderMutexLock(Mutex *mu) SHARED_LOCK_FUNCTION(mu);
+ ReaderMutexLock(Mutex *mu, bool adopt) SHARED_LOCKS_REQUIRED(mu);
+ ~ReaderMutexLock() UNLOCK_FUNCTION();
};
class SCOPED_LOCKABLE ReleasableMutexLock {
@@ -5055,6 +5057,37 @@ class Foo6 {
}
};
-
} // end namespace AcquiredBeforeAfterTest
+
+namespace ScopedAdoptTest {
+
+class Foo {
+ Mutex mu;
+ int a GUARDED_BY(mu);
+ int b;
+
+ void test1() EXCLUSIVE_UNLOCK_FUNCTION(mu) {
+ MutexLock slock(&mu, true);
+ a = 0;
+ }
+
+ void test2() SHARED_UNLOCK_FUNCTION(mu) {
+ ReaderMutexLock slock(&mu, true);
+ b = a;
+ }
+
+ void test3() EXCLUSIVE_LOCKS_REQUIRED(mu) { // expected-note {{mutex acquired here}}
+ MutexLock slock(&mu, true);
+ a = 0;
+ } // expected-warning {{expecting mutex 'mu' to be held at the end of function}}
+
+ void test4() SHARED_LOCKS_REQUIRED(mu) { // expected-note {{mutex acquired here}}
+ ReaderMutexLock slock(&mu, true);
+ b = a;
+ } // expected-warning {{expecting mutex 'mu' to be held at the end of function}}
+
+};
+
+} // end namespace ScopedAdoptTest
+
More information about the cfe-commits
mailing list