Commit 5bb3a66a authored by Rémy Oudompheng's avatar Rémy Oudompheng

sync, sync/atomic: do not corrupt race detector after a nil dereference.

The race detector uses a global lock to analyze atomic
operations. A panic in the middle of the code leaves the
lock acquired.

Similarly, the sync package may leave the race detectro
inconsistent when methods are called on nil pointers.

R=golang-dev, r, minux.ma, dvyukov, rsc, adg
CC=golang-dev
https://golang.org/cl/7981043
parent bd1cd1dd
...@@ -6,6 +6,7 @@ package race_test ...@@ -6,6 +6,7 @@ package race_test
import ( import (
"runtime" "runtime"
"sync"
"sync/atomic" "sync/atomic"
"testing" "testing"
"unsafe" "unsafe"
...@@ -269,3 +270,21 @@ func TestRaceAtomicAddStore(t *testing.T) { ...@@ -269,3 +270,21 @@ func TestRaceAtomicAddStore(t *testing.T) {
a = 42 a = 42
<-c <-c
} }
// A nil pointer in an atomic operation should not deadlock
// the rest of the program. Used to hang indefinitely.
func TestNoRaceAtomicCrash(t *testing.T) {
var mutex sync.Mutex
var nilptr *int32
panics := 0
defer func() {
if x := recover(); x != nil {
mutex.Lock()
panics++
mutex.Unlock()
} else {
panic("no panic")
}
}()
atomic.AddInt32(nilptr, 1)
}
...@@ -195,3 +195,22 @@ func TestRaceGoroutineCreationStack(t *testing.T) { ...@@ -195,3 +195,22 @@ func TestRaceGoroutineCreationStack(t *testing.T) {
x = 2 x = 2
<-ch <-ch
} }
// A nil pointer in a mutex method call should not
// corrupt the race detector state.
// Used to hang indefinitely.
func TestNoRaceNilMutexCrash(t *testing.T) {
var mutex sync.Mutex
panics := 0
defer func() {
if x := recover(); x != nil {
mutex.Lock()
panics++
mutex.Unlock()
} else {
panic("no panic")
}
}()
var othermutex *sync.RWMutex
othermutex.RLock()
}
...@@ -25,6 +25,7 @@ func CompareAndSwapInt32(val *int32, old, new int32) bool { ...@@ -25,6 +25,7 @@ func CompareAndSwapInt32(val *int32, old, new int32) bool {
} }
func CompareAndSwapUint32(val *uint32, old, new uint32) (swapped bool) { func CompareAndSwapUint32(val *uint32, old, new uint32) (swapped bool) {
_ = *val
swapped = false swapped = false
runtime.RaceSemacquire(&mtx) runtime.RaceSemacquire(&mtx)
runtime.RaceRead(unsafe.Pointer(val)) runtime.RaceRead(unsafe.Pointer(val))
...@@ -43,6 +44,7 @@ func CompareAndSwapInt64(val *int64, old, new int64) bool { ...@@ -43,6 +44,7 @@ func CompareAndSwapInt64(val *int64, old, new int64) bool {
} }
func CompareAndSwapUint64(val *uint64, old, new uint64) (swapped bool) { func CompareAndSwapUint64(val *uint64, old, new uint64) (swapped bool) {
_ = *val
swapped = false swapped = false
runtime.RaceSemacquire(&mtx) runtime.RaceSemacquire(&mtx)
runtime.RaceRead(unsafe.Pointer(val)) runtime.RaceRead(unsafe.Pointer(val))
...@@ -57,6 +59,7 @@ func CompareAndSwapUint64(val *uint64, old, new uint64) (swapped bool) { ...@@ -57,6 +59,7 @@ func CompareAndSwapUint64(val *uint64, old, new uint64) (swapped bool) {
} }
func CompareAndSwapPointer(val *unsafe.Pointer, old, new unsafe.Pointer) (swapped bool) { func CompareAndSwapPointer(val *unsafe.Pointer, old, new unsafe.Pointer) (swapped bool) {
_ = *val
swapped = false swapped = false
runtime.RaceSemacquire(&mtx) runtime.RaceSemacquire(&mtx)
runtime.RaceRead(unsafe.Pointer(val)) runtime.RaceRead(unsafe.Pointer(val))
...@@ -71,6 +74,7 @@ func CompareAndSwapPointer(val *unsafe.Pointer, old, new unsafe.Pointer) (swappe ...@@ -71,6 +74,7 @@ func CompareAndSwapPointer(val *unsafe.Pointer, old, new unsafe.Pointer) (swappe
} }
func CompareAndSwapUintptr(val *uintptr, old, new uintptr) (swapped bool) { func CompareAndSwapUintptr(val *uintptr, old, new uintptr) (swapped bool) {
_ = *val
swapped = false swapped = false
runtime.RaceSemacquire(&mtx) runtime.RaceSemacquire(&mtx)
runtime.RaceRead(unsafe.Pointer(val)) runtime.RaceRead(unsafe.Pointer(val))
...@@ -89,6 +93,7 @@ func AddInt32(val *int32, delta int32) int32 { ...@@ -89,6 +93,7 @@ func AddInt32(val *int32, delta int32) int32 {
} }
func AddUint32(val *uint32, delta uint32) (new uint32) { func AddUint32(val *uint32, delta uint32) (new uint32) {
_ = *val
runtime.RaceSemacquire(&mtx) runtime.RaceSemacquire(&mtx)
runtime.RaceRead(unsafe.Pointer(val)) runtime.RaceRead(unsafe.Pointer(val))
runtime.RaceAcquire(unsafe.Pointer(val)) runtime.RaceAcquire(unsafe.Pointer(val))
...@@ -105,6 +110,7 @@ func AddInt64(val *int64, delta int64) int64 { ...@@ -105,6 +110,7 @@ func AddInt64(val *int64, delta int64) int64 {
} }
func AddUint64(val *uint64, delta uint64) (new uint64) { func AddUint64(val *uint64, delta uint64) (new uint64) {
_ = *val
runtime.RaceSemacquire(&mtx) runtime.RaceSemacquire(&mtx)
runtime.RaceRead(unsafe.Pointer(val)) runtime.RaceRead(unsafe.Pointer(val))
runtime.RaceAcquire(unsafe.Pointer(val)) runtime.RaceAcquire(unsafe.Pointer(val))
...@@ -117,6 +123,7 @@ func AddUint64(val *uint64, delta uint64) (new uint64) { ...@@ -117,6 +123,7 @@ func AddUint64(val *uint64, delta uint64) (new uint64) {
} }
func AddUintptr(val *uintptr, delta uintptr) (new uintptr) { func AddUintptr(val *uintptr, delta uintptr) (new uintptr) {
_ = *val
runtime.RaceSemacquire(&mtx) runtime.RaceSemacquire(&mtx)
runtime.RaceRead(unsafe.Pointer(val)) runtime.RaceRead(unsafe.Pointer(val))
runtime.RaceAcquire(unsafe.Pointer(val)) runtime.RaceAcquire(unsafe.Pointer(val))
...@@ -133,6 +140,7 @@ func LoadInt32(addr *int32) int32 { ...@@ -133,6 +140,7 @@ func LoadInt32(addr *int32) int32 {
} }
func LoadUint32(addr *uint32) (val uint32) { func LoadUint32(addr *uint32) (val uint32) {
_ = *addr
runtime.RaceSemacquire(&mtx) runtime.RaceSemacquire(&mtx)
runtime.RaceRead(unsafe.Pointer(addr)) runtime.RaceRead(unsafe.Pointer(addr))
runtime.RaceAcquire(unsafe.Pointer(addr)) runtime.RaceAcquire(unsafe.Pointer(addr))
...@@ -146,6 +154,7 @@ func LoadInt64(addr *int64) int64 { ...@@ -146,6 +154,7 @@ func LoadInt64(addr *int64) int64 {
} }
func LoadUint64(addr *uint64) (val uint64) { func LoadUint64(addr *uint64) (val uint64) {
_ = *addr
runtime.RaceSemacquire(&mtx) runtime.RaceSemacquire(&mtx)
runtime.RaceRead(unsafe.Pointer(addr)) runtime.RaceRead(unsafe.Pointer(addr))
runtime.RaceAcquire(unsafe.Pointer(addr)) runtime.RaceAcquire(unsafe.Pointer(addr))
...@@ -155,6 +164,7 @@ func LoadUint64(addr *uint64) (val uint64) { ...@@ -155,6 +164,7 @@ func LoadUint64(addr *uint64) (val uint64) {
} }
func LoadPointer(addr *unsafe.Pointer) (val unsafe.Pointer) { func LoadPointer(addr *unsafe.Pointer) (val unsafe.Pointer) {
_ = *addr
runtime.RaceSemacquire(&mtx) runtime.RaceSemacquire(&mtx)
runtime.RaceRead(unsafe.Pointer(addr)) runtime.RaceRead(unsafe.Pointer(addr))
runtime.RaceAcquire(unsafe.Pointer(addr)) runtime.RaceAcquire(unsafe.Pointer(addr))
...@@ -164,6 +174,7 @@ func LoadPointer(addr *unsafe.Pointer) (val unsafe.Pointer) { ...@@ -164,6 +174,7 @@ func LoadPointer(addr *unsafe.Pointer) (val unsafe.Pointer) {
} }
func LoadUintptr(addr *uintptr) (val uintptr) { func LoadUintptr(addr *uintptr) (val uintptr) {
_ = *addr
runtime.RaceSemacquire(&mtx) runtime.RaceSemacquire(&mtx)
runtime.RaceRead(unsafe.Pointer(addr)) runtime.RaceRead(unsafe.Pointer(addr))
runtime.RaceAcquire(unsafe.Pointer(addr)) runtime.RaceAcquire(unsafe.Pointer(addr))
...@@ -177,6 +188,7 @@ func StoreInt32(addr *int32, val int32) { ...@@ -177,6 +188,7 @@ func StoreInt32(addr *int32, val int32) {
} }
func StoreUint32(addr *uint32, val uint32) { func StoreUint32(addr *uint32, val uint32) {
_ = *addr
runtime.RaceSemacquire(&mtx) runtime.RaceSemacquire(&mtx)
runtime.RaceRead(unsafe.Pointer(addr)) runtime.RaceRead(unsafe.Pointer(addr))
*addr = val *addr = val
...@@ -189,6 +201,7 @@ func StoreInt64(addr *int64, val int64) { ...@@ -189,6 +201,7 @@ func StoreInt64(addr *int64, val int64) {
} }
func StoreUint64(addr *uint64, val uint64) { func StoreUint64(addr *uint64, val uint64) {
_ = *addr
runtime.RaceSemacquire(&mtx) runtime.RaceSemacquire(&mtx)
runtime.RaceRead(unsafe.Pointer(addr)) runtime.RaceRead(unsafe.Pointer(addr))
*addr = val *addr = val
...@@ -197,6 +210,7 @@ func StoreUint64(addr *uint64, val uint64) { ...@@ -197,6 +210,7 @@ func StoreUint64(addr *uint64, val uint64) {
} }
func StorePointer(addr *unsafe.Pointer, val unsafe.Pointer) { func StorePointer(addr *unsafe.Pointer, val unsafe.Pointer) {
_ = *addr
runtime.RaceSemacquire(&mtx) runtime.RaceSemacquire(&mtx)
runtime.RaceRead(unsafe.Pointer(addr)) runtime.RaceRead(unsafe.Pointer(addr))
*addr = val *addr = val
...@@ -205,6 +219,7 @@ func StorePointer(addr *unsafe.Pointer, val unsafe.Pointer) { ...@@ -205,6 +219,7 @@ func StorePointer(addr *unsafe.Pointer, val unsafe.Pointer) {
} }
func StoreUintptr(addr *uintptr, val uintptr) { func StoreUintptr(addr *uintptr, val uintptr) {
_ = *addr
runtime.RaceSemacquire(&mtx) runtime.RaceSemacquire(&mtx)
runtime.RaceRead(unsafe.Pointer(addr)) runtime.RaceRead(unsafe.Pointer(addr))
*addr = val *addr = val
......
...@@ -57,6 +57,7 @@ func NewCond(l Locker) *Cond { ...@@ -57,6 +57,7 @@ func NewCond(l Locker) *Cond {
// //
func (c *Cond) Wait() { func (c *Cond) Wait() {
if raceenabled { if raceenabled {
_ = c.m.state
raceDisable() raceDisable()
} }
c.m.Lock() c.m.Lock()
...@@ -80,6 +81,7 @@ func (c *Cond) Wait() { ...@@ -80,6 +81,7 @@ func (c *Cond) Wait() {
// during the call. // during the call.
func (c *Cond) Signal() { func (c *Cond) Signal() {
if raceenabled { if raceenabled {
_ = c.m.state
raceDisable() raceDisable()
} }
c.m.Lock() c.m.Lock()
...@@ -106,6 +108,7 @@ func (c *Cond) Signal() { ...@@ -106,6 +108,7 @@ func (c *Cond) Signal() {
// during the call. // during the call.
func (c *Cond) Broadcast() { func (c *Cond) Broadcast() {
if raceenabled { if raceenabled {
_ = c.m.state
raceDisable() raceDisable()
} }
c.m.Lock() c.m.Lock()
......
...@@ -81,6 +81,7 @@ func (m *Mutex) Lock() { ...@@ -81,6 +81,7 @@ func (m *Mutex) Lock() {
// arrange for another goroutine to unlock it. // arrange for another goroutine to unlock it.
func (m *Mutex) Unlock() { func (m *Mutex) Unlock() {
if raceenabled { if raceenabled {
_ = m.state
raceRelease(unsafe.Pointer(m)) raceRelease(unsafe.Pointer(m))
} }
......
...@@ -28,6 +28,7 @@ const rwmutexMaxReaders = 1 << 30 ...@@ -28,6 +28,7 @@ const rwmutexMaxReaders = 1 << 30
// RLock locks rw for reading. // RLock locks rw for reading.
func (rw *RWMutex) RLock() { func (rw *RWMutex) RLock() {
if raceenabled { if raceenabled {
_ = rw.w.state
raceDisable() raceDisable()
} }
if atomic.AddInt32(&rw.readerCount, 1) < 0 { if atomic.AddInt32(&rw.readerCount, 1) < 0 {
...@@ -46,6 +47,7 @@ func (rw *RWMutex) RLock() { ...@@ -46,6 +47,7 @@ func (rw *RWMutex) RLock() {
// on entry to RUnlock. // on entry to RUnlock.
func (rw *RWMutex) RUnlock() { func (rw *RWMutex) RUnlock() {
if raceenabled { if raceenabled {
_ = rw.w.state
raceReleaseMerge(unsafe.Pointer(&rw.writerSem)) raceReleaseMerge(unsafe.Pointer(&rw.writerSem))
raceDisable() raceDisable()
} }
...@@ -69,6 +71,7 @@ func (rw *RWMutex) RUnlock() { ...@@ -69,6 +71,7 @@ func (rw *RWMutex) RUnlock() {
// the lock. // the lock.
func (rw *RWMutex) Lock() { func (rw *RWMutex) Lock() {
if raceenabled { if raceenabled {
_ = rw.w.state
raceDisable() raceDisable()
} }
// First, resolve competition with other writers. // First, resolve competition with other writers.
...@@ -94,6 +97,7 @@ func (rw *RWMutex) Lock() { ...@@ -94,6 +97,7 @@ func (rw *RWMutex) Lock() {
// arrange for another goroutine to RUnlock (Unlock) it. // arrange for another goroutine to RUnlock (Unlock) it.
func (rw *RWMutex) Unlock() { func (rw *RWMutex) Unlock() {
if raceenabled { if raceenabled {
_ = rw.w.state
raceRelease(unsafe.Pointer(&rw.readerSem)) raceRelease(unsafe.Pointer(&rw.readerSem))
raceRelease(unsafe.Pointer(&rw.writerSem)) raceRelease(unsafe.Pointer(&rw.writerSem))
raceDisable() raceDisable()
......
...@@ -43,6 +43,7 @@ type WaitGroup struct { ...@@ -43,6 +43,7 @@ type WaitGroup struct {
// other event to be waited for. See the WaitGroup example. // other event to be waited for. See the WaitGroup example.
func (wg *WaitGroup) Add(delta int) { func (wg *WaitGroup) Add(delta int) {
if raceenabled { if raceenabled {
_ = wg.m.state
raceReleaseMerge(unsafe.Pointer(wg)) raceReleaseMerge(unsafe.Pointer(wg))
raceDisable() raceDisable()
defer raceEnable() defer raceEnable()
...@@ -71,6 +72,7 @@ func (wg *WaitGroup) Done() { ...@@ -71,6 +72,7 @@ func (wg *WaitGroup) Done() {
// Wait blocks until the WaitGroup counter is zero. // Wait blocks until the WaitGroup counter is zero.
func (wg *WaitGroup) Wait() { func (wg *WaitGroup) Wait() {
if raceenabled { if raceenabled {
_ = wg.m.state
raceDisable() raceDisable()
} }
if atomic.LoadInt32(&wg.counter) == 0 { if atomic.LoadInt32(&wg.counter) == 0 {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment