Home | History | Annotate | Download | only in 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 	"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 }
    341