/// \return false if we should keep \p A, true if we should keep \p B.
bool ThreadSafetyAnalyzer::join(const FactEntry &A, const FactEntry &B) {
if (A.kind() != B.kind()) {
- Handler.handleExclusiveAndShared("mutex", B.toString(), B.loc(), A.loc());
- // Take the exclusive capability to reduce further warnings.
- return B.kind() == LK_Exclusive;
+ // For managed capabilities, the destructor should unlock in the right mode
+ // anyway. For asserted capabilities no unlocking is needed.
+ if ((A.managed() || A.asserted()) && (B.managed() || B.asserted())) {
+ // The shared capability subsumes the exclusive capability.
+ return B.kind() == LK_Shared;
+ } else {
+ Handler.handleExclusiveAndShared("mutex", B.toString(), B.loc(), A.loc());
+ // Take the exclusive capability to reduce further warnings.
+ return B.kind() == LK_Exclusive;
+ }
} else {
// The non-asserted capability is the one we want to track.
return A.asserted() && !B.asserted();
x = 2; // expected-warning {{writing variable 'x' requires holding mutex 'mu' exclusively}}
}
+void exclusiveSharedJoin() {
+ RelockableMutexLock scope(&mu, DeferTraits{});
+ if (b)
+ scope.Lock();
+ else
+ scope.ReaderLock();
+ // No warning on join point because the lock will be released by the scope object anyway.
+ print(x);
+ x = 2; // expected-warning {{writing variable 'x' requires holding mutex 'mu' exclusively}}
+}
+
+void sharedExclusiveJoin() {
+ RelockableMutexLock scope(&mu, DeferTraits{});
+ if (b)
+ scope.ReaderLock();
+ else
+ scope.Lock();
+ // No warning on join point because the lock will be released by the scope object anyway.
+ print(x);
+ x = 2; // expected-warning {{writing variable 'x' requires holding mutex 'mu' exclusively}}
+}
+
+void assertJoin() {
+ RelockableMutexLock scope(&mu, DeferTraits{});
+ if (b)
+ scope.Lock();
+ else
+ mu.AssertHeld();
+ x = 2;
+}
+
+void assertSharedJoin() {
+ RelockableMutexLock scope(&mu, DeferTraits{});
+ if (b)
+ scope.ReaderLock();
+ else
+ mu.AssertReaderHeld();
+ print(x);
+ x = 2; // expected-warning {{writing variable 'x' requires holding mutex 'mu' exclusively}}
+}
+
+void assertStrongerJoin() {
+ RelockableMutexLock scope(&mu, DeferTraits{});
+ if (b)
+ scope.ReaderLock();
+ else
+ mu.AssertHeld();
+ print(x);
+ x = 2; // expected-warning {{writing variable 'x' requires holding mutex 'mu' exclusively}}
+}
+
+void assertWeakerJoin() {
+ RelockableMutexLock scope(&mu, DeferTraits{});
+ if (b)
+ scope.Lock();
+ else
+ mu.AssertReaderHeld();
+ print(x);
+ x = 2; // expected-warning {{writing variable 'x' requires holding mutex 'mu' exclusively}}
+}
+
void directUnlock() {
RelockableExclusiveMutexLock scope(&mu);
mu.Unlock();
void test6() {
mu_.AssertHeld();
- mu_.Unlock();
- } // should this be a warning?
+ mu_.Unlock(); // should this be a warning?
+ }
void test7() {
if (c) {
else {
mu_.AssertHeld();
}
+ // FIXME: should warn, because it's unclear whether we need to release or not.
int b = a;
a = 0;
- mu_.Unlock();
+ mu_.Unlock(); // should this be a warning?
}
void test9() {
int b = a;
a = 0;
}
+
+ void test12() {
+ if (c)
+ mu_.ReaderLock(); // expected-warning {{mutex 'mu_' is acquired exclusively and shared in the same scope}}
+ else
+ mu_.AssertHeld(); // expected-note {{the other acquisition of mutex 'mu_' is here}}
+ // FIXME: should instead warn because it's unclear whether we need to release or not.
+ int b = a;
+ a = 0;
+ mu_.Unlock();
+ }
+
+ void test13() {
+ if (c)
+ mu_.Lock(); // expected-warning {{mutex 'mu_' is acquired exclusively and shared in the same scope}}
+ else
+ mu_.AssertReaderHeld(); // expected-note {{the other acquisition of mutex 'mu_' is here}}
+ // FIXME: should instead warn because it's unclear whether we need to release or not.
+ int b = a;
+ a = 0;
+ mu_.Unlock();
+ }
};
} // end namespace AssertHeldTest