rsc.io/go@v0.0.0-20150416155037-e040fd465409/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  	"io/ioutil"
    10  	"os"
    11  	"os/exec"
    12  	. "runtime"
    13  	"runtime/debug"
    14  	"strconv"
    15  	"strings"
    16  	"testing"
    17  	"unsafe"
    18  )
    19  
    20  var errf error
    21  
    22  func errfn() error {
    23  	return errf
    24  }
    25  
    26  func errfn1() error {
    27  	return io.EOF
    28  }
    29  
    30  func BenchmarkIfaceCmp100(b *testing.B) {
    31  	for i := 0; i < b.N; i++ {
    32  		for j := 0; j < 100; j++ {
    33  			if errfn() == io.EOF {
    34  				b.Fatal("bad comparison")
    35  			}
    36  		}
    37  	}
    38  }
    39  
    40  func BenchmarkIfaceCmpNil100(b *testing.B) {
    41  	for i := 0; i < b.N; i++ {
    42  		for j := 0; j < 100; j++ {
    43  			if errfn1() == nil {
    44  				b.Fatal("bad comparison")
    45  			}
    46  		}
    47  	}
    48  }
    49  
    50  func BenchmarkDefer(b *testing.B) {
    51  	for i := 0; i < b.N; i++ {
    52  		defer1()
    53  	}
    54  }
    55  
    56  func defer1() {
    57  	defer func(x, y, z int) {
    58  		if recover() != nil || x != 1 || y != 2 || z != 3 {
    59  			panic("bad recover")
    60  		}
    61  	}(1, 2, 3)
    62  	return
    63  }
    64  
    65  func BenchmarkDefer10(b *testing.B) {
    66  	for i := 0; i < b.N/10; i++ {
    67  		defer2()
    68  	}
    69  }
    70  
    71  func defer2() {
    72  	for i := 0; i < 10; i++ {
    73  		defer func(x, y, z int) {
    74  			if recover() != nil || x != 1 || y != 2 || z != 3 {
    75  				panic("bad recover")
    76  			}
    77  		}(1, 2, 3)
    78  	}
    79  }
    80  
    81  func BenchmarkDeferMany(b *testing.B) {
    82  	for i := 0; i < b.N; i++ {
    83  		defer func(x, y, z int) {
    84  			if recover() != nil || x != 1 || y != 2 || z != 3 {
    85  				panic("bad recover")
    86  			}
    87  		}(1, 2, 3)
    88  	}
    89  }
    90  
    91  // The profiling signal handler needs to know whether it is executing runtime.gogo.
    92  // The constant RuntimeGogoBytes in arch_*.h gives the size of the function;
    93  // we don't have a way to obtain it from the linker (perhaps someday).
    94  // Test that the constant matches the size determined by 'go tool nm -S'.
    95  // The value reported will include the padding between runtime.gogo and the
    96  // next function in memory. That's fine.
    97  func TestRuntimeGogoBytes(t *testing.T) {
    98  	switch GOOS {
    99  	case "android", "nacl":
   100  		t.Skipf("skipping on %s", GOOS)
   101  	case "darwin":
   102  		switch GOARCH {
   103  		case "arm", "arm64":
   104  			t.Skipf("skipping on %s/%s, no fork", GOOS, GOARCH)
   105  		}
   106  	}
   107  
   108  	dir, err := ioutil.TempDir("", "go-build")
   109  	if err != nil {
   110  		t.Fatalf("failed to create temp directory: %v", err)
   111  	}
   112  	defer os.RemoveAll(dir)
   113  
   114  	out, err := exec.Command("go", "build", "-o", dir+"/hello", "../../test/helloworld.go").CombinedOutput()
   115  	if err != nil {
   116  		t.Fatalf("building hello world: %v\n%s", err, out)
   117  	}
   118  
   119  	out, err = exec.Command("go", "tool", "nm", "-size", dir+"/hello").CombinedOutput()
   120  	if err != nil {
   121  		t.Fatalf("go tool nm: %v\n%s", err, out)
   122  	}
   123  
   124  	for _, line := range strings.Split(string(out), "\n") {
   125  		f := strings.Fields(line)
   126  		if len(f) == 4 && f[3] == "runtime.gogo" {
   127  			size, _ := strconv.Atoi(f[1])
   128  			if GogoBytes() != int32(size) {
   129  				t.Fatalf("RuntimeGogoBytes = %d, should be %d", GogoBytes(), size)
   130  			}
   131  			return
   132  		}
   133  	}
   134  
   135  	t.Fatalf("go tool nm did not report size for runtime.gogo")
   136  }
   137  
   138  // golang.org/issue/7063
   139  func TestStopCPUProfilingWithProfilerOff(t *testing.T) {
   140  	SetCPUProfileRate(0)
   141  }
   142  
   143  // Addresses to test for faulting behavior.
   144  // This is less a test of SetPanicOnFault and more a check that
   145  // the operating system and the runtime can process these faults
   146  // correctly. That is, we're indirectly testing that without SetPanicOnFault
   147  // these would manage to turn into ordinary crashes.
   148  // Note that these are truncated on 32-bit systems, so the bottom 32 bits
   149  // of the larger addresses must themselves be invalid addresses.
   150  // We might get unlucky and the OS might have mapped one of these
   151  // addresses, but probably not: they're all in the first page, very high
   152  // adderesses that normally an OS would reserve for itself, or malformed
   153  // addresses. Even so, we might have to remove one or two on different
   154  // systems. We will see.
   155  
   156  var faultAddrs = []uint64{
   157  	// low addresses
   158  	0,
   159  	1,
   160  	0xfff,
   161  	// high (kernel) addresses
   162  	// or else malformed.
   163  	0xffffffffffffffff,
   164  	0xfffffffffffff001,
   165  	0xffffffffffff0001,
   166  	0xfffffffffff00001,
   167  	0xffffffffff000001,
   168  	0xfffffffff0000001,
   169  	0xffffffff00000001,
   170  	0xfffffff000000001,
   171  	0xffffff0000000001,
   172  	0xfffff00000000001,
   173  	0xffff000000000001,
   174  	0xfff0000000000001,
   175  	0xff00000000000001,
   176  	0xf000000000000001,
   177  	0x8000000000000001,
   178  }
   179  
   180  func TestSetPanicOnFault(t *testing.T) {
   181  	old := debug.SetPanicOnFault(true)
   182  	defer debug.SetPanicOnFault(old)
   183  
   184  	nfault := 0
   185  	for _, addr := range faultAddrs {
   186  		testSetPanicOnFault(t, uintptr(addr), &nfault)
   187  	}
   188  	if nfault == 0 {
   189  		t.Fatalf("none of the addresses faulted")
   190  	}
   191  }
   192  
   193  func testSetPanicOnFault(t *testing.T, addr uintptr, nfault *int) {
   194  	if GOOS == "nacl" {
   195  		t.Skip("nacl doesn't seem to fault on high addresses")
   196  	}
   197  
   198  	defer func() {
   199  		if err := recover(); err != nil {
   200  			*nfault++
   201  		}
   202  	}()
   203  
   204  	// The read should fault, except that sometimes we hit
   205  	// addresses that have had C or kernel pages mapped there
   206  	// readable by user code. So just log the content.
   207  	// If no addresses fault, we'll fail the test.
   208  	v := *(*byte)(unsafe.Pointer(addr))
   209  	t.Logf("addr %#x: %#x\n", addr, v)
   210  }
   211  
   212  func eqstring_generic(s1, s2 string) bool {
   213  	if len(s1) != len(s2) {
   214  		return false
   215  	}
   216  	// optimization in assembly versions:
   217  	// if s1.str == s2.str { return true }
   218  	for i := 0; i < len(s1); i++ {
   219  		if s1[i] != s2[i] {
   220  			return false
   221  		}
   222  	}
   223  	return true
   224  }
   225  
   226  func TestEqString(t *testing.T) {
   227  	// This isn't really an exhaustive test of eqstring, it's
   228  	// just a convenient way of documenting (via eqstring_generic)
   229  	// what eqstring does.
   230  	s := []string{
   231  		"",
   232  		"a",
   233  		"c",
   234  		"aaa",
   235  		"ccc",
   236  		"cccc"[:3], // same contents, different string
   237  		"1234567890",
   238  	}
   239  	for _, s1 := range s {
   240  		for _, s2 := range s {
   241  			x := s1 == s2
   242  			y := eqstring_generic(s1, s2)
   243  			if x != y {
   244  				t.Errorf(`eqstring("%s","%s") = %t, want %t`, s1, s2, x, y)
   245  			}
   246  		}
   247  	}
   248  }
   249  
   250  func TestTrailingZero(t *testing.T) {
   251  	// make sure we add padding for structs with trailing zero-sized fields
   252  	type T1 struct {
   253  		n int32
   254  		z [0]byte
   255  	}
   256  	if unsafe.Sizeof(T1{}) != 8 {
   257  		t.Errorf("sizeof(%#v)==%d, want 8", T1{}, unsafe.Sizeof(T1{}))
   258  	}
   259  	type T2 struct {
   260  		n int64
   261  		z struct{}
   262  	}
   263  	if unsafe.Sizeof(T2{}) != 8+unsafe.Sizeof(Uintreg(0)) {
   264  		t.Errorf("sizeof(%#v)==%d, want %d", T2{}, unsafe.Sizeof(T2{}), 8+unsafe.Sizeof(Uintreg(0)))
   265  	}
   266  	type T3 struct {
   267  		n byte
   268  		z [4]struct{}
   269  	}
   270  	if unsafe.Sizeof(T3{}) != 2 {
   271  		t.Errorf("sizeof(%#v)==%d, want 2", T3{}, unsafe.Sizeof(T3{}))
   272  	}
   273  	// make sure padding can double for both zerosize and alignment
   274  	type T4 struct {
   275  		a int32
   276  		b int16
   277  		c int8
   278  		z struct{}
   279  	}
   280  	if unsafe.Sizeof(T4{}) != 8 {
   281  		t.Errorf("sizeof(%#v)==%d, want 8", T4{}, unsafe.Sizeof(T4{}))
   282  	}
   283  	// make sure we don't pad a zero-sized thing
   284  	type T5 struct {
   285  	}
   286  	if unsafe.Sizeof(T5{}) != 0 {
   287  		t.Errorf("sizeof(%#v)==%d, want 0", T5{}, unsafe.Sizeof(T5{}))
   288  	}
   289  }
   290  
   291  func TestBadOpen(t *testing.T) {
   292  	if GOOS == "windows" || GOOS == "nacl" {
   293  		t.Skip("skipping OS that doesn't have open/read/write/close")
   294  	}
   295  	// make sure we get the correct error code if open fails.  Same for
   296  	// read/write/close on the resulting -1 fd.  See issue 10052.
   297  	nonfile := []byte("/notreallyafile")
   298  	fd := Open(&nonfile[0], 0, 0)
   299  	if fd != -1 {
   300  		t.Errorf("open(\"%s\")=%d, want -1", string(nonfile), fd)
   301  	}
   302  	var buf [32]byte
   303  	r := Read(-1, unsafe.Pointer(&buf[0]), int32(len(buf)))
   304  	if r != -1 {
   305  		t.Errorf("read()=%d, want -1", r)
   306  	}
   307  	w := Write(^uintptr(0), unsafe.Pointer(&buf[0]), int32(len(buf)))
   308  	if w != -1 {
   309  		t.Errorf("write()=%d, want -1", w)
   310  	}
   311  	c := Close(-1)
   312  	if c != -1 {
   313  		t.Errorf("close()=%d, want -1", c)
   314  	}
   315  }