]> Cypherpunks repositories - gostls13.git/commitdiff
sync: detect incorrect usages of RWMutex
authorDmitriy Vyukov <dvyukov@google.com>
Fri, 20 Jun 2014 05:19:56 +0000 (22:19 -0700)
committerDmitriy Vyukov <dvyukov@google.com>
Fri, 20 Jun 2014 05:19:56 +0000 (22:19 -0700)
Fixes #7858.

LGTM=ruiu
R=ruiu
CC=golang-codereviews
https://golang.org/cl/92720045

src/pkg/sync/rwmutex.go
src/pkg/sync/rwmutex_test.go

index 3db54199576ecb2f2a7325be173709de4891db5f..0e8a58e5f03ad3830b3efe43cb145b1e3df3a202 100644 (file)
@@ -51,7 +51,11 @@ func (rw *RWMutex) RUnlock() {
                raceReleaseMerge(unsafe.Pointer(&rw.writerSem))
                raceDisable()
        }
-       if atomic.AddInt32(&rw.readerCount, -1) < 0 {
+       if r := atomic.AddInt32(&rw.readerCount, -1); r < 0 {
+               if r+1 == 0 || r+1 == -rwmutexMaxReaders {
+                       raceEnable()
+                       panic("sync: RUnlock of unlocked RWMutex")
+               }
                // A writer is pending.
                if atomic.AddInt32(&rw.readerWait, -1) == 0 {
                        // The last reader unblocks the writer.
@@ -105,6 +109,10 @@ func (rw *RWMutex) Unlock() {
 
        // Announce to readers there is no active writer.
        r := atomic.AddInt32(&rw.readerCount, rwmutexMaxReaders)
+       if r >= rwmutexMaxReaders {
+               raceEnable()
+               panic("sync: Unlock of unlocked RWMutex")
+       }
        // Unblock blocked readers, if any.
        for i := 0; i < int(r); i++ {
                runtime_Semrelease(&rw.readerSem)
index 0436f97239c7a16b823e6b05b4772bc134d064f0..f625bc3a5854de10e6f06b77596db8724a4bdb60 100644 (file)
@@ -155,6 +155,48 @@ func TestRLocker(t *testing.T) {
        }
 }
 
+func TestUnlockPanic(t *testing.T) {
+       defer func() {
+               if recover() == nil {
+                       t.Fatalf("unlock of unlocked RWMutex did not panic")
+               }
+       }()
+       var mu RWMutex
+       mu.Unlock()
+}
+
+func TestUnlockPanic2(t *testing.T) {
+       defer func() {
+               if recover() == nil {
+                       t.Fatalf("unlock of unlocked RWMutex did not panic")
+               }
+       }()
+       var mu RWMutex
+       mu.RLock()
+       mu.Unlock()
+}
+
+func TestRUnlockPanic(t *testing.T) {
+       defer func() {
+               if recover() == nil {
+                       t.Fatalf("read unlock of unlocked RWMutex did not panic")
+               }
+       }()
+       var mu RWMutex
+       mu.RUnlock()
+}
+
+func TestRUnlockPanic2(t *testing.T) {
+       defer func() {
+               if recover() == nil {
+                       t.Fatalf("read unlock of unlocked RWMutex did not panic")
+               }
+       }()
+       var mu RWMutex
+       mu.Lock()
+       mu.RUnlock()
+}
+
 func BenchmarkRWMutexUncontended(b *testing.B) {
        type PaddedRWMutex struct {
                RWMutex