// Test this without pch. // RUN: %clang_cc1 -include %s -fsyntax-only -verify -Wthread-safety -std=c++11 %s // Test with pch. // RUN: %clang_cc1 -emit-pch -o %t %s -std=c++11 // RUN: %clang_cc1 -include-pch %t -fsyntax-only -verify -Wthread-safety -std=c++11 %s #ifndef HEADER #define HEADER #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 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)) class __attribute__((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)); }; class __attribute__((scoped_lockable)) MutexLock { public: MutexLock(Mutex *mu) __attribute__((exclusive_lock_function(mu))); ~MutexLock() __attribute__((unlock_function)); }; class __attribute__((scoped_lockable)) ReaderMutexLock { public: ReaderMutexLock(Mutex *mu) __attribute__((exclusive_lock_function(mu))); ~ReaderMutexLock() __attribute__((unlock_function)); }; class SCOPED_LOCKABLE ReleasableMutexLock { public: ReleasableMutexLock(Mutex *mu) EXCLUSIVE_LOCK_FUNCTION(mu); ~ReleasableMutexLock() UNLOCK_FUNCTION(); void Release() UNLOCK_FUNCTION(); }; // The universal lock, written "*", allows checking to be selectively turned // off for a particular piece of code. void beginNoWarnOnReads() SHARED_LOCK_FUNCTION("*"); void endNoWarnOnReads() UNLOCK_FUNCTION("*"); void beginNoWarnOnWrites() EXCLUSIVE_LOCK_FUNCTION("*"); void endNoWarnOnWrites() UNLOCK_FUNCTION("*"); // For testing handling of smart pointers. template class SmartPtr { public: SmartPtr(T* p) : ptr_(p) { } SmartPtr(const SmartPtr& p) : ptr_(p.ptr_) { } ~SmartPtr(); T* get() const { return ptr_; } T* operator->() const { return ptr_; } T& operator*() const { return *ptr_; } private: T* ptr_; }; // For testing destructor calls and cleanup. class MyString { public: MyString(const char* s); ~MyString(); }; Mutex sls_mu; Mutex sls_mu2 __attribute__((acquired_after(sls_mu))); int sls_guard_var __attribute__((guarded_var)) = 0; int sls_guardby_var __attribute__((guarded_by(sls_mu))) = 0; bool getBool(); class MutexWrapper { public: Mutex mu; int x __attribute__((guarded_by(mu))); void MyLock() __attribute__((exclusive_lock_function(mu))); }; #else MutexWrapper sls_mw; void sls_fun_0() { sls_mw.mu.Lock(); sls_mw.x = 5; sls_mw.mu.Unlock(); } void sls_fun_2() { sls_mu.Lock(); int x = sls_guard_var; sls_mu.Unlock(); } void sls_fun_3() { sls_mu.Lock(); sls_guard_var = 2; sls_mu.Unlock(); } void sls_fun_4() { sls_mu2.Lock(); sls_guard_var = 2; sls_mu2.Unlock(); } void sls_fun_5() { sls_mu.Lock(); int x = sls_guardby_var; sls_mu.Unlock(); } void sls_fun_6() { sls_mu.Lock(); sls_guardby_var = 2; sls_mu.Unlock(); } void sls_fun_7() { sls_mu.Lock(); sls_mu2.Lock(); sls_mu2.Unlock(); sls_mu.Unlock(); } void sls_fun_8() { sls_mu.Lock(); if (getBool()) sls_mu.Unlock(); else sls_mu.Unlock(); } void sls_fun_9() { if (getBool()) sls_mu.Lock(); else sls_mu.Lock(); sls_mu.Unlock(); } void sls_fun_good_6() { if (getBool()) { sls_mu.Lock(); } else { if (getBool()) { getBool(); // EMPTY } else { getBool(); // EMPTY } sls_mu.Lock(); } sls_mu.Unlock(); } void sls_fun_good_7() { sls_mu.Lock(); while (getBool()) { sls_mu.Unlock(); if (getBool()) { if (getBool()) { sls_mu.Lock(); continue; } } sls_mu.Lock(); } sls_mu.Unlock(); } void sls_fun_good_8() { sls_mw.MyLock(); sls_mw.mu.Unlock(); } void sls_fun_bad_1() { sls_mu.Unlock(); // \ // expected-warning{{releasing mutex 'sls_mu' that was not held}} } void sls_fun_bad_2() { sls_mu.Lock(); // expected-note{{mutex acquired here}} sls_mu.Lock(); // \ // expected-warning{{acquiring mutex 'sls_mu' that is already held}} sls_mu.Unlock(); } void sls_fun_bad_3() { sls_mu.Lock(); // expected-note {{mutex acquired here}} } // expected-warning{{mutex 'sls_mu' is still held at the end of function}} void sls_fun_bad_4() { if (getBool()) sls_mu.Lock(); // expected-note{{mutex acquired here}} else sls_mu2.Lock(); // expected-note{{mutex acquired here}} } // expected-warning{{mutex 'sls_mu' is not held on every path through here}} \ // expected-warning{{mutex 'sls_mu2' is not held on every path through here}} void sls_fun_bad_5() { sls_mu.Lock(); // expected-note {{mutex acquired here}} if (getBool()) sls_mu.Unlock(); } // expected-warning{{mutex 'sls_mu' is not held on every path through here}} void sls_fun_bad_6() { if (getBool()) { sls_mu.Lock(); // expected-note {{mutex acquired here}} } else { if (getBool()) { getBool(); // EMPTY } else { getBool(); // EMPTY } } sls_mu.Unlock(); // \ expected-warning{{mutex 'sls_mu' is not held on every path through here}}\ expected-warning{{releasing mutex 'sls_mu' that was not held}} } void sls_fun_bad_7() { sls_mu.Lock(); while (getBool()) { sls_mu.Unlock(); if (getBool()) { if (getBool()) { continue; // \ expected-warning{{expecting mutex 'sls_mu' to be held at start of each loop}} } } sls_mu.Lock(); // expected-note {{mutex acquired here}} } sls_mu.Unlock(); } void sls_fun_bad_8() { sls_mu.Lock(); // expected-note{{mutex acquired here}} do { sls_mu.Unlock(); // expected-warning{{expecting mutex 'sls_mu' to be held at start of each loop}} } while (getBool()); } void sls_fun_bad_9() { do { sls_mu.Lock(); // \ // expected-warning{{expecting mutex 'sls_mu' to be held at start of each loop}} \ // expected-note{{mutex acquired here}} } while (getBool()); sls_mu.Unlock(); } void sls_fun_bad_10() { sls_mu.Lock(); // expected-note 2{{mutex acquired here}} while(getBool()) { // expected-warning{{expecting mutex 'sls_mu' to be held at start of each loop}} sls_mu.Unlock(); } } // expected-warning{{mutex 'sls_mu' is still held at the end of function}} void sls_fun_bad_11() { while (getBool()) { // \ expected-warning{{expecting mutex 'sls_mu' to be held at start of each loop}} sls_mu.Lock(); // expected-note {{mutex acquired here}} } sls_mu.Unlock(); // \ // expected-warning{{releasing mutex 'sls_mu' that was not held}} } void sls_fun_bad_12() { sls_mu.Lock(); // expected-note {{mutex acquired here}} while (getBool()) { sls_mu.Unlock(); if (getBool()) { if (getBool()) { break; // expected-warning{{mutex 'sls_mu' is not held on every path through here}} } } sls_mu.Lock(); } sls_mu.Unlock(); } #endif