Commit f3f29d1d authored by Alex Brainman's avatar Alex Brainman

os/exec: ignore some pipe write errors on windows

This change is windows version of CL 12152.
It also extends test to cover scenarios reported on issue #20445.
Some source files copied and renamed to make code clearer.

Fixes #20445

Change-Id: Idd2f636f27c6bd5cfe98017ba2df911358263382
Reviewed-on: https://go-review.googlesource.com/43910
Run-TryBot: Alex Brainman <alex.brainman@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarBrad Fitzpatrick <bradfitz@golang.org>
parent 5f4f7519
...@@ -877,18 +877,30 @@ func TestHelperProcess(*testing.T) { ...@@ -877,18 +877,30 @@ func TestHelperProcess(*testing.T) {
} }
} }
type delayedInfiniteReader struct{}
func (delayedInfiniteReader) Read(b []byte) (int, error) {
time.Sleep(100 * time.Millisecond)
for i := range b {
b[i] = 'x'
}
return len(b), nil
}
// Issue 9173: ignore stdin pipe writes if the program completes successfully. // Issue 9173: ignore stdin pipe writes if the program completes successfully.
func TestIgnorePipeErrorOnSuccess(t *testing.T) { func TestIgnorePipeErrorOnSuccess(t *testing.T) {
testenv.MustHaveExec(t) testenv.MustHaveExec(t)
// We really only care about testing this on Unixy things. // We really only care about testing this on Unixy and Windowsy things.
if runtime.GOOS == "windows" || runtime.GOOS == "plan9" { if runtime.GOOS == "plan9" {
t.Skipf("skipping test on %q", runtime.GOOS) t.Skipf("skipping test on %q", runtime.GOOS)
} }
testWith := func(r io.Reader) func(*testing.T) {
return func(t *testing.T) {
cmd := helperCommand(t, "echo", "foo") cmd := helperCommand(t, "echo", "foo")
var out bytes.Buffer var out bytes.Buffer
cmd.Stdin = strings.NewReader(strings.Repeat("x", 10<<20)) cmd.Stdin = r
cmd.Stdout = &out cmd.Stdout = &out
if err := cmd.Run(); err != nil { if err := cmd.Run(); err != nil {
t.Fatal(err) t.Fatal(err)
...@@ -896,6 +908,10 @@ func TestIgnorePipeErrorOnSuccess(t *testing.T) { ...@@ -896,6 +908,10 @@ func TestIgnorePipeErrorOnSuccess(t *testing.T) {
if got, want := out.String(), "foo\n"; got != want { if got, want := out.String(), "foo\n"; got != want {
t.Errorf("output = %q; want %q", got, want) t.Errorf("output = %q; want %q", got, want)
} }
}
}
t.Run("10MB", testWith(strings.NewReader(strings.Repeat("x", 10<<20))))
t.Run("Infinite", testWith(delayedInfiniteReader{}))
} }
type badWriter struct{} type badWriter struct{}
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build !plan9 // +build !plan9,!windows
package exec package exec
......
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package exec
import (
"os"
"syscall"
)
func init() {
skipStdinCopyError = func(err error) bool {
// Ignore ERROR_BROKEN_PIPE and ERROR_NO_DATA errors copying
// to stdin if the program completed successfully otherwise.
// See Issue 20445.
const _ERROR_NO_DATA = syscall.Errno(0xe8)
pe, ok := err.(*os.PathError)
return ok &&
pe.Op == "write" && pe.Path == "|1" &&
(pe.Err == syscall.ERROR_BROKEN_PIPE || pe.Err == _ERROR_NO_DATA)
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment