summaryrefslogtreecommitdiff
path: root/test/SemaCXX/warn-thread-safety-analysis.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'test/SemaCXX/warn-thread-safety-analysis.cpp')
-rw-r--r--test/SemaCXX/warn-thread-safety-analysis.cpp203
1 files changed, 143 insertions, 60 deletions
diff --git a/test/SemaCXX/warn-thread-safety-analysis.cpp b/test/SemaCXX/warn-thread-safety-analysis.cpp
index fc1ea5e9e996e..51535be97d97e 100644
--- a/test/SemaCXX/warn-thread-safety-analysis.cpp
+++ b/test/SemaCXX/warn-thread-safety-analysis.cpp
@@ -1,10 +1,11 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -Wthread-safety -Wthread-safety-beta -Wno-thread-safety-negative -fcxx-exceptions -DUSE_ASSERT_CAPABILITY=0 %s
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -Wthread-safety -Wthread-safety-beta -Wno-thread-safety-negative -fcxx-exceptions -DUSE_ASSERT_CAPABILITY=1 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -Wthread-safety -Wthread-safety-beta -Wno-thread-safety-negative -fcxx-exceptions -DUSE_CAPABILITY=0 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -Wthread-safety -Wthread-safety-beta -Wno-thread-safety-negative -fcxx-exceptions -DUSE_CAPABILITY=1 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++17 -Wthread-safety -Wthread-safety-beta -Wno-thread-safety-negative -fcxx-exceptions -DUSE_CAPABILITY=0 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++17 -Wthread-safety -Wthread-safety-beta -Wno-thread-safety-negative -fcxx-exceptions -DUSE_CAPABILITY=1 %s
// 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))
@@ -12,37 +13,49 @@
#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__)))
-#if USE_ASSERT_CAPABILITY
+#if USE_CAPABILITY
+#define LOCKABLE __attribute__((capability("mutex")))
#define ASSERT_EXCLUSIVE_LOCK(...) __attribute__((assert_capability(__VA_ARGS__)))
#define ASSERT_SHARED_LOCK(...) __attribute__((assert_shared_capability(__VA_ARGS__)))
+#define EXCLUSIVE_LOCK_FUNCTION(...) __attribute__((acquire_capability(__VA_ARGS__)))
+#define SHARED_LOCK_FUNCTION(...) __attribute__((acquire_shared_capability(__VA_ARGS__)))
+#define EXCLUSIVE_TRYLOCK_FUNCTION(...) __attribute__((try_acquire_capability(__VA_ARGS__)))
+#define SHARED_TRYLOCK_FUNCTION(...) __attribute__((try_acquire_shared_capability(__VA_ARGS__)))
+#define EXCLUSIVE_LOCKS_REQUIRED(...) __attribute__((requires_capability(__VA_ARGS__)))
+#define SHARED_LOCKS_REQUIRED(...) __attribute__((requires_shared_capability(__VA_ARGS__)))
#else
+#define LOCKABLE __attribute__((lockable))
#define ASSERT_EXCLUSIVE_LOCK(...) __attribute__((assert_exclusive_lock(__VA_ARGS__)))
#define ASSERT_SHARED_LOCK(...) __attribute__((assert_shared_lock(__VA_ARGS__)))
-#endif
-
+#define EXCLUSIVE_LOCK_FUNCTION(...) __attribute__((exclusive_lock_function(__VA_ARGS__)))
+#define SHARED_LOCK_FUNCTION(...) __attribute__((shared_lock_function(__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_LOCKS_REQUIRED(...) __attribute__((exclusive_locks_required(__VA_ARGS__)))
+#define SHARED_LOCKS_REQUIRED(...) __attribute__((shared_locks_required(__VA_ARGS__)))
+#endif
#define EXCLUSIVE_UNLOCK_FUNCTION(...) __attribute__((release_capability(__VA_ARGS__)))
#define SHARED_UNLOCK_FUNCTION(...) __attribute__((release_shared_capability(__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))
class LOCKABLE Mutex {
public:
- void Lock() __attribute__((exclusive_lock_function));
- void ReaderLock() __attribute__((shared_lock_function));
- void Unlock() __attribute__((unlock_function));
- bool TryLock() __attribute__((exclusive_trylock_function(true)));
- bool ReaderTryLock() __attribute__((shared_trylock_function(true)));
- void LockWhen(const int &cond) __attribute__((exclusive_lock_function));
+ void Lock() EXCLUSIVE_LOCK_FUNCTION();
+ void ReaderLock() SHARED_LOCK_FUNCTION();
+ void Unlock() UNLOCK_FUNCTION();
+ void ExclusiveUnlock() EXCLUSIVE_UNLOCK_FUNCTION();
+ void ReaderUnlock() SHARED_UNLOCK_FUNCTION();
+ bool TryLock() EXCLUSIVE_TRYLOCK_FUNCTION(true);
+ bool ReaderTryLock() SHARED_TRYLOCK_FUNCTION(true);
+ void LockWhen(const int &cond) EXCLUSIVE_LOCK_FUNCTION();
+
+ void PromoteShared() SHARED_UNLOCK_FUNCTION() EXCLUSIVE_LOCK_FUNCTION();
+ void DemoteExclusive() EXCLUSIVE_UNLOCK_FUNCTION() SHARED_LOCK_FUNCTION();
// for negative capabilities
const Mutex& operator!() const { return *this; }
@@ -73,11 +86,10 @@ class SCOPED_LOCKABLE ReleasableMutexLock {
void Release() UNLOCK_FUNCTION();
};
-class __attribute__((scoped_lockable)) DoubleMutexLock {
+class SCOPED_LOCKABLE DoubleMutexLock {
public:
- DoubleMutexLock(Mutex *mu1, Mutex *mu2)
- __attribute__((exclusive_lock_function(mu1, mu2)));
- ~DoubleMutexLock() __attribute__((unlock_function));
+ DoubleMutexLock(Mutex *mu1, Mutex *mu2) EXCLUSIVE_LOCK_FUNCTION(mu1, mu2);
+ ~DoubleMutexLock() UNLOCK_FUNCTION();
};
// The universal lock, written "*", allows checking to be selectively turned
@@ -158,7 +170,7 @@ class MutexWrapper {
public:
Mutex mu;
int x __attribute__((guarded_by(mu)));
- void MyLock() __attribute__((exclusive_lock_function(mu)));
+ void MyLock() EXCLUSIVE_LOCK_FUNCTION(mu);
};
MutexWrapper sls_mw;
@@ -371,8 +383,8 @@ Mutex aa_mu;
class GlobalLocker {
public:
- void globalLock() __attribute__((exclusive_lock_function(aa_mu)));
- void globalUnlock() __attribute__((unlock_function(aa_mu)));
+ void globalLock() EXCLUSIVE_LOCK_FUNCTION(aa_mu);
+ void globalUnlock() UNLOCK_FUNCTION(aa_mu);
};
GlobalLocker glock;
@@ -455,7 +467,7 @@ class GBFoo {
// expected-warning {{writing variable 'gb_field' requires holding mutex 'sls_mu' exclusively}}
}
- void testNoAnal() __attribute__((no_thread_safety_analysis)) {
+ void testNoAnal() NO_THREAD_SAFETY_ANALYSIS {
gb_field = 0;
}
};
@@ -549,7 +561,7 @@ public:
int a __attribute__((guarded_by(mu)));
int b;
- void foo() __attribute__((exclusive_locks_required(mu))) { }
+ void foo() EXCLUSIVE_LOCKS_REQUIRED(mu) { }
void test() {
a = 0; // \
@@ -695,6 +707,26 @@ void shared_fun_8() {
sls_mu.Unlock();
}
+void shared_fun_9() {
+ sls_mu.Lock();
+ sls_mu.ExclusiveUnlock();
+
+ sls_mu.ReaderLock();
+ sls_mu.ReaderUnlock();
+}
+
+void shared_fun_10() {
+ sls_mu.Lock();
+ sls_mu.DemoteExclusive();
+ sls_mu.ReaderUnlock();
+}
+
+void shared_fun_11() {
+ sls_mu.ReaderLock();
+ sls_mu.PromoteShared();
+ sls_mu.Unlock();
+}
+
void shared_bad_0() {
sls_mu.Lock(); // \
// expected-warning {{mutex 'sls_mu' is acquired exclusively and shared in the same scope}}
@@ -728,21 +760,47 @@ void shared_bad_2() {
sls_mu.Unlock();
}
+void shared_bad_3() {
+ sls_mu.Lock();
+ sls_mu.ReaderUnlock(); // \
+ // expected-warning {{releasing mutex 'sls_mu' using shared access, expected exclusive access}}
+}
+
+void shared_bad_4() {
+ sls_mu.ReaderLock();
+ sls_mu.ExclusiveUnlock(); // \
+ // expected-warning {{releasing mutex 'sls_mu' using exclusive access, expected shared access}}
+}
+
+void shared_bad_5() {
+ sls_mu.Lock();
+ sls_mu.PromoteShared(); // \
+ // expected-warning {{releasing mutex 'sls_mu' using shared access, expected exclusive access}}
+ sls_mu.ExclusiveUnlock();
+}
+
+void shared_bad_6() {
+ sls_mu.ReaderLock();
+ sls_mu.DemoteExclusive(); // \
+ // expected-warning {{releasing mutex 'sls_mu' using exclusive access, expected shared access}}
+ sls_mu.ReaderUnlock();
+}
+
// FIXME: Add support for functions (not only methods)
class LRBar {
public:
- void aa_elr_fun() __attribute__((exclusive_locks_required(aa_mu)));
- void aa_elr_fun_s() __attribute__((shared_locks_required(aa_mu)));
+ void aa_elr_fun() EXCLUSIVE_LOCKS_REQUIRED(aa_mu);
+ void aa_elr_fun_s() SHARED_LOCKS_REQUIRED(aa_mu);
void le_fun() __attribute__((locks_excluded(sls_mu)));
};
class LRFoo {
public:
- void test() __attribute__((exclusive_locks_required(sls_mu)));
- void testShared() __attribute__((shared_locks_required(sls_mu2)));
+ void test() EXCLUSIVE_LOCKS_REQUIRED(sls_mu);
+ void testShared() SHARED_LOCKS_REQUIRED(sls_mu2);
};
-void elr_fun() __attribute__((exclusive_locks_required(sls_mu)));
+void elr_fun() EXCLUSIVE_LOCKS_REQUIRED(sls_mu);
void elr_fun() {}
LRFoo MyLRFoo;
@@ -794,18 +852,18 @@ void es_fun_7() {
sls_mu.Unlock();
}
-void es_fun_8() __attribute__((no_thread_safety_analysis));
+void es_fun_8() NO_THREAD_SAFETY_ANALYSIS;
void es_fun_8() {
Bar.aa_elr_fun_s();
}
-void es_fun_9() __attribute__((shared_locks_required(aa_mu)));
+void es_fun_9() SHARED_LOCKS_REQUIRED(aa_mu);
void es_fun_9() {
Bar.aa_elr_fun_s();
}
-void es_fun_10() __attribute__((exclusive_locks_required(aa_mu)));
+void es_fun_10() EXCLUSIVE_LOCKS_REQUIRED(aa_mu);
void es_fun_10() {
Bar.aa_elr_fun_s();
}
@@ -1047,7 +1105,7 @@ void main() {
namespace thread_annot_lock_61_modified {
// Modified to fix the compiler errors
// Test the fix for a bug introduced by the support of pass-by-reference
- // paramters.
+ // parameters.
struct Foo { Foo &operator<< (bool) {return *this;} };
Foo &getFoo();
struct Bar { Foo &func () {return getFoo();} };
@@ -1531,23 +1589,23 @@ namespace substitution_test {
public:
Mutex mu;
- void lockData() __attribute__((exclusive_lock_function(mu)));
- void unlockData() __attribute__((unlock_function(mu)));
+ void lockData() EXCLUSIVE_LOCK_FUNCTION(mu);
+ void unlockData() UNLOCK_FUNCTION(mu);
- void doSomething() __attribute__((exclusive_locks_required(mu))) { }
+ void doSomething() EXCLUSIVE_LOCKS_REQUIRED(mu) { }
};
class DataLocker {
public:
- void lockData (MyData *d) __attribute__((exclusive_lock_function(d->mu)));
- void unlockData(MyData *d) __attribute__((unlock_function(d->mu)));
+ void lockData (MyData *d) EXCLUSIVE_LOCK_FUNCTION(d->mu);
+ void unlockData(MyData *d) UNLOCK_FUNCTION(d->mu);
};
class Foo {
public:
- void foo(MyData* d) __attribute__((exclusive_locks_required(d->mu))) { }
+ void foo(MyData* d) EXCLUSIVE_LOCKS_REQUIRED(d->mu) { }
void bar1(MyData* d) {
d->lockData();
@@ -1588,8 +1646,8 @@ namespace constructor_destructor_tests {
class Foo {
public:
- Foo() __attribute__((exclusive_lock_function(fooMu))) { }
- ~Foo() __attribute__((unlock_function(fooMu))) { }
+ Foo() EXCLUSIVE_LOCK_FUNCTION(fooMu) { }
+ ~Foo() UNLOCK_FUNCTION(fooMu) { }
};
void fooTest() {
@@ -1803,7 +1861,7 @@ struct TestTryLock {
bool b = mu.TryLock();
while (cond) {
- if (b) { // b should be uknown at this point b/c of the loop
+ if (b) { // b should be unknown at this point b/c of the loop
a = 10; // expected-warning {{writing variable 'a' requires holding mutex 'mu' exclusively}}
}
b = !b;
@@ -1932,7 +1990,7 @@ void test() {
f1.mu_.Unlock();
bt.barTD(&f1); // \
- // expected-warning {{calling function 'barTD' requires holding mutex 'f1.mu_' exclusively}} \
+ // expected-warning {{calling function 'barTD<TestTemplateAttributeInstantiation::Foo1>' requires holding mutex 'f1.mu_' exclusively}} \
// expected-note {{found near match 'bt.fooBase.mu_'}}
bt.fooBase.mu_.Unlock();
@@ -2020,9 +2078,9 @@ void test() {
namespace GoingNative {
- struct __attribute__((lockable)) mutex {
- void lock() __attribute__((exclusive_lock_function));
- void unlock() __attribute__((unlock_function));
+ struct LOCKABLE mutex {
+ void lock() EXCLUSIVE_LOCK_FUNCTION();
+ void unlock() UNLOCK_FUNCTION();
// ...
};
bool foo();
@@ -2129,10 +2187,10 @@ void test() {
myFoo.foo3(&myFoo); // \
// expected-warning {{calling function 'foo3' requires holding mutex 'myFoo.mu_' exclusively}}
myFoo.fooT1(dummy); // \
- // expected-warning {{calling function 'fooT1' requires holding mutex 'myFoo.mu_' exclusively}}
+ // expected-warning {{calling function 'fooT1<int>' requires holding mutex 'myFoo.mu_' exclusively}}
myFoo.fooT2(dummy); // \
- // expected-warning {{calling function 'fooT2' requires holding mutex 'myFoo.mu_' exclusively}}
+ // expected-warning {{calling function 'fooT2<int>' requires holding mutex 'myFoo.mu_' exclusively}}
fooF1(&myFoo); // \
// expected-warning {{calling function 'fooF1' requires holding mutex 'myFoo.mu_' exclusively}}
@@ -3553,7 +3611,7 @@ struct Cell {
class Foo {
public:
template <class T>
- void elr(Cell<T>* c) __attribute__((exclusive_locks_required(c->mu_)));
+ void elr(Cell<T>* c) EXCLUSIVE_LOCKS_REQUIRED(c->mu_);
void test();
};
@@ -3564,12 +3622,12 @@ void Foo::elr(Cell<T>* c1) { }
void Foo::test() {
Cell<int> cell;
elr(&cell); // \
- // expected-warning {{calling function 'elr' requires holding mutex 'cell.mu_' exclusively}}
+ // expected-warning {{calling function 'elr<int>' requires holding mutex 'cell.mu_' exclusively}}
}
template<class T>
-void globalELR(Cell<T>* c) __attribute__((exclusive_locks_required(c->mu_)));
+void globalELR(Cell<T>* c) EXCLUSIVE_LOCKS_REQUIRED(c->mu_);
template<class T>
void globalELR(Cell<T>* c1) { }
@@ -3577,12 +3635,12 @@ void globalELR(Cell<T>* c1) { }
void globalTest() {
Cell<int> cell;
globalELR(&cell); // \
- // expected-warning {{calling function 'globalELR' requires holding mutex 'cell.mu_' exclusively}}
+ // expected-warning {{calling function 'globalELR<int>' requires holding mutex 'cell.mu_' exclusively}}
}
template<class T>
-void globalELR2(Cell<T>* c) __attribute__((exclusive_locks_required(c->mu_)));
+void globalELR2(Cell<T>* c) EXCLUSIVE_LOCKS_REQUIRED(c->mu_);
// second declaration
template<class T>
@@ -3598,14 +3656,14 @@ void globalELR2(Cell<T>* c4);
void globalTest2() {
Cell<int> cell;
globalELR2(&cell); // \
- // expected-warning {{calling function 'globalELR2' requires holding mutex 'cell.mu_' exclusively}}
+ // expected-warning {{calling function 'globalELR2<int>' requires holding mutex 'cell.mu_' exclusively}}
}
template<class T>
class FooT {
public:
- void elr(Cell<T>* c) __attribute__((exclusive_locks_required(c->mu_)));
+ void elr(Cell<T>* c) EXCLUSIVE_LOCKS_REQUIRED(c->mu_);
};
template<class T>
@@ -4415,7 +4473,7 @@ class A {
(RunHelper)(); // expected-warning {{calling function 'RunHelper' requires holding mutex 'M' exclusively}}
}
- void RunHelper() __attribute__((exclusive_locks_required(M)));
+ void RunHelper() EXCLUSIVE_LOCKS_REQUIRED(M);
Mutex M;
};
@@ -4642,8 +4700,8 @@ namespace NegativeThreadRoles {
typedef int __attribute__((capability("role"))) ThreadRole;
-void acquire(ThreadRole R) __attribute__((exclusive_lock_function(R))) __attribute__((no_thread_safety_analysis)) {}
-void release(ThreadRole R) __attribute__((unlock_function(R))) __attribute__((no_thread_safety_analysis)) {}
+void acquire(ThreadRole R) EXCLUSIVE_LOCK_FUNCTION(R) NO_THREAD_SAFETY_ANALYSIS {}
+void release(ThreadRole R) UNLOCK_FUNCTION(R) NO_THREAD_SAFETY_ANALYSIS {}
ThreadRole FlightControl, Logger;
@@ -5248,3 +5306,28 @@ struct C {
C c;
void f() { c[A()]->g(); }
} // namespace PR34800
+
+namespace ReturnScopedLockable {
+ template<typename Object> class SCOPED_LOCKABLE ReadLockedPtr {
+ public:
+ ReadLockedPtr(Object *ptr) SHARED_LOCK_FUNCTION((*this)->mutex);
+ ReadLockedPtr(ReadLockedPtr &&) SHARED_LOCK_FUNCTION((*this)->mutex);
+ ~ReadLockedPtr() UNLOCK_FUNCTION();
+
+ Object *operator->() const { return object; }
+
+ private:
+ Object *object;
+ };
+
+ struct Object {
+ int f() SHARED_LOCKS_REQUIRED(mutex);
+ Mutex mutex;
+ };
+
+ ReadLockedPtr<Object> get();
+ int use() {
+ auto ptr = get();
+ return ptr->f();
+ }
+}