1// Copyright 2012 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
5package runtime_test
6
7import (
8	"flag"
9	"fmt"
10	"io"
11	. "runtime"
12	"runtime/debug"
13	"slices"
14	"strings"
15	"sync"
16	"testing"
17	"time"
18	"unsafe"
19)
20
21// flagQuick is set by the -quick option to skip some relatively slow tests.
22// This is used by the cmd/dist test runtime:cpu124.
23// The cmd/dist test passes both -test.short and -quick;
24// there are tests that only check testing.Short, and those tests will
25// not be skipped if only -quick is used.
26var flagQuick = flag.Bool("quick", false, "skip slow tests, for cmd/dist test runtime:cpu124")
27
28func init() {
29	// We're testing the runtime, so make tracebacks show things
30	// in the runtime. This only raises the level, so it won't
31	// override GOTRACEBACK=crash from the user.
32	SetTracebackEnv("system")
33}
34
35var errf error
36
37func errfn() error {
38	return errf
39}
40
41func errfn1() error {
42	return io.EOF
43}
44
45func BenchmarkIfaceCmp100(b *testing.B) {
46	for i := 0; i < b.N; i++ {
47		for j := 0; j < 100; j++ {
48			if errfn() == io.EOF {
49				b.Fatal("bad comparison")
50			}
51		}
52	}
53}
54
55func BenchmarkIfaceCmpNil100(b *testing.B) {
56	for i := 0; i < b.N; i++ {
57		for j := 0; j < 100; j++ {
58			if errfn1() == nil {
59				b.Fatal("bad comparison")
60			}
61		}
62	}
63}
64
65var efaceCmp1 any
66var efaceCmp2 any
67
68func BenchmarkEfaceCmpDiff(b *testing.B) {
69	x := 5
70	efaceCmp1 = &x
71	y := 6
72	efaceCmp2 = &y
73	for i := 0; i < b.N; i++ {
74		for j := 0; j < 100; j++ {
75			if efaceCmp1 == efaceCmp2 {
76				b.Fatal("bad comparison")
77			}
78		}
79	}
80}
81
82func BenchmarkEfaceCmpDiffIndirect(b *testing.B) {
83	efaceCmp1 = [2]int{1, 2}
84	efaceCmp2 = [2]int{1, 2}
85	for i := 0; i < b.N; i++ {
86		for j := 0; j < 100; j++ {
87			if efaceCmp1 != efaceCmp2 {
88				b.Fatal("bad comparison")
89			}
90		}
91	}
92}
93
94func BenchmarkDefer(b *testing.B) {
95	for i := 0; i < b.N; i++ {
96		defer1()
97	}
98}
99
100func defer1() {
101	defer func(x, y, z int) {
102		if recover() != nil || x != 1 || y != 2 || z != 3 {
103			panic("bad recover")
104		}
105	}(1, 2, 3)
106}
107
108func BenchmarkDefer10(b *testing.B) {
109	for i := 0; i < b.N/10; i++ {
110		defer2()
111	}
112}
113
114func defer2() {
115	for i := 0; i < 10; i++ {
116		defer func(x, y, z int) {
117			if recover() != nil || x != 1 || y != 2 || z != 3 {
118				panic("bad recover")
119			}
120		}(1, 2, 3)
121	}
122}
123
124func BenchmarkDeferMany(b *testing.B) {
125	for i := 0; i < b.N; i++ {
126		defer func(x, y, z int) {
127			if recover() != nil || x != 1 || y != 2 || z != 3 {
128				panic("bad recover")
129			}
130		}(1, 2, 3)
131	}
132}
133
134func BenchmarkPanicRecover(b *testing.B) {
135	for i := 0; i < b.N; i++ {
136		defer3()
137	}
138}
139
140func defer3() {
141	defer func(x, y, z int) {
142		if recover() == nil {
143			panic("failed recover")
144		}
145	}(1, 2, 3)
146	panic("hi")
147}
148
149// golang.org/issue/7063
150func TestStopCPUProfilingWithProfilerOff(t *testing.T) {
151	SetCPUProfileRate(0)
152}
153
154// Addresses to test for faulting behavior.
155// This is less a test of SetPanicOnFault and more a check that
156// the operating system and the runtime can process these faults
157// correctly. That is, we're indirectly testing that without SetPanicOnFault
158// these would manage to turn into ordinary crashes.
159// Note that these are truncated on 32-bit systems, so the bottom 32 bits
160// of the larger addresses must themselves be invalid addresses.
161// We might get unlucky and the OS might have mapped one of these
162// addresses, but probably not: they're all in the first page, very high
163// addresses that normally an OS would reserve for itself, or malformed
164// addresses. Even so, we might have to remove one or two on different
165// systems. We will see.
166
167var faultAddrs = []uint64{
168	// low addresses
169	0,
170	1,
171	0xfff,
172	// high (kernel) addresses
173	// or else malformed.
174	0xffffffffffffffff,
175	0xfffffffffffff001,
176	0xffffffffffff0001,
177	0xfffffffffff00001,
178	0xffffffffff000001,
179	0xfffffffff0000001,
180	0xffffffff00000001,
181	0xfffffff000000001,
182	0xffffff0000000001,
183	0xfffff00000000001,
184	0xffff000000000001,
185	0xfff0000000000001,
186	0xff00000000000001,
187	0xf000000000000001,
188	0x8000000000000001,
189}
190
191func TestSetPanicOnFault(t *testing.T) {
192	old := debug.SetPanicOnFault(true)
193	defer debug.SetPanicOnFault(old)
194
195	nfault := 0
196	for _, addr := range faultAddrs {
197		testSetPanicOnFault(t, uintptr(addr), &nfault)
198	}
199	if nfault == 0 {
200		t.Fatalf("none of the addresses faulted")
201	}
202}
203
204// testSetPanicOnFault tests one potentially faulting address.
205// It deliberately constructs and uses an invalid pointer,
206// so mark it as nocheckptr.
207//
208//go:nocheckptr
209func testSetPanicOnFault(t *testing.T, addr uintptr, nfault *int) {
210	if GOOS == "js" || GOOS == "wasip1" {
211		t.Skip(GOOS + " does not support catching faults")
212	}
213
214	defer func() {
215		if err := recover(); err != nil {
216			*nfault++
217		}
218	}()
219
220	// The read should fault, except that sometimes we hit
221	// addresses that have had C or kernel pages mapped there
222	// readable by user code. So just log the content.
223	// If no addresses fault, we'll fail the test.
224	v := *(*byte)(unsafe.Pointer(addr))
225	t.Logf("addr %#x: %#x\n", addr, v)
226}
227
228func eqstring_generic(s1, s2 string) bool {
229	if len(s1) != len(s2) {
230		return false
231	}
232	// optimization in assembly versions:
233	// if s1.str == s2.str { return true }
234	for i := 0; i < len(s1); i++ {
235		if s1[i] != s2[i] {
236			return false
237		}
238	}
239	return true
240}
241
242func TestEqString(t *testing.T) {
243	// This isn't really an exhaustive test of == on strings, it's
244	// just a convenient way of documenting (via eqstring_generic)
245	// what == does.
246	s := []string{
247		"",
248		"a",
249		"c",
250		"aaa",
251		"ccc",
252		"cccc"[:3], // same contents, different string
253		"1234567890",
254	}
255	for _, s1 := range s {
256		for _, s2 := range s {
257			x := s1 == s2
258			y := eqstring_generic(s1, s2)
259			if x != y {
260				t.Errorf(`("%s" == "%s") = %t, want %t`, s1, s2, x, y)
261			}
262		}
263	}
264}
265
266func TestTrailingZero(t *testing.T) {
267	// make sure we add padding for structs with trailing zero-sized fields
268	type T1 struct {
269		n int32
270		z [0]byte
271	}
272	if unsafe.Sizeof(T1{}) != 8 {
273		t.Errorf("sizeof(%#v)==%d, want 8", T1{}, unsafe.Sizeof(T1{}))
274	}
275	type T2 struct {
276		n int64
277		z struct{}
278	}
279	if unsafe.Sizeof(T2{}) != 8+unsafe.Sizeof(uintptr(0)) {
280		t.Errorf("sizeof(%#v)==%d, want %d", T2{}, unsafe.Sizeof(T2{}), 8+unsafe.Sizeof(uintptr(0)))
281	}
282	type T3 struct {
283		n byte
284		z [4]struct{}
285	}
286	if unsafe.Sizeof(T3{}) != 2 {
287		t.Errorf("sizeof(%#v)==%d, want 2", T3{}, unsafe.Sizeof(T3{}))
288	}
289	// make sure padding can double for both zerosize and alignment
290	type T4 struct {
291		a int32
292		b int16
293		c int8
294		z struct{}
295	}
296	if unsafe.Sizeof(T4{}) != 8 {
297		t.Errorf("sizeof(%#v)==%d, want 8", T4{}, unsafe.Sizeof(T4{}))
298	}
299	// make sure we don't pad a zero-sized thing
300	type T5 struct {
301	}
302	if unsafe.Sizeof(T5{}) != 0 {
303		t.Errorf("sizeof(%#v)==%d, want 0", T5{}, unsafe.Sizeof(T5{}))
304	}
305}
306
307func TestAppendGrowth(t *testing.T) {
308	var x []int64
309	check := func(want int) {
310		if cap(x) != want {
311			t.Errorf("len=%d, cap=%d, want cap=%d", len(x), cap(x), want)
312		}
313	}
314
315	check(0)
316	want := 1
317	for i := 1; i <= 100; i++ {
318		x = append(x, 1)
319		check(want)
320		if i&(i-1) == 0 {
321			want = 2 * i
322		}
323	}
324}
325
326var One = []int64{1}
327
328func TestAppendSliceGrowth(t *testing.T) {
329	var x []int64
330	check := func(want int) {
331		if cap(x) != want {
332			t.Errorf("len=%d, cap=%d, want cap=%d", len(x), cap(x), want)
333		}
334	}
335
336	check(0)
337	want := 1
338	for i := 1; i <= 100; i++ {
339		x = append(x, One...)
340		check(want)
341		if i&(i-1) == 0 {
342			want = 2 * i
343		}
344	}
345}
346
347func TestGoroutineProfileTrivial(t *testing.T) {
348	// Calling GoroutineProfile twice in a row should find the same number of goroutines,
349	// but it's possible there are goroutines just about to exit, so we might end up
350	// with fewer in the second call. Try a few times; it should converge once those
351	// zombies are gone.
352	for i := 0; ; i++ {
353		n1, ok := GoroutineProfile(nil) // should fail, there's at least 1 goroutine
354		if n1 < 1 || ok {
355			t.Fatalf("GoroutineProfile(nil) = %d, %v, want >0, false", n1, ok)
356		}
357		n2, ok := GoroutineProfile(make([]StackRecord, n1))
358		if n2 == n1 && ok {
359			break
360		}
361		t.Logf("GoroutineProfile(%d) = %d, %v, want %d, true", n1, n2, ok, n1)
362		if i >= 10 {
363			t.Fatalf("GoroutineProfile not converging")
364		}
365	}
366}
367
368func BenchmarkGoroutineProfile(b *testing.B) {
369	run := func(fn func() bool) func(b *testing.B) {
370		runOne := func(b *testing.B) {
371			latencies := make([]time.Duration, 0, b.N)
372
373			b.ResetTimer()
374			for i := 0; i < b.N; i++ {
375				start := time.Now()
376				ok := fn()
377				if !ok {
378					b.Fatal("goroutine profile failed")
379				}
380				latencies = append(latencies, time.Since(start))
381			}
382			b.StopTimer()
383
384			// Sort latencies then report percentiles.
385			slices.Sort(latencies)
386			b.ReportMetric(float64(latencies[len(latencies)*50/100]), "p50-ns")
387			b.ReportMetric(float64(latencies[len(latencies)*90/100]), "p90-ns")
388			b.ReportMetric(float64(latencies[len(latencies)*99/100]), "p99-ns")
389		}
390		return func(b *testing.B) {
391			b.Run("idle", runOne)
392
393			b.Run("loaded", func(b *testing.B) {
394				stop := applyGCLoad(b)
395				runOne(b)
396				// Make sure to stop the timer before we wait! The load created above
397				// is very heavy-weight and not easy to stop, so we could end up
398				// confusing the benchmarking framework for small b.N.
399				b.StopTimer()
400				stop()
401			})
402		}
403	}
404
405	// Measure the cost of counting goroutines
406	b.Run("small-nil", run(func() bool {
407		GoroutineProfile(nil)
408		return true
409	}))
410
411	// Measure the cost with a small set of goroutines
412	n := NumGoroutine()
413	p := make([]StackRecord, 2*n+2*GOMAXPROCS(0))
414	b.Run("small", run(func() bool {
415		_, ok := GoroutineProfile(p)
416		return ok
417	}))
418
419	// Measure the cost with a large set of goroutines
420	ch := make(chan int)
421	var ready, done sync.WaitGroup
422	for i := 0; i < 5000; i++ {
423		ready.Add(1)
424		done.Add(1)
425		go func() { ready.Done(); <-ch; done.Done() }()
426	}
427	ready.Wait()
428
429	// Count goroutines with a large allgs list
430	b.Run("large-nil", run(func() bool {
431		GoroutineProfile(nil)
432		return true
433	}))
434
435	n = NumGoroutine()
436	p = make([]StackRecord, 2*n+2*GOMAXPROCS(0))
437	b.Run("large", run(func() bool {
438		_, ok := GoroutineProfile(p)
439		return ok
440	}))
441
442	close(ch)
443	done.Wait()
444
445	// Count goroutines with a large (but unused) allgs list
446	b.Run("sparse-nil", run(func() bool {
447		GoroutineProfile(nil)
448		return true
449	}))
450
451	// Measure the cost of a large (but unused) allgs list
452	n = NumGoroutine()
453	p = make([]StackRecord, 2*n+2*GOMAXPROCS(0))
454	b.Run("sparse", run(func() bool {
455		_, ok := GoroutineProfile(p)
456		return ok
457	}))
458}
459
460func TestVersion(t *testing.T) {
461	// Test that version does not contain \r or \n.
462	vers := Version()
463	if strings.Contains(vers, "\r") || strings.Contains(vers, "\n") {
464		t.Fatalf("cr/nl in version: %q", vers)
465	}
466}
467
468func TestTimediv(t *testing.T) {
469	for _, tc := range []struct {
470		num int64
471		div int32
472		ret int32
473		rem int32
474	}{
475		{
476			num: 8,
477			div: 2,
478			ret: 4,
479			rem: 0,
480		},
481		{
482			num: 9,
483			div: 2,
484			ret: 4,
485			rem: 1,
486		},
487		{
488			// Used by runtime.check.
489			num: 12345*1000000000 + 54321,
490			div: 1000000000,
491			ret: 12345,
492			rem: 54321,
493		},
494		{
495			num: 1<<32 - 1,
496			div: 2,
497			ret: 1<<31 - 1, // no overflow.
498			rem: 1,
499		},
500		{
501			num: 1 << 32,
502			div: 2,
503			ret: 1<<31 - 1, // overflow.
504			rem: 0,
505		},
506		{
507			num: 1 << 40,
508			div: 2,
509			ret: 1<<31 - 1, // overflow.
510			rem: 0,
511		},
512		{
513			num: 1<<40 + 1,
514			div: 1 << 10,
515			ret: 1 << 30,
516			rem: 1,
517		},
518	} {
519		name := fmt.Sprintf("%d div %d", tc.num, tc.div)
520		t.Run(name, func(t *testing.T) {
521			// Double check that the inputs make sense using
522			// standard 64-bit division.
523			ret64 := tc.num / int64(tc.div)
524			rem64 := tc.num % int64(tc.div)
525			if ret64 != int64(int32(ret64)) {
526				// Simulate timediv overflow value.
527				ret64 = 1<<31 - 1
528				rem64 = 0
529			}
530			if ret64 != int64(tc.ret) {
531				t.Errorf("%d / %d got ret %d rem %d want ret %d rem %d", tc.num, tc.div, ret64, rem64, tc.ret, tc.rem)
532			}
533
534			var rem int32
535			ret := Timediv(tc.num, tc.div, &rem)
536			if ret != tc.ret || rem != tc.rem {
537				t.Errorf("timediv %d / %d got ret %d rem %d want ret %d rem %d", tc.num, tc.div, ret, rem, tc.ret, tc.rem)
538			}
539		})
540	}
541}
542