Open
Description
The current implementation of cmd.Wait has a race condition: if multiple goroutines call it, it might cause a panic.
In the first part of the method, copied below, two concurrent calls might check c.finished
, get false, set it to true, invoke c.Process.Wait()
and close c.waitDone
before any error checking is performed. c.waitDone
is a chan struct{}
, and a double close will cause a panic.
func (c *Cmd) Wait() error {
if c.Process == nil {
return errors.New("exec: not started")
}
if c.finished {
return errors.New("exec: Wait was already called")
}
c.finished = true
state, err := c.Process.Wait()
if c.waitDone != nil {
close(c.waitDone)
}
//[...]
Since waiting is a synchronization primitive I'd expect one of the two:
- The documentation should state that this is not safe for concurrent use (probably the best approach here)
- Some form of synchronization to prevent races. I would either atomically CAS
c.finished
(but I'm not a fan of atomics and would require to change type to some sort of int) or protectc
with a mutex, which would be my suggested solution for this case
I would happily send in CLs in both cases.