summaryrefslogtreecommitdiffstats
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.cpp1008
1 files changed, 943 insertions, 65 deletions
diff --git a/test/SemaCXX/warn-thread-safety-analysis.cpp b/test/SemaCXX/warn-thread-safety-analysis.cpp
index 566e5c1..17a1931 100644
--- a/test/SemaCXX/warn-thread-safety-analysis.cpp
+++ b/test/SemaCXX/warn-thread-safety-analysis.cpp
@@ -1,4 +1,7 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -Wthread-safety %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wthread-safety -std=c++11 %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))
@@ -48,6 +51,30 @@ class __attribute__((scoped_lockable)) ReaderMutexLock {
~ReaderMutexLock() __attribute__((unlock_function));
};
+class SCOPED_LOCKABLE ReleasableMutexLock {
+ public:
+ ReleasableMutexLock(Mutex *mu) EXCLUSIVE_LOCK_FUNCTION(mu);
+ ~ReleasableMutexLock() UNLOCK_FUNCTION();
+
+ void Release() UNLOCK_FUNCTION();
+};
+
+
+template<class T>
+class SmartPtr {
+public:
+ SmartPtr(T* p) : ptr_(p) { }
+ SmartPtr(const SmartPtr<T>& p) : ptr_(p.ptr_) { }
+ ~SmartPtr();
+
+ T* get() const { return ptr_; }
+ T* operator->() const { return ptr_; }
+ T& operator*() const { return *ptr_; }
+
+private:
+ T* ptr_;
+};
+
Mutex sls_mu;
@@ -177,14 +204,11 @@ void sls_fun_bad_3() {
void sls_fun_bad_4() {
if (getBool())
- sls_mu.Lock(); // \
- expected-warning{{mutex 'sls_mu2' is not locked on every path through here}} \
- expected-note{{mutex acquired here}}
-
+ sls_mu.Lock(); // expected-note{{mutex acquired here}}
else
- sls_mu2.Lock(); // \
- expected-note{{mutex acquired here}}
-} // expected-warning{{mutex 'sls_mu' is not locked on every path through here}}
+ sls_mu2.Lock(); // expected-note{{mutex acquired here}}
+} // expected-warning{{mutex 'sls_mu' is not locked on every path through here}} \
+ // expected-warning{{mutex 'sls_mu2' is not locked on every path through here}}
void sls_fun_bad_5() {
sls_mu.Lock(); // expected-note {{mutex acquired here}}
@@ -225,15 +249,14 @@ void sls_fun_bad_7() {
void sls_fun_bad_8() {
sls_mu.Lock(); // expected-note{{mutex acquired here}}
- // FIXME: TERRIBLE SOURCE LOCATION!
- do { // expected-warning{{expecting mutex 'sls_mu' to be locked at start of each loop}}
- sls_mu.Unlock();
+ do {
+ sls_mu.Unlock(); // expected-warning{{expecting mutex 'sls_mu' to be locked at start of each loop}}
} while (getBool());
}
void sls_fun_bad_9() {
do {
- sls_mu.Lock(); // \
+ sls_mu.Lock(); // \
// expected-warning{{expecting mutex 'sls_mu' to be locked at start of each loop}} \
// expected-note{{mutex acquired here}}
} while (getBool());
@@ -241,15 +264,15 @@ void sls_fun_bad_9() {
}
void sls_fun_bad_10() {
- sls_mu.Lock(); // expected-note 2{{mutex acquired here}}
- while(getBool()) {
- sls_mu.Unlock(); // expected-warning{{expecting mutex 'sls_mu' to be locked at start of each loop}}
+ sls_mu.Lock(); // expected-note 2{{mutex acquired here}}
+ while(getBool()) { // expected-warning{{expecting mutex 'sls_mu' to be locked at start of each loop}}
+ sls_mu.Unlock();
}
} // expected-warning{{mutex 'sls_mu' is still locked at the end of function}}
void sls_fun_bad_11() {
while (getBool()) { // \
- expected-warning{{expecting mutex 'sls_mu' to be locked at start of each loop}}
+ expected-warning{{expecting mutex 'sls_mu' to be locked at start of each loop}}
sls_mu.Lock(); // expected-note {{mutex acquired here}}
}
sls_mu.Unlock(); // \
@@ -506,7 +529,7 @@ void late_bad_0() {
LateFoo fooB;
fooA.mu.Lock();
fooB.a = 5; // \
- // expected-warning{{writing variable 'a' requires locking 'mu' exclusively}}
+ // expected-warning{{writing variable 'a' requires locking 'fooB.mu' exclusively}}
fooA.mu.Unlock();
}
@@ -516,7 +539,7 @@ void late_bad_1() {
b1.mu1_.Lock();
int res = b1.a_ + b3->b_;
b3->b_ = *b1.q; // \
- // expected-warning{{reading the value pointed to by 'q' requires locking 'mu'}}
+ // expected-warning{{reading the value pointed to by 'q' requires locking 'b1.mu'}}
b1.mu1_.Unlock();
b1.b_ = res;
mu.Unlock();
@@ -526,7 +549,7 @@ void late_bad_2() {
LateBar BarA;
BarA.FooPointer->mu.Lock();
BarA.Foo.a = 2; // \
- // expected-warning{{writing variable 'a' requires locking 'mu' exclusively}}
+ // expected-warning{{writing variable 'a' requires locking 'BarA.Foo.mu' exclusively}}
BarA.FooPointer->mu.Unlock();
}
@@ -534,7 +557,7 @@ void late_bad_3() {
LateBar BarA;
BarA.Foo.mu.Lock();
BarA.FooPointer->a = 2; // \
- // expected-warning{{writing variable 'a' requires locking 'mu' exclusively}}
+ // expected-warning{{writing variable 'a' requires locking 'BarA.FooPointer->mu' exclusively}}
BarA.Foo.mu.Unlock();
}
@@ -542,7 +565,7 @@ void late_bad_4() {
LateBar BarA;
BarA.Foo.mu.Lock();
BarA.Foo2.a = 2; // \
- // expected-warning{{writing variable 'a' requires locking 'mu' exclusively}}
+ // expected-warning{{writing variable 'a' requires locking 'BarA.Foo2.mu' exclusively}}
BarA.Foo.mu.Unlock();
}
@@ -1176,13 +1199,13 @@ void main()
{
Foo f1, *f2;
f1.mu_.Lock();
- f1.bar(); // expected-warning {{cannot call function 'bar' while mutex 'mu_' is locked}}
+ f1.bar(); // expected-warning {{cannot call function 'bar' while mutex 'f1.mu_' is locked}}
mu2.Lock();
f1.foo();
mu2.Unlock();
f1.mu_.Unlock();
f2->mu_.Lock();
- f2->bar(); // expected-warning {{cannot call function 'bar' while mutex 'mu_' is locked}}
+ f2->bar(); // expected-warning {{cannot call function 'bar' while mutex 'f2->mu_' is locked}}
f2->mu_.Unlock();
mu2.Lock();
w = 2;
@@ -1210,7 +1233,7 @@ void func()
{
b1->MyLock();
b1->a_ = 5;
- b2->a_ = 3; // expected-warning {{writing variable 'a_' requires locking 'mu1_' exclusively}}
+ b2->a_ = 3; // expected-warning {{writing variable 'a_' requires locking 'b2->mu1_' exclusively}}
b2->MyLock();
b2->MyUnlock();
b1->MyUnlock();
@@ -1239,12 +1262,12 @@ int func(int i)
{
int x;
b3->mu1_.Lock();
- res = b1.a_ + b3->b_; // expected-warning {{reading variable 'a_' requires locking 'mu1_'}} \
+ res = b1.a_ + b3->b_; // expected-warning {{reading variable 'a_' requires locking 'b1.mu1_'}} \
// expected-warning {{writing variable 'res' requires locking 'mu' exclusively}}
*p = i; // expected-warning {{reading variable 'p' requires locking 'mu'}} \
// expected-warning {{writing the value pointed to by 'p' requires locking 'mu' exclusively}}
b1.a_ = res + b3->b_; // expected-warning {{reading variable 'res' requires locking 'mu'}} \
- // expected-warning {{writing variable 'a_' requires locking 'mu1_' exclusively}}
+ // expected-warning {{writing variable 'a_' requires locking 'b1.mu1_' exclusively}}
b3->b_ = *b1.q; // expected-warning {{reading the value pointed to by 'q' requires locking 'mu'}}
b3->mu1_.Unlock();
b1.b_ = res; // expected-warning {{reading variable 'res' requires locking 'mu'}}
@@ -1269,8 +1292,8 @@ class Foo {
child->Func(new_foo); // There shouldn't be any warning here as the
// acquired lock is not in child.
- child->bar(7); // expected-warning {{calling function 'bar' requires exclusive lock on 'lock_'}}
- child->a_ = 5; // expected-warning {{writing variable 'a_' requires locking 'lock_' exclusively}}
+ child->bar(7); // expected-warning {{calling function 'bar' requires exclusive lock on 'child->lock_'}}
+ child->a_ = 5; // expected-warning {{writing variable 'a_' requires locking 'child->lock_' exclusively}}
lock_.Unlock();
}
@@ -1307,7 +1330,7 @@ void Foo::Func(Foo* child) {
lock_.Lock();
child->lock_.Lock();
- child->Func(new_foo); // expected-warning {{cannot call function 'Func' while mutex 'lock_' is locked}}
+ child->Func(new_foo); // expected-warning {{cannot call function 'Func' while mutex 'child->lock_' is locked}}
child->bar(7);
child->a_ = 5;
child->lock_.Unlock();
@@ -1355,8 +1378,8 @@ Foo *foo;
void func()
{
- foo->f1(); // expected-warning {{calling function 'f1' requires exclusive lock on 'mu2'}} \
- // expected-warning {{calling function 'f1' requires exclusive lock on 'mu1'}}
+ foo->f1(); // expected-warning {{calling function 'f1' requires exclusive lock on 'foo->mu2'}} \
+ // expected-warning {{calling function 'f1' requires exclusive lock on 'foo->mu1'}}
}
} // end namespace thread_annot_lock_42
@@ -1379,14 +1402,14 @@ void main() {
Child *c;
Base *b = c;
- b->func1(); // expected-warning {{calling function 'func1' requires exclusive lock on 'mu_'}}
+ b->func1(); // expected-warning {{calling function 'func1' requires exclusive lock on 'b->mu_'}}
b->mu_.Lock();
- b->func2(); // expected-warning {{cannot call function 'func2' while mutex 'mu_' is locked}}
+ b->func2(); // expected-warning {{cannot call function 'func2' while mutex 'b->mu_' is locked}}
b->mu_.Unlock();
- c->func1(); // expected-warning {{calling function 'func1' requires exclusive lock on 'mu_'}}
+ c->func1(); // expected-warning {{calling function 'func1' requires exclusive lock on 'c->mu_'}}
c->mu_.Lock();
- c->func2(); // expected-warning {{cannot call function 'func2' while mutex 'mu_' is locked}}
+ c->func2(); // expected-warning {{cannot call function 'func2' while mutex 'c->mu_' is locked}}
c->mu_.Unlock();
}
} // end namespace thread_annot_lock_46
@@ -1413,9 +1436,9 @@ int Foo::method1(int i) {
void main()
{
Foo a;
- a.method1(1); // expected-warning {{calling function 'method1' requires shared lock on 'mu1'}} \
+ a.method1(1); // expected-warning {{calling function 'method1' requires shared lock on 'a.mu1'}} \
// expected-warning {{calling function 'method1' requires shared lock on 'mu'}} \
- // expected-warning {{calling function 'method1' requires shared lock on 'mu2'}} \
+ // expected-warning {{calling function 'method1' requires shared lock on 'a.mu2'}} \
// expected-warning {{calling function 'method1' requires shared lock on 'mu3'}}
}
} // end namespace thread_annot_lock_67_modified
@@ -1461,14 +1484,14 @@ namespace substitution_test {
DataLocker dlr;
dlr.lockData(d1); // expected-note {{mutex acquired here}}
dlr.unlockData(d2); // \
- // expected-warning {{unlocking 'mu' that was not locked}}
- } // expected-warning {{mutex 'mu' is still locked at the end of function}}
+ // expected-warning {{unlocking 'd2->mu' that was not locked}}
+ } // expected-warning {{mutex 'd1->mu' is still locked at the end of function}}
void bar4(MyData* d1, MyData* d2) {
DataLocker dlr;
dlr.lockData(d1);
foo(d2); // \
- // expected-warning {{calling function 'foo' requires exclusive lock on 'mu'}}
+ // expected-warning {{calling function 'foo' requires exclusive lock on 'd2->mu'}}
dlr.unlockData(d1);
}
};
@@ -1527,7 +1550,7 @@ namespace template_member_test {
struct IndirectLock {
int DoNaughtyThings(T *t) {
u->n = 0; // expected-warning {{reading variable 'u' requires locking 'm'}}
- return t->s->n; // expected-warning {{reading variable 's' requires locking 'm'}}
+ return t->s->n; // expected-warning {{reading variable 's' requires locking 't->m'}}
}
};
@@ -1543,7 +1566,7 @@ namespace template_member_test {
template<typename U> struct W {
V v;
void f(U u) {
- v.p->f(u); // expected-warning {{reading variable 'p' requires locking 'm'}}
+ v.p->f(u); // expected-warning {{reading variable 'p' requires locking 'v.m'}}
}
};
template struct W<int>; // expected-note {{here}}
@@ -1581,7 +1604,7 @@ struct TestScopedLockable {
MutexLock mulock_a(&mu1);
MutexLock mulock_b(&mu1); // \
// expected-warning {{locking 'mu1' that is already locked}}
- } // expected-warning {{unlocking 'mu1' that was not locked}}
+ }
void foo4() {
MutexLock mulock1(&mu1), mulock2(&mu2);
@@ -1606,7 +1629,7 @@ Foo fooObj;
void foo() EXCLUSIVE_LOCKS_REQUIRED(fooObj.mu_);
void bar() {
- foo(); // expected-warning {{calling function 'foo' requires exclusive lock on 'mu_'}}
+ foo(); // expected-warning {{calling function 'foo' requires exclusive lock on 'fooObj.mu_'}}
fooObj.mu_.Lock();
foo();
fooObj.mu_.Unlock();
@@ -1679,7 +1702,7 @@ struct TestTryLock {
bool b2 = b;
if (cond)
b = true;
- if (b) { // b should be unknown at this point, becuase of the join point
+ if (b) { // b should be unknown at this point, because of the join point
a = 8; // expected-warning {{writing variable 'a' requires locking 'mu' exclusively}}
}
if (b2) { // b2 should be known at this point.
@@ -1806,7 +1829,7 @@ void test() {
f1.mu_.Unlock();
bt.barTD(&f1); // \
- // expected-warning {{calling function 'barTD' requires exclusive lock on 'mu_'}}
+ // expected-warning {{calling function 'barTD' requires exclusive lock on 'f1.mu_'}}
bt.fooBase.mu_.Unlock();
bt.fooBaseT.mu_.Unlock();
@@ -1814,7 +1837,7 @@ void test() {
Cell<int> cell;
cell.data = 0; // \
- // expected-warning {{writing variable 'data' requires locking 'mu_' exclusively}}
+ // expected-warning {{writing variable 'data' requires locking 'cell.mu_' exclusively}}
cell.foo();
cell.mu_.Lock();
cell.fooEx();
@@ -1883,7 +1906,7 @@ void Foo::foo1(Foo *f_defined) {
void test() {
Foo myfoo;
myfoo.foo1(&myfoo); // \
- // expected-warning {{calling function 'foo1' requires exclusive lock on 'mu_'}}
+ // expected-warning {{calling function 'foo1' requires exclusive lock on 'myfoo.mu_'}}
myfoo.mu_.Lock();
myfoo.foo1(&myfoo);
myfoo.mu_.Unlock();
@@ -1998,29 +2021,28 @@ void test() {
Foo myFoo;
myFoo.foo2(); // \
- // expected-warning {{calling function 'foo2' requires exclusive lock on 'mu_'}}
+ // expected-warning {{calling function 'foo2' requires exclusive lock on 'myFoo.mu_'}}
myFoo.foo3(&myFoo); // \
- // expected-warning {{calling function 'foo3' requires exclusive lock on 'mu_'}}
+ // expected-warning {{calling function 'foo3' requires exclusive lock on 'myFoo.mu_'}}
myFoo.fooT1(dummy); // \
- // expected-warning {{calling function 'fooT1' requires exclusive lock on 'mu_'}}
+ // expected-warning {{calling function 'fooT1' requires exclusive lock on 'myFoo.mu_'}}
- // FIXME: uncomment with template instantiation of attributes patch
- // myFoo.fooT2(dummy); // expected warning
+ myFoo.fooT2(dummy); // \
+ // expected-warning {{calling function 'fooT2' requires exclusive lock on 'myFoo.mu_'}}
fooF1(&myFoo); // \
- // expected-warning {{calling function 'fooF1' requires exclusive lock on 'mu_'}}
+ // expected-warning {{calling function 'fooF1' requires exclusive lock on 'myFoo.mu_'}}
fooF2(&myFoo); // \
- // expected-warning {{calling function 'fooF2' requires exclusive lock on 'mu_'}}
+ // expected-warning {{calling function 'fooF2' requires exclusive lock on 'myFoo.mu_'}}
fooF3(&myFoo); // \
- // expected-warning {{calling function 'fooF3' requires exclusive lock on 'mu_'}}
+ // expected-warning {{calling function 'fooF3' requires exclusive lock on 'myFoo.mu_'}}
myFoo.mu_.Lock();
myFoo.foo2();
myFoo.foo3(&myFoo);
myFoo.fooT1(dummy);
- // FIXME: uncomment with template instantiation of attributes patch
- // myFoo.fooT2(dummy);
+ myFoo.fooT2(dummy);
fooF1(&myFoo);
fooF2(&myFoo);
@@ -2029,7 +2051,7 @@ void test() {
FooT<int> myFooT;
myFooT.foo(); // \
- // expected-warning {{calling function 'foo' requires exclusive lock on 'mu_'}}
+ // expected-warning {{calling function 'foo' requires exclusive lock on 'myFooT.mu_'}}
}
} // end namespace FunctionDefinitionTest
@@ -2213,31 +2235,887 @@ void test() {
bar.getFoo().mu_.Lock();
bar.getFooey().a = 0; // \
- // expected-warning {{writing variable 'a' requires locking 'mu_' exclusively}}
+ // expected-warning {{writing variable 'a' requires locking 'bar.getFooey().mu_' exclusively}}
bar.getFoo().mu_.Unlock();
bar.getFoo2(a).mu_.Lock();
bar.getFoo2(b).a = 0; // \
- // expected-warning {{writing variable 'a' requires locking 'mu_' exclusively}}
+ // expected-warning {{writing variable 'a' requires locking 'bar.getFoo2(b).mu_' exclusively}}
bar.getFoo2(a).mu_.Unlock();
bar.getFoo3(a, b).mu_.Lock();
bar.getFoo3(a, c).a = 0; // \
- // expected-warning {{writing variable 'a' requires locking 'mu_' exclusively}}
+ // expected-warning {{writing variable 'a' requires locking 'bar.getFoo3(a,c).mu_' exclusively}}
bar.getFoo3(a, b).mu_.Unlock();
getBarFoo(bar, a).mu_.Lock();
getBarFoo(bar, b).a = 0; // \
- // expected-warning {{writing variable 'a' requires locking 'mu_' exclusively}}
+ // expected-warning {{writing variable 'a' requires locking 'getBarFoo(bar,b).mu_' exclusively}}
getBarFoo(bar, a).mu_.Unlock();
(a > 0 ? fooArray[1] : fooArray[b]).mu_.Lock();
(a > 0 ? fooArray[b] : fooArray[c]).a = 0; // \
- // expected-warning {{writing variable 'a' requires locking 'mu_' exclusively}}
+ // expected-warning {{writing variable 'a' requires locking '((a#_)#_#fooArray[b]).mu_' exclusively}}
(a > 0 ? fooArray[1] : fooArray[b]).mu_.Unlock();
}
-} // end namespace
+} // end namespace MoreLockExpressions
+
+
+namespace TrylockJoinPoint {
+
+class Foo {
+ Mutex mu;
+ bool c;
+
+ void foo() {
+ if (c) {
+ if (!mu.TryLock())
+ return;
+ } else {
+ mu.Lock();
+ }
+ mu.Unlock();
+ }
+};
+
+} // end namespace TrylockJoinPoint
+
+
+namespace LockReturned {
+
+class Foo {
+public:
+ int a GUARDED_BY(mu_);
+ void foo() EXCLUSIVE_LOCKS_REQUIRED(mu_);
+ void foo2(Foo* f) EXCLUSIVE_LOCKS_REQUIRED(mu_, f->mu_);
+
+ static void sfoo(Foo* f) EXCLUSIVE_LOCKS_REQUIRED(f->mu_);
+
+ Mutex* getMu() LOCK_RETURNED(mu_);
+
+ Mutex mu_;
+
+ static Mutex* getMu(Foo* f) LOCK_RETURNED(f->mu_);
+};
+
+
+// Calls getMu() directly to lock and unlock
+void test1(Foo* f1, Foo* f2) {
+ f1->a = 0; // expected-warning {{writing variable 'a' requires locking 'f1->mu_' exclusively}}
+ f1->foo(); // expected-warning {{calling function 'foo' requires exclusive lock on 'f1->mu_'}}
+
+ f1->foo2(f2); // expected-warning {{calling function 'foo2' requires exclusive lock on 'f1->mu_'}} \
+ // expected-warning {{calling function 'foo2' requires exclusive lock on 'f2->mu_'}}
+ Foo::sfoo(f1); // expected-warning {{calling function 'sfoo' requires exclusive lock on 'f1->mu_'}}
+
+ f1->getMu()->Lock();
+
+ f1->a = 0;
+ f1->foo();
+ f1->foo2(f2); // expected-warning {{calling function 'foo2' requires exclusive lock on 'f2->mu_'}}
+
+ Foo::getMu(f2)->Lock();
+ f1->foo2(f2);
+ Foo::getMu(f2)->Unlock();
+
+ Foo::sfoo(f1);
+
+ f1->getMu()->Unlock();
+}
+
+
+Mutex* getFooMu(Foo* f) LOCK_RETURNED(Foo::getMu(f));
+
+class Bar : public Foo {
+public:
+ int b GUARDED_BY(getMu());
+ void bar() EXCLUSIVE_LOCKS_REQUIRED(getMu());
+ void bar2(Bar* g) EXCLUSIVE_LOCKS_REQUIRED(getMu(this), g->getMu());
+
+ static void sbar(Bar* g) EXCLUSIVE_LOCKS_REQUIRED(g->getMu());
+ static void sbar2(Bar* g) EXCLUSIVE_LOCKS_REQUIRED(getFooMu(g));
+};
+
+
+
+// Use getMu() within other attributes.
+// This requires at lest levels of substitution, more in the case of
+void test2(Bar* b1, Bar* b2) {
+ b1->b = 0; // expected-warning {{writing variable 'b' requires locking 'b1->mu_' exclusively}}
+ b1->bar(); // expected-warning {{calling function 'bar' requires exclusive lock on 'b1->mu_'}}
+ b1->bar2(b2); // expected-warning {{calling function 'bar2' requires exclusive lock on 'b1->mu_'}} \
+ // expected-warning {{calling function 'bar2' requires exclusive lock on 'b2->mu_'}}
+ Bar::sbar(b1); // expected-warning {{calling function 'sbar' requires exclusive lock on 'b1->mu_'}}
+ Bar::sbar2(b1); // expected-warning {{calling function 'sbar2' requires exclusive lock on 'b1->mu_'}}
+
+ b1->getMu()->Lock();
+
+ b1->b = 0;
+ b1->bar();
+ b1->bar2(b2); // expected-warning {{calling function 'bar2' requires exclusive lock on 'b2->mu_'}}
+
+ b2->getMu()->Lock();
+ b1->bar2(b2);
+
+ b2->getMu()->Unlock();
+
+ Bar::sbar(b1);
+ Bar::sbar2(b1);
+
+ b1->getMu()->Unlock();
+}
+
+
+// Sanity check -- lock the mutex directly, but use attributes that call getMu()
+// Also lock the mutex using getFooMu, which calls a lock_returned function.
+void test3(Bar* b1, Bar* b2) {
+ b1->mu_.Lock();
+ b1->b = 0;
+ b1->bar();
+
+ getFooMu(b2)->Lock();
+ b1->bar2(b2);
+ getFooMu(b2)->Unlock();
+
+ Bar::sbar(b1);
+ Bar::sbar2(b1);
+
+ b1->mu_.Unlock();
+}
+
+} // end namespace LockReturned
+
+
+namespace ReleasableScopedLock {
+
+class Foo {
+ Mutex mu_;
+ bool c;
+ int a GUARDED_BY(mu_);
+
+ void test1();
+ void test2();
+ void test3();
+ void test4();
+ void test5();
+};
+
+
+void Foo::test1() {
+ ReleasableMutexLock rlock(&mu_);
+ rlock.Release();
+}
+
+void Foo::test2() {
+ ReleasableMutexLock rlock(&mu_);
+ if (c) { // test join point -- held/not held during release
+ rlock.Release();
+ }
+}
+
+void Foo::test3() {
+ ReleasableMutexLock rlock(&mu_);
+ a = 0;
+ rlock.Release();
+ a = 1; // expected-warning {{writing variable 'a' requires locking 'mu_' exclusively}}
+}
+
+void Foo::test4() {
+ ReleasableMutexLock rlock(&mu_);
+ rlock.Release();
+ rlock.Release(); // expected-warning {{unlocking 'mu_' that was not locked}}
+}
+
+void Foo::test5() {
+ ReleasableMutexLock rlock(&mu_);
+ if (c) {
+ rlock.Release();
+ }
+ // no warning on join point for managed lock.
+ rlock.Release(); // expected-warning {{unlocking 'mu_' that was not locked}}
+}
+
+
+} // end namespace ReleasableScopedLock
+
+
+namespace TrylockFunctionTest {
+
+class Foo {
+public:
+ Mutex mu1_;
+ Mutex mu2_;
+ bool c;
+
+ bool lockBoth() EXCLUSIVE_TRYLOCK_FUNCTION(true, mu1_, mu2_);
+};
+
+bool Foo::lockBoth() {
+ if (!mu1_.TryLock())
+ return false;
+
+ mu2_.Lock();
+ if (!c) {
+ mu1_.Unlock();
+ mu2_.Unlock();
+ return false;
+ }
+
+ return true;
+}
+
+
+} // end namespace TrylockFunctionTest
+
+
+
+namespace DoubleLockBug {
+
+class Foo {
+public:
+ Mutex mu_;
+ int a GUARDED_BY(mu_);
+
+ void foo1() EXCLUSIVE_LOCKS_REQUIRED(mu_);
+ int foo2() SHARED_LOCKS_REQUIRED(mu_);
+};
+
+
+void Foo::foo1() EXCLUSIVE_LOCKS_REQUIRED(mu_) {
+ a = 0;
+}
+
+int Foo::foo2() SHARED_LOCKS_REQUIRED(mu_) {
+ return a;
+}
+
+}
+
+
+
+namespace UnlockBug {
+
+class Foo {
+public:
+ Mutex mutex_;
+
+ void foo1() EXCLUSIVE_LOCKS_REQUIRED(mutex_) { // expected-note {{mutex acquired here}}
+ mutex_.Unlock();
+ } // expected-warning {{expecting mutex 'mutex_' to be locked at the end of function}}
+
+
+ void foo2() SHARED_LOCKS_REQUIRED(mutex_) { // expected-note {{mutex acquired here}}
+ mutex_.Unlock();
+ } // expected-warning {{expecting mutex 'mutex_' to be locked at the end of function}}
+};
+
+} // end namespace UnlockBug
+
+
+
+namespace FoolishScopedLockableBug {
+
+class SCOPED_LOCKABLE WTF_ScopedLockable {
+public:
+ WTF_ScopedLockable(Mutex* mu) EXCLUSIVE_LOCK_FUNCTION(mu);
+
+ // have to call release() manually;
+ ~WTF_ScopedLockable();
+
+ void release() UNLOCK_FUNCTION();
+};
+
+
+class Foo {
+ Mutex mu_;
+ int a GUARDED_BY(mu_);
+ bool c;
+
+ void doSomething();
+
+ void test1() {
+ WTF_ScopedLockable wtf(&mu_);
+ wtf.release();
+ }
+
+ void test2() {
+ WTF_ScopedLockable wtf(&mu_); // expected-note {{mutex acquired here}}
+ } // expected-warning {{mutex 'mu_' is still locked at the end of function}}
+
+ void test3() {
+ if (c) {
+ WTF_ScopedLockable wtf(&mu_);
+ wtf.release();
+ }
+ }
+
+ void test4() {
+ if (c) {
+ doSomething();
+ }
+ else {
+ WTF_ScopedLockable wtf(&mu_);
+ wtf.release();
+ }
+ }
+
+ void test5() {
+ if (c) {
+ WTF_ScopedLockable wtf(&mu_); // expected-note {{mutex acquired here}}
+ }
+ } // expected-warning {{mutex 'mu_' is not locked on every path through here}}
+
+ void test6() {
+ if (c) {
+ doSomething();
+ }
+ else {
+ WTF_ScopedLockable wtf(&mu_); // expected-note {{mutex acquired here}}
+ }
+ } // expected-warning {{mutex 'mu_' is not locked on every path through here}}
+};
+
+
+} // end namespace FoolishScopedLockableBug
+
+
+
+namespace TemporaryCleanupExpr {
+
+class Foo {
+ int a GUARDED_BY(getMutexPtr().get());
+
+ SmartPtr<Mutex> getMutexPtr();
+
+ void test();
+};
+
+
+void Foo::test() {
+ {
+ ReaderMutexLock lock(getMutexPtr().get());
+ int b = a;
+ }
+ int b = a; // expected-warning {{reading variable 'a' requires locking 'getMutexPtr()'}}
+}
+
+} // end namespace TemporaryCleanupExpr
+
+
+
+namespace SmartPointerTests {
+
+class Foo {
+public:
+ SmartPtr<Mutex> mu_;
+ int a GUARDED_BY(mu_);
+ int b GUARDED_BY(mu_.get());
+ int c GUARDED_BY(*mu_);
+
+ void Lock() EXCLUSIVE_LOCK_FUNCTION(mu_);
+ void Unlock() UNLOCK_FUNCTION(mu_);
+
+ void test0();
+ void test1();
+ void test2();
+ void test3();
+ void test4();
+ void test5();
+ void test6();
+ void test7();
+ void test8();
+};
+
+void Foo::test0() {
+ a = 0; // expected-warning {{writing variable 'a' requires locking 'mu_' exclusively}}
+ b = 0; // expected-warning {{writing variable 'b' requires locking 'mu_' exclusively}}
+ c = 0; // expected-warning {{writing variable 'c' requires locking 'mu_' exclusively}}
+}
+
+void Foo::test1() {
+ mu_->Lock();
+ a = 0;
+ b = 0;
+ c = 0;
+ mu_->Unlock();
+}
+
+void Foo::test2() {
+ (*mu_).Lock();
+ a = 0;
+ b = 0;
+ c = 0;
+ (*mu_).Unlock();
+}
+
+
+void Foo::test3() {
+ mu_.get()->Lock();
+ a = 0;
+ b = 0;
+ c = 0;
+ mu_.get()->Unlock();
+}
+
+
+void Foo::test4() {
+ MutexLock lock(mu_.get());
+ a = 0;
+ b = 0;
+ c = 0;
+}
+
+
+void Foo::test5() {
+ MutexLock lock(&(*mu_));
+ a = 0;
+ b = 0;
+ c = 0;
+}
+
+
+void Foo::test6() {
+ Lock();
+ a = 0;
+ b = 0;
+ c = 0;
+ Unlock();
+}
+
+
+void Foo::test7() {
+ {
+ Lock();
+ mu_->Unlock();
+ }
+ {
+ mu_->Lock();
+ Unlock();
+ }
+ {
+ mu_.get()->Lock();
+ mu_->Unlock();
+ }
+ {
+ mu_->Lock();
+ mu_.get()->Unlock();
+ }
+ {
+ mu_.get()->Lock();
+ (*mu_).Unlock();
+ }
+ {
+ (*mu_).Lock();
+ mu_->Unlock();
+ }
+}
+
+
+void Foo::test8() {
+ mu_->Lock();
+ mu_.get()->Lock(); // expected-warning {{locking 'mu_' that is already locked}}
+ (*mu_).Lock(); // expected-warning {{locking 'mu_' that is already locked}}
+ mu_.get()->Unlock();
+ Unlock(); // expected-warning {{unlocking 'mu_' that was not locked}}
+}
+
+
+class Bar {
+ SmartPtr<Foo> foo;
+
+ void test0();
+ void test1();
+ void test2();
+ void test3();
+};
+
+
+void Bar::test0() {
+ foo->a = 0; // expected-warning {{writing variable 'a' requires locking 'foo->mu_' exclusively}}
+ (*foo).b = 0; // expected-warning {{writing variable 'b' requires locking 'foo->mu_' exclusively}}
+ foo.get()->c = 0; // expected-warning {{writing variable 'c' requires locking 'foo->mu_' exclusively}}
+}
+
+
+void Bar::test1() {
+ foo->mu_->Lock();
+ foo->a = 0;
+ (*foo).b = 0;
+ foo.get()->c = 0;
+ foo->mu_->Unlock();
+}
+
+
+void Bar::test2() {
+ (*foo).mu_->Lock();
+ foo->a = 0;
+ (*foo).b = 0;
+ foo.get()->c = 0;
+ foo.get()->mu_->Unlock();
+}
+
+
+void Bar::test3() {
+ MutexLock lock(foo->mu_.get());
+ foo->a = 0;
+ (*foo).b = 0;
+ foo.get()->c = 0;
+}
+
+} // end namespace SmartPointerTests
+
+
+
+namespace DuplicateAttributeTest {
+
+class LOCKABLE Foo {
+public:
+ Mutex mu1_;
+ Mutex mu2_;
+ Mutex mu3_;
+ int a GUARDED_BY(mu1_);
+ int b GUARDED_BY(mu2_);
+ int c GUARDED_BY(mu3_);
+
+ void lock() EXCLUSIVE_LOCK_FUNCTION();
+ void unlock() UNLOCK_FUNCTION();
+
+ void lock1() EXCLUSIVE_LOCK_FUNCTION(mu1_);
+ void slock1() SHARED_LOCK_FUNCTION(mu1_);
+ void lock3() EXCLUSIVE_LOCK_FUNCTION(mu1_, mu2_, mu3_);
+ void locklots()
+ EXCLUSIVE_LOCK_FUNCTION(mu1_)
+ EXCLUSIVE_LOCK_FUNCTION(mu2_)
+ EXCLUSIVE_LOCK_FUNCTION(mu1_, mu2_, mu3_);
+
+ void unlock1() UNLOCK_FUNCTION(mu1_);
+ void unlock3() UNLOCK_FUNCTION(mu1_, mu2_, mu3_);
+ void unlocklots()
+ UNLOCK_FUNCTION(mu1_)
+ UNLOCK_FUNCTION(mu2_)
+ UNLOCK_FUNCTION(mu1_, mu2_, mu3_);
+};
+
+
+void Foo::lock() EXCLUSIVE_LOCK_FUNCTION() { }
+void Foo::unlock() UNLOCK_FUNCTION() { }
+
+void Foo::lock1() EXCLUSIVE_LOCK_FUNCTION(mu1_) {
+ mu1_.Lock();
+}
+
+void Foo::slock1() SHARED_LOCK_FUNCTION(mu1_) {
+ mu1_.Lock();
+}
+
+void Foo::lock3() EXCLUSIVE_LOCK_FUNCTION(mu1_, mu2_, mu3_) {
+ mu1_.Lock();
+ mu2_.Lock();
+ mu3_.Lock();
+}
+
+void Foo::locklots()
+ EXCLUSIVE_LOCK_FUNCTION(mu1_, mu2_)
+ EXCLUSIVE_LOCK_FUNCTION(mu2_, mu3_) {
+ mu1_.Lock();
+ mu2_.Lock();
+ mu3_.Lock();
+}
+
+void Foo::unlock1() UNLOCK_FUNCTION(mu1_) {
+ mu1_.Unlock();
+}
+
+void Foo::unlock3() UNLOCK_FUNCTION(mu1_, mu2_, mu3_) {
+ mu1_.Unlock();
+ mu2_.Unlock();
+ mu3_.Unlock();
+}
+
+void Foo::unlocklots()
+ UNLOCK_FUNCTION(mu1_, mu2_)
+ UNLOCK_FUNCTION(mu2_, mu3_) {
+ mu1_.Unlock();
+ mu2_.Unlock();
+ mu3_.Unlock();
+}
+
+
+void test0() {
+ Foo foo;
+ foo.lock();
+ foo.unlock();
+
+ foo.lock();
+ foo.lock(); // expected-warning {{locking 'foo' that is already locked}}
+ foo.unlock();
+ foo.unlock(); // expected-warning {{unlocking 'foo' that was not locked}}
+}
+
+
+void test1() {
+ Foo foo;
+ foo.lock1();
+ foo.a = 0;
+ foo.unlock1();
+
+ foo.lock1();
+ foo.lock1(); // expected-warning {{locking 'foo.mu1_' that is already locked}}
+ foo.a = 0;
+ foo.unlock1();
+ foo.unlock1(); // expected-warning {{unlocking 'foo.mu1_' that was not locked}}
+}
+
+
+int test2() {
+ Foo foo;
+ foo.slock1();
+ int d1 = foo.a;
+ foo.unlock1();
+
+ foo.slock1();
+ foo.slock1(); // expected-warning {{locking 'foo.mu1_' that is already locked}}
+ int d2 = foo.a;
+ foo.unlock1();
+ foo.unlock1(); // expected-warning {{unlocking 'foo.mu1_' that was not locked}}
+ return d1 + d2;
+}
+
+
+void test3() {
+ Foo foo;
+ foo.lock3();
+ foo.a = 0;
+ foo.b = 0;
+ foo.c = 0;
+ foo.unlock3();
+
+ foo.lock3();
+ foo.lock3(); // \
+ // expected-warning {{locking 'foo.mu1_' that is already locked}} \
+ // expected-warning {{locking 'foo.mu2_' that is already locked}} \
+ // expected-warning {{locking 'foo.mu3_' that is already locked}}
+ foo.a = 0;
+ foo.b = 0;
+ foo.c = 0;
+ foo.unlock3();
+ foo.unlock3(); // \
+ // expected-warning {{unlocking 'foo.mu1_' that was not locked}} \
+ // expected-warning {{unlocking 'foo.mu2_' that was not locked}} \
+ // expected-warning {{unlocking 'foo.mu3_' that was not locked}}
+}
+
+
+void testlots() {
+ Foo foo;
+ foo.locklots();
+ foo.a = 0;
+ foo.b = 0;
+ foo.c = 0;
+ foo.unlocklots();
+
+ foo.locklots();
+ foo.locklots(); // \
+ // expected-warning {{locking 'foo.mu1_' that is already locked}} \
+ // expected-warning {{locking 'foo.mu2_' that is already locked}} \
+ // expected-warning {{locking 'foo.mu3_' that is already locked}}
+ foo.a = 0;
+ foo.b = 0;
+ foo.c = 0;
+ foo.unlocklots();
+ foo.unlocklots(); // \
+ // expected-warning {{unlocking 'foo.mu1_' that was not locked}} \
+ // expected-warning {{unlocking 'foo.mu2_' that was not locked}} \
+ // expected-warning {{unlocking 'foo.mu3_' that was not locked}}
+}
+
+} // end namespace DuplicateAttributeTest
+
+
+
+namespace TryLockEqTest {
+
+class Foo {
+ Mutex mu_;
+ int a GUARDED_BY(mu_);
+ bool c;
+
+ int tryLockMutexI() EXCLUSIVE_TRYLOCK_FUNCTION(1, mu_);
+ Mutex* tryLockMutexP() EXCLUSIVE_TRYLOCK_FUNCTION(1, mu_);
+ void unlock() UNLOCK_FUNCTION(mu_);
+
+ void test1();
+ void test2();
+};
+
+
+void Foo::test1() {
+ if (tryLockMutexP() == 0) {
+ a = 0; // expected-warning {{writing variable 'a' requires locking 'mu_' exclusively}}
+ return;
+ }
+ a = 0;
+ unlock();
+
+ if (tryLockMutexP() != 0) {
+ a = 0;
+ unlock();
+ }
+
+ if (0 != tryLockMutexP()) {
+ a = 0;
+ unlock();
+ }
+
+ if (!(tryLockMutexP() == 0)) {
+ a = 0;
+ unlock();
+ }
+
+ if (tryLockMutexI() == 0) {
+ a = 0; // expected-warning {{writing variable 'a' requires locking 'mu_' exclusively}}
+ return;
+ }
+ a = 0;
+ unlock();
+
+ if (0 == tryLockMutexI()) {
+ a = 0; // expected-warning {{writing variable 'a' requires locking 'mu_' exclusively}}
+ return;
+ }
+ a = 0;
+ unlock();
+
+ if (tryLockMutexI() == 1) {
+ a = 0;
+ unlock();
+ }
+
+ if (mu_.TryLock() == false) {
+ a = 0; // expected-warning {{writing variable 'a' requires locking 'mu_' exclusively}}
+ return;
+ }
+ a = 0;
+ unlock();
+
+ if (mu_.TryLock() == true) {
+ a = 0;
+ unlock();
+ }
+ else {
+ a = 0; // expected-warning {{writing variable 'a' requires locking 'mu_' exclusively}}
+ }
+
+#if __has_feature(cxx_nullptr)
+ if (tryLockMutexP() == nullptr) {
+ a = 0; // expected-warning {{writing variable 'a' requires locking 'mu_' exclusively}}
+ return;
+ }
+ a = 0;
+ unlock();
+#endif
+}
+
+
+void Foo::test2() {
+/* FIXME: these tests depend on changes to the CFG.
+ *
+ if (mu_.TryLock() && c) {
+ a = 0;
+ unlock();
+ }
+ else return;
+
+ if (c && mu_.TryLock()) {
+ a = 0;
+ unlock();
+ }
+ else return;
+
+ if (!(mu_.TryLock() && c))
+ return;
+ a = 0;
+ unlock();
+
+ if (!(c && mu_.TryLock()))
+ return;
+ a = 0;
+ unlock();
+
+ if (!(mu_.TryLock() == 0) && c) {
+ a = 0;
+ unlock();
+ }
+
+ if (!mu_.TryLock() || c)
+ return;
+ a = 0;
+ unlock();
+*/
+}
+
+} // end namespace TryLockEqTest
+
+
+namespace ExistentialPatternMatching {
+
+class Graph {
+public:
+ Mutex mu_;
+};
+
+void LockAllGraphs() EXCLUSIVE_LOCK_FUNCTION(&Graph::mu_);
+void UnlockAllGraphs() UNLOCK_FUNCTION(&Graph::mu_);
+
+class Node {
+public:
+ int a GUARDED_BY(&Graph::mu_);
+
+ void foo() EXCLUSIVE_LOCKS_REQUIRED(&Graph::mu_) {
+ a = 0;
+ }
+ void foo2() LOCKS_EXCLUDED(&Graph::mu_);
+};
+
+void test() {
+ Graph g1;
+ Graph g2;
+ Node n1;
+
+ n1.a = 0; // expected-warning {{writing variable 'a' requires locking '&ExistentialPatternMatching::Graph::mu_' exclusively}}
+ n1.foo(); // expected-warning {{calling function 'foo' requires exclusive lock on '&ExistentialPatternMatching::Graph::mu_'}}
+ n1.foo2();
+
+ g1.mu_.Lock();
+ n1.a = 0;
+ n1.foo();
+ n1.foo2(); // expected-warning {{cannot call function 'foo2' while mutex '&ExistentialPatternMatching::Graph::mu_' is locked}}
+ g1.mu_.Unlock();
+
+ g2.mu_.Lock();
+ n1.a = 0;
+ n1.foo();
+ n1.foo2(); // expected-warning {{cannot call function 'foo2' while mutex '&ExistentialPatternMatching::Graph::mu_' is locked}}
+ g2.mu_.Unlock();
+
+ LockAllGraphs();
+ n1.a = 0;
+ n1.foo();
+ n1.foo2(); // expected-warning {{cannot call function 'foo2' while mutex '&ExistentialPatternMatching::Graph::mu_' is locked}}
+ UnlockAllGraphs();
+
+ LockAllGraphs();
+ g1.mu_.Unlock();
+
+ LockAllGraphs();
+ g2.mu_.Unlock();
+
+ LockAllGraphs();
+ g1.mu_.Lock(); // expected-warning {{locking 'g1.mu_' that is already locked}}
+ g1.mu_.Unlock();
+}
+} // end namespace ExistentialPatternMatching
OpenPOWER on IntegriCloud