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