1// Copyright 2017 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//go:build !js && !plan9 && !wasip1 && !windows
6
7package os_test
8
9import (
10	"fmt"
11	"io"
12	"math/rand"
13	"os"
14	"os/signal"
15	"runtime"
16	"sync"
17	"syscall"
18	"testing"
19	"time"
20)
21
22func TestNonpollableDeadline(t *testing.T) {
23	// On BSD systems regular files seem to be pollable,
24	// so just run this test on Linux.
25	if runtime.GOOS != "linux" {
26		t.Skipf("skipping on %s", runtime.GOOS)
27	}
28	t.Parallel()
29
30	f, err := os.CreateTemp("", "ostest")
31	if err != nil {
32		t.Fatal(err)
33	}
34	defer os.Remove(f.Name())
35	defer f.Close()
36	deadline := time.Now().Add(10 * time.Second)
37	if err := f.SetDeadline(deadline); err != os.ErrNoDeadline {
38		t.Errorf("SetDeadline on file returned %v, wanted %v", err, os.ErrNoDeadline)
39	}
40	if err := f.SetReadDeadline(deadline); err != os.ErrNoDeadline {
41		t.Errorf("SetReadDeadline on file returned %v, wanted %v", err, os.ErrNoDeadline)
42	}
43	if err := f.SetWriteDeadline(deadline); err != os.ErrNoDeadline {
44		t.Errorf("SetWriteDeadline on file returned %v, wanted %v", err, os.ErrNoDeadline)
45	}
46}
47
48// noDeadline is a zero time.Time value, which cancels a deadline.
49var noDeadline time.Time
50
51var readTimeoutTests = []struct {
52	timeout time.Duration
53	xerrs   [2]error // expected errors in transition
54}{
55	// Tests that read deadlines work, even if there's data ready
56	// to be read.
57	{-5 * time.Second, [2]error{os.ErrDeadlineExceeded, os.ErrDeadlineExceeded}},
58
59	{50 * time.Millisecond, [2]error{nil, os.ErrDeadlineExceeded}},
60}
61
62// There is a very similar copy of this in net/timeout_test.go.
63func TestReadTimeout(t *testing.T) {
64	t.Parallel()
65
66	r, w, err := os.Pipe()
67	if err != nil {
68		t.Fatal(err)
69	}
70	defer r.Close()
71	defer w.Close()
72
73	if _, err := w.Write([]byte("READ TIMEOUT TEST")); err != nil {
74		t.Fatal(err)
75	}
76
77	for i, tt := range readTimeoutTests {
78		if err := r.SetReadDeadline(time.Now().Add(tt.timeout)); err != nil {
79			t.Fatalf("#%d: %v", i, err)
80		}
81		var b [1]byte
82		for j, xerr := range tt.xerrs {
83			for {
84				n, err := r.Read(b[:])
85				if xerr != nil {
86					if !isDeadlineExceeded(err) {
87						t.Fatalf("#%d/%d: %v", i, j, err)
88					}
89				}
90				if err == nil {
91					time.Sleep(tt.timeout / 3)
92					continue
93				}
94				if n != 0 {
95					t.Fatalf("#%d/%d: read %d; want 0", i, j, n)
96				}
97				break
98			}
99		}
100	}
101}
102
103// There is a very similar copy of this in net/timeout_test.go.
104func TestReadTimeoutMustNotReturn(t *testing.T) {
105	t.Parallel()
106
107	r, w, err := os.Pipe()
108	if err != nil {
109		t.Fatal(err)
110	}
111	defer r.Close()
112	defer w.Close()
113
114	max := time.NewTimer(100 * time.Millisecond)
115	defer max.Stop()
116	ch := make(chan error)
117	go func() {
118		if err := r.SetDeadline(time.Now().Add(-5 * time.Second)); err != nil {
119			t.Error(err)
120		}
121		if err := r.SetWriteDeadline(time.Now().Add(-5 * time.Second)); err != nil {
122			t.Error(err)
123		}
124		if err := r.SetReadDeadline(noDeadline); err != nil {
125			t.Error(err)
126		}
127		var b [1]byte
128		_, err := r.Read(b[:])
129		ch <- err
130	}()
131
132	select {
133	case err := <-ch:
134		t.Fatalf("expected Read to not return, but it returned with %v", err)
135	case <-max.C:
136		w.Close()
137		err := <-ch // wait for tester goroutine to stop
138		if os.IsTimeout(err) {
139			t.Fatal(err)
140		}
141	}
142}
143
144var writeTimeoutTests = []struct {
145	timeout time.Duration
146	xerrs   [2]error // expected errors in transition
147}{
148	// Tests that write deadlines work, even if there's buffer
149	// space available to write.
150	{-5 * time.Second, [2]error{os.ErrDeadlineExceeded, os.ErrDeadlineExceeded}},
151
152	{10 * time.Millisecond, [2]error{nil, os.ErrDeadlineExceeded}},
153}
154
155// There is a very similar copy of this in net/timeout_test.go.
156func TestWriteTimeout(t *testing.T) {
157	t.Parallel()
158
159	for i, tt := range writeTimeoutTests {
160		t.Run(fmt.Sprintf("#%d", i), func(t *testing.T) {
161			r, w, err := os.Pipe()
162			if err != nil {
163				t.Fatal(err)
164			}
165			defer r.Close()
166			defer w.Close()
167
168			if err := w.SetWriteDeadline(time.Now().Add(tt.timeout)); err != nil {
169				t.Fatalf("%v", err)
170			}
171			for j, xerr := range tt.xerrs {
172				for {
173					n, err := w.Write([]byte("WRITE TIMEOUT TEST"))
174					if xerr != nil {
175						if !isDeadlineExceeded(err) {
176							t.Fatalf("%d: %v", j, err)
177						}
178					}
179					if err == nil {
180						time.Sleep(tt.timeout / 3)
181						continue
182					}
183					if n != 0 {
184						t.Fatalf("%d: wrote %d; want 0", j, n)
185					}
186					break
187				}
188			}
189		})
190	}
191}
192
193// There is a very similar copy of this in net/timeout_test.go.
194func TestWriteTimeoutMustNotReturn(t *testing.T) {
195	t.Parallel()
196
197	r, w, err := os.Pipe()
198	if err != nil {
199		t.Fatal(err)
200	}
201	defer r.Close()
202	defer w.Close()
203
204	max := time.NewTimer(100 * time.Millisecond)
205	defer max.Stop()
206	ch := make(chan error)
207	go func() {
208		if err := w.SetDeadline(time.Now().Add(-5 * time.Second)); err != nil {
209			t.Error(err)
210		}
211		if err := w.SetReadDeadline(time.Now().Add(-5 * time.Second)); err != nil {
212			t.Error(err)
213		}
214		if err := w.SetWriteDeadline(noDeadline); err != nil {
215			t.Error(err)
216		}
217		var b [1]byte
218		for {
219			if _, err := w.Write(b[:]); err != nil {
220				ch <- err
221				break
222			}
223		}
224	}()
225
226	select {
227	case err := <-ch:
228		t.Fatalf("expected Write to not return, but it returned with %v", err)
229	case <-max.C:
230		r.Close()
231		err := <-ch // wait for tester goroutine to stop
232		if os.IsTimeout(err) {
233			t.Fatal(err)
234		}
235	}
236}
237
238const (
239	// minDynamicTimeout is the minimum timeout to attempt for
240	// tests that automatically increase timeouts until success.
241	//
242	// Lower values may allow tests to succeed more quickly if the value is close
243	// to the true minimum, but may require more iterations (and waste more time
244	// and CPU power on failed attempts) if the timeout is too low.
245	minDynamicTimeout = 1 * time.Millisecond
246
247	// maxDynamicTimeout is the maximum timeout to attempt for
248	// tests that automatically increase timeouts until success.
249	//
250	// This should be a strict upper bound on the latency required to hit a
251	// timeout accurately, even on a slow or heavily-loaded machine. If a test
252	// would increase the timeout beyond this value, the test fails.
253	maxDynamicTimeout = 4 * time.Second
254)
255
256// timeoutUpperBound returns the maximum time that we expect a timeout of
257// duration d to take to return the caller.
258func timeoutUpperBound(d time.Duration) time.Duration {
259	switch runtime.GOOS {
260	case "openbsd", "netbsd":
261		// NetBSD and OpenBSD seem to be unable to reliably hit deadlines even when
262		// the absolute durations are long.
263		// In https://build.golang.org/log/c34f8685d020b98377dd4988cd38f0c5bd72267e,
264		// we observed that an openbsd-amd64-68 builder took 4.090948779s for a
265		// 2.983020682s timeout (37.1% overhead).
266		// (See https://go.dev/issue/50189 for further detail.)
267		// Give them lots of slop to compensate.
268		return d * 3 / 2
269	}
270	// Other platforms seem to hit their deadlines more reliably,
271	// at least when they are long enough to cover scheduling jitter.
272	return d * 11 / 10
273}
274
275// nextTimeout returns the next timeout to try after an operation took the given
276// actual duration with a timeout shorter than that duration.
277func nextTimeout(actual time.Duration) (next time.Duration, ok bool) {
278	if actual >= maxDynamicTimeout {
279		return maxDynamicTimeout, false
280	}
281	// Since the previous attempt took actual, we can't expect to beat that
282	// duration by any significant margin. Try the next attempt with an arbitrary
283	// factor above that, so that our growth curve is at least exponential.
284	next = actual * 5 / 4
285	if next > maxDynamicTimeout {
286		return maxDynamicTimeout, true
287	}
288	return next, true
289}
290
291// There is a very similar copy of this in net/timeout_test.go.
292func TestReadTimeoutFluctuation(t *testing.T) {
293	t.Parallel()
294
295	r, w, err := os.Pipe()
296	if err != nil {
297		t.Fatal(err)
298	}
299	defer r.Close()
300	defer w.Close()
301
302	d := minDynamicTimeout
303	b := make([]byte, 256)
304	for {
305		t.Logf("SetReadDeadline(+%v)", d)
306		t0 := time.Now()
307		deadline := t0.Add(d)
308		if err = r.SetReadDeadline(deadline); err != nil {
309			t.Fatalf("SetReadDeadline(%v): %v", deadline, err)
310		}
311		var n int
312		n, err = r.Read(b)
313		t1 := time.Now()
314
315		if n != 0 || err == nil || !isDeadlineExceeded(err) {
316			t.Errorf("Read did not return (0, timeout): (%d, %v)", n, err)
317		}
318
319		actual := t1.Sub(t0)
320		if t1.Before(deadline) {
321			t.Errorf("Read took %s; expected at least %s", actual, d)
322		}
323		if t.Failed() {
324			return
325		}
326		if want := timeoutUpperBound(d); actual > want {
327			next, ok := nextTimeout(actual)
328			if !ok {
329				t.Fatalf("Read took %s; expected at most %v", actual, want)
330			}
331			// Maybe this machine is too slow to reliably schedule goroutines within
332			// the requested duration. Increase the timeout and try again.
333			t.Logf("Read took %s (expected %s); trying with longer timeout", actual, d)
334			d = next
335			continue
336		}
337
338		break
339	}
340}
341
342// There is a very similar copy of this in net/timeout_test.go.
343func TestWriteTimeoutFluctuation(t *testing.T) {
344	t.Parallel()
345
346	r, w, err := os.Pipe()
347	if err != nil {
348		t.Fatal(err)
349	}
350	defer r.Close()
351	defer w.Close()
352
353	d := minDynamicTimeout
354	for {
355		t.Logf("SetWriteDeadline(+%v)", d)
356		t0 := time.Now()
357		deadline := t0.Add(d)
358		if err := w.SetWriteDeadline(deadline); err != nil {
359			t.Fatalf("SetWriteDeadline(%v): %v", deadline, err)
360		}
361		var n int64
362		var err error
363		for {
364			var dn int
365			dn, err = w.Write([]byte("TIMEOUT TRANSMITTER"))
366			n += int64(dn)
367			if err != nil {
368				break
369			}
370		}
371		t1 := time.Now()
372		// Inv: err != nil
373		if !isDeadlineExceeded(err) {
374			t.Fatalf("Write did not return (any, timeout): (%d, %v)", n, err)
375		}
376
377		actual := t1.Sub(t0)
378		if t1.Before(deadline) {
379			t.Errorf("Write took %s; expected at least %s", actual, d)
380		}
381		if t.Failed() {
382			return
383		}
384		if want := timeoutUpperBound(d); actual > want {
385			if n > 0 {
386				// SetWriteDeadline specifies a time “after which I/O operations fail
387				// instead of blocking”. However, the kernel's send buffer is not yet
388				// full, we may be able to write some arbitrary (but finite) number of
389				// bytes to it without blocking.
390				t.Logf("Wrote %d bytes into send buffer; retrying until buffer is full", n)
391				if d <= maxDynamicTimeout/2 {
392					// We don't know how long the actual write loop would have taken if
393					// the buffer were full, so just guess and double the duration so that
394					// the next attempt can make twice as much progress toward filling it.
395					d *= 2
396				}
397			} else if next, ok := nextTimeout(actual); !ok {
398				t.Fatalf("Write took %s; expected at most %s", actual, want)
399			} else {
400				// Maybe this machine is too slow to reliably schedule goroutines within
401				// the requested duration. Increase the timeout and try again.
402				t.Logf("Write took %s (expected %s); trying with longer timeout", actual, d)
403				d = next
404			}
405			continue
406		}
407
408		break
409	}
410}
411
412// There is a very similar copy of this in net/timeout_test.go.
413func TestVariousDeadlines(t *testing.T) {
414	t.Parallel()
415	testVariousDeadlines(t)
416}
417
418// There is a very similar copy of this in net/timeout_test.go.
419func TestVariousDeadlines1Proc(t *testing.T) {
420	// Cannot use t.Parallel - modifies global GOMAXPROCS.
421	if testing.Short() {
422		t.Skip("skipping in short mode")
423	}
424	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1))
425	testVariousDeadlines(t)
426}
427
428// There is a very similar copy of this in net/timeout_test.go.
429func TestVariousDeadlines4Proc(t *testing.T) {
430	// Cannot use t.Parallel - modifies global GOMAXPROCS.
431	if testing.Short() {
432		t.Skip("skipping in short mode")
433	}
434	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
435	testVariousDeadlines(t)
436}
437
438type neverEnding byte
439
440func (b neverEnding) Read(p []byte) (int, error) {
441	for i := range p {
442		p[i] = byte(b)
443	}
444	return len(p), nil
445}
446
447func testVariousDeadlines(t *testing.T) {
448	type result struct {
449		n   int64
450		err error
451		d   time.Duration
452	}
453
454	handler := func(w *os.File, pasvch chan result) {
455		// The writer, with no timeouts of its own,
456		// sending bytes to clients as fast as it can.
457		t0 := time.Now()
458		n, err := io.Copy(w, neverEnding('a'))
459		dt := time.Since(t0)
460		pasvch <- result{n, err, dt}
461	}
462
463	for _, timeout := range []time.Duration{
464		1 * time.Nanosecond,
465		2 * time.Nanosecond,
466		5 * time.Nanosecond,
467		50 * time.Nanosecond,
468		100 * time.Nanosecond,
469		200 * time.Nanosecond,
470		500 * time.Nanosecond,
471		750 * time.Nanosecond,
472		1 * time.Microsecond,
473		5 * time.Microsecond,
474		25 * time.Microsecond,
475		250 * time.Microsecond,
476		500 * time.Microsecond,
477		1 * time.Millisecond,
478		5 * time.Millisecond,
479		100 * time.Millisecond,
480		250 * time.Millisecond,
481		500 * time.Millisecond,
482		1 * time.Second,
483	} {
484		numRuns := 3
485		if testing.Short() {
486			numRuns = 1
487			if timeout > 500*time.Microsecond {
488				continue
489			}
490		}
491		for run := 0; run < numRuns; run++ {
492			t.Run(fmt.Sprintf("%v-%d", timeout, run+1), func(t *testing.T) {
493				r, w, err := os.Pipe()
494				if err != nil {
495					t.Fatal(err)
496				}
497				defer r.Close()
498				defer w.Close()
499
500				pasvch := make(chan result)
501				go handler(w, pasvch)
502
503				tooLong := 5 * time.Second
504				max := time.NewTimer(tooLong)
505				defer max.Stop()
506				actvch := make(chan result)
507				go func() {
508					t0 := time.Now()
509					if err := r.SetDeadline(t0.Add(timeout)); err != nil {
510						t.Error(err)
511					}
512					n, err := io.Copy(io.Discard, r)
513					dt := time.Since(t0)
514					r.Close()
515					actvch <- result{n, err, dt}
516				}()
517
518				select {
519				case res := <-actvch:
520					if !isDeadlineExceeded(err) {
521						t.Logf("good client timeout after %v, reading %d bytes", res.d, res.n)
522					} else {
523						t.Fatalf("client Copy = %d, %v; want timeout", res.n, res.err)
524					}
525				case <-max.C:
526					t.Fatalf("timeout (%v) waiting for client to timeout (%v) reading", tooLong, timeout)
527				}
528
529				select {
530				case res := <-pasvch:
531					t.Logf("writer in %v wrote %d: %v", res.d, res.n, res.err)
532				case <-max.C:
533					t.Fatalf("timeout waiting for writer to finish writing")
534				}
535			})
536		}
537	}
538}
539
540// There is a very similar copy of this in net/timeout_test.go.
541func TestReadWriteDeadlineRace(t *testing.T) {
542	t.Parallel()
543
544	N := 1000
545	if testing.Short() {
546		N = 50
547	}
548
549	r, w, err := os.Pipe()
550	if err != nil {
551		t.Fatal(err)
552	}
553	defer r.Close()
554	defer w.Close()
555
556	var wg sync.WaitGroup
557	wg.Add(3)
558	go func() {
559		defer wg.Done()
560		tic := time.NewTicker(2 * time.Microsecond)
561		defer tic.Stop()
562		for i := 0; i < N; i++ {
563			if err := r.SetReadDeadline(time.Now().Add(2 * time.Microsecond)); err != nil {
564				break
565			}
566			if err := w.SetWriteDeadline(time.Now().Add(2 * time.Microsecond)); err != nil {
567				break
568			}
569			<-tic.C
570		}
571	}()
572	go func() {
573		defer wg.Done()
574		var b [1]byte
575		for i := 0; i < N; i++ {
576			_, err := r.Read(b[:])
577			if err != nil && !isDeadlineExceeded(err) {
578				t.Error("Read returned non-timeout error", err)
579			}
580		}
581	}()
582	go func() {
583		defer wg.Done()
584		var b [1]byte
585		for i := 0; i < N; i++ {
586			_, err := w.Write(b[:])
587			if err != nil && !isDeadlineExceeded(err) {
588				t.Error("Write returned non-timeout error", err)
589			}
590		}
591	}()
592	wg.Wait() // wait for tester goroutine to stop
593}
594
595// TestRacyRead tests that it is safe to mutate the input Read buffer
596// immediately after cancellation has occurred.
597func TestRacyRead(t *testing.T) {
598	t.Parallel()
599
600	r, w, err := os.Pipe()
601	if err != nil {
602		t.Fatal(err)
603	}
604	defer r.Close()
605	defer w.Close()
606
607	var wg sync.WaitGroup
608	defer wg.Wait()
609
610	go io.Copy(w, rand.New(rand.NewSource(0)))
611
612	r.SetReadDeadline(time.Now().Add(time.Millisecond))
613	for i := 0; i < 10; i++ {
614		wg.Add(1)
615		go func() {
616			defer wg.Done()
617
618			b1 := make([]byte, 1024)
619			b2 := make([]byte, 1024)
620			for j := 0; j < 100; j++ {
621				_, err := r.Read(b1)
622				copy(b1, b2) // Mutate b1 to trigger potential race
623				if err != nil {
624					if !isDeadlineExceeded(err) {
625						t.Error(err)
626					}
627					r.SetReadDeadline(time.Now().Add(time.Millisecond))
628				}
629			}
630		}()
631	}
632}
633
634// TestRacyWrite tests that it is safe to mutate the input Write buffer
635// immediately after cancellation has occurred.
636func TestRacyWrite(t *testing.T) {
637	t.Parallel()
638
639	r, w, err := os.Pipe()
640	if err != nil {
641		t.Fatal(err)
642	}
643	defer r.Close()
644	defer w.Close()
645
646	var wg sync.WaitGroup
647	defer wg.Wait()
648
649	go io.Copy(io.Discard, r)
650
651	w.SetWriteDeadline(time.Now().Add(time.Millisecond))
652	for i := 0; i < 10; i++ {
653		wg.Add(1)
654		go func() {
655			defer wg.Done()
656
657			b1 := make([]byte, 1024)
658			b2 := make([]byte, 1024)
659			for j := 0; j < 100; j++ {
660				_, err := w.Write(b1)
661				copy(b1, b2) // Mutate b1 to trigger potential race
662				if err != nil {
663					if !isDeadlineExceeded(err) {
664						t.Error(err)
665					}
666					w.SetWriteDeadline(time.Now().Add(time.Millisecond))
667				}
668			}
669		}()
670	}
671}
672
673// Closing a TTY while reading from it should not hang.  Issue 23943.
674func TestTTYClose(t *testing.T) {
675	// Ignore SIGTTIN in case we are running in the background.
676	signal.Ignore(syscall.SIGTTIN)
677	defer signal.Reset(syscall.SIGTTIN)
678
679	f, err := os.Open("/dev/tty")
680	if err != nil {
681		t.Skipf("skipping because opening /dev/tty failed: %v", err)
682	}
683
684	go func() {
685		var buf [1]byte
686		f.Read(buf[:])
687	}()
688
689	// Give the goroutine a chance to enter the read.
690	// It doesn't matter much if it occasionally fails to do so,
691	// we won't be testing what we want to test but the test will pass.
692	time.Sleep(time.Millisecond)
693
694	c := make(chan bool)
695	go func() {
696		defer close(c)
697		f.Close()
698	}()
699
700	select {
701	case <-c:
702	case <-time.After(time.Second):
703		t.Error("timed out waiting for close")
704	}
705
706	// On some systems the goroutines may now be hanging.
707	// There's not much we can do about that.
708}
709