Brad Fitzpatrick | 5194744 | 2016-03-01 22:57:46 +0000 | [diff] [blame] | 1 | // Copyright 2012 The Go Authors. All rights reserved. |
Russ Cox | f91cc3b | 2012-02-11 00:19:24 -0500 | [diff] [blame] | 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 ( |
Russ Cox | 94471f6 | 2017-10-27 13:30:09 -0400 | [diff] [blame] | 8 | "flag" |
Russ Cox | f91cc3b | 2012-02-11 00:19:24 -0500 | [diff] [blame] | 9 | "io" |
Russ Cox | 439f939 | 2013-09-13 14:19:23 -0400 | [diff] [blame] | 10 | . "runtime" |
Russ Cox | e56c6e7 | 2014-02-20 16:18:05 -0500 | [diff] [blame] | 11 | "runtime/debug" |
Russ Cox | 7e9fa3c | 2016-12-05 11:11:47 -0500 | [diff] [blame] | 12 | "strings" |
Russ Cox | f91cc3b | 2012-02-11 00:19:24 -0500 | [diff] [blame] | 13 | "testing" |
Russ Cox | e56c6e7 | 2014-02-20 16:18:05 -0500 | [diff] [blame] | 14 | "unsafe" |
Russ Cox | f91cc3b | 2012-02-11 00:19:24 -0500 | [diff] [blame] | 15 | ) |
| 16 | |
Russ Cox | 94471f6 | 2017-10-27 13:30:09 -0400 | [diff] [blame] | 17 | var flagQuick = flag.Bool("quick", false, "skip slow tests, for second run in all.bash") |
| 18 | |
Austin Clements | 1556c31 | 2016-01-14 16:43:40 -0500 | [diff] [blame] | 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 | |
Russ Cox | f91cc3b | 2012-02-11 00:19:24 -0500 | [diff] [blame] | 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 | } |
Russ Cox | 0de7161 | 2012-12-22 14:54:39 -0500 | [diff] [blame] | 55 | |
Keith Randall | e67d881 | 2017-03-24 14:03:15 -0700 | [diff] [blame] | 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 | |
Russ Cox | 0de7161 | 2012-12-22 14:54:39 -0500 | [diff] [blame] | 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) |
Russ Cox | 0de7161 | 2012-12-22 14:54:39 -0500 | [diff] [blame] | 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 | } |
Russ Cox | 439f939 | 2013-09-13 14:19:23 -0400 | [diff] [blame] | 112 | |
Emil Hessman | aeeda70 | 2014-01-06 09:53:55 -0800 | [diff] [blame] | 113 | // golang.org/issue/7063 |
| 114 | func TestStopCPUProfilingWithProfilerOff(t *testing.T) { |
| 115 | SetCPUProfileRate(0) |
| 116 | } |
Russ Cox | e56c6e7 | 2014-02-20 16:18:05 -0500 | [diff] [blame] | 117 | |
Russ Cox | 17f9423 | 2014-04-03 19:07:33 -0400 | [diff] [blame] | 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 |
Martin Möhrmann | fdd0179 | 2016-02-24 11:55:20 +0100 | [diff] [blame] | 127 | // addresses that normally an OS would reserve for itself, or malformed |
Russ Cox | 17f9423 | 2014-04-03 19:07:33 -0400 | [diff] [blame] | 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, |
Russ Cox | 5fdea34 | 2014-09-18 21:43:09 -0400 | [diff] [blame] | 140 | 0xffffffffffff0001, |
| 141 | 0xfffffffffff00001, |
Russ Cox | 17f9423 | 2014-04-03 19:07:33 -0400 | [diff] [blame] | 142 | 0xffffffffff000001, |
| 143 | 0xfffffffff0000001, |
| 144 | 0xffffffff00000001, |
| 145 | 0xfffffff000000001, |
| 146 | 0xffffff0000000001, |
| 147 | 0xfffff00000000001, |
| 148 | 0xffff000000000001, |
| 149 | 0xfff0000000000001, |
| 150 | 0xff00000000000001, |
| 151 | 0xf000000000000001, |
| 152 | 0x8000000000000001, |
| 153 | } |
| 154 | |
Russ Cox | e56c6e7 | 2014-02-20 16:18:05 -0500 | [diff] [blame] | 155 | func TestSetPanicOnFault(t *testing.T) { |
| 156 | old := debug.SetPanicOnFault(true) |
| 157 | defer debug.SetPanicOnFault(old) |
| 158 | |
Russ Cox | 5fdea34 | 2014-09-18 21:43:09 -0400 | [diff] [blame] | 159 | nfault := 0 |
Russ Cox | 17f9423 | 2014-04-03 19:07:33 -0400 | [diff] [blame] | 160 | for _, addr := range faultAddrs { |
Russ Cox | 5fdea34 | 2014-09-18 21:43:09 -0400 | [diff] [blame] | 161 | testSetPanicOnFault(t, uintptr(addr), &nfault) |
| 162 | } |
| 163 | if nfault == 0 { |
| 164 | t.Fatalf("none of the addresses faulted") |
Russ Cox | 17f9423 | 2014-04-03 19:07:33 -0400 | [diff] [blame] | 165 | } |
| 166 | } |
| 167 | |
Russ Cox | 5fdea34 | 2014-09-18 21:43:09 -0400 | [diff] [blame] | 168 | func testSetPanicOnFault(t *testing.T, addr uintptr, nfault *int) { |
Russ Cox | 0c2a727 | 2014-05-20 12:10:19 -0400 | [diff] [blame] | 169 | if GOOS == "nacl" { |
| 170 | t.Skip("nacl doesn't seem to fault on high addresses") |
| 171 | } |
| 172 | |
Russ Cox | e56c6e7 | 2014-02-20 16:18:05 -0500 | [diff] [blame] | 173 | defer func() { |
Russ Cox | 5fdea34 | 2014-09-18 21:43:09 -0400 | [diff] [blame] | 174 | if err := recover(); err != nil { |
| 175 | *nfault++ |
Russ Cox | e56c6e7 | 2014-02-20 16:18:05 -0500 | [diff] [blame] | 176 | } |
| 177 | }() |
| 178 | |
Russ Cox | 5fdea34 | 2014-09-18 21:43:09 -0400 | [diff] [blame] | 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. |
Keith Randall | 3b2577c | 2014-09-20 23:31:11 -0700 | [diff] [blame] | 183 | v := *(*byte)(unsafe.Pointer(addr)) |
| 184 | t.Logf("addr %#x: %#x\n", addr, v) |
Russ Cox | e56c6e7 | 2014-02-20 16:18:05 -0500 | [diff] [blame] | 185 | } |
Keith Randall | b36ed90 | 2014-06-16 21:00:37 -0700 | [diff] [blame] | 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) { |
Martin Möhrmann | 3216e0c | 2017-08-07 22:36:22 +0200 | [diff] [blame] | 202 | // This isn't really an exhaustive test of == on strings, it's |
Keith Randall | b36ed90 | 2014-06-16 21:00:37 -0700 | [diff] [blame] | 203 | // just a convenient way of documenting (via eqstring_generic) |
Martin Möhrmann | 3216e0c | 2017-08-07 22:36:22 +0200 | [diff] [blame] | 204 | // what == does. |
Keith Randall | b36ed90 | 2014-06-16 21:00:37 -0700 | [diff] [blame] | 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 { |
Martin Möhrmann | 3216e0c | 2017-08-07 22:36:22 +0200 | [diff] [blame] | 219 | t.Errorf(`("%s" == "%s") = %t, want %t`, s1, s2, x, y) |
Keith Randall | b36ed90 | 2014-06-16 21:00:37 -0700 | [diff] [blame] | 220 | } |
| 221 | } |
| 222 | } |
| 223 | } |
Keith Randall | 6f07ac2 | 2015-01-07 09:25:23 -0800 | [diff] [blame] | 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 | } |
David Crawshaw | 1e0e2ff | 2015-02-26 10:01:37 -0500 | [diff] [blame] | 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))) |
Keith Randall | 6f07ac2 | 2015-01-07 09:25:23 -0800 | [diff] [blame] | 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 | } |
Keith Randall | f584c05 | 2015-03-02 20:16:48 -0800 | [diff] [blame] | 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 | } |
Brad Fitzpatrick | 5fea2cc | 2016-03-01 23:21:55 +0000 | [diff] [blame] | 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. |
Keith Randall | f584c05 | 2015-03-02 20:16:48 -0800 | [diff] [blame] | 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 | } |
Russ Cox | 32fddad | 2015-06-25 19:27:20 -0400 | [diff] [blame] | 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 | } |
Russ Cox | 313fd1c | 2016-01-26 22:58:59 -0500 | [diff] [blame] | 331 | |
| 332 | func TestGoroutineProfileTrivial(t *testing.T) { |
Russ Cox | 1c6a35b | 2016-02-02 10:15:34 -0500 | [diff] [blame] | 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 | } |
Russ Cox | 313fd1c | 2016-01-26 22:58:59 -0500 | [diff] [blame] | 350 | } |
| 351 | } |
Russ Cox | 7e9fa3c | 2016-12-05 11:11:47 -0500 | [diff] [blame] | 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 | } |