Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

os/exec: possible data race when using same writer for Stdout and Stderr #19804

Closed
nussjustin opened this issue Mar 31, 2017 · 2 comments
Closed

Comments

@nussjustin
Copy link
Contributor

What did you do?

Wrote a simple program that concurrently writes to stdout and stderr: https://play.golang.org/p/S-t6xqdZl7

Wrote a test that runs the program with the same io.Writer for Cmd.Stdout and Cmd.Stderr: https://play.golang.org/p/BYWBCHPA5l

What did you expect to see?

No data race. The documentation of Stdout and Stderr say:

// If Stdout and Stderr are the same writer, at most one
// goroutine at a time will call Write.

What did you see instead?

A data race.

==================
WARNING: DATA RACE
Write at 0x0000012ba190 by goroutine 8:
  _/Users/justin.nuss/Workspace_test.glob..func1()
      /Users/justin.nuss/Workspace/race_test.go:17 +0x41
  _/Users/justin.nuss/Workspace_test.WriterFunc.Write()
      /Users/justin.nuss/Workspace/race_test.go:11 +0x55
  io.copyBuffer()
      /usr/local/Cellar/go/1.8/libexec/src/io/io.go:392 +0x27d
  io.Copy()
      /usr/local/Cellar/go/1.8/libexec/src/io/io.go:360 +0x7e
  os/exec.(*Cmd).writerDescriptor.func1()
      /usr/local/Cellar/go/1.8/libexec/src/os/exec/exec.go:254 +0x68
  os/exec.(*Cmd).Start.func1()
      /usr/local/Cellar/go/1.8/libexec/src/os/exec/exec.go:371 +0x38

Previous write at 0x0000012ba190 by goroutine 7:
  _/Users/justin.nuss/Workspace_test.glob..func1()
      /Users/justin.nuss/Workspace/race_test.go:17 +0x41
  _/Users/justin.nuss/Workspace_test.WriterFunc.Write()
      /Users/justin.nuss/Workspace/race_test.go:11 +0x55
  io.copyBuffer()
      /usr/local/Cellar/go/1.8/libexec/src/io/io.go:392 +0x27d
  io.Copy()
      /usr/local/Cellar/go/1.8/libexec/src/io/io.go:360 +0x7e
  os/exec.(*Cmd).writerDescriptor.func1()
      /usr/local/Cellar/go/1.8/libexec/src/os/exec/exec.go:254 +0x68
  os/exec.(*Cmd).Start.func1()
      /usr/local/Cellar/go/1.8/libexec/src/os/exec/exec.go:371 +0x38

Goroutine 8 (running) created at:
  os/exec.(*Cmd).Start()
      /usr/local/Cellar/go/1.8/libexec/src/os/exec/exec.go:372 +0x924
  os/exec.(*Cmd).Run()
      /usr/local/Cellar/go/1.8/libexec/src/os/exec/exec.go:277 +0x3c
  _/Users/justin.nuss/Workspace_test.TestRace()
      /Users/justin.nuss/Workspace/race_test.go:27 +0x122
  testing.tRunner()
      /usr/local/Cellar/go/1.8/libexec/src/testing/testing.go:657 +0x107

Goroutine 7 (running) created at:
  os/exec.(*Cmd).Start()
      /usr/local/Cellar/go/1.8/libexec/src/os/exec/exec.go:372 +0x924
  os/exec.(*Cmd).Run()
      /usr/local/Cellar/go/1.8/libexec/src/os/exec/exec.go:277 +0x3c
  _/Users/justin.nuss/Workspace_test.TestRace()
      /Users/justin.nuss/Workspace/race_test.go:27 +0x122
  testing.tRunner()
      /usr/local/Cellar/go/1.8/libexec/src/testing/testing.go:657 +0x107
==================
--- FAIL: TestRace (8.15s)
        testing.go:610: race detected during execution of test
FAIL
exit status 1
FAIL    _/Users/justin.nuss/Workspace   8.171s

System details

go version go1.8 darwin/amd64
GOARCH="amd64"
GOBIN=""
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"
GOPATH="/Users/justin.nuss/Workspace/go"
GORACE=""
GOROOT="/usr/local/Cellar/go/1.8/libexec"
GOTOOLDIR="/usr/local/Cellar/go/1.8/libexec/pkg/tool/darwin_amd64"
GCCGO="gccgo"
CC="clang"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/xf/87dlggns3qlbtpz8dw5f9nbjns0xpd/T/go-build904089654=/tmp/go-build -gno-record-gcc-switches -fno-common"
CXX="clang++"
CGO_ENABLED="1"
PKG_CONFIG="pkg-config"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
GOROOT/bin/go version: go version go1.8 darwin/amd64
GOROOT/bin/go tool compile -V: compile version go1.8 X:framepointer
uname -v: Darwin Kernel Version 16.4.0: Thu Dec 22 22:53:21 PST 2016; root:xnu-3789.41.3~3/RELEASE_X86_64
ProductName:	Mac OS X
ProductVersion:	10.12.3
BuildVersion:	16D32
lldb --version: lldb-360.1.70

Explanation

Cmd.stderr calls interfaceEqual to check whether both Stdout and Stderr are equal. interfaceEqual returns false for non comparable types, which results in two goroutines being spawned, both writing (possibly) concurrently to the same io.Writer.

Although probably a rather rare case, I still think the documentation should still be updated to explain how uncomparable types are handled.

@nussjustin
Copy link
Contributor Author

/cc @bradfitz

@bradfitz bradfitz added this to the Go1.9Maybe milestone Mar 31, 2017
@gopherbot
Copy link

CL https://golang.org/cl/42052 mentions this issue.

@golang golang locked and limited conversation to collaborators Apr 28, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants