diff options
author | Ian Lance Taylor <iant@golang.org> | 2010-06-30 13:14:46 -0700 |
---|---|---|
committer | Ian Lance Taylor <iant@golang.org> | 2010-06-30 13:14:46 -0700 |
commit | d364bb8ed786ab6c4877f19f0b286ed05894f0b0 (patch) | |
tree | 6d971ec4784d9c080bec2fc01c9cf132750705c6 | |
parent | 84cdef467e565d5fa3e43cc7b4307211cb17af30 (diff) | |
download | golang-d364bb8ed786ab6c4877f19f0b286ed05894f0b0.tar.gz |
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
http://codereview.appspot.com/1682048
-rw-r--r-- | src/pkg/io/pipe.go | 3 |
1 files changed, 2 insertions, 1 deletions
diff --git a/src/pkg/io/pipe.go b/src/pkg/io/pipe.go index 79221bd49..898526921 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 |