diff options
author | DeLesley Hutchins <delesley@google.com> | 2012-07-02 22:26:29 +0000 |
---|---|---|
committer | DeLesley Hutchins <delesley@google.com> | 2012-07-02 22:26:29 +0000 |
commit | bbe334142b38d2f9dad3ae2eb7b332c54a5b2cc1 (patch) | |
tree | 8e9c9ea971cac96d9d56a6080bf8140a6566f607 | |
parent | 70cbf3cc09eb21db1108396d30a414ea66d842cc (diff) |
Thread safety analysis: fixed bug that occurs when very silly people
use scoped_lockable without putting unlock_function on the
destructor.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@159609 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/Analysis/ThreadSafety.cpp | 47 | ||||
-rw-r--r-- | test/SemaCXX/warn-thread-safety-analysis.cpp | 65 |
2 files changed, 98 insertions, 14 deletions
diff --git a/lib/Analysis/ThreadSafety.cpp b/lib/Analysis/ThreadSafety.cpp index b82bc55dff..f9d93ee0df 100644 --- a/lib/Analysis/ThreadSafety.cpp +++ b/lib/Analysis/ThreadSafety.cpp @@ -1558,20 +1558,29 @@ Lockset ThreadSafetyAnalyzer::intersectAndWarn(const Lockset &LSet1, for (Lockset::iterator I = LSet2.begin(), E = LSet2.end(); I != E; ++I) { const MutexID &LSet2Mutex = I.getKey(); - const LockData &LSet2LockData = I.getData(); - if (const LockData *LD = LSet1.lookup(LSet2Mutex)) { - if (LD->LKind != LSet2LockData.LKind) { + const LockData &LDat2 = I.getData(); + if (const LockData *LDat1 = LSet1.lookup(LSet2Mutex)) { + if (LDat1->LKind != LDat2.LKind) { Handler.handleExclusiveAndShared(LSet2Mutex.getName(), - LSet2LockData.AcquireLoc, - LD->AcquireLoc); - if (LD->LKind != LK_Exclusive) - Intersection = LocksetFactory.add(Intersection, LSet2Mutex, - LSet2LockData); + LDat2.AcquireLoc, + LDat1->AcquireLoc); + if (LDat1->LKind != LK_Exclusive) + Intersection = LocksetFactory.add(Intersection, LSet2Mutex, LDat2); } } else { - if (!LSet2LockData.Managed) + if (LDat2.UnderlyingMutex.isValid()) { + if (LSet2.lookup(LDat2.UnderlyingMutex)) { + // If this is a scoped lock that manages another mutex, and if the + // underlying mutex is still held, then warn about the underlying + // mutex. + Handler.handleMutexHeldEndOfScope(LDat2.UnderlyingMutex.getName(), + LDat2.AcquireLoc, + JoinLoc, LEK1); + } + } + else if (!LDat2.Managed) Handler.handleMutexHeldEndOfScope(LSet2Mutex.getName(), - LSet2LockData.AcquireLoc, + LDat2.AcquireLoc, JoinLoc, LEK1); } } @@ -1579,11 +1588,21 @@ Lockset ThreadSafetyAnalyzer::intersectAndWarn(const Lockset &LSet1, for (Lockset::iterator I = LSet1.begin(), E = LSet1.end(); I != E; ++I) { if (!LSet2.contains(I.getKey())) { const MutexID &Mutex = I.getKey(); - const LockData &MissingLock = I.getData(); - - if (!MissingLock.Managed) + const LockData &LDat1 = I.getData(); + + if (LDat1.UnderlyingMutex.isValid()) { + if (LSet1.lookup(LDat1.UnderlyingMutex)) { + // If this is a scoped lock that manages another mutex, and if the + // underlying mutex is still held, then warn about the underlying + // mutex. + Handler.handleMutexHeldEndOfScope(LDat1.UnderlyingMutex.getName(), + LDat1.AcquireLoc, + JoinLoc, LEK1); + } + } + else if (!LDat1.Managed) Handler.handleMutexHeldEndOfScope(Mutex.getName(), - MissingLock.AcquireLoc, + LDat1.AcquireLoc, JoinLoc, LEK2); Intersection = LocksetFactory.remove(Intersection, Mutex); } diff --git a/test/SemaCXX/warn-thread-safety-analysis.cpp b/test/SemaCXX/warn-thread-safety-analysis.cpp index 35a2dd0121..2bf9ed4079 100644 --- a/test/SemaCXX/warn-thread-safety-analysis.cpp +++ b/test/SemaCXX/warn-thread-safety-analysis.cpp @@ -2470,3 +2470,68 @@ public: } // 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 + |