]> Cypherpunks repositories - gostls13.git/commitdiff
os/exec: ignore some pipe write errors on windows
authorAlex Brainman <alex.brainman@gmail.com>
Mon, 22 May 2017 07:17:39 +0000 (17:17 +1000)
committerAlex Brainman <alex.brainman@gmail.com>
Tue, 23 May 2017 04:27:01 +0000 (04:27 +0000)
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: Brad Fitzpatrick <bradfitz@golang.org>
src/os/exec/exec_test.go
src/os/exec/exec_unix.go [moved from src/os/exec/exec_posix.go with 95% similarity]
src/os/exec/exec_windows.go [new file with mode: 0644]

index 95af597f1546a793dc783166275f8e0884bb008d..0132906933b1dc9c6f64f27e5dc87df4997f606a 100644 (file)
@@ -877,25 +877,41 @@ 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.
 func TestIgnorePipeErrorOnSuccess(t *testing.T) {
        testenv.MustHaveExec(t)
 
-       // We really only care about testing this on Unixy things.
-       if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
+       // We really only care about testing this on Unixy and Windowsy things.
+       if runtime.GOOS == "plan9" {
                t.Skipf("skipping test on %q", runtime.GOOS)
        }
 
-       cmd := helperCommand(t, "echo", "foo")
-       var out bytes.Buffer
-       cmd.Stdin = strings.NewReader(strings.Repeat("x", 10<<20))
-       cmd.Stdout = &out
-       if err := cmd.Run(); err != nil {
-               t.Fatal(err)
-       }
-       if got, want := out.String(), "foo\n"; got != want {
-               t.Errorf("output = %q; want %q", got, want)
+       testWith := func(r io.Reader) func(*testing.T) {
+               return func(t *testing.T) {
+                       cmd := helperCommand(t, "echo", "foo")
+                       var out bytes.Buffer
+                       cmd.Stdin = r
+                       cmd.Stdout = &out
+                       if err := cmd.Run(); err != nil {
+                               t.Fatal(err)
+                       }
+                       if got, want := out.String(), "foo\n"; 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{}
similarity index 95%
rename from src/os/exec/exec_posix.go
rename to src/os/exec/exec_unix.go
index 5e1113748cd6ced67d3af2300e4b1a28c2c40a41..9c3e17d23ab55ecc63b04f6cbc667fc1f025430b 100644 (file)
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build !plan9
+// +build !plan9,!windows
 
 package exec
 
diff --git a/src/os/exec/exec_windows.go b/src/os/exec/exec_windows.go
new file mode 100644 (file)
index 0000000..af8cd97
--- /dev/null
@@ -0,0 +1,23 @@
+// 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)
+       }
+}