Source file src/runtime/runtime_test.go

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

View as plain text