Commit 83dfc3b0 authored by Keith Randall's avatar Keith Randall Committed by Keith Randall

runtime: ignore races between close and len/cap

They aren't really races, or at least they don't have any
observable effect. The spec is silent on whether these are actually
races or not.

Fix this problem by not using the address of len (or of cap)
as the location where channel operations are recorded to occur.
Use a random other field of hchan for that.

I'm not 100% sure we should in fact fix this. Opinions welcome.

Fixes #27070

Change-Id: Ib4efd4b62e0d1ef32fa51e373035ef207a655084
Reviewed-on: https://go-review.googlesource.com/135698Reviewed-by: default avatarDmitry Vyukov <dvyukov@google.com>
parent 77f9b272
...@@ -92,7 +92,7 @@ func makechan(t *chantype, size int) *hchan { ...@@ -92,7 +92,7 @@ func makechan(t *chantype, size int) *hchan {
// Queue or element size is zero. // Queue or element size is zero.
c = (*hchan)(mallocgc(hchanSize, nil, true)) c = (*hchan)(mallocgc(hchanSize, nil, true))
// Race detector uses this location for synchronization. // Race detector uses this location for synchronization.
c.buf = unsafe.Pointer(c) c.buf = c.raceaddr()
case elem.kind&kindNoPointers != 0: case elem.kind&kindNoPointers != 0:
// Elements do not contain pointers. // Elements do not contain pointers.
// Allocate hchan and buf in one call. // Allocate hchan and buf in one call.
...@@ -151,7 +151,7 @@ func chansend(c *hchan, ep unsafe.Pointer, block bool, callerpc uintptr) bool { ...@@ -151,7 +151,7 @@ func chansend(c *hchan, ep unsafe.Pointer, block bool, callerpc uintptr) bool {
} }
if raceenabled { if raceenabled {
racereadpc(unsafe.Pointer(c), callerpc, funcPC(chansend)) racereadpc(c.raceaddr(), callerpc, funcPC(chansend))
} }
// Fast path: check for failed non-blocking operation without acquiring the lock. // Fast path: check for failed non-blocking operation without acquiring the lock.
...@@ -337,8 +337,8 @@ func closechan(c *hchan) { ...@@ -337,8 +337,8 @@ func closechan(c *hchan) {
if raceenabled { if raceenabled {
callerpc := getcallerpc() callerpc := getcallerpc()
racewritepc(unsafe.Pointer(c), callerpc, funcPC(closechan)) racewritepc(c.raceaddr(), callerpc, funcPC(closechan))
racerelease(unsafe.Pointer(c)) racerelease(c.raceaddr())
} }
c.closed = 1 c.closed = 1
...@@ -361,7 +361,7 @@ func closechan(c *hchan) { ...@@ -361,7 +361,7 @@ func closechan(c *hchan) {
gp := sg.g gp := sg.g
gp.param = nil gp.param = nil
if raceenabled { if raceenabled {
raceacquireg(gp, unsafe.Pointer(c)) raceacquireg(gp, c.raceaddr())
} }
glist.push(gp) glist.push(gp)
} }
...@@ -379,7 +379,7 @@ func closechan(c *hchan) { ...@@ -379,7 +379,7 @@ func closechan(c *hchan) {
gp := sg.g gp := sg.g
gp.param = nil gp.param = nil
if raceenabled { if raceenabled {
raceacquireg(gp, unsafe.Pointer(c)) raceacquireg(gp, c.raceaddr())
} }
glist.push(gp) glist.push(gp)
} }
...@@ -454,7 +454,7 @@ func chanrecv(c *hchan, ep unsafe.Pointer, block bool) (selected, received bool) ...@@ -454,7 +454,7 @@ func chanrecv(c *hchan, ep unsafe.Pointer, block bool) (selected, received bool)
if c.closed != 0 && c.qcount == 0 { if c.closed != 0 && c.qcount == 0 {
if raceenabled { if raceenabled {
raceacquire(unsafe.Pointer(c)) raceacquire(c.raceaddr())
} }
unlock(&c.lock) unlock(&c.lock)
if ep != nil { if ep != nil {
...@@ -732,6 +732,15 @@ func (q *waitq) dequeue() *sudog { ...@@ -732,6 +732,15 @@ func (q *waitq) dequeue() *sudog {
} }
} }
func (c *hchan) raceaddr() unsafe.Pointer {
// Treat read-like and write-like operations on the channel to
// happen at this address. Avoid using the address of qcount
// or dataqsiz, because the len() and cap() builtins read
// those addresses, and we don't want them racing with
// operations like close().
return unsafe.Pointer(&c.buf)
}
func racesync(c *hchan, sg *sudog) { func racesync(c *hchan, sg *sudog) {
racerelease(chanbuf(c, 0)) racerelease(chanbuf(c, 0))
raceacquireg(sg.g, chanbuf(c, 0)) raceacquireg(sg.g, chanbuf(c, 0))
......
...@@ -577,18 +577,32 @@ func TestRaceChanItselfCap(t *testing.T) { ...@@ -577,18 +577,32 @@ func TestRaceChanItselfCap(t *testing.T) {
<-compl <-compl
} }
func TestRaceChanCloseLen(t *testing.T) { func TestNoRaceChanCloseLen(t *testing.T) {
v := 0
_ = v
c := make(chan int, 10) c := make(chan int, 10)
c <- 0 r := make(chan int, 10)
go func() {
r <- len(c)
}()
go func() { go func() {
v = 1
close(c) close(c)
r <- 0
}() }()
time.Sleep(1e7) <-r
_ = len(c) <-r
v = 2 }
func TestNoRaceChanCloseCap(t *testing.T) {
c := make(chan int, 10)
r := make(chan int, 10)
go func() {
r <- cap(c)
}()
go func() {
close(c)
r <- 0
}()
<-r
<-r
} }
func TestRaceChanCloseSend(t *testing.T) { func TestRaceChanCloseSend(t *testing.T) {
......
...@@ -245,7 +245,7 @@ loop: ...@@ -245,7 +245,7 @@ loop:
case caseSend: case caseSend:
if raceenabled { if raceenabled {
racereadpc(unsafe.Pointer(c), cas.pc, chansendpc) racereadpc(c.raceaddr(), cas.pc, chansendpc)
} }
if c.closed != 0 { if c.closed != 0 {
goto sclose goto sclose
...@@ -462,7 +462,7 @@ rclose: ...@@ -462,7 +462,7 @@ rclose:
typedmemclr(c.elemtype, cas.elem) typedmemclr(c.elemtype, cas.elem)
} }
if raceenabled { if raceenabled {
raceacquire(unsafe.Pointer(c)) raceacquire(c.raceaddr())
} }
goto retc goto retc
......
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