1 // Copyright 2015 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 // Test broken pipes on Unix systems.
6 // +build !windows,!plan9,!nacl,!js
29 func TestEPIPE(t
*testing
.T
) {
30 r
, w
, err
:= os
.Pipe()
34 if err
:= r
.Close(); err
!= nil {
38 // Every time we write to the pipe we should get an EPIPE.
39 for i
:= 0; i
< 20; i
++ {
40 _
, err
= w
.Write([]byte("hi"))
42 t
.Fatal("unexpected success of Write to broken pipe")
44 if pe
, ok
:= err
.(*os
.PathError
); ok
{
47 if se
, ok
:= err
.(*os
.SyscallError
); ok
{
50 if err
!= syscall
.EPIPE
{
51 t
.Errorf("iteration %d: got %v, expected EPIPE", i
, err
)
56 func TestStdPipe(t
*testing
.T
) {
57 testenv
.MustHaveExec(t
)
58 r
, w
, err
:= os
.Pipe()
62 if err
:= r
.Close(); err
!= nil {
65 // Invoke the test program to run the test and write to a closed pipe.
67 // writing to stdout or stderr should cause an immediate SIGPIPE;
68 // writing to descriptor 3 should fail with EPIPE and then exit 0.
70 // all writes should fail with EPIPE and then exit 0.
71 for _
, sig
:= range []bool{false, true} {
72 for dest
:= 1; dest
< 4; dest
++ {
73 cmd
:= osexec
.Command(os
.Args
[0], "-test.run", "TestStdPipeHelper")
76 cmd
.ExtraFiles
= []*os
.File
{w
}
77 cmd
.Env
= append(os
.Environ(), fmt
.Sprintf("GO_TEST_STD_PIPE_HELPER=%d", dest
))
79 cmd
.Env
= append(cmd
.Env
, "GO_TEST_STD_PIPE_HELPER_SIGNAL=1")
81 if err
:= cmd
.Run(); err
== nil {
83 t
.Errorf("unexpected success of write to closed pipe %d sig %t in child", dest
, sig
)
85 } else if ee
, ok
:= err
.(*osexec
.ExitError
); !ok
{
86 t
.Errorf("unexpected exec error type %T: %v", err
, err
)
87 } else if ws
, ok
:= ee
.Sys().(syscall
.WaitStatus
); !ok
{
88 t
.Errorf("unexpected wait status type %T: %v", ee
.Sys(), ee
.Sys())
89 } else if ws
.Signaled() && ws
.Signal() == syscall
.SIGPIPE
{
91 t
.Errorf("unexpected SIGPIPE signal for descriptor %d sig %t", dest
, sig
)
94 t
.Errorf("unexpected exit status %v for descriptor %d sig %t", err
, dest
, sig
)
100 // This is a helper for TestStdPipe. It's not a test in itself.
101 func TestStdPipeHelper(t
*testing
.T
) {
102 if os
.Getenv("GO_TEST_STD_PIPE_HELPER_SIGNAL") != "" {
103 signal
.Notify(make(chan os
.Signal
, 1), syscall
.SIGPIPE
)
105 switch os
.Getenv("GO_TEST_STD_PIPE_HELPER") {
107 os
.Stdout
.Write([]byte("stdout"))
109 os
.Stderr
.Write([]byte("stderr"))
111 if _
, err
:= os
.NewFile(3, "3").Write([]byte("3")); err
== nil {
115 t
.Skip("skipping test helper")
117 // For stdout/stderr, we should have crashed with a broken pipe error.
118 // The caller will be looking for that exit status,
119 // so just exit normally here to cause a failure in the caller.
120 // For descriptor 3, a normal exit is expected.
124 func testClosedPipeRace(t
*testing
.T
, read
bool) {
125 switch runtime
.GOOS
{
127 t
.Skip("FreeBSD does not use the poller; issue 19093")
132 // Get the amount we have to write to overload a pipe
135 if b
, err
:= ioutil
.ReadFile("/proc/sys/fs/pipe-max-size"); err
== nil {
136 if i
, err
:= strconv
.Atoi(strings
.TrimSpace(string(b
))); err
== nil {
140 t
.Logf("using pipe write limit of %d", limit
)
143 r
, w
, err
:= os
.Pipe()
150 // Close the read end of the pipe in a goroutine while we are
151 // writing to the write end, or vice-versa.
153 // Give the main goroutine a chance to enter the Read or
154 // Write call. This is sloppy but the test will pass even
155 // if we close before the read/write.
156 time
.Sleep(20 * time
.Millisecond
)
169 b
:= make([]byte, limit
)
171 _
, err
= r
.Read(b
[:])
173 _
, err
= w
.Write(b
[:])
176 t
.Error("I/O on closed pipe unexpectedly succeeded")
177 } else if pe
, ok
:= err
.(*os
.PathError
); !ok
{
178 t
.Errorf("I/O on closed pipe returned unexpected error type %T; expected os.PathError", pe
)
179 } else if pe
.Err
!= os
.ErrClosed
{
180 t
.Errorf("got error %q but expected %q", pe
.Err
, os
.ErrClosed
)
182 t
.Logf("I/O returned expected error %q", err
)
186 func TestClosedPipeRaceRead(t
*testing
.T
) {
187 testClosedPipeRace(t
, true)
190 func TestClosedPipeRaceWrite(t
*testing
.T
) {
191 testClosedPipeRace(t
, false)
194 // Issue 20915: Reading on nonblocking fd should not return "waiting
195 // for unsupported file type." Currently it returns EAGAIN; it is
196 // possible that in the future it will simply wait for data.
197 func TestReadNonblockingFd(t
*testing
.T
) {
198 if os
.Getenv("GO_WANT_READ_NONBLOCKING_FD") == "1" {
199 fd
:= int(os
.Stdin
.Fd())
200 syscall
.SetNonblock(fd
, true)
201 defer syscall
.SetNonblock(fd
, false)
202 _
, err
:= os
.Stdin
.Read(make([]byte, 1))
204 if perr
, ok
:= err
.(*os
.PathError
); !ok || perr
.Err
!= syscall
.EAGAIN
{
205 t
.Fatalf("read on nonblocking stdin got %q, should have gotten EAGAIN", err
)
211 testenv
.MustHaveExec(t
)
212 r
, w
, err
:= os
.Pipe()
218 cmd
:= osexec
.Command(os
.Args
[0], "-test.run="+t
.Name())
219 cmd
.Env
= append(os
.Environ(), "GO_WANT_READ_NONBLOCKING_FD=1")
221 output
, err
:= cmd
.CombinedOutput()
224 t
.Errorf("child process failed: %v", err
)
228 func TestCloseWithBlockingReadByNewFile(t
*testing
.T
) {
230 err
:= syscall
.Pipe(p
[:])
234 // os.NewFile returns a blocking mode file.
235 testCloseWithBlockingRead(t
, os
.NewFile(uintptr(p
[0]), "reader"), os
.NewFile(uintptr(p
[1]), "writer"))
238 func TestCloseWithBlockingReadByFd(t
*testing
.T
) {
239 r
, w
, err
:= os
.Pipe()
243 // Calling Fd will put the file into blocking mode.
245 testCloseWithBlockingRead(t
, r
, w
)
248 // Test that we don't let a blocking read prevent a close.
249 func testCloseWithBlockingRead(t
*testing
.T
, r
, w
*os
.File
) {
253 c1
, c2
:= make(chan bool), make(chan bool)
254 var wg sync
.WaitGroup
257 go func(c
chan bool) {
259 // Give the other goroutine a chance to enter the Read
260 // or Write call. This is sloppy but the test will
261 // pass even if we close before the read/write.
262 time
.Sleep(20 * time
.Millisecond
)
264 if err
:= r
.Close(); err
!= nil {
271 go func(c
chan bool) {
274 _
, err
:= r
.Read(b
[:])
277 t
.Error("I/O on closed pipe unexpectedly succeeded")
280 t
.Errorf("got %v, expected io.EOF", err
)
284 for c1
!= nil || c2
!= nil {
288 // r.Close has completed, but the blocking Read
289 // is hanging. Close the writer to unblock it.
293 case <-time
.After(1 * time
.Second
):
295 case c1
!= nil && c2
!= nil:
296 t
.Error("timed out waiting for Read and Close")
299 t
.Error("timed out waiting for Close")
301 t
.Error("timed out waiting for Read")
303 t
.Error("impossible case")
311 // Issue 24164, for pipes.
312 func TestPipeEOF(t
*testing
.T
) {
313 r
, w
, err
:= os
.Pipe()
318 var wg sync
.WaitGroup
324 if err
:= w
.Close(); err
!= nil {
325 t
.Errorf("error closing writer: %v", err
)
329 for i
:= 0; i
< 3; i
++ {
330 time
.Sleep(10 * time
.Millisecond
)
331 _
, err
:= fmt
.Fprintf(w
, "line %d\n", i
)
333 t
.Errorf("error writing to fifo: %v", err
)
337 time
.Sleep(10 * time
.Millisecond
)
342 done
:= make(chan bool)
347 if err
:= r
.Close(); err
!= nil {
348 t
.Errorf("error closing reader: %v", err
)
352 rbuf
:= bufio
.NewReader(r
)
354 b
, err
:= rbuf
.ReadBytes('\n')
362 t
.Logf("%s\n", bytes
.TrimSpace(b
))
369 case <-time
.After(time
.Second
):
370 t
.Error("timed out waiting for read")
371 // Close the reader to force the read to complete.
377 func TestFdRace(t
*testing
.T
) {
378 r
, w
, err
:= os
.Pipe()
385 var wg sync
.WaitGroup
392 for i
:= 0; i
< tries
; i
++ {
399 func TestFdReadRace(t
*testing
.T
) {
402 r
, w
, err
:= os
.Pipe()
410 var wg sync
.WaitGroup
415 r
.SetReadDeadline(time
.Now().Add(time
.Second
))
417 if _
, err
:= r
.Read(buf
[:]); os
.IsTimeout(err
) {
418 t
.Error("read timed out")
426 // Give the other goroutine a chance to enter the Read.
427 // It doesn't matter if this occasionally fails, the test
428 // will still pass, it just won't test anything.
429 time
.Sleep(10 * time
.Millisecond
)
432 // The bug was that Fd would hang until Read timed out.
433 // If the bug is fixed, then closing r here will cause
434 // the Read to exit before the timeout expires.