github.com/riscv/riscv-go@v0.0.0-20200123204226-124ebd6fcc8e/src/runtime/runtime_test.go (about)

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