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 | bc60c3c | 2021-12-15 01:09:00 -0800 | [diff] [blame] | 56 | var efaceCmp1 any |
| 57 | var efaceCmp2 any |
Dan Willemsen | d279748 | 2017-07-26 13:13:13 -0700 | [diff] [blame] | 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 | |
Patrice Arruda | 748609c | 2020-06-25 12:12:21 -0700 | [diff] [blame] | 125 | func BenchmarkPanicRecover(b *testing.B) { |
| 126 | for i := 0; i < b.N; i++ { |
| 127 | defer3() |
| 128 | } |
| 129 | } |
| 130 | |
| 131 | func defer3() { |
| 132 | defer func(x, y, z int) { |
| 133 | if recover() == nil { |
| 134 | panic("failed recover") |
| 135 | } |
| 136 | }(1, 2, 3) |
| 137 | panic("hi") |
| 138 | } |
| 139 | |
Brent Austin | ba3052e | 2015-04-21 16:08:23 -0700 | [diff] [blame] | 140 | // golang.org/issue/7063 |
| 141 | func TestStopCPUProfilingWithProfilerOff(t *testing.T) { |
| 142 | SetCPUProfileRate(0) |
| 143 | } |
| 144 | |
| 145 | // Addresses to test for faulting behavior. |
| 146 | // This is less a test of SetPanicOnFault and more a check that |
| 147 | // the operating system and the runtime can process these faults |
| 148 | // correctly. That is, we're indirectly testing that without SetPanicOnFault |
| 149 | // these would manage to turn into ordinary crashes. |
| 150 | // Note that these are truncated on 32-bit systems, so the bottom 32 bits |
| 151 | // of the larger addresses must themselves be invalid addresses. |
| 152 | // We might get unlucky and the OS might have mapped one of these |
| 153 | // 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] | 154 | // addresses that normally an OS would reserve for itself, or malformed |
Brent Austin | ba3052e | 2015-04-21 16:08:23 -0700 | [diff] [blame] | 155 | // addresses. Even so, we might have to remove one or two on different |
| 156 | // systems. We will see. |
| 157 | |
| 158 | var faultAddrs = []uint64{ |
| 159 | // low addresses |
| 160 | 0, |
| 161 | 1, |
| 162 | 0xfff, |
| 163 | // high (kernel) addresses |
| 164 | // or else malformed. |
| 165 | 0xffffffffffffffff, |
| 166 | 0xfffffffffffff001, |
| 167 | 0xffffffffffff0001, |
| 168 | 0xfffffffffff00001, |
| 169 | 0xffffffffff000001, |
| 170 | 0xfffffffff0000001, |
| 171 | 0xffffffff00000001, |
| 172 | 0xfffffff000000001, |
| 173 | 0xffffff0000000001, |
| 174 | 0xfffff00000000001, |
| 175 | 0xffff000000000001, |
| 176 | 0xfff0000000000001, |
| 177 | 0xff00000000000001, |
| 178 | 0xf000000000000001, |
| 179 | 0x8000000000000001, |
| 180 | } |
| 181 | |
| 182 | func TestSetPanicOnFault(t *testing.T) { |
Brent Austin | ba3052e | 2015-04-21 16:08:23 -0700 | [diff] [blame] | 183 | old := debug.SetPanicOnFault(true) |
| 184 | defer debug.SetPanicOnFault(old) |
| 185 | |
| 186 | nfault := 0 |
| 187 | for _, addr := range faultAddrs { |
| 188 | testSetPanicOnFault(t, uintptr(addr), &nfault) |
| 189 | } |
| 190 | if nfault == 0 { |
| 191 | t.Fatalf("none of the addresses faulted") |
| 192 | } |
| 193 | } |
| 194 | |
Patrice Arruda | 748609c | 2020-06-25 12:12:21 -0700 | [diff] [blame] | 195 | // testSetPanicOnFault tests one potentially faulting address. |
| 196 | // It deliberately constructs and uses an invalid pointer, |
| 197 | // so mark it as nocheckptr. |
| 198 | //go:nocheckptr |
Brent Austin | ba3052e | 2015-04-21 16:08:23 -0700 | [diff] [blame] | 199 | func testSetPanicOnFault(t *testing.T, addr uintptr, nfault *int) { |
Dan Willemsen | c741332 | 2018-08-27 23:21:26 -0700 | [diff] [blame] | 200 | if GOOS == "js" { |
| 201 | t.Skip("js does not support catching faults") |
| 202 | } |
Brent Austin | ba3052e | 2015-04-21 16:08:23 -0700 | [diff] [blame] | 203 | |
| 204 | defer func() { |
| 205 | if err := recover(); err != nil { |
| 206 | *nfault++ |
| 207 | } |
| 208 | }() |
| 209 | |
| 210 | // The read should fault, except that sometimes we hit |
| 211 | // addresses that have had C or kernel pages mapped there |
| 212 | // readable by user code. So just log the content. |
| 213 | // If no addresses fault, we'll fail the test. |
| 214 | v := *(*byte)(unsafe.Pointer(addr)) |
| 215 | t.Logf("addr %#x: %#x\n", addr, v) |
| 216 | } |
| 217 | |
| 218 | func eqstring_generic(s1, s2 string) bool { |
| 219 | if len(s1) != len(s2) { |
| 220 | return false |
| 221 | } |
| 222 | // optimization in assembly versions: |
| 223 | // if s1.str == s2.str { return true } |
| 224 | for i := 0; i < len(s1); i++ { |
| 225 | if s1[i] != s2[i] { |
| 226 | return false |
| 227 | } |
| 228 | } |
| 229 | return true |
| 230 | } |
| 231 | |
| 232 | func TestEqString(t *testing.T) { |
Dan Willemsen | a322328 | 2018-02-27 19:41:43 -0800 | [diff] [blame] | 233 | // This isn't really an exhaustive test of == on strings, it's |
Brent Austin | ba3052e | 2015-04-21 16:08:23 -0700 | [diff] [blame] | 234 | // just a convenient way of documenting (via eqstring_generic) |
Dan Willemsen | a322328 | 2018-02-27 19:41:43 -0800 | [diff] [blame] | 235 | // what == does. |
Brent Austin | ba3052e | 2015-04-21 16:08:23 -0700 | [diff] [blame] | 236 | s := []string{ |
| 237 | "", |
| 238 | "a", |
| 239 | "c", |
| 240 | "aaa", |
| 241 | "ccc", |
| 242 | "cccc"[:3], // same contents, different string |
| 243 | "1234567890", |
| 244 | } |
| 245 | for _, s1 := range s { |
| 246 | for _, s2 := range s { |
| 247 | x := s1 == s2 |
| 248 | y := eqstring_generic(s1, s2) |
| 249 | if x != y { |
Dan Willemsen | a322328 | 2018-02-27 19:41:43 -0800 | [diff] [blame] | 250 | t.Errorf(`("%s" == "%s") = %t, want %t`, s1, s2, x, y) |
Brent Austin | ba3052e | 2015-04-21 16:08:23 -0700 | [diff] [blame] | 251 | } |
| 252 | } |
| 253 | } |
| 254 | } |
Dan Willemsen | 09eb3b1 | 2015-09-16 14:34:17 -0700 | [diff] [blame] | 255 | |
| 256 | func TestTrailingZero(t *testing.T) { |
| 257 | // make sure we add padding for structs with trailing zero-sized fields |
| 258 | type T1 struct { |
| 259 | n int32 |
| 260 | z [0]byte |
| 261 | } |
| 262 | if unsafe.Sizeof(T1{}) != 8 { |
| 263 | t.Errorf("sizeof(%#v)==%d, want 8", T1{}, unsafe.Sizeof(T1{})) |
| 264 | } |
| 265 | type T2 struct { |
| 266 | n int64 |
| 267 | z struct{} |
| 268 | } |
Dan Willemsen | cc753b7 | 2021-08-31 13:25:42 -0700 | [diff] [blame] | 269 | if unsafe.Sizeof(T2{}) != 8+unsafe.Sizeof(uintptr(0)) { |
| 270 | t.Errorf("sizeof(%#v)==%d, want %d", T2{}, unsafe.Sizeof(T2{}), 8+unsafe.Sizeof(uintptr(0))) |
Dan Willemsen | 09eb3b1 | 2015-09-16 14:34:17 -0700 | [diff] [blame] | 271 | } |
| 272 | type T3 struct { |
| 273 | n byte |
| 274 | z [4]struct{} |
| 275 | } |
| 276 | if unsafe.Sizeof(T3{}) != 2 { |
| 277 | t.Errorf("sizeof(%#v)==%d, want 2", T3{}, unsafe.Sizeof(T3{})) |
| 278 | } |
| 279 | // make sure padding can double for both zerosize and alignment |
| 280 | type T4 struct { |
| 281 | a int32 |
| 282 | b int16 |
| 283 | c int8 |
| 284 | z struct{} |
| 285 | } |
| 286 | if unsafe.Sizeof(T4{}) != 8 { |
| 287 | t.Errorf("sizeof(%#v)==%d, want 8", T4{}, unsafe.Sizeof(T4{})) |
| 288 | } |
| 289 | // make sure we don't pad a zero-sized thing |
| 290 | type T5 struct { |
| 291 | } |
| 292 | if unsafe.Sizeof(T5{}) != 0 { |
| 293 | t.Errorf("sizeof(%#v)==%d, want 0", T5{}, unsafe.Sizeof(T5{})) |
| 294 | } |
| 295 | } |
| 296 | |
Dan Willemsen | 09eb3b1 | 2015-09-16 14:34:17 -0700 | [diff] [blame] | 297 | func TestAppendGrowth(t *testing.T) { |
| 298 | var x []int64 |
| 299 | check := func(want int) { |
| 300 | if cap(x) != want { |
| 301 | t.Errorf("len=%d, cap=%d, want cap=%d", len(x), cap(x), want) |
| 302 | } |
| 303 | } |
| 304 | |
| 305 | check(0) |
| 306 | want := 1 |
| 307 | for i := 1; i <= 100; i++ { |
| 308 | x = append(x, 1) |
| 309 | check(want) |
| 310 | if i&(i-1) == 0 { |
| 311 | want = 2 * i |
| 312 | } |
| 313 | } |
| 314 | } |
| 315 | |
| 316 | var One = []int64{1} |
| 317 | |
| 318 | func TestAppendSliceGrowth(t *testing.T) { |
| 319 | var x []int64 |
| 320 | check := func(want int) { |
| 321 | if cap(x) != want { |
| 322 | t.Errorf("len=%d, cap=%d, want cap=%d", len(x), cap(x), want) |
| 323 | } |
| 324 | } |
| 325 | |
| 326 | check(0) |
| 327 | want := 1 |
| 328 | for i := 1; i <= 100; i++ { |
| 329 | x = append(x, One...) |
| 330 | check(want) |
| 331 | if i&(i-1) == 0 { |
| 332 | want = 2 * i |
| 333 | } |
| 334 | } |
| 335 | } |
Dan Willemsen | 38f2dba | 2016-07-08 14:54:35 -0700 | [diff] [blame] | 336 | |
| 337 | func TestGoroutineProfileTrivial(t *testing.T) { |
| 338 | // Calling GoroutineProfile twice in a row should find the same number of goroutines, |
| 339 | // but it's possible there are goroutines just about to exit, so we might end up |
| 340 | // with fewer in the second call. Try a few times; it should converge once those |
| 341 | // zombies are gone. |
| 342 | for i := 0; ; i++ { |
| 343 | n1, ok := GoroutineProfile(nil) // should fail, there's at least 1 goroutine |
| 344 | if n1 < 1 || ok { |
| 345 | t.Fatalf("GoroutineProfile(nil) = %d, %v, want >0, false", n1, ok) |
| 346 | } |
| 347 | n2, ok := GoroutineProfile(make([]StackRecord, n1)) |
| 348 | if n2 == n1 && ok { |
| 349 | break |
| 350 | } |
| 351 | t.Logf("GoroutineProfile(%d) = %d, %v, want %d, true", n1, n2, ok, n1) |
| 352 | if i >= 10 { |
| 353 | t.Fatalf("GoroutineProfile not converging") |
| 354 | } |
| 355 | } |
| 356 | } |
Dan Willemsen | ebae302 | 2017-01-13 23:01:08 -0800 | [diff] [blame] | 357 | |
| 358 | func TestVersion(t *testing.T) { |
| 359 | // Test that version does not contain \r or \n. |
| 360 | vers := Version() |
| 361 | if strings.Contains(vers, "\r") || strings.Contains(vers, "\n") { |
| 362 | t.Fatalf("cr/nl in version: %q", vers) |
| 363 | } |
| 364 | } |