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