-
Notifications
You must be signed in to change notification settings - Fork 17.7k
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
cmd/go,os: EAGAIN
when writing to stdout/stderr during test
#58408
Comments
I'm surprised that a write to What was the exact How reproducible is this failure mode? (CC @ianlancetaylor) |
EAGAIN
when writing to stdout/stderr during test
One more question: what version of Linux (and what container environment, if any) is the test running under? |
It looks like In the child process,
So the only way I see for an I see a path on which that may be possible:
So my hypothesis is that somehow |
EAGAIN
when writing to stdout/stderr during testEAGAIN
when writing to stdout/stderr during test
I've managed to narrow this down somewhat: // print_test.go
package print_test
import (
"bufio"
"bytes"
"fmt"
"os"
"os/exec"
"testing"
)
func TestPrint(t *testing.T) {
cmd := exec.Command("npx", "hardhat", "run", "--no-compile", "test.js")
stdout, err := cmd.StdoutPipe()
check(err)
cmd.Stderr = os.Stderr
outReader := bufio.NewReader(stdout)
check(cmd.Start())
_, err = outReader.ReadBytes('\n')
check(err)
var buf bytes.Buffer
for i := 0; i < 100_000; i++ {
fmt.Fprintf(&buf, "%04d\n", i)
}
s := buf.String()
fmt.Fprintf(os.Stderr, "about to write %d bytes\n", len(s))
if _, err := fmt.Fprint(os.Stderr, s); err != nil {
panic(err)
}
}
func check(err error) {
if err != nil {
panic(err)
}
} // test.js
async function main() {
console.log('1');
await delay(1000);
}
main().catch((err) => {
console.error(err);
process.exit(1);
});
function delay(time) {
return new Promise(resolve => setTimeout(resolve, time));
} Run with
Observed output
OS Version: Linux Mint 21 (Vanessa)
No containers/sandboxing. |
isn't that a race on the stderr resource?
|
Thanks for the complete test case. Unfortunately, I can't recreate the problem. My first guess would be that the |
It does seem to be the case that nodejs sometimes puts stdout/err into non-blocking mode. Removing the The purpose of this line is to forward error/log messages from the child and make them show up in the terminal. It's not really an issue if the child process and the main one write to stderr at the same time so I wouldn't consider it a race condition. |
@ianlancetaylor, it occurs to me that Go probably causes the dual problem itself in |
For the particular symptom at hand, would it be feasible to either always initialize runtime polling support in |
I think you're right: we do seem to lose track of the fact that the descriptor passed to Detecting @adob Given the behavior of nodejs here, I recommend that you not to try share stderr between the Go program and the nodejs program. It is straightforward to add (untested) stderr, err := cmd.StderrPipe()
check(err)
go func() { io.Copy(os.Stderr, stderr) }() |
A simpler workaround might be: cmd.Stderr = struct{ *os.File }{os.Stderr} which I think should cause the |
Change https://go.dev/cl/495079 mentions this issue: |
For #58408 Fixes #60211 Change-Id: I30f5678b46e15121865b19d1c0f82698493fad4e Reviewed-on: https://go-review.googlesource.com/c/go/+/495079 Run-TryBot: Ian Lance Taylor <iant@golang.org> Reviewed-by: Ian Lance Taylor <iant@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Bryan Mills <bcmills@google.com> Auto-Submit: Ian Lance Taylor <iant@google.com> Run-TryBot: Ian Lance Taylor <iant@google.com>
Change https://go.dev/cl/496015 mentions this issue: |
…t in Fd method For #58408 For #60211 Fixes #60217 Change-Id: I30f5678b46e15121865b19d1c0f82698493fad4e Reviewed-on: https://go-review.googlesource.com/c/go/+/495079 Run-TryBot: Ian Lance Taylor <iant@golang.org> Reviewed-by: Ian Lance Taylor <iant@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Bryan Mills <bcmills@google.com> Auto-Submit: Ian Lance Taylor <iant@google.com> Run-TryBot: Ian Lance Taylor <iant@google.com> (cherry picked from commit f777726) Reviewed-on: https://go-review.googlesource.com/c/go/+/496015 Reviewed-by: Heschi Kreinick <heschi@google.com> Auto-Submit: Heschi Kreinick <heschi@google.com>
Change https://go.dev/cl/496715 mentions this issue: |
…cking descriptor Historically net.Conn.File.Fd has returned a descriptor in blocking mode. That was broken by CL 495079, which changed the behavior for os.OpenFile and os.NewFile without intending to affect net.Conn.File.Fd. Use a hidden os entry point to preserve the historical behavior, to ensure backward compatibility. For #58408 For #60211 For #60217 Change-Id: I8d14b9296070ddd52bb8940cb88c6a8b2dc28c27 Reviewed-on: https://go-review.googlesource.com/c/go/+/496080 Run-TryBot: Ian Lance Taylor <iant@google.com> Reviewed-by: Bryan Mills <bcmills@google.com> Reviewed-by: Ian Lance Taylor <iant@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Run-TryBot: Ian Lance Taylor <iant@golang.org> Auto-Submit: Ian Lance Taylor <iant@google.com> (cherry picked from commit b950cc8) Reviewed-on: https://go-review.googlesource.com/c/go/+/496715
…t in Fd method For golang#58408 For golang#60211 Fixes golang#60217 Change-Id: I30f5678b46e15121865b19d1c0f82698493fad4e Reviewed-on: https://go-review.googlesource.com/c/go/+/495079 Run-TryBot: Ian Lance Taylor <iant@golang.org> Reviewed-by: Ian Lance Taylor <iant@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Bryan Mills <bcmills@google.com> Auto-Submit: Ian Lance Taylor <iant@google.com> Run-TryBot: Ian Lance Taylor <iant@google.com> (cherry picked from commit f777726) Reviewed-on: https://go-review.googlesource.com/c/go/+/496015 Reviewed-by: Heschi Kreinick <heschi@google.com> Auto-Submit: Heschi Kreinick <heschi@google.com>
…cking descriptor Historically net.Conn.File.Fd has returned a descriptor in blocking mode. That was broken by CL 495079, which changed the behavior for os.OpenFile and os.NewFile without intending to affect net.Conn.File.Fd. Use a hidden os entry point to preserve the historical behavior, to ensure backward compatibility. For golang#58408 For golang#60211 For golang#60217 Change-Id: I8d14b9296070ddd52bb8940cb88c6a8b2dc28c27 Reviewed-on: https://go-review.googlesource.com/c/go/+/496080 Run-TryBot: Ian Lance Taylor <iant@google.com> Reviewed-by: Bryan Mills <bcmills@google.com> Reviewed-by: Ian Lance Taylor <iant@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Run-TryBot: Ian Lance Taylor <iant@golang.org> Auto-Submit: Ian Lance Taylor <iant@google.com> (cherry picked from commit b950cc8) Reviewed-on: https://go-review.googlesource.com/c/go/+/496715
…t in Fd method For golang#58408 For golang#60211 Fixes golang#60217 Change-Id: I30f5678b46e15121865b19d1c0f82698493fad4e Reviewed-on: https://go-review.googlesource.com/c/go/+/495079 Run-TryBot: Ian Lance Taylor <iant@golang.org> Reviewed-by: Ian Lance Taylor <iant@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Bryan Mills <bcmills@google.com> Auto-Submit: Ian Lance Taylor <iant@google.com> Run-TryBot: Ian Lance Taylor <iant@google.com> (cherry picked from commit f777726) Reviewed-on: https://go-review.googlesource.com/c/go/+/496015 Reviewed-by: Heschi Kreinick <heschi@google.com> Auto-Submit: Heschi Kreinick <heschi@google.com>
…cking descriptor Historically net.Conn.File.Fd has returned a descriptor in blocking mode. That was broken by CL 495079, which changed the behavior for os.OpenFile and os.NewFile without intending to affect net.Conn.File.Fd. Use a hidden os entry point to preserve the historical behavior, to ensure backward compatibility. For golang#58408 For golang#60211 For golang#60217 Change-Id: I8d14b9296070ddd52bb8940cb88c6a8b2dc28c27 Reviewed-on: https://go-review.googlesource.com/c/go/+/496080 Run-TryBot: Ian Lance Taylor <iant@google.com> Reviewed-by: Bryan Mills <bcmills@google.com> Reviewed-by: Ian Lance Taylor <iant@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Run-TryBot: Ian Lance Taylor <iant@golang.org> Auto-Submit: Ian Lance Taylor <iant@google.com> (cherry picked from commit b950cc8) Reviewed-on: https://go-review.googlesource.com/c/go/+/496715
Change https://go.dev/cl/501699 mentions this issue: |
The returned descriptor now remains in non-blocking mode. For #58408 For #60211 Change-Id: I88d33c180db642d055b4fed3b03a9afa02e746bd Reviewed-on: https://go-review.googlesource.com/c/go/+/501699 Auto-Submit: Ian Lance Taylor <iant@google.com> TryBot-Bypass: Ian Lance Taylor <iant@google.com> Reviewed-by: Ian Lance Taylor <iant@google.com> Reviewed-by: Bryan Mills <bcmills@google.com>
Node will sometimes set stdout or stderr into non-blocking mode, but go will not notice this. When go attempts to write, we get an error: `write /dev/stdout: resource temporarily unavailable`. To avoid this issue, we copy the output of the command to the stdout and stderr of the go process. golang/go#58408 (comment)
Node will sometimes set stdout or stderr into non-blocking mode, but go will not notice this. When go attempts to write, we get an error: `write /dev/stdout: resource temporarily unavailable`. To avoid this issue, we copy the output of the command to the stdout and stderr of the go process. golang/go#58408 (comment) Fixes #16503
Node will sometimes set stdout or stderr into non-blocking mode, but go will not notice this. When go attempts to write, we get an error: `write /dev/stdout: resource temporarily unavailable`. To avoid this issue, we copy the output of the command to the stdout and stderr of the go process. golang/go#58408 (comment) Fixes #16503
Node will sometimes set stdout or stderr into non-blocking mode, but go will not notice this. When go attempts to write, we get an error: `write /dev/stdout: resource temporarily unavailable`. To avoid this issue, we copy the output of the command to the stdout and stderr of the go process. golang/go#58408 (comment) Fixes #16503
Node will sometimes set stdout or stderr into non-blocking mode, but go will not notice this. When go attempts to write, we get an error: `write /dev/stdout: resource temporarily unavailable`. To avoid this issue, we copy the output of the command to the stdout and stderr of the go process. golang/go#58408 (comment) Fixes #16503
Node will sometimes set stdout or stderr into non-blocking mode, but go will not notice this. When go attempts to write, we get an error: `write /dev/stdout: resource temporarily unavailable`. To avoid this issue, we copy the output of the command to the stdout and stderr of the go process. golang/go#58408 (comment) Fixes #16503
Node will sometimes set stdout or stderr into non-blocking mode, but go will not notice this. When go attempts to write, we get an error: `write /dev/stdout: resource temporarily unavailable`. To avoid this issue, we copy the output of the command to the stdout and stderr of the go process. golang/go#58408 (comment) Fixes #16503
Node will sometimes set stdout or stderr into non-blocking mode, but go will not notice this. When go attempts to write, we get an error: `write /dev/stdout: resource temporarily unavailable`. To avoid this issue, we copy the output of the command to the stdout and stderr of the go process. golang/go#58408 (comment) Fixes #16503
Nodejs sometimes sets stdout/stderr to non-blocking mode. When a nodejs subprocess is directly handed the go process's stdout/stderr file descriptors, nodejs's non-blocking configuration goes unnoticed by go, and a write from go can result in an error `write /dev/stdout: resource temporarily unavailable`. The solution to this is to not provide nodejs with the go process's stdout/stderr file descriptors, and instead proxy the writes through something else. In #16504 we used Command.StdoutPipe/StderrPipe for this. However this introduced a potential bug, as it is not safe to use these specific pipes along with Command.Run. The issue is that these pipes will be closed as soon as the process exits, which can lead to missing data when stdout/stderr are slow, or worse an error due to an attempted read from a closed pipe. (Creating our own os.Pipes for this would be fine.) A better workaround is to wrap stdout/stderr in an io.Writer. This makes exec.Command use a copying goroutine to shuffle the data from the subprocess to stdout/stderr. Command.Run will wait for all the data to be copied before returning, ensuring we do not miss any data. Non-blocking issue: golang/go#58408 (comment) StdoutPipe/StderrPipe issues: https://pkg.go.dev/os/exec#Cmd.StdoutPipe Waiting for data: https://cs.opensource.google/go/go/+/refs/tags/go1.22.5:src/os/exec/exec.go;l=201
Nodejs sometimes sets stdout/stderr to non-blocking mode. When a nodejs subprocess is directly handed the go process's stdout/stderr file descriptors, nodejs's non-blocking configuration goes unnoticed by go, and a write from go can result in an error `write /dev/stdout: resource temporarily unavailable`. The solution to this is to not provide nodejs with the go process's stdout/stderr file descriptors, and instead proxy the writes through something else. In #16504 we used Cmd.StdoutPipe/StderrPipe for this. However this introduced a potential bug, as it is not safe to use these specific pipes along with Cmd.Run. The issue is that these pipes will be closed as soon as the process exits, which can lead to missing data when stdout/stderr are slow, or worse an error due to an attempted read from a closed pipe. (Creating our own os.Pipes for this would be fine.) A better workaround is to wrap stdout/stderr in an io.Writer. This makes exec.Cmd use a copying goroutine to shuffle the data from the subprocess to stdout/stderr. Cmd.Run will wait for all the data to be copied before returning, ensuring we do not miss any data. Non-blocking issue: golang/go#58408 (comment) StdoutPipe/StderrPipe issues: https://pkg.go.dev/os/exec#Cmd.StdoutPipe Waiting for data: https://cs.opensource.google/go/go/+/refs/tags/go1.22.5:src/os/exec/exec.go;l=201
Nodejs sometimes sets stdout/stderr to non-blocking mode. When a nodejs subprocess is directly handed the go process's stdout/stderr file descriptors, nodejs's non-blocking configuration goes unnoticed by go, and a write from go can result in an error `write /dev/stdout: resource temporarily unavailable`. The solution to this is to not provide nodejs with the go process's stdout/stderr file descriptors, and instead proxy the writes through something else. In #16504 we used Cmd.StdoutPipe/StderrPipe for this. However this introduced a potential bug, as it is not safe to use these specific pipes along with Cmd.Run. The issue is that these pipes will be closed as soon as the process exits, which can lead to missing data when stdout/stderr are slow, or worse an error due to an attempted read from a closed pipe. (Creating our own os.Pipes for this would be fine.) A better workaround is to wrap stdout/stderr in an io.Writer. This makes exec.Cmd use a copying goroutine to shuffle the data from the subprocess to stdout/stderr. Cmd.Run will wait for all the data to be copied before returning, ensuring we do not miss any data. Non-blocking issue: golang/go#58408 (comment) StdoutPipe/StderrPipe issues: https://pkg.go.dev/os/exec#Cmd.StdoutPipe Waiting for data: https://cs.opensource.google/go/go/+/refs/tags/go1.22.5:src/os/exec/exec.go;l=201
Nodejs sometimes sets stdout/stderr to non-blocking mode. When a nodejs subprocess is directly handed the go process's stdout/stderr file descriptors, nodejs's non-blocking configuration goes unnoticed by go, and a write from go can result in an error `write /dev/stdout: resource temporarily unavailable`. The solution to this is to not provide nodejs with the go process's stdout/stderr file descriptors, and instead proxy the writes through something else. In #16504 we used Cmd.StdoutPipe/StderrPipe for this. However this introduced a potential bug, as it is not safe to use these specific pipes along with Cmd.Run. The issue is that these pipes will be closed as soon as the process exits, which can lead to missing data when stdout/stderr are slow, or worse an error due to an attempted read from a closed pipe. (Creating our own os.Pipes for this would be fine.) A better workaround is to wrap stdout/stderr in an io.Writer. This makes exec.Cmd use a copying goroutine to shuffle the data from the subprocess to stdout/stderr. Cmd.Run will wait for all the data to be copied before returning, ensuring we do not miss any data. Non-blocking issue: golang/go#58408 (comment) StdoutPipe/StderrPipe issues: https://pkg.go.dev/os/exec#Cmd.StdoutPipe Waiting for data: https://cs.opensource.google/go/go/+/refs/tags/go1.22.5:src/os/exec/exec.go;l=201
Nodejs sometimes sets stdout/stderr to non-blocking mode. When a nodejs subprocess is directly handed the go process's stdout/stderr file descriptors, nodejs's non-blocking configuration goes unnoticed by go, and a write from go can result in an error `write /dev/stdout: resource temporarily unavailable`. The solution to this is to not provide nodejs with the go process's stdout/stderr file descriptors, and instead proxy the writes through something else. In #16504 we used Cmd.StdoutPipe/StderrPipe for this. However this introduced a potential bug, as it is not safe to use these specific pipes along with Cmd.Run. The issue is that these pipes will be closed as soon as the process exits, which can lead to missing data when stdout/stderr are slow, or worse an error due to an attempted read from a closed pipe. (Creating our own os.Pipes for this would be fine.) A better workaround is to wrap stdout/stderr in an io.Writer. This makes exec.Cmd use a copying goroutine to shuffle the data from the subprocess to stdout/stderr. Cmd.Run will wait for all the data to be copied before returning, ensuring we do not miss any data. Non-blocking issue: golang/go#58408 (comment) StdoutPipe/StderrPipe issues: https://pkg.go.dev/os/exec#Cmd.StdoutPipe Waiting for data: https://cs.opensource.google/go/go/+/refs/tags/go1.22.5:src/os/exec/exec.go;l=201
Nodejs sometimes sets stdout/stderr to non-blocking mode. When a nodejs subprocess is directly handed the go process's stdout/stderr file descriptors, nodejs's non-blocking configuration goes unnoticed by go, and a write from go can result in an error `write /dev/stdout: resource temporarily unavailable`. The solution to this is to not provide nodejs with the go process's stdout/stderr file descriptors, and instead proxy the writes through something else. In #16504 we used Cmd.StdoutPipe/StderrPipe for this. However this introduced a potential bug, as it is not safe to use these specific pipes along with Cmd.Run. The issue is that these pipes will be closed as soon as the process exits, which can lead to missing data when stdout/stderr are slow, or worse an error due to an attempted read from a closed pipe. (Creating our own os.Pipes for this would be fine.) A better workaround is to wrap stdout/stderr in an io.Writer. This makes exec.Cmd use a copying goroutine to shuffle the data from the subprocess to stdout/stderr. Cmd.Run will wait for all the data to be copied before returning, ensuring we do not miss any data. Non-blocking issue: golang/go#58408 (comment) StdoutPipe/StderrPipe issues: https://pkg.go.dev/os/exec#Cmd.StdoutPipe Waiting for data: https://cs.opensource.google/go/go/+/refs/tags/go1.22.5:src/os/exec/exec.go;l=201
Nodejs sometimes sets stdout/stderr to non-blocking mode. When a nodejs subprocess is directly handed the go process's stdout/stderr file descriptors, nodejs's non-blocking configuration goes unnoticed by go, and a write from go can result in an error `write /dev/stdout: resource temporarily unavailable`. The solution to this is to not provide nodejs with the go process's stdout/stderr file descriptors, and instead proxy the writes through something else. In #16504 we used Cmd.StdoutPipe/StderrPipe for this. However this introduced a potential bug, as it is not safe to use these specific pipes along with Cmd.Run. The issue is that these pipes will be closed as soon as the process exits, which can lead to missing data when stdout/stderr are slow, or worse an error due to an attempted read from a closed pipe. (Creating our own os.Pipes for this would be fine.) A better workaround is to wrap stdout/stderr in an io.Writer. This makes exec.Cmd use a copying goroutine to shuffle the data from the subprocess to stdout/stderr. Cmd.Run will wait for all the data to be copied before returning, ensuring we do not miss any data. Non-blocking issue: golang/go#58408 (comment) StdoutPipe/StderrPipe issues: https://pkg.go.dev/os/exec#Cmd.StdoutPipe Waiting for data: https://cs.opensource.google/go/go/+/refs/tags/go1.22.5:src/os/exec/exec.go;l=201
What version of Go are you using (
go version
)?Does this issue reproduce with the latest release?
Yes
What operating system and processor architecture are you using (
go env
)?go env
OutputWhat did you do?
Calls to
fmt.Printf()
during test fail with/dev/stdout: resource temporarily unavailable
when printing long lines after part of the output has been printed. The output is truncated.This can be worked around by passing the
-bench
flag to suppress output redirection during test execution.The text was updated successfully, but these errors were encountered: