github.com/hikaru7719/go@v0.0.0-20181025140707-c8b2ac68906a/src/os/pipe_test.go (about) 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. 4 5 // Test broken pipes on Unix systems. 6 // +build !windows,!plan9,!nacl,!js 7 8 package os_test 9 10 import ( 11 "bufio" 12 "bytes" 13 "fmt" 14 "internal/testenv" 15 "io" 16 "io/ioutil" 17 "os" 18 osexec "os/exec" 19 "os/signal" 20 "runtime" 21 "strconv" 22 "strings" 23 "sync" 24 "syscall" 25 "testing" 26 "time" 27 ) 28 29 func TestEPIPE(t *testing.T) { 30 r, w, err := os.Pipe() 31 if err != nil { 32 t.Fatal(err) 33 } 34 if err := r.Close(); err != nil { 35 t.Fatal(err) 36 } 37 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")) 41 if err == nil { 42 t.Fatal("unexpected success of Write to broken pipe") 43 } 44 if pe, ok := err.(*os.PathError); ok { 45 err = pe.Err 46 } 47 if se, ok := err.(*os.SyscallError); ok { 48 err = se.Err 49 } 50 if err != syscall.EPIPE { 51 t.Errorf("iteration %d: got %v, expected EPIPE", i, err) 52 } 53 } 54 } 55 56 func TestStdPipe(t *testing.T) { 57 testenv.MustHaveExec(t) 58 r, w, err := os.Pipe() 59 if err != nil { 60 t.Fatal(err) 61 } 62 if err := r.Close(); err != nil { 63 t.Fatal(err) 64 } 65 // Invoke the test program to run the test and write to a closed pipe. 66 // If sig is false: 67 // writing to stdout or stderr should cause an immediate SIGPIPE; 68 // writing to descriptor 3 should fail with EPIPE and then exit 0. 69 // If sig is true: 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") 74 cmd.Stdout = w 75 cmd.Stderr = w 76 cmd.ExtraFiles = []*os.File{w} 77 cmd.Env = append(os.Environ(), fmt.Sprintf("GO_TEST_STD_PIPE_HELPER=%d", dest)) 78 if sig { 79 cmd.Env = append(cmd.Env, "GO_TEST_STD_PIPE_HELPER_SIGNAL=1") 80 } 81 if err := cmd.Run(); err == nil { 82 if !sig && dest < 3 { 83 t.Errorf("unexpected success of write to closed pipe %d sig %t in child", dest, sig) 84 } 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 { 90 if sig || dest > 2 { 91 t.Errorf("unexpected SIGPIPE signal for descriptor %d sig %t", dest, sig) 92 } 93 } else { 94 t.Errorf("unexpected exit status %v for descriptor %d sig %t", err, dest, sig) 95 } 96 } 97 } 98 } 99 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) 104 } 105 switch os.Getenv("GO_TEST_STD_PIPE_HELPER") { 106 case "1": 107 os.Stdout.Write([]byte("stdout")) 108 case "2": 109 os.Stderr.Write([]byte("stderr")) 110 case "3": 111 if _, err := os.NewFile(3, "3").Write([]byte("3")); err == nil { 112 os.Exit(3) 113 } 114 default: 115 t.Skip("skipping test helper") 116 } 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. 121 os.Exit(0) 122 } 123 124 func testClosedPipeRace(t *testing.T, read bool) { 125 switch runtime.GOOS { 126 case "freebsd": 127 t.Skip("FreeBSD does not use the poller; issue 19093") 128 } 129 130 limit := 1 131 if !read { 132 // Get the amount we have to write to overload a pipe 133 // with no reader. 134 limit = 65537 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 { 137 limit = i + 1 138 } 139 } 140 t.Logf("using pipe write limit of %d", limit) 141 } 142 143 r, w, err := os.Pipe() 144 if err != nil { 145 t.Fatal(err) 146 } 147 defer r.Close() 148 defer w.Close() 149 150 // Close the read end of the pipe in a goroutine while we are 151 // writing to the write end, or vice-versa. 152 go func() { 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) 157 158 var err error 159 if read { 160 err = r.Close() 161 } else { 162 err = w.Close() 163 } 164 if err != nil { 165 t.Error(err) 166 } 167 }() 168 169 b := make([]byte, limit) 170 if read { 171 _, err = r.Read(b[:]) 172 } else { 173 _, err = w.Write(b[:]) 174 } 175 if err == nil { 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) 181 } else { 182 t.Logf("I/O returned expected error %q", err) 183 } 184 } 185 186 func TestClosedPipeRaceRead(t *testing.T) { 187 testClosedPipeRace(t, true) 188 } 189 190 func TestClosedPipeRaceWrite(t *testing.T) { 191 testClosedPipeRace(t, false) 192 } 193 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)) 203 if err != nil { 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) 206 } 207 } 208 os.Exit(0) 209 } 210 211 testenv.MustHaveExec(t) 212 r, w, err := os.Pipe() 213 if err != nil { 214 t.Fatal(err) 215 } 216 defer r.Close() 217 defer w.Close() 218 cmd := osexec.Command(os.Args[0], "-test.run="+t.Name()) 219 cmd.Env = append(os.Environ(), "GO_WANT_READ_NONBLOCKING_FD=1") 220 cmd.Stdin = r 221 output, err := cmd.CombinedOutput() 222 t.Logf("%s", output) 223 if err != nil { 224 t.Errorf("child process failed: %v", err) 225 } 226 } 227 228 func TestCloseWithBlockingReadByNewFile(t *testing.T) { 229 var p [2]int 230 err := syscall.Pipe(p[:]) 231 if err != nil { 232 t.Fatal(err) 233 } 234 // os.NewFile returns a blocking mode file. 235 testCloseWithBlockingRead(t, os.NewFile(uintptr(p[0]), "reader"), os.NewFile(uintptr(p[1]), "writer")) 236 } 237 238 func TestCloseWithBlockingReadByFd(t *testing.T) { 239 r, w, err := os.Pipe() 240 if err != nil { 241 t.Fatal(err) 242 } 243 // Calling Fd will put the file into blocking mode. 244 _ = r.Fd() 245 testCloseWithBlockingRead(t, r, w) 246 } 247 248 // Test that we don't let a blocking read prevent a close. 249 func testCloseWithBlockingRead(t *testing.T, r, w *os.File) { 250 defer r.Close() 251 defer w.Close() 252 253 c1, c2 := make(chan bool), make(chan bool) 254 var wg sync.WaitGroup 255 256 wg.Add(1) 257 go func(c chan bool) { 258 defer wg.Done() 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) 263 264 if err := r.Close(); err != nil { 265 t.Error(err) 266 } 267 close(c) 268 }(c1) 269 270 wg.Add(1) 271 go func(c chan bool) { 272 defer wg.Done() 273 var b [1]byte 274 _, err := r.Read(b[:]) 275 close(c) 276 if err == nil { 277 t.Error("I/O on closed pipe unexpectedly succeeded") 278 } 279 if err != io.EOF { 280 t.Errorf("got %v, expected io.EOF", err) 281 } 282 }(c2) 283 284 for c1 != nil || c2 != nil { 285 select { 286 case <-c1: 287 c1 = nil 288 // r.Close has completed, but the blocking Read 289 // is hanging. Close the writer to unblock it. 290 w.Close() 291 case <-c2: 292 c2 = nil 293 case <-time.After(1 * time.Second): 294 switch { 295 case c1 != nil && c2 != nil: 296 t.Error("timed out waiting for Read and Close") 297 w.Close() 298 case c1 != nil: 299 t.Error("timed out waiting for Close") 300 case c2 != nil: 301 t.Error("timed out waiting for Read") 302 default: 303 t.Error("impossible case") 304 } 305 } 306 } 307 308 wg.Wait() 309 } 310 311 // Issue 24164, for pipes. 312 func TestPipeEOF(t *testing.T) { 313 r, w, err := os.Pipe() 314 if err != nil { 315 t.Fatal(err) 316 } 317 318 var wg sync.WaitGroup 319 wg.Add(1) 320 go func() { 321 defer wg.Done() 322 323 defer func() { 324 if err := w.Close(); err != nil { 325 t.Errorf("error closing writer: %v", err) 326 } 327 }() 328 329 for i := 0; i < 3; i++ { 330 time.Sleep(10 * time.Millisecond) 331 _, err := fmt.Fprintf(w, "line %d\n", i) 332 if err != nil { 333 t.Errorf("error writing to fifo: %v", err) 334 return 335 } 336 } 337 time.Sleep(10 * time.Millisecond) 338 }() 339 340 defer wg.Wait() 341 342 done := make(chan bool) 343 go func() { 344 defer close(done) 345 346 defer func() { 347 if err := r.Close(); err != nil { 348 t.Errorf("error closing reader: %v", err) 349 } 350 }() 351 352 rbuf := bufio.NewReader(r) 353 for { 354 b, err := rbuf.ReadBytes('\n') 355 if err == io.EOF { 356 break 357 } 358 if err != nil { 359 t.Error(err) 360 return 361 } 362 t.Logf("%s\n", bytes.TrimSpace(b)) 363 } 364 }() 365 366 select { 367 case <-done: 368 // Test succeeded. 369 case <-time.After(time.Second): 370 t.Error("timed out waiting for read") 371 // Close the reader to force the read to complete. 372 r.Close() 373 } 374 } 375 376 // Issue 24481. 377 func TestFdRace(t *testing.T) { 378 r, w, err := os.Pipe() 379 if err != nil { 380 t.Fatal(err) 381 } 382 defer r.Close() 383 defer w.Close() 384 385 var wg sync.WaitGroup 386 call := func() { 387 defer wg.Done() 388 w.Fd() 389 } 390 391 const tries = 100 392 for i := 0; i < tries; i++ { 393 wg.Add(1) 394 go call() 395 } 396 wg.Wait() 397 } 398 399 func TestFdReadRace(t *testing.T) { 400 t.Parallel() 401 402 r, w, err := os.Pipe() 403 if err != nil { 404 t.Fatal(err) 405 } 406 defer r.Close() 407 defer w.Close() 408 409 c := make(chan bool) 410 var wg sync.WaitGroup 411 wg.Add(1) 412 go func() { 413 defer wg.Done() 414 var buf [10]byte 415 r.SetReadDeadline(time.Now().Add(time.Second)) 416 c <- true 417 if _, err := r.Read(buf[:]); os.IsTimeout(err) { 418 t.Error("read timed out") 419 } 420 }() 421 422 wg.Add(1) 423 go func() { 424 defer wg.Done() 425 <-c 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) 430 r.Fd() 431 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. 435 r.Close() 436 }() 437 438 wg.Wait() 439 }