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 }