diff options
Diffstat (limited to 'test/SemaCXX/warn-thread-safety-analysis.cpp')
-rw-r--r-- | test/SemaCXX/warn-thread-safety-analysis.cpp | 203 |
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(); + } +} |