blob: 1ca1fa2f05ebe971bfd090dfa623a7d1879a4eb5 [file] [log] [blame]
Dan Willemsen38f2dba2016-07-08 14:54:35 -07001// Copyright 2012 The Go Authors. All rights reserved.
Brent Austinba3052e2015-04-21 16:08:23 -07002// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package runtime_test
6
7import (
Dan Willemsena3223282018-02-27 19:41:43 -08008 "flag"
Brent Austinba3052e2015-04-21 16:08:23 -07009 "io"
Brent Austinba3052e2015-04-21 16:08:23 -070010 . "runtime"
11 "runtime/debug"
Dan Willemsenebae3022017-01-13 23:01:08 -080012 "strings"
Brent Austinba3052e2015-04-21 16:08:23 -070013 "testing"
14 "unsafe"
15)
16
Dan Willemsena3223282018-02-27 19:41:43 -080017var flagQuick = flag.Bool("quick", false, "skip slow tests, for second run in all.bash")
18
Dan Willemsen38f2dba2016-07-08 14:54:35 -070019func 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 Austinba3052e2015-04-21 16:08:23 -070026var errf error
27
28func errfn() error {
29 return errf
30}
31
32func errfn1() error {
33 return io.EOF
34}
35
36func 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
46func 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 Willemsenbc60c3c2021-12-15 01:09:00 -080056var efaceCmp1 any
57var efaceCmp2 any
Dan Willemsend2797482017-07-26 13:13:13 -070058
59func 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 Cross430342c2019-09-07 08:36:04 -070073func 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 Austinba3052e2015-04-21 16:08:23 -070085func BenchmarkDefer(b *testing.B) {
86 for i := 0; i < b.N; i++ {
87 defer1()
88 }
89}
90
91func 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 Austinba3052e2015-04-21 16:08:23 -070097}
98
99func BenchmarkDefer10(b *testing.B) {
100 for i := 0; i < b.N/10; i++ {
101 defer2()
102 }
103}
104
105func 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
115func 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 Arruda748609c2020-06-25 12:12:21 -0700125func BenchmarkPanicRecover(b *testing.B) {
126 for i := 0; i < b.N; i++ {
127 defer3()
128 }
129}
130
131func 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 Austinba3052e2015-04-21 16:08:23 -0700140// golang.org/issue/7063
141func 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 Willemsen38f2dba2016-07-08 14:54:35 -0700154// addresses that normally an OS would reserve for itself, or malformed
Brent Austinba3052e2015-04-21 16:08:23 -0700155// addresses. Even so, we might have to remove one or two on different
156// systems. We will see.
157
158var 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
182func TestSetPanicOnFault(t *testing.T) {
Brent Austinba3052e2015-04-21 16:08:23 -0700183 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 Arruda748609c2020-06-25 12:12:21 -0700195// 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 Austinba3052e2015-04-21 16:08:23 -0700199func testSetPanicOnFault(t *testing.T, addr uintptr, nfault *int) {
Dan Willemsenc7413322018-08-27 23:21:26 -0700200 if GOOS == "js" {
201 t.Skip("js does not support catching faults")
202 }
Brent Austinba3052e2015-04-21 16:08:23 -0700203
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
218func 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
232func TestEqString(t *testing.T) {
Dan Willemsena3223282018-02-27 19:41:43 -0800233 // This isn't really an exhaustive test of == on strings, it's
Brent Austinba3052e2015-04-21 16:08:23 -0700234 // just a convenient way of documenting (via eqstring_generic)
Dan Willemsena3223282018-02-27 19:41:43 -0800235 // what == does.
Brent Austinba3052e2015-04-21 16:08:23 -0700236 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 Willemsena3223282018-02-27 19:41:43 -0800250 t.Errorf(`("%s" == "%s") = %t, want %t`, s1, s2, x, y)
Brent Austinba3052e2015-04-21 16:08:23 -0700251 }
252 }
253 }
254}
Dan Willemsen09eb3b12015-09-16 14:34:17 -0700255
256func 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 Willemsencc753b72021-08-31 13:25:42 -0700269 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 Willemsen09eb3b12015-09-16 14:34:17 -0700271 }
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 Willemsen09eb3b12015-09-16 14:34:17 -0700297func 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
316var One = []int64{1}
317
318func 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 Willemsen38f2dba2016-07-08 14:54:35 -0700336
337func 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 Willemsenebae3022017-01-13 23:01:08 -0800357
358func 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}