github.com/guyezi/gofrontend@v0.0.0-20200228202240-7a62a49e62c0/libgo/go/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 !plan9,!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 expect := syscall.EPIPE 39 if runtime.GOOS == "windows" { 40 // 232 is Windows error code ERROR_NO_DATA, "The pipe is being closed". 41 expect = syscall.Errno(232) 42 } 43 // Every time we write to the pipe we should get an EPIPE. 44 for i := 0; i < 20; i++ { 45 _, err = w.Write([]byte("hi")) 46 if err == nil { 47 t.Fatal("unexpected success of Write to broken pipe") 48 } 49 if pe, ok := err.(*os.PathError); ok { 50 err = pe.Err 51 } 52 if se, ok := err.(*os.SyscallError); ok { 53 err = se.Err 54 } 55 if err != expect { 56 t.Errorf("iteration %d: got %v, expected %v", i, err, expect) 57 } 58 } 59 } 60 61 func TestStdPipe(t *testing.T) { 62 switch runtime.GOOS { 63 case "windows": 64 t.Skip("Windows doesn't support SIGPIPE") 65 } 66 testenv.MustHaveExec(t) 67 r, w, err := os.Pipe() 68 if err != nil { 69 t.Fatal(err) 70 } 71 if err := r.Close(); err != nil { 72 t.Fatal(err) 73 } 74 // Invoke the test program to run the test and write to a closed pipe. 75 // If sig is false: 76 // writing to stdout or stderr should cause an immediate SIGPIPE; 77 // writing to descriptor 3 should fail with EPIPE and then exit 0. 78 // If sig is true: 79 // all writes should fail with EPIPE and then exit 0. 80 for _, sig := range []bool{false, true} { 81 for dest := 1; dest < 4; dest++ { 82 cmd := osexec.Command(os.Args[0], "-test.run", "TestStdPipeHelper") 83 cmd.Stdout = w 84 cmd.Stderr = w 85 cmd.ExtraFiles = []*os.File{w} 86 cmd.Env = append(os.Environ(), fmt.Sprintf("GO_TEST_STD_PIPE_HELPER=%d", dest)) 87 if sig { 88 cmd.Env = append(cmd.Env, "GO_TEST_STD_PIPE_HELPER_SIGNAL=1") 89 } 90 if err := cmd.Run(); err == nil { 91 if !sig && dest < 3 { 92 t.Errorf("unexpected success of write to closed pipe %d sig %t in child", dest, sig) 93 } 94 } else if ee, ok := err.(*osexec.ExitError); !ok { 95 t.Errorf("unexpected exec error type %T: %v", err, err) 96 } else if ws, ok := ee.Sys().(syscall.WaitStatus); !ok { 97 t.Errorf("unexpected wait status type %T: %v", ee.Sys(), ee.Sys()) 98 } else if ws.Signaled() && ws.Signal() == syscall.SIGPIPE { 99 if sig || dest > 2 { 100 t.Errorf("unexpected SIGPIPE signal for descriptor %d sig %t", dest, sig) 101 } 102 } else { 103 t.Errorf("unexpected exit status %v for descriptor %d sig %t", err, dest, sig) 104 } 105 } 106 } 107 } 108 109 // This is a helper for TestStdPipe. It's not a test in itself. 110 func TestStdPipeHelper(t *testing.T) { 111 if os.Getenv("GO_TEST_STD_PIPE_HELPER_SIGNAL") != "" { 112 signal.Notify(make(chan os.Signal, 1), syscall.SIGPIPE) 113 } 114 switch os.Getenv("GO_TEST_STD_PIPE_HELPER") { 115 case "1": 116 os.Stdout.Write([]byte("stdout")) 117 case "2": 118 os.Stderr.Write([]byte("stderr")) 119 case "3": 120 if _, err := os.NewFile(3, "3").Write([]byte("3")); err == nil { 121 os.Exit(3) 122 } 123 default: 124 t.Skip("skipping test helper") 125 } 126 // For stdout/stderr, we should have crashed with a broken pipe error. 127 // The caller will be looking for that exit status, 128 // so just exit normally here to cause a failure in the caller. 129 // For descriptor 3, a normal exit is expected. 130 os.Exit(0) 131 } 132 133 func testClosedPipeRace(t *testing.T, read bool) { 134 switch runtime.GOOS { 135 case "freebsd": 136 t.Skip("FreeBSD does not use the poller; issue 19093") 137 } 138 139 limit := 1 140 if !read { 141 // Get the amount we have to write to overload a pipe 142 // with no reader. 143 limit = 131073 144 if b, err := ioutil.ReadFile("/proc/sys/fs/pipe-max-size"); err == nil { 145 if i, err := strconv.Atoi(strings.TrimSpace(string(b))); err == nil { 146 limit = i + 1 147 } 148 } 149 t.Logf("using pipe write limit of %d", limit) 150 } 151 152 r, w, err := os.Pipe() 153 if err != nil { 154 t.Fatal(err) 155 } 156 defer r.Close() 157 defer w.Close() 158 159 // Close the read end of the pipe in a goroutine while we are 160 // writing to the write end, or vice-versa. 161 go func() { 162 // Give the main goroutine a chance to enter the Read or 163 // Write call. This is sloppy but the test will pass even 164 // if we close before the read/write. 165 time.Sleep(20 * time.Millisecond) 166 167 var err error 168 if read { 169 err = r.Close() 170 } else { 171 err = w.Close() 172 } 173 if err != nil { 174 t.Error(err) 175 } 176 }() 177 178 b := make([]byte, limit) 179 if read { 180 _, err = r.Read(b[:]) 181 } else { 182 _, err = w.Write(b[:]) 183 } 184 if err == nil { 185 t.Error("I/O on closed pipe unexpectedly succeeded") 186 } else if pe, ok := err.(*os.PathError); !ok { 187 t.Errorf("I/O on closed pipe returned unexpected error type %T; expected os.PathError", pe) 188 } else if pe.Err != os.ErrClosed { 189 t.Errorf("got error %q but expected %q", pe.Err, os.ErrClosed) 190 } else { 191 t.Logf("I/O returned expected error %q", err) 192 } 193 } 194 195 func TestClosedPipeRaceRead(t *testing.T) { 196 testClosedPipeRace(t, true) 197 } 198 199 func TestClosedPipeRaceWrite(t *testing.T) { 200 testClosedPipeRace(t, false) 201 } 202 203 // Issue 20915: Reading on nonblocking fd should not return "waiting 204 // for unsupported file type." Currently it returns EAGAIN; it is 205 // possible that in the future it will simply wait for data. 206 func TestReadNonblockingFd(t *testing.T) { 207 switch runtime.GOOS { 208 case "windows": 209 t.Skip("Windows doesn't support SetNonblock") 210 } 211 if os.Getenv("GO_WANT_READ_NONBLOCKING_FD") == "1" { 212 fd := syscallDescriptor(os.Stdin.Fd()) 213 syscall.SetNonblock(fd, true) 214 defer syscall.SetNonblock(fd, false) 215 _, err := os.Stdin.Read(make([]byte, 1)) 216 if err != nil { 217 if perr, ok := err.(*os.PathError); !ok || perr.Err != syscall.EAGAIN { 218 t.Fatalf("read on nonblocking stdin got %q, should have gotten EAGAIN", err) 219 } 220 } 221 os.Exit(0) 222 } 223 224 testenv.MustHaveExec(t) 225 r, w, err := os.Pipe() 226 if err != nil { 227 t.Fatal(err) 228 } 229 defer r.Close() 230 defer w.Close() 231 cmd := osexec.Command(os.Args[0], "-test.run="+t.Name()) 232 cmd.Env = append(os.Environ(), "GO_WANT_READ_NONBLOCKING_FD=1") 233 cmd.Stdin = r 234 output, err := cmd.CombinedOutput() 235 t.Logf("%s", output) 236 if err != nil { 237 t.Errorf("child process failed: %v", err) 238 } 239 } 240 241 func TestCloseWithBlockingReadByNewFile(t *testing.T) { 242 var p [2]syscallDescriptor 243 err := syscall.Pipe(p[:]) 244 if err != nil { 245 t.Fatal(err) 246 } 247 // os.NewFile returns a blocking mode file. 248 testCloseWithBlockingRead(t, os.NewFile(uintptr(p[0]), "reader"), os.NewFile(uintptr(p[1]), "writer")) 249 } 250 251 func TestCloseWithBlockingReadByFd(t *testing.T) { 252 r, w, err := os.Pipe() 253 if err != nil { 254 t.Fatal(err) 255 } 256 // Calling Fd will put the file into blocking mode. 257 _ = r.Fd() 258 testCloseWithBlockingRead(t, r, w) 259 } 260 261 // Test that we don't let a blocking read prevent a close. 262 func testCloseWithBlockingRead(t *testing.T, r, w *os.File) { 263 defer r.Close() 264 defer w.Close() 265 266 c1, c2 := make(chan bool), make(chan bool) 267 var wg sync.WaitGroup 268 269 wg.Add(1) 270 go func(c chan bool) { 271 defer wg.Done() 272 // Give the other goroutine a chance to enter the Read 273 // or Write call. This is sloppy but the test will 274 // pass even if we close before the read/write. 275 time.Sleep(20 * time.Millisecond) 276 277 if err := r.Close(); err != nil { 278 t.Error(err) 279 } 280 close(c) 281 }(c1) 282 283 wg.Add(1) 284 go func(c chan bool) { 285 defer wg.Done() 286 var b [1]byte 287 _, err := r.Read(b[:]) 288 close(c) 289 if err == nil { 290 t.Error("I/O on closed pipe unexpectedly succeeded") 291 } 292 if pe, ok := err.(*os.PathError); ok { 293 err = pe.Err 294 } 295 if err != io.EOF && err != os.ErrClosed { 296 t.Errorf("got %v, expected EOF or closed", err) 297 } 298 }(c2) 299 300 for c1 != nil || c2 != nil { 301 select { 302 case <-c1: 303 c1 = nil 304 // r.Close has completed, but the blocking Read 305 // is hanging. Close the writer to unblock it. 306 w.Close() 307 case <-c2: 308 c2 = nil 309 case <-time.After(1 * time.Second): 310 switch { 311 case c1 != nil && c2 != nil: 312 t.Error("timed out waiting for Read and Close") 313 w.Close() 314 case c1 != nil: 315 t.Error("timed out waiting for Close") 316 case c2 != nil: 317 t.Error("timed out waiting for Read") 318 default: 319 t.Error("impossible case") 320 } 321 } 322 } 323 324 wg.Wait() 325 } 326 327 // Issue 24164, for pipes. 328 func TestPipeEOF(t *testing.T) { 329 r, w, err := os.Pipe() 330 if err != nil { 331 t.Fatal(err) 332 } 333 334 var wg sync.WaitGroup 335 wg.Add(1) 336 go func() { 337 defer wg.Done() 338 339 defer func() { 340 if err := w.Close(); err != nil { 341 t.Errorf("error closing writer: %v", err) 342 } 343 }() 344 345 for i := 0; i < 3; i++ { 346 time.Sleep(10 * time.Millisecond) 347 _, err := fmt.Fprintf(w, "line %d\n", i) 348 if err != nil { 349 t.Errorf("error writing to fifo: %v", err) 350 return 351 } 352 } 353 time.Sleep(10 * time.Millisecond) 354 }() 355 356 defer wg.Wait() 357 358 done := make(chan bool) 359 go func() { 360 defer close(done) 361 362 defer func() { 363 if err := r.Close(); err != nil { 364 t.Errorf("error closing reader: %v", err) 365 } 366 }() 367 368 rbuf := bufio.NewReader(r) 369 for { 370 b, err := rbuf.ReadBytes('\n') 371 if err == io.EOF { 372 break 373 } 374 if err != nil { 375 t.Error(err) 376 return 377 } 378 t.Logf("%s\n", bytes.TrimSpace(b)) 379 } 380 }() 381 382 select { 383 case <-done: 384 // Test succeeded. 385 case <-time.After(time.Second): 386 t.Error("timed out waiting for read") 387 // Close the reader to force the read to complete. 388 r.Close() 389 } 390 } 391 392 // Issue 24481. 393 func TestFdRace(t *testing.T) { 394 r, w, err := os.Pipe() 395 if err != nil { 396 t.Fatal(err) 397 } 398 defer r.Close() 399 defer w.Close() 400 401 var wg sync.WaitGroup 402 call := func() { 403 defer wg.Done() 404 w.Fd() 405 } 406 407 const tries = 100 408 for i := 0; i < tries; i++ { 409 wg.Add(1) 410 go call() 411 } 412 wg.Wait() 413 } 414 415 func TestFdReadRace(t *testing.T) { 416 t.Parallel() 417 418 r, w, err := os.Pipe() 419 if err != nil { 420 t.Fatal(err) 421 } 422 defer r.Close() 423 defer w.Close() 424 425 c := make(chan bool) 426 var wg sync.WaitGroup 427 wg.Add(1) 428 go func() { 429 defer wg.Done() 430 var buf [10]byte 431 r.SetReadDeadline(time.Now().Add(time.Minute)) 432 c <- true 433 if _, err := r.Read(buf[:]); os.IsTimeout(err) { 434 t.Error("read timed out") 435 } 436 }() 437 438 wg.Add(1) 439 go func() { 440 defer wg.Done() 441 <-c 442 // Give the other goroutine a chance to enter the Read. 443 // It doesn't matter if this occasionally fails, the test 444 // will still pass, it just won't test anything. 445 time.Sleep(10 * time.Millisecond) 446 r.Fd() 447 448 // The bug was that Fd would hang until Read timed out. 449 // If the bug is fixed, then closing r here will cause 450 // the Read to exit before the timeout expires. 451 r.Close() 452 }() 453 454 wg.Wait() 455 }