-
Notifications
You must be signed in to change notification settings - Fork 17.6k
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: data race between StdoutPipe and Wait #19685
Comments
/cc @ianlancetaylor |
Could you please paste the data race report here. Thanks.
…On Fri, 24 Mar 2017, 10:00 Brad Fitzpatrick ***@***.***> wrote:
/cc @ianlancetaylor <https://github.com/ianlancetaylor>
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#19685 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AAAcA89SewVYFUnq2mBkVG87xGqUjCKTks5rovlvgaJpZM4MneFa>
.
|
Yes of course, here it is.
|
@xxorde I think (although not an expert on this) @ianlancetaylor's comment is relevant here. i.e. you package main
import (
"bufio"
"fmt"
"os"
"os/exec"
)
func main() {
cmdName := "echo"
cmdArgs := []string{"hello", "world"}
cmd := exec.Command(cmdName, cmdArgs...)
cmdReader, err := cmd.StdoutPipe()
if err != nil {
fmt.Fprintln(os.Stderr, "Error creating StdoutPipe for Cmd", err)
os.Exit(1)
}
done := make(chan struct{})
scanner := bufio.NewScanner(cmdReader)
go func() {
for scanner.Scan() {
fmt.Printf("%s\n", scanner.Text())
}
done <- struct{}{}
}()
err = cmd.Start()
if err != nil {
fmt.Fprintln(os.Stderr, "Error starting Cmd", err)
os.Exit(1)
}
<-done
err = cmd.Wait()
if err != nil {
fmt.Fprintln(os.Stderr, "Error waiting for Cmd", err)
os.Exit(1)
}
} |
@myitcv thank you for this hint. I will most likely do exactly this in my own code. The problem why I consider this still as a bug is that this behavior is not obvious to most users. |
@xxorde again I'll defer to wiser heads on this, but I'm not sure this is a bug in implementation or documentation: https://godoc.org/os/exec#Cmd.Wait
Critically it waits for the command to exit. When this happens:
which implies it will tidy up the By making it explicit that you're finished reading (which will happen either when you choose (i.e. you don't want to read all the output) or when you reach |
I can't reproduce the race anymore with the race detector with the example program. Maybe #7970 fixed this? |
Thanks for looking at this. I agree: I think this is fixed in 1.9. The closely related problem #18874 is not fixed, but this one should be OK now. |
The docs need a update though. https://godoc.org/os/exec#Cmd.StderrPipe
|
@nhooyr I think the docs are OK. It's still a logical error, it just doesn't lead to a race condition. If you call Wait before all the reads have completed, then the current in-progress read will complete, but any remaining data on the pipe will be lost. |
Fair enough. |
Hi just came accross this issue in my code. Partly because of copying the code from one of the faulty examples available on the internet. So to summarise this thread, this is a non-issue that appeared because the code makes some wrong assumptions about the cmd.Wait(), am I correct?? If yes then is @myitcv suggested code work-around of acquiring a channel and releasing a channel the correct way to go about it fixing this... I am using go v1.9.3, linux/amd64. |
@eff-kay Nobody really tracks discussions on closed issues. More importantly, you didn't show us the code, so I don't know what you are seeing. In general, yes, you need some sort of coordination between a goroutine reading from a pipe from a subprocess, and waiting for the subprocess. Using a channel will work, and there are other possibilities. If you are looking for help with your code, I recommend that you use a forum rather than a discussion on a closed issue; see https://golang.org/wiki/Questions . |
@ianlancetaylor thanks for the tip. The code is mostly similar to the one above. Yea I think adding a chan resolved the issue... |
Problem
If you are reading from cmd.StdoutPipe() and call cmd.Wait() concurrent you get a race condition.
I needed some time to find this in my code, but once I knew what I was looking for I found the same problem in other codebases, blogposts, ect.
This is really similar to: #9307
I am quite sure I am not the first one to find this, but I could not find a matching issue, please close this if there is one.
Example
Here is a little example.
I did not constructed it, I actually found it in a blog post.
Here you can see it failing on different CI / Go versions: https://github.com/xxorde/race
What version of Go are you using (
go version
)?What operating system and processor architecture are you using (
go env
)?linux, amd64
The text was updated successfully, but these errors were encountered: