mirror of
https://github.com/golang/go
synced 2024-11-23 12:10:11 -07:00
os/exec: add closeOnce.WriteString method
Add an explicit WriteString method to closeOnce that acquires the writers lock. This overrides the one promoted from the embedded *os.File field. The promoted one naturally does not acquire the lock, and can therefore race with the Close method. Fixes #17647. Change-Id: I3460f2a0d503449481cfb2fd4628b4855ab0ecdf Reviewed-on: https://go-review.googlesource.com/33298 Run-TryBot: Ian Lance Taylor <iant@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
parent
1b66b38e25
commit
b906df653b
4
src/cmd/dist/test.go
vendored
4
src/cmd/dist/test.go
vendored
@ -1055,7 +1055,7 @@ func (t *tester) runFlag(rx string) string {
|
||||
func (t *tester) raceTest(dt *distTest) error {
|
||||
t.addCmd(dt, "src", "go", "test", "-race", "-i", "runtime/race", "flag", "os/exec")
|
||||
t.addCmd(dt, "src", "go", "test", "-race", t.runFlag("Output"), "runtime/race")
|
||||
t.addCmd(dt, "src", "go", "test", "-race", "-short", t.runFlag("TestParse|TestEcho"), "flag", "os/exec")
|
||||
t.addCmd(dt, "src", "go", "test", "-race", "-short", t.runFlag("TestParse|TestEcho|TestStdinCloseRace"), "flag", "os/exec")
|
||||
// We don't want the following line, because it
|
||||
// slows down all.bash (by 10 seconds on my laptop).
|
||||
// The race builder should catch any error here, but doesn't.
|
||||
@ -1068,7 +1068,7 @@ func (t *tester) raceTest(dt *distTest) error {
|
||||
}
|
||||
if t.extLink() {
|
||||
// Test with external linking; see issue 9133.
|
||||
t.addCmd(dt, "src", "go", "test", "-race", "-short", "-ldflags=-linkmode=external", t.runFlag("TestParse|TestEcho"), "flag", "os/exec")
|
||||
t.addCmd(dt, "src", "go", "test", "-race", "-short", "-ldflags=-linkmode=external", t.runFlag("TestParse|TestEcho|TestStdinCloseRace"), "flag", "os/exec")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -579,6 +579,13 @@ func (c *closeOnce) Write(b []byte) (int, error) {
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (c *closeOnce) WriteString(s string) (int, error) {
|
||||
c.writers.RLock()
|
||||
n, err := c.File.WriteString(s)
|
||||
c.writers.RUnlock()
|
||||
return n, err
|
||||
}
|
||||
|
||||
// StdoutPipe returns a pipe that will be connected to the command's
|
||||
// standard output when the command starts.
|
||||
//
|
||||
|
@ -246,6 +246,32 @@ func TestStdinClose(t *testing.T) {
|
||||
check("Wait", cmd.Wait())
|
||||
}
|
||||
|
||||
// Issue 17647.
|
||||
func TestStdinCloseRace(t *testing.T) {
|
||||
cmd := helperCommand(t, "stdinClose")
|
||||
stdin, err := cmd.StdinPipe()
|
||||
if err != nil {
|
||||
t.Fatalf("StdinPipe: %v", err)
|
||||
}
|
||||
if err := cmd.Start(); err != nil {
|
||||
t.Fatalf("Start: %v", err)
|
||||
}
|
||||
go func() {
|
||||
if err := cmd.Process.Kill(); err != nil {
|
||||
t.Errorf("Kill: %v", err)
|
||||
}
|
||||
}()
|
||||
go func() {
|
||||
io.Copy(stdin, strings.NewReader(stdinCloseTestString))
|
||||
if err := stdin.Close(); err != nil {
|
||||
t.Errorf("stdin.Close: %v", err)
|
||||
}
|
||||
}()
|
||||
if err := cmd.Wait(); err == nil {
|
||||
t.Fatalf("Wait: succeeded unexpectedly")
|
||||
}
|
||||
}
|
||||
|
||||
// Issue 5071
|
||||
func TestPipeLookPathLeak(t *testing.T) {
|
||||
fd0, lsof0 := numOpenFDS(t)
|
||||
|
Loading…
Reference in New Issue
Block a user