Black Lives Matter. Support the Equal Justice Initiative.

Source file src/runtime/runtime_test.go

Documentation: runtime

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

View as plain text