aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2010-06-30 13:14:46 -0700
committerIan Lance Taylor <iant@golang.org>2010-06-30 13:14:46 -0700
commit7c1be45f5809169393eb19404ddd73fb4bf60e49 (patch)
tree7f6c21e5c44bd35f570e80439eb6bdc19415bc6e
parentd3c3c15b1769c7167fb4188dbdb95b8f1d24c5e5 (diff)
downloadgo-7c1be45f5809169393eb19404ddd73fb4bf60e49.tar.gz
go-7c1be45f5809169393eb19404ddd73fb4bf60e49.zip
io: Avoid race condition in pipe.
One goroutine started up and was waiting in rw. Then another goroutine decided to close the pipe. The closing goroutine stalled calling p.io.Lock() in pipeHalf.close. (This happened in gccgo). If the closing goroutine had been able to set the ioclosed flag, it would have gone on to tell the runner that the pipe was closed, which would then send an EINVAL to the goroutine sleeping in rw. Unlocking p.io before sleeping in rw avoids the race. R=rsc, rsc1 CC=golang-dev https://golang.org/cl/1682048
-rw-r--r--src/pkg/io/pipe.go3
1 files changed, 2 insertions, 1 deletions
diff --git a/src/pkg/io/pipe.go b/src/pkg/io/pipe.go
index 79221bd497..898526921f 100644
--- a/src/pkg/io/pipe.go
+++ b/src/pkg/io/pipe.go
@@ -144,10 +144,11 @@ func (p *pipeHalf) rw(data []byte) (n int, err os.Error) {
// Run i/o operation.
// Check ioclosed flag under lock to make sure we're still allowed to do i/o.
p.io.Lock()
- defer p.io.Unlock()
if p.ioclosed {
+ p.io.Unlock()
return 0, os.EINVAL
}
+ p.io.Unlock()
p.c1 <- data
res := <-p.c2
return res.n, res.err